找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 8665|回复: 10
打印 上一主题 下一主题
收起左侧

基于单片机和NRF24L01的无线PID电机转速控制器设计

  [复制链接]
跳转到指定楼层
楼主
基于NRF24L01的PID电机转速控制器,采用51单片机控制,有发送端和接收端的完整图纸和程序代码
下面是已经制作成功的实物图:


原理图:


项目介绍
在过程控制中,按偏差的比例(P)、积分(I)和微分(D)进行控制的PID控制器(亦称PID调节器)是应用最为广泛的一种自动控制器。它具有原理简单,易于实现,适用面广,控制参数相互独立,参数的选定比较简单等优点;而且在理论上可以证明,对于过程控制的典型对象──“一阶滞后+纯滞后二阶滞后+纯滞后的控制对象,PID控制器是一种最优控制。PID调节规律是连续系统动态品质校正的一种有效方法,它的参数整定方式简便,结构改变灵活(PIPDPID)。
然而PID算法在工业发展中也占据不小的地位,例如,液位,压力,温度,流量的控制都能利用PID算法进行精准控制。本项目将PID的算法用在了直流电机的控制当中,用于精准控制电机转速,简化电机控制难度。为了使操作者能够简单,方便,实时,快捷的控制电机的转速,我又在此基础上加上了无线模块,使得操作者能够更加简单的操作本产品,操作者只需简单改变主控板的设定值,接收机即可将电机转速控制在设定值以内,误差范围控制在正负20r/s(转/秒)。
一、   功能设计要点
1.        控制核心:接收和发射核心控制部分均采用STC12C5A60S2单片机进行控制
2.        显示部分:接收机显示采用普通的12864液晶显示,发射部分为了减小其体积采用OLED液晶,功耗低,体积小,显示效果好
3.        电机驱动部分:采用的是L298N电机驱动模块,价格低,抗干扰能力强,安全性高,可靠性强,大大提高了电机的效率。
4.        速度检测部分:采用44E开关型霍尔传感器,成本低,电路简单,可与单片机IO口直接连接,操作方便。
5.        无线数据传输采用NRF24L01无线模块,工作在 2.4~2.5GHz 世界通用 ISM 频段,工作电流只有 10.5mA, 接收时工作电流只有 18mA, 多种低功率工作模式, 功耗低。
6.        核心控制算法PID:此电路采用的是PID算法里的增量式算法,
file:///Z:\TEMP\msohtmlclip1\01\clip_image002.jpg
pid.voltage=pid.Kp*pid.err+pid.Ki*pid.integral+pid.Kd*(pid.err-pid.err_last);
增量式算法不需做累加, 计算误差和计算精度问题对控制量的计算影响较小;


四、系统工作原理方框图




单片机源程序如下(无线接收部分):
  1. #include <STC12C5A60S2.H>
  2. #include <intrins.h>
  3. #include"delay.h"
  4. #include"12864.h"
  5. #include "nrf24l01.h"
  6. #include"mian.h"
  7. #include "keyscan.h"
  8. #include"display.h"
  9. #include"display1.h"
  10. uchar code tab11[]="0123456789:";
  11. uchar RX_BUF[TX_PLOAD_WIDTH];
  12. uchar TX_BUF[TX_PLOAD_WIDTH];
  13. uchar flag;                   //读取接收数据完成标志位
  14. uchar temp,fuck;
  15. uchar str[4];//存储转换的字符串
  16. int speed_change;
  17. sbit  pulse=P1^7 ;        //从此引脚输出脉冲信号
  18. bit g_bPIDRunFlag = 0;
  19. uchar bdata sta;
  20. sbit  RX_DR         = sta^6; //接收数据中断
  21. sbit  TX_DS         = sta^5; //数据发送完成中断
  22. sbit  MAX_RT = sta^4; //达到最多次重发中断
  23. //sbit led=P1^6;
  24. /**************************************************
  25. 函数:Check_ACK()

  26. 描述:
  27.     检查接收设备有无接收到数据包,设定没有收到应答信
  28.         号是否重发
  29. /**************************************************/
  30. uchar Check_ACK(bit clear)
  31. {   
  32.         while(IRQ);                                                          //等待应答
  33.         sta = SPI_RW(NOP);                    // 返回状态寄存器
  34.         if(MAX_RT)                                                          //如果达到最大重发次数
  35.                 if(clear)                         // 是否清除TX FIFO,没有清除在复位MAX_RT中断标志后重发
  36.                 SPI_RW(FLUSH_TX);                          //清除TX FIFO
  37.         SPI_RW_Reg(WRITE_REG + STATUS, sta);  // 清除TX_DS或MAX_RT中断标志
  38.         IRQ = 1;                                                          //中断复位
  39.         if(TX_DS)                                                          //发送完成中断
  40.                 return(0x00);
  41.         else
  42.                 return(0xff);
  43. }

  44. /****pid***/
  45. struct _pid{
  46.     double SetSpeed;           //定义设定值
  47.     double ActualSpeed;        //定义实际值
  48.     double err;                //定义偏差值
  49.     double err_last;            //定义上一个偏差值
  50.         double err_second;            //定义上一个偏差值
  51.     double Kp,Ki,Kd;            //定义比例、积分、微分系数
  52.     double voltage;          //定义电压值(控制执行器的变量)
  53.     double integral;            //定义积分值
  54. }pid;


  55. void PID_init(){

  56.     pid.SetSpeed=0;                           //定义设定值
  57.     pid.ActualSpeed=0;                    //定义实际值
  58.     pid.err=0;                                            //定义偏差值
  59.     pid.err_last=0;                                  //定义上一个偏差值
  60.     pid.voltage=0;                                  //定义电压值(控制执行器的变量)
  61.     pid.integral=0;                                          //定义积分值
  62.     pid.Kp=0.4956;                          //                  定义比例
  63.     pid.Ki=0.000197;                  //                   积分
  64.     pid.Kd=0.0004;                          //                    微分系数
  65.   //  printf("PID_init end \n");
  66. }

  67. float PID_realize(double speed)
  68. {
  69.     pid.SetSpeed=speed;         //实际值=每分钟电机转速
  70.     pid.err=pid.SetSpeed-pid.ActualSpeed;  //转速偏差=设定值-实际值
  71.     pid.integral+=pid.err;
  72.     pid.voltage=pid.Kp*pid.err+pid.Ki*pid.integral+pid.Kd*(pid.err-pid.err_last);
  73. //        pid.voltage=pid.Kp*pid.err+(0.05/pid.Ki)*pid.integral+(pid.Kd/0.05)*(pid.err-pid.err_last);
  74.     pid.err_last=pid.err;
  75.     pid.ActualSpeed=pid.voltage*1;
  76.     return pid.ActualSpeed;
  77. }

  78. void init_timer(void)
  79. {        
  80.         
  81.         TMOD = 0x01;                //设置定时器模式
  82.         TL0 = 0x00;                //设置定时初值
  83.         TH0 = 0x28;                //设置定时初值

  84.     TR0=1;                 //启动定时器1
  85.     ET0=1;                 //Timer1中断禁止
  86.     IT0=1;                 //下降沿触发方式
  87.     EX0=1;                 //外部INT0中断允许
  88.     EA=1;                  //开全局中断
  89. }


  90. void main()
  91. {        pulse=1;
  92.     lcd_init();
  93.         display();
  94.         delay_50_ms(50);
  95.         lcd_init();
  96.         PWM_init ();
  97.         init_timer() ;
  98.     PID_init();
  99.         NRF24L01_init();
  100.         RX_Mode();
  101. display_init();
  102. // DS1302_Init();
  103.         while(1)//循环
  104.         {         

  105.             
  106.                 sta = SPI_Read(STATUS);          // 读状态寄存器
  107.                 temp=sta;   
  108.                 temp=(temp>>1)&0x07;  
  109.             if(RX_DR)                                  // 判断是否接受到数据
  110.                 {
  111.                         SPI_Read_Buf(RD_RX_PLOAD, RX_BUF, TX_PLOAD_WIDTH);  // 从RX FIFO读出数据
  112.                         flag = 1;
  113.                 }
  114.                 SPI_RW_Reg(WRITE_REG + STATUS, sta);  // 清除RX_DS中断标志
  115.                   if(flag)                           // 接受完成
  116.                 {
  117.                         flag = 0;                                                                                                                  
  118.                          sheding=RX_BUF[0]*10+RX_BUF[1];
  119. //                                xianshi(0x92,tab11[RX_BUF[0]/10],tab11[RX_BUF[0]%10]);
  120. //                                xianshi(0x94,tab11[RX_BUF[1]/10],tab11[RX_BUF[1]%10]);
  121. //                                xianshi(0x96,tab11[0],tab11[1]);  xianshi(0x97,tab11[2],tab11[3]);
  122.        }
  123.              if(g_bPIDRunFlag)        //PID调节
  124.                              {
  125.                                    g_bPIDRunFlag=0;
  126. //                                   pulse=0;
  127.                                    pid.ActualSpeed=zhuansu;          // pid.ActualSpeed-实际值  speed_c-每分钟电机转速
  128.                                    speed_change=PID_realize(sheding);//pid.ActualSpeed  rad_set
  129.                            //  printf("%f\n",speed);
  130.                         //          if(speed_change<0)
  131.                         //          speed_change=speed_change*(-1);
  132.                                   pwm_1=255-PID_realize(sheding);
  133.                              if(pwm_1>255)
  134.                                           {
  135.                                             pwm_1=254;
  136.                                                           PWM0_set(pwm_1); //设置PWM占空比
  137.                                           }
  138.                                           if(pwm_1<0)
  139.                                           {
  140.                                              pwm_1=0;                                                                                                                        
  141.                                                 PWM0_set(pwm_1);    //设置PWM占空比
  142.                                              }
  143.                                         PWM0_set(pwm_1);
  144. //                                         pulse=1;
  145.                              }
  146.                                  display2();
  147.                                  keyscan();
  148.     }   
  149. }         
  150. void INIT0(void) interrupt 0
  151. {
  152.          x1++;
  153.    
  154. }
  155. void timer1(void) interrupt 1
  156. {
  157.          static uchar a = 0;
  158.            TL0 = 0x00;                //设置定时初值
  159.            TH0 = 0x28;                //设置定时初值5MS
  160. //                   TL0 = 0x00;                //设置定时初值
  161. //        TH0 = 0x04;                //设置定时初值
  162. ……………………

  163. …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码

所有资料51hei提供下载:
第二届单片机大赛作品.zip (6.87 MB, 下载次数: 149)




评分

参与人数 1黑币 +100 收起 理由
admin + 100 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏5 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:1 发表于 2017-6-19 22:13 | 只看该作者
好资料,51黑有你更精彩!!!
回复

使用道具 举报

板凳
ID:163950 发表于 2017-6-21 09:17 | 只看该作者
楼主为什么打开后都是问题!
NRF24L01.C(71): error C202: 'CSN': undefined identifier
NRF24L01.C(77): error C202: 'CE': undefined identifier
NRF24L01.C(102): error C202: 'CE': undefined identifier
NRF24L01.C(156): error C202: 'CE': undefined identifier
NRF24L01.C(166): error C202: 'CE': undefined identifier
NRF24L01.C(172): error C202: 'CE': undefined identifier
NRF24L01.C(173): error C202: 'CSN': undefined identifier
NRF24L01.C(174): error C202: 'SCK': undefined identifier
NRF24L01.C(175): error C202: 'IRQ': undefined identifier
Target not created
回复

使用道具 举报

地板
ID:249545 发表于 2017-11-24 17:12 | 只看该作者
好文,好文,真不错!
回复

使用道具 举报

5#
ID:312760 发表于 2018-4-20 22:44 | 只看该作者
好东西,正好学习pid调节
回复

使用道具 举报

6#
ID:288865 发表于 2018-4-22 15:05 | 只看该作者
正在学习谢谢
回复

使用道具 举报

7#
ID:330988 发表于 2018-5-16 14:02 | 只看该作者
很好  可以学习一下
回复

使用道具 举报

8#
ID:715082 发表于 2020-4-5 13:43 | 只看该作者
c03131401 发表于 2017-6-21 09:17
楼主为什么打开后都是问题!
NRF24L01.C(71): error C202: 'CSN': undefined identifier
NRF24L01.C(77): ...

您好,可能引脚定义丢失了,我也有问题,请问您有在软件里找到3144霍尔P32引脚的定义吗?万望回复,谢谢您
回复

使用道具 举报

9#
ID:110278 发表于 2020-4-7 14:16 | 只看该作者
资料挺全的,感谢分享。
回复

使用道具 举报

10#
ID:89217 发表于 2020-4-11 22:44 | 只看该作者
学习了。感谢分享
回复

使用道具 举报

11#
ID:701252 发表于 2020-10-17 09:37 | 只看该作者

学习了!谢谢楼主分享,正想学习pid调节呢!
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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