关于STC8G单片机的PCA_10PWM输出注意事项

[复制链接]
查看161 | 回复0 | 2021-5-9 20:17:17 | 显示全部楼层 |阅读模式
003818jdf8m856kdd8nk1e.png

以前用过STC15W的8位PWM,配置很简单。
数据手册上也有参考代码。
一直渴望STC能出8个脚带AD的单片机,终于等到了,去年STC8G系列上市。这款芯片带10位ADC,6/7/8/10位硬件PWM等待。价格0.8元左右。
这几天公司接了个电位器调光的项目,这让我想到了STC8G1K08A单片机,自带的功能刚才满足产品要求。
说实在的,真心不敢用。毕竟是新品,也不知道质量咋样?抱着支持国产芯片的想法,决定试试。
说干就干,于是在某一个宝上买了几片。这个调光产品主要用到ADC和PWM。
测试ADC,没问题!
测试8位PWM,没问题!(以前玩过15系列的,代码基本相同)
想着有10位的PWM干嘛要用8位的呢?决定用10位的PWM.
结果搞了一天,愣是没搞出来。有波形输出,但是不是自己想要的波形。半夜了,睡觉吧!!!!!

这里说明下关于PWM寄存器:
005110b7u6a4m5zn66617c.png 005126w0n7re9n0qtm0dxg.png 005136rba4yqj8dc1za8c8.png

10位PWM重装值和比较值的高2位和低8位在两个寄存器,PCA_PWMn和CCAPnH。
以前写代码习惯了根据数据手册的寄存器从上往下配置,特殊寄存器除外。
以前配置8位PWM初始化代码如下:
  1. //8位PWM_PCA初始化
  2. void PCA_Init()
  3. {
  4.         CCON=0x00;  //关闭PCA计数器,清除相关标志位
  5.         CMOD=PCA_SYSCLK2;  //PCA时钟源为系统时钟2分频  33.1776/2/1024=0.0162MHZ ==>16.2KHZ
  6.         CL  =0x00;  //计数器清零
  7.         CH  =0x00;
  8. /*------------------------PWM0部分-----------------------------*/
  9.         CCAPM0=0x42; //使能PCA模块0_PWM输出
  10.         CCAP0L=0X00;    //捕获比较寄存器低8位,比较值
  11.         CCAP0H=0X00;    //捕获比较寄存器高8位,重装值
  12.         PCA_PWM0=0x00;  //8位PWM输出        
  13. /*------------------------PWM1部分-----------------------------*/
  14.         CCAPM1=0x42; //使能PCA模块0_PWM输出
  15.         CCAP1L=0X00;    //捕获比较寄存器低8位,比较值
  16.         CCAP1H=0X00;    //捕获比较寄存器高8位,重装值
  17.         PCA_PWM1=0x00; //8位PWM输出

  18.         CCON|=  1<<6;   //启动计数器
  19. }
复制代码


这样,调节自己想要的占空比就OK了,8位PWM正常使用。所以,觉得修改PWM位数就行了。
于是,10位PWM配置如下:
  1. //10位PWM_PCA初始化
  2. //用电位器调节占空比
  3. void PCA_Init()
  4. {
  5.         CCON=0x00;  //关闭PCA计数器,清除相关标志位
  6.         CMOD=PCA_SYSCLK2;  //PCA时钟源为系统时钟2分频  33.1776/2/1024=0.0162MHZ ==>16.2KHZ
  7.         CL  =0x00;  //计数器清零
  8.         CH  =0x00;
  9. /*------------------------PWM0部分-----------------------------*/
  10.         CCAPM0=0x42; //使能PCA模块0_PWM输出
  11.         CCAP0L=0X00;    //捕获比较寄存器低8位,比较值
  12.         CCAP0H=0X00;    //捕获比较寄存器高8位,重装值
  13.         PCA_PWM0=0xC0;  //10位PWM输出        
  14. /*------------------------PWM1部分-----------------------------*/
  15.         CCAPM1=0x42; //使能PCA模块0_PWM输出
  16.         CCAP1L=0X00;    //捕获比较寄存器低8位,比较值
  17.         CCAP1H=0X00;    //捕获比较寄存器高8位,重装值
  18.         PCA_PWM1=0xC0; //10位PWM输出

  19.         CCON|=  1<<6;   //启动计数器
  20. }
复制代码

调节占空比的时候用示波器观察波形,发现波形不对,波形的确是10位的,这点可以肯定。数据手册看了一遍又一遍,觉得代码没问题啊。
实在没办法了。后来添加了串口功能,决定把相关寄存器通过串口发出来看看。
通过观察发现,PWM重装值高2位永远是00,低8位没问题,调节占空比的代码如下:
  1. //设置脉冲宽度
  2. void PWM0_Set_Duty(u16 Duty)
  3. {
  4.         //注意:在更新 10 位 PWM 的重载值时,必须先写高两位 XCCAPnH[1:0],再写低 8 位 CCAPnH[7:0]。
  5.         PCA_PWM0&= ~(3<<4);        //清零重装值高2位
  6.         PCA_PWM0|= (Duty>>4)&0x30; //设置新的重装值高2位
  7.         CCAP0H   = Duty;           //重装值低8位
  8. }
复制代码

这样写应该没错啊,咋回事呢?
于是在main函数里测试下:
  1. void main()
  2. {
  3.         u8 st;
  4.         
  5.         P_SW2|=0x80; //可以访问扩展的RAM        
  6.         UART1_Init();        
  7.         ADC_Init();
  8.         PCA_Init();
  9.         Timer0_Init();
  10.         SCH_Task_Init();
  11.         
  12.         st=SCH_Task_Add(PWM_Out,30,30,0,ENABLE);        
  13.         Timer0_Cmd(ENABLE);
  14.         
  15.         PCA_PWM0=0xFF;
  16.         UART1_SendByte(PCA_PWM0);
  17.         while(1)
  18.         {
  19.                 SCH_Task_Dispatch();
  20.         }
  21. }
复制代码

结果发现,串口发出来的是0xCF。明明赋值0xFF,为啥读出来的却是0xCF呢?明摆着那两个位没写进去。奇怪了!!!
于是我把//PCA_Init();初始化函数注释掉.再来测试下,给PCA_PWM0寄存器赋值0xFF,读出来是0xFF。可以写进去了。
这就证明问题出在PCA_Init();初始化函数。回头看看初始化函数.....................省略繁琐的过程............................!
最后发现是CCAPM0寄存器的问题,这个寄存器我用到了,允许比较功能和使能PWM 输出。
问题就出在使能PWM输出这个位上。使能了PWM输出,Pwm重装值高2位就写不进去,也就没办法调节占空比。
013446ghmz1f2b7sdb7lfa.png

这和资料上的最后一句话是不是冲突了。这算不算一个BUG呢。
在修改重装值前,先禁止PWM 输出,修改好后再打开。这能算无干扰吗???

最后代码修改如下:
  1. //10位PWMPCA初始化
  2. void PCA_Init()
  3. {
  4.         CCON=0x00;  //关闭PCA计数器,清除相关标志位
  5.         CMOD=PCA_SYSCLK2;  //PCA时钟源为系统时钟2分频  33.1776/2/1024=0.0162MHZ ==>16.2KHZ
  6.         CL  =0x00;  //计数器清零
  7.         CH  =0x00;
  8. /*------------------------PWM0部分-----------------------------*/
  9.         CCAPM0 = 0x40;  //失能PCA模块0_PWM输出
  10.         CCAP0L=0X00;    //捕获比较寄存器低8位,比较值
  11.         CCAP0H=0X00;    //捕获比较寄存器高8位,重装值
  12.         PCA_PWM0=0xC0;  //10位PWM输出
  13.         CCAPM0=0x42; //使能PCA模块0_PWM输出
  14.         
  15. /*------------------------PWM1部分-----------------------------*/
  16.         CCAPM1 = 0x40;  //失能PCA模块1_PWM输出
  17.         CCAP1L=0X00;    //捕获比较寄存器低8位,比较值
  18.         CCAP1H=0X00;    //捕获比较寄存器高8位,重装值
  19.         PCA_PWM1=0xC0; //10位PWM输出
  20.         CCAPM1=0x42; //使能PCA模块0_PWM输出
  21.         
  22.         CCON|=  1<<6;   //启动计数器
  23. }


  24. //设置脉冲宽度
  25. void PWM0_Set_Duty(u16 Duty)
  26. {
  27.         //注意:在更新 10 位 PWM 的重载值时,必须先写高两位 XCCAPnH[1:0],再写低 8 位 CCAPnH[7:0]。
  28.         
  29.         CCAPM0   = 0x40;           //失能PCA模块0_PWM输出
  30.         PCA_PWM0&= ~(3<<4);        //清零重装值高2位
  31.         PCA_PWM0|= (Duty>>4)&0x30; //设置新的重装值高2位
  32.         CCAP0H   = Duty;           //重装值低8位
  33.         CCAPM0   = 0x42;           //使能PCA模块0_PWM输出
  34. }


  35. //设置脉冲宽度
  36. void PWM1_Set_Duty(u16 Duty)
  37. {
  38.         //注意:在更新 10 位 PWM 的重载值时,必须先写高两位 XCCAPnH[1:0],再写低 8 位 CCAPnH[7:0]。
  39.         
  40.         CCAPM1   = 0x40;           //失能PCA模块1_PWM输出
  41.         PCA_PWM1&= ~(3<<4);        //清零重装值高2位
  42.         PCA_PWM1|= (Duty>>4)&0x30; //设置新的重装值高2位
  43.         CCAP1H   = Duty;           //重装值低8位
  44.         CCAPM1   = 0x42;           //使能PCA模块0_PWM输出
  45. }
复制代码

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则