打印
[PIC®/AVR®/dsPIC®产品]

请问谁能解释下PIC单片机10位PWM与8位计数寄存器的关系?

[复制链接]
6212|18
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
panxiaoyi|  楼主 | 2021-7-30 17:48 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式


请问谁能解释一下PIC单片机10位PWM与8位计数寄存器的关系?

大家好,我在使用 PIC18F27Q10 的 PWM4 与 TIM2 计数器时,看了好几个不同型号的 PIC 手册,它们都讲述了【脉宽调制 PWM】(不是捕捉/比较/PWM 模块)

其中,PWM的比较匹配寄存器(设置占空比)是 H 和 L 组成 10 位,但是,计数寄存器 T2_TMR 却是 8 位的,而且周期寄存器 T2_PR 也是 8 位的

比如说,设置 PR=123,那么 TMR 计数到 123+1 时就会清零重新计数,而 TMR 的后分频器会 ++1 ,这样说来,这时候的 TMR 要么是8位的,要么就是逢 124 进 1 的相当于大于8位的寄存器

这时候,上面的 10 位比较寄存器 H 和 L 怎样和这个 TMR 比较呢 ?

就是说, PWM 的频率怎样计数 ?占空比怎样计数 ?

备注,如果按8位,就很好计算,频率 = 计数时钟  / ( 计数周期值+1)

使用特权

评论回复
沙发
panxiaoyi|  楼主 | 2021-7-30 17:58 | 只看该作者
本帖最后由 panxiaoyi 于 2021-7-30 19:46 编辑

单纯请教不好意思,发个小例子,独立按键处理例子,包括长按 、短按,按键防抖动

【独立按键处理】PIC18F27Q10.rar

264.85 KB

使用特权

评论回复
板凳
panxiaoyi|  楼主 | 2021-7-30 18:03 | 只看该作者
本帖最后由 panxiaoyi 于 2021-7-30 19:58 编辑

下面是我编写的最简单的PWM例子,我就很困惑,寄存器 H 和 L 怎样和 T2PR 比较?

#include "Configuration.h"
#include <xc.h>

void TIM2_Init(void)
{
    T2PR=200;
    T2CLKCON = 1;                            //时钟选择Fosc/4
    T2CON = 0xF0;                            //对输入时钟进行128分频,启动T2
}

void PWM3_PulseWidth(unsigned short width)  //脉冲宽度调整函数
{
    unsigned short temp = width;
    unsigned char* p;
    temp<<=6;
    p=&temp;
    PWM3DCH = *(p+1);
    PWM3DCL = *p;;
}

void PWM3_Init(void)
{
    RC5PPS = 0x07;                            //PWM3输出映射到端口
    TRISC &= !(1<<5);                         //IO口输出PWM
    PWM3_PulseWidth(0);                       //3设置脉冲宽度
    PWM3CON = 0x80;                           //启动PWM

    TIM2_Init();
}

void main(void)
{
    PWM3_Init();
    PWM3_PulseWidth(570);
    while(1);
    return;
}


使用特权

评论回复
地板
panxiaoyi|  楼主 | 2021-7-30 22:22 | 只看该作者
本帖最后由 panxiaoyi 于 2021-8-2 21:00 编辑

自己回复的,没用,后面已经更新

使用特权

评论回复
5
panxiaoyi|  楼主 | 2021-7-30 22:31 | 只看该作者
本帖最后由 panxiaoyi 于 2021-8-2 21:01 编辑

自己回复的,没用,后面已经更新,但是上面的代码是正确的

使用特权

评论回复
6
cooldog123pp| | 2021-7-31 15:13 | 只看该作者
虽然我不是很明白,但是路过了就帮忙楼主顶贴一下,希望楼主问题早日解决。

使用特权

评论回复
7
panxiaoyi|  楼主 | 2021-7-31 16:56 | 只看该作者
上面说的比较模糊,但是代码是可以正常运行的,下面是我的理解:

00:假设单片机是 PIC18F27Q10,使用 PWM3。
01:默认使用 8 位计数器 T2 ,计数寄存器 T2TMR 在时钟脉冲的输入下不断 +1,最大值等于周期寄存器 T2PR 的值。
02:当 T2TMR 达到最大值后,再来壹个计数时钟,则 T2TMR 清零,同时后分频计数器 +1,请注意,后分频计数器是隐藏的。
03:隐藏的后分频计数器不断与 OUTPS ( 后分频设置 ) 的值比较,当相等时,中断标记置位,这时隐藏的后分频计数器是否会清零还有待考证
04:PWM3 的占空比寄存器由 PWM3DCH 和 PWM3DCL 组成,简称 HL 。
05:假设用户的占空比输入数是 u16 A=123,则先将 A 的值左移 6 位,即数据左对齐,然后再把这个数值赋值给占空比寄存器 HL 。
06:重点,用户输入的占空比最大值是 1023,即 10Bit ,那它怎样和上面 8 位的 T2 计数器比较从而改变 PWM 的占空比或者频率呢。
07:答案就是,这个 PWM 很奇葩,PWM 脉宽占空比 = A /(( T2PR + 1 )* 4 ) ,其中 4 是常数。PWM 频率 = T2时钟 / T2PR
08:在上面的式子  A /(( T2PR + 1 )* 4 )中,由于分子是可以连续变化的用户输入值,而分母是壹个能被4整除的数。
09:如果用户输入占空比 A=120 或 121、122、123,由于只有120能被4整除,因此,这 4 个数的占空比是否相同?这还有待考证
10:在 T2TMR 由最大值变成清零时,PWM 默认输出高电平,在 (( T2TMR + 1 )* 4 )达到占空比 A 时,PWM默认输出零电平
11:在首个 PWM 运行周期时,即 T2TMR 由 0 增加到最大值时,PWM3 没有输出。

希望有经验的人能帮我指正一下,谢谢

使用特权

评论回复
8
panxiaoyi|  楼主 | 2021-7-31 17:11 | 只看该作者
由于没有示波器,而 PICkit3 下载这个 128K 的单片机速度奇慢,仿真也很慢,比如,单步仿真,考证 T2TMR 计数与其它设置的关系,每考证一个东西都要等待一个漫长的时间

使用特权

评论回复
9
panxiaoyi|  楼主 | 2021-7-31 18:30 | 只看该作者
经仿真测试,上面的第 3 条已经证实,中断标记置位,这时隐藏的后分频计数器会清零
但是第 9 条就真的不知道要用什么方法去验证了

使用特权

评论回复
10
panxiaoyi|  楼主 | 2021-7-31 18:37 | 只看该作者
更正一下,第 7 条,应该是:  PWM 频率 = T2时钟 / ( T2PR + 1 ),其中,T2PR 的最大值是 255

使用特权

评论回复
11
panxiaoyi|  楼主 | 2021-8-2 20:57 | 只看该作者
总算理解了,总结如下:

【 PIC单片机10位PWM脉宽调制学习总结 】

00:假设单片机是 PIC18F27Q10,使用 PWM3。默认使用 8 位计数器 T2 。

01:计数寄存器 T2TMR 在时钟脉冲的输入下不断 +1,最大值 = 周期寄存器 T2PR 的值, 封顶是 255 。

02:当 T2TMR 达到最大值后,再来壹个计数时钟,则 T2TMR 清零,同时隐藏的后分频计数器 +1。

03:隐藏的后分频计数器 = OUTPS ( 后分频设置 ) 的值时,中断标记置位,再下个时钟所有计数器清零。

04:PWM3 的占空比寄存器由 PWM3DCH 和 PWM3DCL 组成,简称 HL 。

05:设占空比输入数是 A=570,则先将 A 的值左移 6 位,变成 A=2280,然后再把这个数赋值给占空比寄存器 HL 。

06:PWM 频率 = 分频后的T2时钟 /( T2PR + 1 )。

07:在 T2TMR 由最大值变成清零后,再来一个时钟,PWM 默认输出高电平。

08:在 T2 计数值 = 占空比 A=570 时,PWM 默认由高电平变为零电平,这个 T2 计数值请看下面详解。

19:在首个 PWM 运行周期时,即 T2TMR 由 0 增加到最大值时,PWM3 没有输出。

10:内部时钟选择 Fosc/4 和 MFINTOSC(31 kHz)都可以。选择 Fosc 、HFINTOSC 、LFINTOSC 则 PWM 异常

下面的是重点,PWM 输出占空比 与 T2计数值 可以这样理解:

首先,我们把 T2计数值 看成是这样的: B7_B6_B5_B4_B3_B2_B1_B0_b1_b0 ,即高 8 位 + 低 2 位组成10位。

其中高 8 位可以理解成 T2TMR ,低 2 位可以理解成是隐藏的计数。

然后,它们是这样计数的 :B7_B6_B5_B4_B3_B2_B1_B0_b1_b0 <—— 时钟从这个小写的 b0 开始输入计数。

假设我们看到的 T2MR 计数到 123,事实上是 123左移2位后 = 492,然后 492 再 + 0 或者 1 或者 2 或者 3

这样,我们就得到了一个最大可以是10位的计数,我们把它叫做 真值。

最后,这个真值就可以和用户输入的A值进行比较了,当它们相对时,PWM默认由高电平变成低电平

请注意,占空比 A 的值 不能大于(( T2PR + 1 )* 4 )。最大1023

设:内部震荡时钟=64MHz,预分频=128,周期值T2PR=200,用户输入占空比=570

如果T2输入时钟 =(Fosc/4)时钟 = 64000000/4=16MHz

则:PWM频率  = 16000000 /((200+1 ) * 128 )= 622 Hz

如果T2输入时钟 = MFINTOSC(31 kHz),则

则:PWM频率  = 31000 /((200+1 ) * 128 )= 1.2 Hz

脉宽占空比 = 570 /(( 200+1 )* 4 )= 71 % ( 此时T2计数到0b10001110_10后PWM电平翻转 )

其中我们仿真时可以看到 T2TMR 的 8 位值是 0b10001110,后面的两位 10 是“隐藏的”


使用特权

评论回复
12
panxiaoyi|  楼主 | 2021-8-2 21:05 | 只看该作者
以前用AVR或者51,还有刚刚学的32位机,都没有遇到过这种奇葩的设计,这个问题烧了我几天的脑,^_^

使用特权

评论回复
13
lcczg| | 2021-8-3 10:27 | 只看该作者
感谢楼主的详细分析。从datasheet看,T2的时钟只能是 FOSC/4.
It is required to have FOSC/4 as the selected clock input to the timer for correct PWM operation.

使用特权

评论回复
14
panxiaoyi|  楼主 | 2021-8-4 22:05 | 只看该作者
刚刚使用MCC试看了一下,生成如下代码
 void PWM3_LoadDutyValue(uint16_t dutyValue)
{
     // Writing to 8 MSBs of PWM duty cycle in PWMDCH register
     PWM3DCH = (dutyValue & 0x03FC)>>2;
     
     // Writing to 2 LSBs of PWM duty cycle in PWMDCL register
     PWM3DCL = (dutyValue & 0x0003)<<6;
}
请问,上面的这些代码是不是不够严谨?16位赋值给8位可以理解,但是还要先运算再赋值,如果不是官方的例程,我还真的有点担心
还有,请问下面的语句运行速度是否会比上面的快?功能是一样的
void PWM3_PulseWidth(unsigned short width)                                    //脉冲占空比宽度调整函数(宽度值)
{
    unsigned short* p16;
    unsigned char* p;
   
    width*=64;                                                                  //相当于左移6位,PIC18有硬件乘法
    p16=&width;
    p=p16;
    PWM3DCH = *(p+1);
    PWM3DCL = *p;
}


使用特权

评论回复
15
zljiu| | 2021-8-11 15:29 | 只看该作者
主要是比较哪方面呢

使用特权

评论回复
16
coshi| | 2021-8-13 13:07 | 只看该作者
如何定义代码是不是严谨呢

使用特权

评论回复
17
drer| | 2021-8-13 13:08 | 只看该作者
可以自己写一个测试程序慢慢比对

使用特权

评论回复
18
gwsan| | 2021-8-13 13:09 | 只看该作者
我自己也有些糊涂了

使用特权

评论回复
19
kxsi| | 2021-8-13 13:11 | 只看该作者
最后规整的非常到位啊

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

50

主题

397

帖子

2

粉丝