本帖最后由 johnrey 于 2014-8-25 10:48 编辑
等灯等灯,就是各种调光模式的展示,比如预设、手动、自动调光等等,因此少不了和pwm打交道。pwm只在最近的STC上临时玩过一次,并无太多深入,这次看来要啃硬骨头了。虽说开发板自带的就有PWM的程序,可是不把其中的原理和控制寄存器搞清楚,要改个PWM的频率或是占空比,那也不是省心的事。之所以PWM看起来比较烦,是因为它通常是timer的其中一个功能,timer另有定时、计数、捕捉、脉冲输出等五花八门的功能,功能一多自然寄存器就多,想绕开其他功能只学pwm是不可能的。后面会看到,瑞萨的这个pwm还要两路timer协同工作才能输出,自然又增加了难度。所以,慢慢来看吧。对照开发板例程中的void TAU0_PWM_Init(void)函数,我们来细细学习timer的寄存器们,原版函数注释还是比较清晰的,只不过是英文的而已。看看下表,总共大概有15、6个寄存器。
首先要配置timer工作时钟,PER0.0是TAU0EN,用来使能时钟,TPS0则用来对时钟设置分频,这样有个好处,不用像51一样,上来就是固定1M频率,想定时长点都不行。TPS0分高4位和低4位,分频效果从不分频到2^15,所以可以得到两个时钟CK01和CK00。不过大家注意不要被名字搞糊涂了,两个ch都可以选CK01或CK00,而不是和名字一一对应。所以例程中TPS0 = 0x0F;就是选择了Fclk(/2^0)和Fclk/2^F(就是15),作为两个定时器的时钟源。一个处理高频,一个处理低频。
下面一组是用来控制定时器单元启停的TE、TS、TT。照理说TE0中的后两位是用来使能两个通道的,可是在初始化程序中死活找不到。最后还是官方文档给出了说明,就是不用直接操作啦,那要这个寄存器干啥??? TS0 |= 0x03; TT0 |= 0x03;分别表示启停两个通道。所以例程中写TT0 = 0x00U;表示停止all channel其实是不对的,不过好在TE0复位后本身是00,所以默认是停止的。
接着一组是用来控制输出的,TOE、TO、TOM、TOL。其中TOE控制管脚是否输出,TO控制输出高电平还是低电平,不过对于输出波形的话,这个电平有什么用呢?决定初始电平的吧?如果是这样,对方波是没啥影响的,对pwm可能有影响,比如影响PWM的初始电平(注:实验了一下,没有影响)。TOM是用来决定通道的独立性的。如果要上pwm,ch1必须位从属通道,所以TOM=0x02。这是确定的。TOL也是在联动时用的,但是说实话,文档看不懂。例程里设为0x02。大概实验一下,设0x02,占空,设0x00,占满。也就是PWM的初始电平由TOL决定。
对照着硬件说明书,再去看例程代码,例程有些设定就很无理了。比如通道0不输出,TOE0 |= ~0x01;这玩儿不能保证啥啊,应该是TOE0 &= ~0x01;吧??!!通道1输出,又写了2条,TO0 &= ~0x02; TO0 |= 0x02U;应该只要后面一句就可以了。两个通道的控制总的TO0=0x02就全部搞定了。
以上所说的是和定时器单元有关的,下面要考虑和每个定时器相关的了,共有4个,分别是TMR、TSR、TCR和TDR,PWM使用中只用到TMR(模式)和TDR(数据)。TCR是用来递增或递减的那位,一般不会去读取;而TSR只有在捕捉时才会用到。
TMR是这里的重头戏,每个通道有2个8位。TMR0xH和TMR0xL,必须连续存取,必须在停止的时候来设置。TMR0xH稍有不同,但是如果我们不把1通道用作两个8位的话,就是一样的。前4位是时钟选择bit7选择CK01或CK00,bit4选择计数是内时钟还是外部事件(选1表示从TI0x引入,这时候一般就是捕捉或者外部事件模式)。最后3位是触发模式选择,看了下例程,主通道一般都是000,软件触发;而从属通道,则要采用100,就是主通道的中断信号。这里的触发是指定时器开始工作吗?TMR0xL都一样,最高2位是输入用的,分别决定计数器对上升沿,下降沿或者是双沿发生响应,这个PWM用不到。最低4位用来指定模式,还是挺复杂的,大家可以去看表,对于PWM而言,主通道为间隔定时(决定周期),所以是0x01,从通道是单计数,所以是0x09。有一点要注意,pwm中,TMR00H和TMR01H的最高位必须相同。
至于每个模式中计数初值或者pwm占空比都是由TDR0xH和TDR0xL决定的,在通道1不拆分的情况下,都用做16bit,自动重载,重载的数值就在以上两个寄存器中。如果用作捕捉功能来测量周期或者脉宽的话,那么捕捉后的值就在这两个寄存器中。具体到PWM,通道0决定周期。TDR00设为4999,在5M的运行频率下,PWM频率就是是1KHz,控制的应该比较精细了。而TDR01的值则在0-4999之间变化。值越大,占空比越大,如果是控制板上的灯,那会越亮;后面通过基极去控制高亮LED,则越暗。
按照上面的学习,把官方板子例程做了修改,占空比增加速度为每次50,就是1%,减小速度位每次500,就是10%。所以是慢慢变亮,很快变暗。每一个变化周期为110个计数周期,才110ms。看下板上小灯效果,就是狂闪,算不上呼吸。看了看资料,人呼吸频率大概是16-20次每分钟,因此周期应该放大20-30倍比较合适。因此在每次中断时,增加了一个参数,cnt>29后才开始改变占空比,看下么又显太慢。最后cnt定在19,感觉差不多,2秒左右一个循环周期。还有一个问题就是,照片或者录像对光强的感应没有人眼那么强烈,在比较亮的时候,根本看不出变化,加上手头这破手机录像不带对焦功能,所以就不上录像了,大家可以下载附件,解压烧进去看下效果就行。呼吸速度的控制在最后的interrupt_inttm00()中断里面,if (cnt[0]>19),这里面的数控制呼吸的快慢,数越大,呼吸频率越低。Btw,代码在官方例程基础上修改,解压缩时请大家注意不要覆盖掉原版程序目录。
调试tips,只能打2个断点,必须吐槽。另外PWM把两路定时器全占了,资源还是有点紧缺的啊。