原创 STM8与汇编语言(16)--PWM

2010-6-13 09:42 5102 7 7 分类: MCU/ 嵌入式

                 STM8与汇编语言(16)--PWM<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />


 


在单片机应用系统中,也常常会用到PWM信号输出,例如电机转速的控制。现在很多高档的单片机也都集成了PWM功能模块,方便用户的应用。


对于PWM信号,主要涉及到两个概念,一个就是PWM信号的周期或频率,另一个就是PWM信号的占空比。例如一个频率为1KHZ,占空比为30%,有效信号为1PWM信号,在用示波器测量时,就是高电平的时间为300uS,低电平的时间为700uS的周期波形。


在单片机中实现PWM信号的功能模块,实际上就是带比较器的计数器模块。首先该计数器循环计数,例如从0N,那么这个N就决定了PWM的周期,PWM周期=N+1*计数器时钟的周期。在计数器模块中一定还有一个比较器,比较器有2个输入,一个就是计数器的当前值,另一个是可以设置的数,这个数来自一个比较寄存器。当计数器的值小于比较寄存器的值时,输出为1(可以设置为0),当计数器的值大于或等于比较寄存器的值时,输出为0(也可设置为1,与前面对应)。


了解了这个基本原理后,我们就可以使用STM8单片机中的PWM模块了。下面的实验程序首先将定时器2的通道2设置成PWM输出方式,然后通过设置自动装载寄存器TIM2_CCR2,决定PWM信号的周期。在程序的主循环中,循环修改占空比,先是从0逐渐递增到128,然后再从128递减到0


当把下面的程序在ST的三合一板上运行时,可以看到发光二极管LD1逐渐变亮,然后又逐渐变暗,就这样循环往复。如果用示波器看,可以看到驱动LD1的信号波形的占空比从0变到50%,然后又从50%变到0


同样还是利用ST的开发工具,生成一个汇编程序的框架,然后修改其中的main.asm,修改后的代码如下。


stm8/


 


       #include "mapping.inc"


       #include "STM8S<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />207C_S.INC"


 


; 定义堆栈空间的起始位置和结束位置


stack_start.w  EQU    $stack_segment_start


stack_end.w    EQU    $stack_segment_end


 


      


 


               segment 'rom'            ; 下面开始定义一个段,该段位于ROM


main.l                            ; 定义复位后的第一条指令的标号(即入口地址)


;


; 首先要初始化堆栈指针


        LDW     X,#stack_end         


        LDW     SP,X


;                                                                       


        CALL    CLK_Init          ; 初始化时钟


        CALL    TIM_Init          ; 初始化定时器       


;


; 下面的循环将占空比逐渐从0递增到128


        LD      A,#$00


MAIN_LOOP.L                      


        PUSH    A                 ; 保存当前占空比


        LD      A,#$00


        LD      TIM2_CCR2H,A


        POP     A


        LD      TIM2_CCR2L,A      ; 设置占空比


        PUSH    A                 ; 保存当前占空比


        LD      A,#$5             


        CALL    DELAY_MS          ; 延时5MS


        POP     A                 ; 恢复占空比 


        INC     A                 ; 当前占空比+1


        CP      A,#128             


        JRNE    MAIN_LOOP         ; 若不等于128,则循环


;


; 下面的循环将占空比逐渐128递减到0


MAIN_LOOP2.L                      


        PUSH    A                 ; 保存当前占空比


        LD      A,#$00


        LD      TIM2_CCR2H,A


        POP     A


        LD      TIM2_CCR2L,A      ; 设置占空比


        PUSH    A                 ; 保存当前占空比


        LD      A,#$5


        CALL    DELAY_MS          ; 延时5MS


        POP     A                 ; 恢复占空比 


        DEC     A                 ; 当前占空比-1


        CP      A,#$00


        JRNE    MAIN_LOOP2        ; 若不等于0,则循环


        


        JRA     MAIN_LOOP         ; 重新开始大循环


 


; 函数功能:延时


; 输入参数:寄存器A -- 要延时的毫秒数,这里假设CPU的主频为2MHZ


; 输出参数:无


; 值:无


;     注:无


DELAY_MS.L


        PUSH    A                 ; 将入口参数保存到堆栈中


        LD      A,#250            ; 寄存器A<-250,作为下面的循环数 


DELAY_MS_1.L


        NOP                       ; 用空操作指令进行延时4T


        NOP


        NOP


        NOP


        NOP


        DEC     A                 ; 寄存器A<-A-1,本条指令执行之间为1T


        JRNE    DELAY_MS_1        ; 若不等于0,则循环,


                                        ; 本条指令执行时间为2T(跳时)或1T(不跳时)


        POP     A                 ; 从堆栈中恢复入口参数


        DEC     A                 ; 将要延时的MS数-1 


        JRNE    DELAY_MS          ; 若不等于0,则循环


        RET                       ; 函数返回 


 


; 函数功能:初始化时钟


; 输入参数:无


; 输出参数:无


; 值:无


;     注:无


CLK_Init.L


        LD      A,#$E1


        LD      CLK_CMSR,A        ; HSI作为主时钟源


        LD      A,CLK_CKDIVR


        AND     A,#$E7


        OR      A,#$10


        LD      CLK_CKDIVR,A      ; 10: fHSI= fHSI RC output/ 4


                                  ; fHSI = fHSI RC输出/4 = 4MHZ


                                  ; 这个时钟也作为外设的时钟  


        OR      A,#$01


        LD      CLK_CKDIVR,A      ; 001: fCPU="fMASTER/2". = 2MHZ


        RET


;


; 函数功能:初始化定时器2的通道2,用于控制LED的亮度


; 输入参数:无


; 输出参数:无


; 值:无


;     注:无


TIM_Init.L


        LD      A,TIM2_CCMR2


        OR      A,#$70


        LD      TIM2_CCMR2,A ; Output mode PWM2.                      */


                             ; 通道2被设置成比较输出方式


                             ; OC2M = 111,PWM模式2


                             ; 向上计数时,若计数器小于比较值,为无效电平


                             ; 即当计数器在0到比较值时,输出为1,否则为0


    


        LD      A,TIM2_CCER1


        OR      A,#$30


        LD      TIM2_CCER1,A      ; CC polarity low,enable PWM output      */


                                  ; CC2P = 1,低电平为有效电平


                                  ; CC2E = 1,开启输出引脚                


   


;初始化自动装载寄存器,决定PWM方波的频率,Fpwm=4000000/256=15625HZ       


        LD      A,#$00


        LD      TIM2_ARRH,A


        LD      A,#$FF


        LD      TIM2_ARRL,A


       


;初始化比较寄存器,决定PWM方波的占空比             


        LD      A,#$00


        LD      TIM2_CCR2H,A


        LD      A,#$00


        LD      TIM2_CCR2L,A


       


;初始化时钟分频器为1,即计数器的时钟频率为Fmaster=4MHZ


        LD      A,#$00


        LD      TIM2_PSCR,A


;启动计数


        LD      A,TIM2_CR1


        OR      A,#$01


        LD      TIM2_CR1,A


        RET


 


 


  interrupt NonHandledInterrupt


NonHandledInterrupt.l


        iret


 


; 下面定义中断向量表      


        segment 'vectit'


        dc.l {$82000000+main}                       ; reset


        dc.l {$82000000+NonHandledInterrupt}    ; trap


        dc.l {$82000000+NonHandledInterrupt}    ; irq0


        dc.l {$82000000+NonHandledInterrupt}    ; irq1


        dc.l {$82000000+NonHandledInterrupt}    ; irq2


        dc.l {$82000000+NonHandledInterrupt}    ; irq3


        dc.l {$82000000+NonHandledInterrupt}    ; irq4


        dc.l {$82000000+NonHandledInterrupt}    ; irq5


        dc.l {$82000000+NonHandledInterrupt}    ; irq6


        dc.l {$82000000+NonHandledInterrupt}    ; irq7


        dc.l {$82000000+NonHandledInterrupt}    ; irq8


        dc.l {$82000000+NonHandledInterrupt}    ; irq9


        dc.l {$82000000+NonHandledInterrupt}    ; irq10


        dc.l {$82000000+NonHandledInterrupt}    ; irq11


        dc.l {$82000000+NonHandledInterrupt}    ; irq12


        dc.l {$82000000+NonHandledInterrupt}    ; irq13


        dc.l {$82000000+NonHandledInterrupt}    ; irq14


        dc.l {$82000000+NonHandledInterrupt}    ; irq15


        dc.l {$82000000+NonHandledInterrupt}    ; irq16


        dc.l {$82000000+NonHandledInterrupt}    ; irq17


        dc.l {$82000000+NonHandledInterrupt}    ; irq18


        dc.l {$82000000+NonHandledInterrupt}    ; irq19


        dc.l {$82000000+NonHandledInterrupt}    ; irq20


        dc.l {$82000000+NonHandledInterrupt}    ; irq21


        dc.l {$82000000+NonHandledInterrupt}    ; irq22


        dc.l {$82000000+NonHandledInterrupt}    ; irq23


        dc.l {$82000000+NonHandledInterrupt}    ; irq24


        dc.l {$82000000+NonHandledInterrupt}    ; irq25


        dc.l {$82000000+NonHandledInterrupt}    ; irq26


        dc.l {$82000000+NonHandledInterrupt}    ; irq27


        dc.l {$82000000+NonHandledInterrupt}    ; irq28


        dc.l {$82000000+NonHandledInterrupt}    ; irq29


 


       end


 


                       2010-6-13

文章评论0条评论)

登录后参与讨论
我要评论
0
7
关闭 站长推荐上一条 /2 下一条