基于NRF24L01的PID电机转速控制器,采用51单片机控制,有发送端和接收端的完整图纸和程序代码
下面是已经制作成功的实物图:
原理图:
项目介绍
在过程控制中,按偏差的比例(P)、积分(I)和微分(D)进行控制的PID控制器(亦称PID调节器)是应用最为广泛的一种自动控制器。它具有原理简单,易于实现,适用面广,控制参数相互独立,参数的选定比较简单等优点;而且在理论上可以证明,对于过程控制的典型对象──“一阶滞后+纯滞后”与“二阶滞后+纯滞后”的控制对象,PID控制器是一种最优控制。PID调节规律是连续系统动态品质校正的一种有效方法,它的参数整定方式简便,结构改变灵活(PI、PD、PID)。
然而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);
增量式算法不需做累加, 计算误差和计算精度问题对控制量的计算影响较小;
四、系统工作原理方框图
单片机源程序如下(无线接收部分):
- #include <STC12C5A60S2.H>
- #include <intrins.h>
- #include"delay.h"
- #include"12864.h"
- #include "nrf24l01.h"
- #include"mian.h"
- #include "keyscan.h"
- #include"display.h"
- #include"display1.h"
- uchar code tab11[]="0123456789:";
- uchar RX_BUF[TX_PLOAD_WIDTH];
- uchar TX_BUF[TX_PLOAD_WIDTH];
- uchar flag; //读取接收数据完成标志位
- uchar temp,fuck;
- uchar str[4];//存储转换的字符串
- int speed_change;
- sbit pulse=P1^7 ; //从此引脚输出脉冲信号
- bit g_bPIDRunFlag = 0;
- uchar bdata sta;
- sbit RX_DR = sta^6; //接收数据中断
- sbit TX_DS = sta^5; //数据发送完成中断
- sbit MAX_RT = sta^4; //达到最多次重发中断
- //sbit led=P1^6;
- /**************************************************
- 函数:Check_ACK()
- 描述:
- 检查接收设备有无接收到数据包,设定没有收到应答信
- 号是否重发
- /**************************************************/
- uchar Check_ACK(bit clear)
- {
- while(IRQ); //等待应答
- sta = SPI_RW(NOP); // 返回状态寄存器
- if(MAX_RT) //如果达到最大重发次数
- if(clear) // 是否清除TX FIFO,没有清除在复位MAX_RT中断标志后重发
- SPI_RW(FLUSH_TX); //清除TX FIFO
- SPI_RW_Reg(WRITE_REG + STATUS, sta); // 清除TX_DS或MAX_RT中断标志
- IRQ = 1; //中断复位
- if(TX_DS) //发送完成中断
- return(0x00);
- else
- return(0xff);
- }
- /****pid***/
- struct _pid{
- double SetSpeed; //定义设定值
- double ActualSpeed; //定义实际值
- double err; //定义偏差值
- double err_last; //定义上一个偏差值
- double err_second; //定义上一个偏差值
- double Kp,Ki,Kd; //定义比例、积分、微分系数
- double voltage; //定义电压值(控制执行器的变量)
- double integral; //定义积分值
- }pid;
- void PID_init(){
- pid.SetSpeed=0; //定义设定值
- pid.ActualSpeed=0; //定义实际值
- pid.err=0; //定义偏差值
- pid.err_last=0; //定义上一个偏差值
- pid.voltage=0; //定义电压值(控制执行器的变量)
- pid.integral=0; //定义积分值
- pid.Kp=0.4956; // 定义比例
- pid.Ki=0.000197; // 积分
- pid.Kd=0.0004; // 微分系数
- // printf("PID_init end \n");
- }
- float PID_realize(double speed)
- {
- pid.SetSpeed=speed; //实际值=每分钟电机转速
- pid.err=pid.SetSpeed-pid.ActualSpeed; //转速偏差=设定值-实际值
- pid.integral+=pid.err;
- pid.voltage=pid.Kp*pid.err+pid.Ki*pid.integral+pid.Kd*(pid.err-pid.err_last);
- // pid.voltage=pid.Kp*pid.err+(0.05/pid.Ki)*pid.integral+(pid.Kd/0.05)*(pid.err-pid.err_last);
- pid.err_last=pid.err;
- pid.ActualSpeed=pid.voltage*1;
- return pid.ActualSpeed;
- }
- void init_timer(void)
- {
-
- TMOD = 0x01; //设置定时器模式
- TL0 = 0x00; //设置定时初值
- TH0 = 0x28; //设置定时初值
- TR0=1; //启动定时器1
- ET0=1; //Timer1中断禁止
- IT0=1; //下降沿触发方式
- EX0=1; //外部INT0中断允许
- EA=1; //开全局中断
- }
- void main()
- { pulse=1;
- lcd_init();
- display();
- delay_50_ms(50);
- lcd_init();
- PWM_init ();
- init_timer() ;
- PID_init();
- NRF24L01_init();
- RX_Mode();
- display_init();
- // DS1302_Init();
- while(1)//循环
- {
-
- sta = SPI_Read(STATUS); // 读状态寄存器
- temp=sta;
- temp=(temp>>1)&0x07;
- if(RX_DR) // 判断是否接受到数据
- {
- SPI_Read_Buf(RD_RX_PLOAD, RX_BUF, TX_PLOAD_WIDTH); // 从RX FIFO读出数据
- flag = 1;
- }
- SPI_RW_Reg(WRITE_REG + STATUS, sta); // 清除RX_DS中断标志
- if(flag) // 接受完成
- {
- flag = 0;
- sheding=RX_BUF[0]*10+RX_BUF[1];
- // xianshi(0x92,tab11[RX_BUF[0]/10],tab11[RX_BUF[0]%10]);
- // xianshi(0x94,tab11[RX_BUF[1]/10],tab11[RX_BUF[1]%10]);
- // xianshi(0x96,tab11[0],tab11[1]); xianshi(0x97,tab11[2],tab11[3]);
- }
- if(g_bPIDRunFlag) //PID调节
- {
- g_bPIDRunFlag=0;
- // pulse=0;
- pid.ActualSpeed=zhuansu; // pid.ActualSpeed-实际值 speed_c-每分钟电机转速
- speed_change=PID_realize(sheding);//pid.ActualSpeed rad_set
- // printf("%f\n",speed);
- // if(speed_change<0)
- // speed_change=speed_change*(-1);
- pwm_1=255-PID_realize(sheding);
- if(pwm_1>255)
- {
- pwm_1=254;
- PWM0_set(pwm_1); //设置PWM占空比
- }
- if(pwm_1<0)
- {
- pwm_1=0;
- PWM0_set(pwm_1); //设置PWM占空比
- }
- PWM0_set(pwm_1);
- // pulse=1;
- }
- display2();
- keyscan();
- }
- }
- void INIT0(void) interrupt 0
- {
- x1++;
-
- }
- void timer1(void) interrupt 1
- {
- static uchar a = 0;
- TL0 = 0x00; //设置定时初值
- TH0 = 0x28; //设置定时初值5MS
- // TL0 = 0x00; //设置定时初值
- // TH0 = 0x04; //设置定时初值
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
所有资料51hei提供下载:
第二届单片机大赛作品.zip
(6.87 MB, 下载次数: 149)
|