当前位置:   article > 正文

GNU ARM汇编--(九)s3c2440的PWM_s3c2440 的 pwm 模块的自动加载模式和双缓冲模式的主要作用。

s3c2440 的 pwm 模块的自动加载模式和双缓冲模式的主要作用。

        依旧从datasheet开始看起,锻炼下阅读英文技术手册的能力

PWM TIMER
概述
    s3c2440有5个16bit的定时器.Timer0,1,2和3有PWM功能.Timer4是没有输出管脚的内部定时器.Timer0有一个dead-zone产生器,用于大电流设备.
    Timer0和1共用一个8bit的预分频器,而timer2,3,4共用另外一个8bit的预分频器.每一个定时器都有一个时钟除法器,可以产生5个不同的除法信号(1/2,1/4,1/8,1/16和TCLK).每一个定时器从时钟除法器接收各自的时钟信号,除法器从各自的8bit预分频器接收时钟.8bit的预分频器是可编程控制的,将PCLK除成要加载的值,存在TCFG0和TCFG1中.
    当定时器启用时定时器计数缓冲寄存器(TCNTBn)将初始值加载到down-counter中.定时器比较缓冲寄存器(TCMPBn)将初始值加载到比较寄存器中与donw-counter的值比较.当频率变化时TCNTBn和TCMPBn的双缓冲属性保证定时器产生稳定的输出.
    每个定时器有自己的16bit down-counter,由定时器时钟驱动.当down-counter为0,定时器中断请求产生来通知CPU定时器操作以及完成了.当定时器的计数器为0,相关的TCNTBn的值会自动的加载到down-counter中来继续下一次操作.然而,当定时器停止,比如在定时器运行中清除TCONn的定时器使能位,TCNTBn不会重加载到计数器中.
    TCMPBn的值被用于PWM.当down-counter的值与比较寄存器的值吻合时,定时器控制逻辑会改变输出电平.所以比较寄存器决定PWM输出的打开时间.


属性
    5个16bit的定时器
    两个8bit的预分频器&两个4bit的除法器
    输出波形可编程控制
    自动重加载模式或one-shot pulse mode
    dead-zone产生器


PWM TIMER OPERATION
Prescaler&Divider


BASIC TIMER OPERATION
    一个定时器(除了5)有TCNTBn,TCNTn,TCMPBn和TCMPn.当定时器为0时TCNTBn和TCMPBn加载到TCNTn和TCMPn中.当TCNTn为0,如果中断开启的话就会产生一个中断请求.
    
AUTO RELOAD&DOUBLE BUFFERING
    PWM定时器有一个双缓冲功能,保证下次定时器操作时重加载的值改变时无需停止当前的定时器操作.所以新的定时器的值设定,当前的定时器操作也可以成功完成.
    定时器的值可以写到TCNTBn中,定时器的当前计数值可以从TCNTOn中读到.TCNTBn被读取的值,不表明计数器的当前状态,而是下一次定时器持续期间的重加载值.
    当TCNTn为0,自动重加载操作会复制TCNTBn到TCNTn中.如果TCNTn为0,而自动重加载的使能位为0,那么TCNTn不会再操作了.


TIMER INITIALIZATION USING MANUAL UPDATE BIT AND INVERTER BIT
    当down-counter为0,定时器的自动重加载操作就会动作.所以user要预先定义TCNTn的初始值.在这种情况下,初始值通过手动更新位进行加载.下面的步骤描述如何启动一个定时器:
    1.向TCNTBn和TCMPBn中些初始值
    2.设置定时器的手动更新位.推荐配置inverter on/off bit(不管用不用)
    3.设置定时器的开始位来启动定时器(同时清除手动更新位)
    如果定时器被强行停止,TCNTn保持计数器的值而且不会从TCNTBm中重加载.如果要设置一个新值,要执行手动更新.
    注意:不论何时TOUT inverter on/off bit被更改,在定时器运行时TOUTn的逻辑值都会改变.因此,最好在配置手动更新位的时候配置inverter on/off bit.
    TIMER OPERATION

上面的图是下面操作的结果:

1.使能自动重加载功能.设置TCNTBn为160(50+110),TCMPBn为110.设置手动更新位并配置反转位(on/off).手动更新位将TCNTn和TCMPn的值更新到TCNTBn和TCMPBn中.   接下来设置TCNTBn为80(40+40),TCMPBn为40,它们决定下一次重加载的值.

2.设置开始位,手动更新位设为0.关闭反转器,打开自动重加载.在等待时间后定时器开始计数

3.当TCNTn和TCMPn有相同的值时,TOUTn的逻辑电平由低变为高

4.当TCNTn为0时,中断请求产生,TCNTBn的值被加载到一个临时寄存器.在下次定时器周期,TCNTn会重载临时寄存器的值.

5.在中断服务例程中,TCNTBn设为80(20+60),TCMPBn设置为60,同样用于下一次周期.

6.当TCNTn和TCMPn有相同的值时,TOUTn的逻辑电平由低变为高

7.当TCNTn为0,TCNTn自动加载TCNTBn的值,触发中断请求.

8.在中断服务例程中自动重加载和中断请求被禁用,停止定时器

9.当TCNTn与TCMPn有相同值,TOUTn的逻辑电平由低变为高

10.即使TCNT0为0,因为自动重加载被禁用了所以TCNTn不会再重加载,定时器停止了

11.没有中断请求产生了


PULSE WIDTH MODULATION(PWM)

    通过使用TCMPBn来实现PWM功能.PWM的频率由TCNTBn来决定.
    减少TCMPBn的值可以有更高的PWM值.增加TCMPBn的值可以有更低的PWM值.如果输出反转使能了,增加和减少操作也要反转.
    双缓冲功能允许在ISR中将下一次PWM的TCMPBn的值在当前PWM的周期的任何一个时间点被写入.


OUTPUT LEVEL CONTROL

    假定反转功能时关闭的,下面的步骤描述如何保证TOUT是高还是低:
    1.关闭自动重加载位.TOUTn时高电平,当TCNTn为0时定时器停止.
    2.通过清除定时器的开始位来停止定时器.如果TCNTn<=TCMPn,输出高;如果TCNTn>TCMPn,输出低.
    3.可以通过TCON的反转开关来决定TOUT是否反转.反转器会移除额外的电流来适应输出电平.

PWM的各个寄存器描述

(注:因为TQ2440的板子是用TOUT0来控制蜂鸣器的,所以有些寄存器就不关注了)

定时器配置寄存器0(TCFG0)

定时器输入时钟周期 = PCLK/(prescaler + 1)/(divider value)

{prescaler} = 0~255

{divider value} = 2,4,8,16

Register            Address              R/W                           Description

TCFG0          0x51000000           R/W                       配置两个8的预分频器


TCFG0                               Bit                                           Description

Dead zone length             [23:16]                         死区的长度,长度等于timer0的单位长度

Prescaler1                        [15:8]                           这个是给Timer2 3 4用的

Prescaler0                        [7:0]                             这个是给Timer0 1用的


定时器配置寄存器1(TCFG1)

Register            Address                         R/W                                        Description 

TCFG1           0x51000004                     R/W                               5路MUX和DMA模式选择寄存器


TCFG1                  Bit                                       Description                

DMA mode          [23:20]                           选择DMA请求通道

                                                                  0000=No select  0001=Timer0 0010=Timer1  

                                                                  0011=Timer2 0100=Timer3  0101=Timer4 

MUX4                  [19:16]                           为PWM Timer4选择复用输入

                                                                   0000=1/2 0001=1/4 0000=1/8

                                                                   0011=1/16  01xx=External TCLK1

MUX3                  [15:12]                            为PWM Timer3选择复用输入

                                                                    0000=1/2 0001=1/4 0000=1/8

                                                                    0011=1/16  01xx=External TCLK1

MUX2                  [11:8]                              为PWM Timer2选择复用输入

                                                                    0000=1/2 0001=1/4 0000=1/8

                                                                    0011=1/16  01xx=External TCLK1

MUX1                  [7:4]                               为PWM Timer1选择复用输入

                                                                    0000=1/2 0001=1/4 0010=1/8

                                                                    0011=1/16  01xx=External TCLK1

MUX0                  [3:0]                               为PWM Timer0选择复用输入

                                                                    0000=1/2 0001=1/4 0010=1/8

                                                                    0011=1/16  01xx=External TCLK1


Timer控制寄存器     
Register                  Address              R/W                  Description
TCON                     0x51000008        R/W             定时器控制寄存器

TCON                                        Bit                       Descrption         
Dead zone enable                     [4]                      决定死区的操作 0=disable 1=enable
Timer0 auto reload on/off          [3]                      决定Timer0的自动重载 0=one-shot 1=auto reload
Timer0 output inverter on/off     [2]                      决定Timer0的输出电平反转开关0=关闭 1=打开TOUT0的反转
Timer0手动更新(注意)               [1]                      决定Timer0的手动更新位0=不操作  1=更新TCNTB0&TCMPB0
Timer0开始/停止                        [0]                      决定Timer0的开始/关闭0=停止  1=开启
注意:在下次写之前要被清除

Timer0 COUNT BUFFER REGISTER & COMPARE BUFFER REGISTER(TCNTB0/TCMPB0)
Register                      Address                          R/W                                         Description
TCNTB0                     0x5100000c                    R/W                                         Timer0计数缓冲寄存器
TCMPB0                     0x51000010                   R/W                                          Timer0比较缓冲寄存器

TCMPB0                                                  Bit                                              Description
定时器比较缓冲寄存器                            [15:0]                                   为Timer0设置比较缓冲值
TCNTB0                                                   Bit                                              Description
定时器计数缓冲寄存器                            [15:0]                                    为Timer0设置计数缓冲值

Timer0计数观察寄存器(TCNTO0)
Register                          Address                  R/W                                         Description
TCNTO0                         0x51000014             R                                     Timer0计数观察寄存器

按照datasheet的一些说明和步骤,给出汇编代码:
  1. /*
  2. copyleft@ dndxhej@gmail.com
  3. */
  4. .equ NOINT, 0xc0
  5. .equ GPBCON, 0x56000010 @led
  6. .equ GPBDAT, 0x56000014 @led
  7. .equ GPBUP, 0x56000018 @led
  8. .equ GPFCON, 0x56000050 @interrupt config
  9. .equ EINTMASK, 0x560000a4
  10. .equ EXTINT0, 0x56000088
  11. .equ EXTINT1, 0x5600008c
  12. .equ EXTINT2, 0x56000090
  13. .equ INTMSK, 0x4A000008
  14. .equ EINTPEND, 0x560000a8
  15. .equ SUBSRCPND, 0x4a000018
  16. .equ INTSUBMSK, 0x4a00001c
  17. .equ SRCPND, 0X4A000000
  18. .equ INTPND, 0X4A000010
  19. .equ GPHCON, 0x56000070
  20. .equ GPHDAT, 0x56000074
  21. .equ GPB5_out, (1<<(5*2))
  22. .equ GPB6_out, (1<<(6*2))
  23. .equ GPB7_out, (1<<(7*2))
  24. .equ GPB8_out, (1<<(8*2))
  25. .equ GPBVALUE, (GPB5_out | GPB6_out | GPB7_out | GPB8_out)
  26. .equ LOCKTIME, 0x4c000000
  27. .equ MPLLCON, 0x4c000004
  28. .equ UPLLCON, 0x4c000008
  29. .equ M_MDIV, 92
  30. .equ M_PDIV, 1
  31. .equ M_SDIV, 1
  32. .equ U_MDIV, 56
  33. .equ U_PDIV, 2
  34. .equ U_SDIV, 2
  35. .equ CLKDIVN, 0x4c000014
  36. .equ DIVN_UPLL, 0
  37. .equ HDIVN, 1
  38. .equ PDIVN, 1 @FCLK : HCLK : PCLK = 1:2:4
  39. .equ WTCON, 0x53000000
  40. .equ Pre_scaler, 249
  41. .equ wd_timer, 1
  42. .equ clock_select, 00 @316
  43. .equ int_gen, 1 @开中断
  44. .equ reset_enable, 0 @关掉重启信号
  45. .equ WTDAT,0x53000004
  46. .equ Count_reload,50000 @定时器定为2S PCLK = 100M PCLK/(Pre_scaler+1)/clock_select = 100M/(249+1)/16=25k 50000/25k=2s
  47. .equ WTCNT,0x53000008
  48. .equ Count,50000
  49. .equ TCFG0,0x51000000
  50. .equ Prescaler1,0x00 @[15:8]Timer234
  51. .equ Prescaler0,249 @[7:0]Timer01
  52. .equ TCFG1,0x51000004
  53. .equ DMA_MODE,0x0 @[23:20]no dma channal
  54. .equ MUX0,0x2 @[3:0] 1/8
  55. @定时器输入时钟周期 = PCLK/(prescaler + 1)/(divider value)
  56. @clk = 100M/(249+1)/8=25k
  57. .equ TCON,0x51000008
  58. .equ DZ_eable,0 @[4]关闭死区的操作
  59. .equ auto_reload,1 @[3]auto_reload
  60. .equ inverter,1 @[2]打开电平反转
  61. .equ man_update,1 @[1]手动更新
  62. .equ clear_man_update,0
  63. .equ start,1 @[0]开始
  64. .equ stop,0 @[0]停止
  65. .equ TCNTB0,0x5100000c
  66. .equ TCMPB0,0x51000010
  67. .equ TCNTO0,0x51000014
  68. .equ ULCON0, 0x50000000
  69. .equ IR_MODE, 0x0 @[6]正常模式
  70. .equ Parity_Mode, 0x0 @[5:3]无校验位
  71. .equ Num_of_stop_bit, 0x0 @[2]一个停止位
  72. .equ Word_length, 0b11 @[1:0]8个数据位
  73. .equ UCON0, 0x50000004
  74. .equ FCLK_Div, 0 @[15:12] 时钟源选择用PCLK,所以这里用默认值
  75. .equ Clk_select, 0b00 @[11:10] 时钟源选择使用PCLK
  76. .equ Tx_Int_Type, 1 @[9] 中断请求类型为Level
  77. .equ Rx_Int_Type, 0 @1 @[8] 中断请求类型为Level
  78. .equ Rx_Timeout, 0 @[7]
  79. .equ Rx_Error_Stat_Int, 1 @[6]
  80. .equ Loopback_Mode, 0 @[5] 正常模式
  81. .equ Break_Sig, 0 @[4] 不发送终止信号
  82. .equ Tx_Mode, 0b01 @[3:2] 中断请求或轮循模式
  83. .equ Rx_Mode, 0b01 @[1:0] 中断请求或轮循模式
  84. .equ UFCON0, 0x50000008
  85. .equ Tx_FIFO_Trig_Level, 0b00 @[7:6]
  86. .equ Rx_FIFO_Trig_Level, 0b00 @[5:4]
  87. .equ Tx_FIFO_Reset, 0b0 @[2]
  88. .equ Rx_FIFO_Reset, 0b0 @[1]
  89. .equ FIFO_Enable, 0b0 @[0] 非FIFO模式
  90. .equ UMCON0, 0x5000000C @这个寄存器可以不管的
  91. .equ UTRSTAT0, 0x50000010
  92. .equ UERSTAT0, 0x50000014
  93. .equ UFSTAT0, 0x50000018
  94. .equ UMSTAT0, 0x5000001C
  95. .equ UTXH0, 0x50000020 @(L 小端)
  96. .equ URXH0, 0x50000024 @(L 小端)
  97. .equ UBRDIV0, 0x50000028
  98. .equ UBRDIV, 0x35 @PCLK=400M/4=100M UBRDIV = (int)(100M/115200/16) - 1 = 53 = 0x35
  99. .global Buzzer_Freq_Set
  100. .global _start
  101. _start: b reset
  102. ldr pc, _undefined_instruction
  103. ldr pc, _software_interrupt
  104. ldr pc, _prefetch_abort
  105. ldr pc, _data_abort
  106. ldr pc, _not_used
  107. @b irq
  108. ldr pc, _irq
  109. ldr pc, _fiq
  110. _undefined_instruction: .word undefined_instruction
  111. _software_interrupt: .word software_interrupt
  112. _prefetch_abort: .word prefetch_abort
  113. _data_abort: .word data_abort
  114. _not_used: .word not_used
  115. _irq: .word irq
  116. _fiq: .word fiq
  117. .balignl 16,0xdeadbeef
  118. reset:
  119. ldr r3, =WTCON
  120. mov r4, #0x0
  121. str r4, [r3] @ disable watchdog
  122. ldr r0, =GPBCON
  123. ldr r1, =0x15400 @这个时候暂不配置GPB0为TOUT0,这时候只是配置GPB0为TOUT0
  124. str r1, [r0]
  125. ldr r2, =GPBDAT
  126. ldr r1, =0x160
  127. str r1, [r2]
  128. bl clock_setup
  129. bl uart_init
  130. //bl delay
  131. msr cpsr_c, #0xd2 @进入中断模式
  132. ldr sp, =3072 @中断模式的栈指针定义
  133. msr cpsr_c, #0xd3 @进入系统模式
  134. ldr sp, =4096 @设置系统模式的栈指针
  135. @--------------------------------------------
  136. ldr r0, =GPBUP
  137. ldr r1, =0x03f0
  138. str r1, [r0]
  139. ldr r0, =GPFCON
  140. ldr r1, =0x2ea@0x2
  141. str r1, [r0]
  142. ldr r0, =EXTINT0
  143. @ldr r1, =0x8f888@0x0@0x8f888 @~(7|(7<<4)|(7<<8)|(7<<16)) //低电平触发中断
  144. ldr r1, =0xafaaa@0x0@0x8f888 //下降沿触发中断
  145. str r1, [r0]
  146. ldr r0, =EINTPEND
  147. ldr r1, =0xf0@0b10000
  148. str r1, [r0]
  149. ldr r0, =EINTMASK
  150. ldr r1, =0x00@0b00000
  151. str r1, [r0]
  152. ldr r0, =SRCPND
  153. ldr r1, =0x3ff@0x1@0b11111
  154. str r1, [r0]
  155. ldr r0, =SUBSRCPND
  156. ldr r1, =0x1<<13
  157. str r1, [r0]
  158. ldr r0, =INTPND
  159. ldr r1, =0x3ff@0x1@0b11111
  160. str r1, [r0]
  161. ldr r0, =INTSUBMSK
  162. ldr r1, =0x0<<13
  163. str r1, [r0]
  164. ldr r0, =INTMSK
  165. ldr r1, =0xfffff000@0b00000
  166. str r1, [r0]
  167. MRS r1, cpsr
  168. BIC r1, r1, #0x80
  169. MSR cpsr_c, r1
  170. bl main
  171. irq:
  172. sub lr,lr,#4
  173. stmfd sp!,{r0-r12,lr}
  174. bl irq_isr
  175. ldmfd sp!,{r0-r12,pc}^
  176. irq_isr:
  177. ldr r2, =GPBDAT
  178. ldr r1, =0x0e0
  179. str r1, [r2]
  180. ldr r0,=EINTPEND
  181. ldr r1,=0xf0
  182. str r1,[r0]
  183. ldr r0, =SRCPND
  184. ldr r1, =0x3ff@0b11111
  185. str r1, [r0]
  186. ldr r0, =SUBSRCPND
  187. ldr r1, =0x3ff@0x1<<13
  188. str r1, [r0]
  189. ldr r0, =INTPND
  190. ldr r1, =0x3ff@0b11111
  191. str r1, [r0]
  192. mov pc,lr
  193. delay:
  194. ldr r3,=0xffffff
  195. delay1:
  196. sub r3,r3,#1
  197. cmp r3,#0x0
  198. bne delay1
  199. mov pc,lr
  200. clock_setup:
  201. ldr r0,=LOCKTIME
  202. ldr r1,=0xffffffff
  203. str r1, [r0]
  204. ldr r0,=CLKDIVN
  205. ldr r1,=(DIVN_UPLL<<3) | (HDIVN<<1) | (PDIVN<<0)
  206. str r1, [r0]
  207. ldr r0,=UPLLCON
  208. ldr r1,=(U_MDIV<<12) | (U_PDIV<<4) | (U_SDIV<<0) @Fin=12M UPLL=48M
  209. str r1, [r0]
  210. nop
  211. nop
  212. nop
  213. nop
  214. nop
  215. nop
  216. nop
  217. ldr r0,=MPLLCON
  218. ldr r1,=(M_MDIV<<12) | (M_PDIV<<4) | (M_SDIV<<0) @Fin=12M FCLK=400M
  219. str r1, [r0]
  220. mov pc,lr
  221. uart_init:
  222. ldr r0,=GPHCON
  223. ldr r1,=0x2aaaa @配置GPIO复用规则为串口
  224. str r1, [r0]
  225. ldr r0,=ULCON0
  226. ldr r1,=(IR_MODE<<6) | (Parity_Mode<<3) | (Num_of_stop_bit<<2) | (Word_length<<0) @
  227. str r1, [r0]
  228. ldr r0,=UCON0
  229. ldr r1,=(FCLK_Div<<12) | (Clk_select<<10) | (Tx_Int_Type<<9) | (Rx_Int_Type<<8) | (Rx_Timeout<<7) | (Rx_Error_Stat_Int<<6) |(Loopback_Mode<<5) | (Break_Sig<<4) | (Tx_Mode<<2) | (Rx_Mode<<0)
  230. str r1, [r0]
  231. ldr r0,=UFCON0
  232. ldr r1,=(Tx_FIFO_Trig_Level<<6) | (Rx_FIFO_Trig_Level<<4) | (Tx_FIFO_Reset<<2) | (Rx_FIFO_Reset<<1) | (FIFO_Enable<<0) @
  233. str r1, [r0]
  234. ldr r0,=UBRDIV0
  235. ldr r1,=(UBRDIV<<0)
  236. str r1, [r0]
  237. mov pc,lr
  238. Buzzer_Freq_Set:
  239. //ldr r0, =GPBCON
  240. //ldr r1, =0x15400 @这个时候暂不配置GPB0为TOUT0,这时候只是配置GPB0为TOUT0
  241. //str r1, [r0]
  242. ldr r2, =GPBDAT
  243. ldr r1, =0x1c1
  244. str r1, [r2]
  245. ldr r2, =GPBCON
  246. ldr r1,[r2]
  247. ldr r1,[r1]
  248. //ldr r1, =0x15400
  249. bic r1,r1,#0x3
  250. orr r1,r1,#0x2
  251. str r1,[r2]
  252. ldr r2, =GPBDAT
  253. ldr r1, =0x1a0
  254. str r1, [r2]
  255. ldr r1,=TCFG0
  256. ldr r2,=(Prescaler0<<0)
  257. str r2, [r1]
  258. ldr r1,=TCFG1
  259. ldr r2,=(DMA_MODE<<20) | (MUX0<<0)
  260. str r2, [r1]
  261. // ldr r3,[r0]
  262. // str r3,[r2]
  263. //mov r2, r0
  264. ldr r1,=TCNTB0
  265. //ldr r2,=200
  266. str r0, [r1]
  267. mov r0,r0,LSR #2
  268. ldr r1,=TCMPB0
  269. //ldr r2,=50
  270. str r0, [r1]
  271. ldr r1,=TCON
  272. ldr r2,=(DZ_eable<<4) | (auto_reload<<3) | (inverter<<2) | (man_update<<1) | (start<<0)
  273. str r2, [r1]
  274. ldr r1,=TCON
  275. ldr r2,=(DZ_eable<<4) | (auto_reload<<3) | (inverter<<2) | (clear_man_update<<1) | (start<<0)
  276. str r2, [r1]
  277. ldr r2, =GPBDAT
  278. ldr r1, =0x1a0
  279. str r1, [r2]
  280. mov pc,lr
  281. main:
  282. ldr r1,=TCON
  283. ldr r2,=(DZ_eable<<4) | (auto_reload<<3) | (inverter<<2) | (man_update<<1) | (stop<<0)
  284. str r2, [r1]
  285. ldr lr, =loop
  286. ldr pc, _pwm_uart_test
  287. _pwm_uart_test: .word pwm_uart_test
  288. loop:
  289. b loop @ 死循环
  290. undefined_instruction:
  291. nop
  292. software_interrupt:
  293. nop
  294. prefetch_abort:
  295. nop
  296. data_abort:
  297. nop
  298. not_used:
  299. nop
  300. fiq:
  301. nop



pwm_uart_test.c内容如下:
  1. #include "pwm_uart_test.h"
  2. extern void Buzzer_Freq_Set(int freq);
  3. //extern void Buzzer_Freq_Set( void );
  4. char uart_GetByte(void)
  5. {
  6. while(!(rUTRSTAT0 & 0x1)); //Wait until THR is empty.
  7. return RdURXH0();
  8. }
  9. void uart_GetString(char *pt)
  10. {
  11. while(*pt)
  12. uart_GetByte();
  13. }
  14. void uart_SendByte(int data)
  15. {
  16. if(data=='\n')
  17. {
  18. while(!(rUTRSTAT0 & 0x2));
  19. WrUTXH0('\r');
  20. }
  21. while(!(rUTRSTAT0 & 0x2)); //Wait until THR is empty.
  22. WrUTXH0(data);
  23. }
  24. //====================================================================
  25. void uart_SendString(char *pt)
  26. {
  27. while(*pt)
  28. uart_SendByte(*pt++);
  29. }
  30. void uart_test(void)
  31. {
  32. char str[20] = "\nhello world\n";
  33. int a = 97;
  34. //while(1)
  35. // uart_SendByte(a);
  36. uart_SendString(str);
  37. char s = uart_GetByte();
  38. //if(s == 'a')
  39. if(s == 97)
  40. rGPBDAT = 0x1c0;
  41. //uart_SendByte(a);
  42. //uart_SendByte(97);
  43. //uart_SendByte('a');
  44. uart_SendByte((int)s);
  45. uart_SendByte((int)'s');
  46. }
  47. void pwm_uart_test(void)
  48. {
  49. int freq = 10;
  50. Buzzer_Freq_Set( freq ) ;
  51. //Buzzer_Freq_Set( ) ;
  52. uart_SendString("start\n");
  53. /*
  54. int i;
  55. for(i=0;i<1000;i++)
  56. uart_SendString("wait\n");
  57. while( 1 )
  58. {
  59. char key = uart_GetByte();
  60. uart_SendByte(key);
  61. if( key == 'a' || key == 'A' )
  62. {
  63. if( freq < 2000 ) //lci 20000
  64. freq += 10 ;
  65. uart_SendByte('a');
  66. Buzzer_Freq_Set( freq ) ;
  67. }
  68. if( key == 'b' || key == 'B' )
  69. {
  70. if( freq > 11 )
  71. freq -= 10 ;
  72. uart_SendByte('b');
  73. Buzzer_Freq_Set( freq ) ;
  74. }
  75. //uart_SendString( "\tFreq = %d\n", freq ) ;
  76. //if( key == ESC_KEY )
  77. //{
  78. // Buzzer_Stop() ;
  79. // return ;
  80. //}
  81. }
  82. */
  83. }


在这个例子中,既有汇编调用c,也有c调用汇编.可供以后参考.目前,串口输入还有些问题,还得继续调一下.串口遇到一个想不明白的问题,单单串口是正常的,但在打开PWM定时器后,串口就出问题了,打印只能出前面几个字符,这是个神马情况,有人知道的请帮我下,thks!

从代码中有这样的设定:
定时器的输入时钟为@定时器输入时钟周期 = PCLK/(prescaler + 1)/(divider value)
@clk = 100M/(249+1)/8=25k


TCNTB0设为200,而TCMPB0为50,则TOUT0输出占空比为25%的方波,方波的周期为200/clk=8ms

如果有示波器,倒可以验证一下这个结果.如果有对朋友觉得这个方波估计的不对,欢迎指出,谢谢!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/75983
推荐阅读
相关标签
  

闽ICP备14008679号