找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 967|回复: 4
收起左侧

大佬们能帮忙看看这个电机调速单片机程序有啥问题吗?

[复制链接]
ID:1009113 发表于 2022-3-26 22:29 | 显示全部楼层 |阅读模式
在另一位大佬贴出来的程序的基础上改的,各部分程序的作用也都理解了但是烧录到单片机后电机就是不会调速自己一直看不出有啥问题,请大佬们帮忙看看

单片机源程序如下:
  1. #include<reg51.h>
  2. #include "intrins.h"
  3. #include <LCD1602.H>
  4. #define uchar unsigned char
  5. #define uint unsigned int
  6. #define GPIO_KEY P2
  7. sbit PWM=P1^3;                  
  8. uchar speed1[4]={"000"};//设定转速
  9. uchar speed2[3]={"000"};//占空比        
  10. uchar speed[]={"000"};  //当前转速
  11. uchar KeyValue=0;       //键值
  12. uint AA,count=0,flag;
  13. float pid_p=0.003,pid_i=0.003,pid_d=0.002;        //PID三个参数初值
  14. uint SpeedSet=50,CurrentSpeed;              //设定转速 当前转速
  15. unsigned char pid_val_mid;                  //pid_val_mid脉冲宽度
  16. unsigned int lastError=0;                   //之前误差初始为0
  17. long int sumError=0;                        //偏差积累初始为0
  18.         
  19. void delay1(unsigned int i)
  20. {
  21.    unsigned int j;
  22.          for(;i>0;i--)
  23.          for(j=0;j<333;j++)
  24.          {;}
  25. }        
  26. /********************* 键盘扫描*************/
  27. void KeyDown(void)               
  28. {
  29.         GPIO_KEY=0x0f; //设置按键触点初始值为0;0000 1111
  30.                 delay1(10);
  31.         if(GPIO_KEY!=0x0f) //判断按键是否按下
  32.         {
  33.                 delay1(10);  //延时消抖
  34.                 if(GPIO_KEY!=0x0f) //再次判断按键是否按下,低电平有效
  35.                 {
  36.                         GPIO_KEY=0X0F;
  37.                         delay1(10);
  38.                         //测试列
  39.                         switch(GPIO_KEY)
  40.                         {
  41.                                 case(0X07):        KeyValue=0;break;//0000 0111
  42.                                 case(0X0b):        KeyValue=1;break;//0000 1011
  43.                                 case(0X0d): KeyValue=2;break;//0000 1101
  44.                                 case(0X0e):        KeyValue=3;break;//0000 1110
  45.                         }
  46.                         //测试行
  47.                         GPIO_KEY=0XF0;//设置按键触点初始值为1;1111 0000
  48.                         delay1(10);
  49.                         switch(GPIO_KEY)
  50.                         {                                                                                                                  //键盘表:
  51.                                 case(0X70):        KeyValue=KeyValue+0;break;//0111 0000      0  1  2  3   
  52.                                 case(0Xb0):        KeyValue=KeyValue+4;break;//1011 0000           4  5  6  7
  53.                                 case(0Xd0): KeyValue=KeyValue+8;break;//1101 0000           8  9  a  b
  54.                                 case(0Xe0):        KeyValue=KeyValue+12;break;//1110 0000           c  d  e  f
  55.                         }
  56.                 }
  57.         }
  58. }

  59. void timer()
  60. {
  61.          TMOD=0x11;//定时器0工作方式1.16位定时,定时器1工作方式1,16位定时;
  62.          TH0=0x4c;//11.0592mhz下的50ms初值  (65535-50000)/256 12mhz是0x3c
  63.          TL0=0x00;//                                (65535-50000)%256        0xb0
  64.          TH1=0xfc;//11.0592mhz下的1msPWM控制
  65.          TL1=0x66;
  66.          TR1=1;           //定时器1启动位,该位由软件清零
  67.          ET1=1;           //定时器T1溢出中断允许
  68.          IT0=1;    //外部中断下降沿触发
  69.          TR0=1;           //定时器0启动位,该位由软件清零
  70.          ET0=1;           //定时器T0溢出中断允许
  71.          EX0=1;           //外部中断0中断允许
  72.          EA=1;           //CPU全局中断开放
  73. }
  74. /***********************lcd显示*************/
  75. void  display()
  76. {   
  77.             speed[0]=CurrentSpeed/100+0x30; //当前转速
  78.                 speed[1]=CurrentSpeed/10%10+0x30;//0x30对应ASCII的数值0
  79.                 speed[2]=CurrentSpeed%10+0x30;
  80.                 speed1[0]=SpeedSet/100+0x30;//设定转速
  81.                 speed1[1]=SpeedSet/10%10+0x30;
  82.                 speed1[2]=SpeedSet%10+0x30;  
  83.                 speed2[0]=pid_val_mid/100+0x30;//占空比
  84.                 speed2[1]=pid_val_mid/10%10+0x30;
  85.                 speed2[2]=pid_val_mid%10+0x30;

  86.             LCD_ShowString(1,1,"SET:"); //设定速度
  87.                 LCD_ShowNum(1,5,speed1,3);
  88.                 LCD_ShowString(1,8,"R/MIN");
  89.                 LCD_ShowString(2,1,"NOW:"); //当前速度
  90.                 LCD_ShowNum(2,5,speed,3);
  91.                 LCD_ShowString(2,8,"R/MIN");        
  92.                
  93. }
  94. /************************电机控制*************/
  95. void keyKZ()
  96. {
  97.                         if(KeyValue==7)//c设定速度加10
  98.                         SpeedSet+=10;
  99.                         if(KeyValue==15)//d设定速度减10
  100.                         SpeedSet-=10;
  101.                         if(KeyValue==3)//e设定速度加1
  102.                         SpeedSet+=1;
  103.                         if(KeyValue==11)//f设定速度减1
  104.                         SpeedSet-=1;
  105.                         KeyValue=0;                                
  106. }
  107. /************************PID控制算法*************/
  108. unsigned int PID()
  109. {  
  110.   int dError=0,Error=0,B;
  111.     Error=SpeedSet-CurrentSpeed;//当前误差
  112.     sumError=Error+sumError;//误差积累
  113.     dError=Error-lastError;//误差偏差
  114.     lastError=Error;
  115.     B=pid_p*Error+pid_i*sumError+pid_d*dError;//三个参数计算
  116.         
  117.         if(B>100) pid_val_mid=100;
  118.     if(B<0) pid_val_mid=0;      
  119.         if(B>=0&&B<=100)
  120.     pid_val_mid=B;              
  121.         return(0);
  122. }
  123. void Timer0_isr() interrupt 1  //定时器0中断
  124. {
  125.          AA++;                     
  126.          TH0=0x4b;                 //重装50ms
  127.          TL0=0xfe;
  128.          if(AA==20)        //1s      
  129.          {               
  130.            CurrentSpeed=count/96*60;//一分钟的转速:count/96(96线编码器)得出1s内圈数也就是r/s,圈数*60得到r/min
  131.                                 count=0;
  132.                                 AA=0;
  133.                                 PID();
  134.          }
  135. }
  136. void key_int() interrupt 0         //外部中断0  P3.2口接a相
  137. {
  138.         count++;                 //a相脉冲计数
  139. }

  140. void Timer1() interrupt 3    //定时器1中断
  141. {
  142.    static int c=0;                                   //static静态变量,只有第一次会赋值
  143.                  TH1=0xfc;                 //重新赋值1mspwm,也就是每间隔1ms中断一次
  144.                   TL1=0x66;
  145.                  c++;                      //每次定时器溢出加1                  
  146.           if(c<=pid_val_mid) PWM=1;           //当中断次数小于设定的脉宽给高电平,
  147.           if(c>pid_val_mid)  PWM=0;           //等到了设定脉宽值就变为低电平
  148.           if(c>=100)         c=0;                    //一个周期分为100段高低电平,大于100就是下一个周期
  149. }
  150. void main()
  151. {
  152.                 timer();   //定时器初始化
  153.                 LCD_Init();//LCD初始化
  154.                 while(1)
  155.                 {
  156.                    KeyDown();  //键盘扫描
  157.                    keyKZ();  //键盘控制
  158.                    display();//显示LCD
  159.                 }
  160. }        
复制代码


回复

使用道具 举报

ID:394424 发表于 2022-3-27 09:56 | 显示全部楼层
调试是一步步来才能找到问题的  比如先让电机动起来  然后可快可慢  这样才能知道问题点
回复

使用道具 举报

ID:161164 发表于 2022-3-27 11:43 | 显示全部楼层
你PID三个参数的初值设得太小
    float pid_p=0.003,pid_i=0.003,pid_d=0.002;
    Error=SpeedSet-CurrentSpeed;//当前误差
    sumError=Error+sumError;//误差积累
    dError=Error-lastError;//误差偏差
    lastError=Error;
    B=pid_p*Error+pid_i*sumError+pid_d*dError;//三个参数计算假设CurrentSpeed=40;SpeedSet=50;Error=10;
Error小于333, pid_p等于没用
sumError要34秒后才大于333
dError要Error有改变才有用

研究一下PID三个参数值的正确设置吧
回复

使用道具 举报

ID:1009113 发表于 2022-3-27 11:53 | 显示全部楼层
Wprogrammer 发表于 2022-3-27 09:56
调试是一步步来才能找到问题的  比如先让电机动起来  然后可快可慢  这样才能知道问题点

现在的情况就是LCD会显示但是显示的速度值不对,电机通电就能转但是按按键啥速度不会改变只能慢慢调试了
回复

使用道具 举报

ID:587810 发表于 2022-3-27 16:56 | 显示全部楼层
不可以光改设速度。对应的PID参数也要改的,每一套PID参数都是对应当前设定速度的。
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表