51单片机IO口模拟PWM,问题看了一晚上找不到原因

2020-01-23 14:40发布

PWM周期:20ms,也就是50Hz频率
由于用于控制舵机,高电平是0.5ms~2.5ms,所以打算把20ms分为200份,没份时间就是20ms/200=0.1ms,这样5份高电平就代表0.5ms了
单片机是常用的STC89C52RC,烧录程序后从示波器看波形却傻眼了....波形上面频率是170Hz左右,看了一晚上的程序居然没看出问题。所谓旁观者清,各位来指点指点吧。

程序如下,一看就懂
  1. /*********************************************************************************
  2. ====舵机驱动程序=========
  3. 编写:小刘
  4. 晶振:12MHz
  5. 舵机型号:MG996
  6. 舵机周期驱动信号周期:20ms
  7. 电压:4.8-7.2V
  8. **********************************************************************************/

  9. #include<reg52.h> //包含特殊功能寄存器的定义
  10. sbit p11=P1^1;//输出pwm脉冲

  11. #define uchar unsigned char
  12. #define uint unsigned int
  13. /* 函数&变量申明 -----------------------------------------------*/
  14. void Init_Timer0(void);        //定时器定时20ms,分为200份,每份时间0.1ms=100us
  15. void Init_Uart() ;
  16. uchar receive;
  17. uchar pwm=25;//阀值,25就是2.5ms 的高电平时间
  18. uchar period=200;//舵机信号周期20ms,分成200份
  19. uchar i=0;//用于计数
  20. bit temp=0;
  21. /*
  22. ********************************************************************************
  23. ** 函数名称 : main(void)
  24. ** 函数功能 : 主函数
  25. ********************************************************************************
  26. */
  27. main()
  28. {
  29.         Init_Timer0();
  30.     Init_Uart() ;
  31.         while(1);
  32. }


  33. /*
  34. ********************************************************************************
  35. ** 函数名称 : Init_Timer0(void)
  36. ** 函数功能 : 定时器初始化子程序
  37. ********************************************************************************
  38. */
  39. void Init_Timer0(void)                  //定时器初始化子程序
  40. {
  41.         TMOD |= 0x01;          //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响                     
  42.         //给定初值,每份定时时间0.1ms,一个周期200份=20ms
  43.         TH0=(65535-100)/256;//0XFF             
  44.         TL0=(65535-100)%256;//0X9C
  45.         EA=1;            //总中断打开
  46.         ET0=1;           //定时器中断打开
  47.         TR0=1;           //定时器开关打开
  48. }
  49. /*
  50. ********************************************************************************
  51. ** 函数名称 : void Init_Uart()
  52. ** 函数功能 : 串口初始化子程序
  53. ********************************************************************************
  54. */
  55. void Init_Uart()
  56. {
  57.           TMOD=0x20;                   //用定时器设置串口波特率
  58.         TH1=0xfd;
  59.         TL1=0xfd;
  60.         TR1=1;
  61.         REN=1;          //串口初始化
  62.         SM0=0;
  63.         SM1=1;
  64.         EA=1;           //开启总中断
  65.         ES=1; //开串口中断
  66. }
  67. /*
  68. ********************************************************************************
  69. ** 函数名称 : Timer0_isr(void) interrupt 1 using 1
  70. ** 函数功能 : 定时器中断程序
  71. ********************************************************************************
  72. */
  73. void Timer0_isr(void) interrupt 1
  74. {
  75.         TH0=(65535-100)/256;             
  76.         TL0=(65535-100)%256;
  77.         i++;
  78.         if (i>=pwm)p11=0; //如果超过了阀值就是电平

  79.         if (i==200){i=0;p11=1;}        //0.1ms*200=20ms 周期时间到,默认给输出高电平


  80. }
  81. /*
  82. ********************************************************************************
  83. ** 函数名称 : void Uart()
  84. ** 函数功能 : 串口接收中断程序
  85. ********************************************************************************
  86. */
  87. void Uart() interrupt 4                //串口中断响应程序
  88. {
  89.         ES=0;//关闭串口中断
  90.         if(RI)
  91.         {
  92.         RI=0;//清除接收中断标志位
  93.         receive=SBUF;//读取SBUF
  94.         }
  95.         ES=1;//打开串口中断

  96. }
复制代码
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
16条回答
mobile02
1楼-- · 2020-01-25 17:07
不知道 STC PWM 死区怎么设定?
tim4146
2楼-- · 2020-01-25 22:13
wkman 发表于 2014-5-19 14:58
换 stc12c 有记录硬件pwm输出,这样方便点

够用的情况下我一直用STC89C52的,比较简单,后来试着用了STM32. 现在的STC12C价格怎么样?
millwood0
3楼-- · 2020-01-25 22:47
You are very challenged.


  1.         TH0 = -100 >> 8;//TH0=(65535-100)/256;//0XFF              
  2.         TL0 = -100;        //TL0=(65535-100)%256;//0X9C
复制代码

  1. void Timer0_isr(void) interrupt 1
  2. {
  3.         TH0=(65535-100)/256;              
  4.         //TL0=(65535-100)%256;
  5.         TL0 += -100;
复制代码

  1. void Uart() interrupt 4                //串口中断响应程序
  2. {
  3.         ES=0;//关闭串口中断
复制代码

Speechless.

Just think about it.
tim4146
4楼-- · 2020-01-26 02:02
millwood0 发表于 2014-5-25 23:44
You are very challenged.

It seems to be a good idea,use" TL0 += -100;" to offset the time spent before.
Thank u ,u r so helpful~

一周热门 更多>