这是楼主的课程作业,代码写的可能有点乱,见谅见谅。
可能后面串口部分代码注释不是很多,赶时间,没办法
移植注意了,我用的是12Mhz的晶振,1200波特率
数码管用了IO扩展芯片,所以看代码时注意
直流电机速度闭环控制实验 一.实物图 1.1 补充材料清单 (1)原理:直流减速电机尾部为霍尔测速传感器,每转一圈,产生两个脉冲,单片机外部中断计数,在用定时器得到准确的时间,可以计算出电机转速和位置。 (2)用读取脉冲的单片机资源配置如下
每500ms读取一次速度,由于电机每一转产生两个脉冲,因此500ms的计数可以近似看作每一秒钟转过的圈数。 分正反转累加或累减,可以得到电机的位置。 用Keil C编写程序,串口调试助手控制和显示电机状态,如下图   
单片机源程序如下:
- /************************************
- 在基础版上增加了串口控制功能
- 计数方式由计数器变为外部中断0,编码器输出口接P32
- 波特率为1200,晶振为12Mhz 移植需注意
- 串口控制命令
- #start# 启动
- #stop# 停止
- #foreward# 正转
- #back# 反转
- #speed up-N# 占空比增加N%
- #speed down-N# 占空比减少N%
- #pwm-N# 占空比调到N%
- ***************************************/
- #include "reg52.h" //此文件中定义了单片机的一些特殊功能寄存器
- #include "stdio.h" //printf头文件
- #include "string.h" //字符串处理 头文件
- #define T0_time 1000 //计时器T0时间 单位us 晶振12MHz
- #define Total_PWM 100 //占空比可以100级调整
- #define GPIO_KEY P1 //矩阵键盘
- typedef unsigned char u8;
- typedef unsigned int u16;
- sbit Int1=P2^0;
- sbit Int2=P2^1;
- sbit LSA=P2^2;
- sbit LSB=P2^3;
- sbit LSC=P2^4;
- int SetPoint=0; //目标速度
- double Proportion=0.32; //比例常数
- double Integral=0.15; //积分常数
- double Derlvative=0.12; //微分常数
- int LastError; //Error[-1]
- int PrevError; //Error[-2]
- int Pid_flag=0;
- long angle=0; //记录角度
- int i=0,j=0,Data=0,flag=1; //用于串口接受数据,不得用于其他地方,flag用于区分接收指令1还是数据0
- char ReceiveData,Command[15]; //command接收指令
- char code Command_Choose[][20]={"start","stop","foreward","back","speed up","speed down","pwm","pid"};
-
- int PWM_TIME_H=0,PWM=0; //用于控制占空比,高电平比例,最大为100
- u16 count=0,int_time=0,speed=0; //count计脉冲数,int_time多少时间读取一次脉冲数
- u8 key=0,gear=0,speed_show_time=0; //key表示被按下的按键,gear=1正转,2反转 .0停止 speed_show_time用于显示数码管
- u8 code smgduan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
- 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//显示0~F的值
- u8 code smgduan_direction[3]={0x00,0x00,0x40};
- void delay(unsigned int z); //延时函数
- void speed_out(); //数码管速度显示
- void Init(void); //初始化定时器T0,计数器T1
- void Motor(); //电机驱动
- void KeyDown(void); //检测按键
- int PID(int NextPoint); //增量式PID算法
- void ChooseFunction(void); //执行按键对应的功能
- void main()
- {
- Init();
- while(1)
- {
- if(gear)
- {
- if(gear==1)
- printf("PWM=%d%%, Speed=%dn/s",PWM_TIME_H,speed);
- if(gear==2)
- printf("PWM=%d%%, Speed=-%dn/s",PWM_TIME_H,speed);
-
- if(Pid_flag||key>=5&&key<=8) //如果处于pid模式
- printf(", PID=%d",SetPoint);
- //角度读取
- printf(", angle=180*%ld\n",angle);
- }
- else
- printf("PWM=%d%%, Waiting to start\n",PWM_TIME_H);
- KeyDown(); //按键
- }
- }
- int PID(int NextPoint)
- {
- int iError,PID; //当前误差和反馈量
- iError = SetPoint-NextPoint; //计算当前误差
- PID = Proportion*iError //E[K]
- + Integral*LastError //E[K-1]
- + Derlvative*PrevError; //E[K-2]
-
- PrevError = LastError; //存储误差
- LastError = iError;
- return PID;
- }
- void uart_receiver(void) interrupt 4 //串口中断
- {
- if(RI) // 判断是串口接收产生中断
- {
- RI = 0; // 清接收中断标志
- ReceiveData = SBUF; // 接收到的数据写入缓冲BUF
- if(flag) Command[i++]= ReceiveData; //保存到字符组
- if(flag==0 && ReceiveData != '#')
- Data=Data*10 + (int)ReceiveData-48; //计算出数值
-
- if(ReceiveData == '-')
- Data=0,flag=0,Command[i-1]='\0'; //准备开始接收数据
-
- if(ReceiveData == '#')
- { Command[i-1]='\0',i=0,flag=1; //接收数据完成,i清零,准备下次接收
- Pid_flag=0,key=0; //每次先关闭pid调速
- for(j=0;j<10;j++)
- {
- if(strcmp(Command,Command_Choose[j])==0)
- {
- switch(j) //每个按键对应相应的功能
- {
- case(0): //开始
- gear=1;break;
- case(1): //停止
- gear=0;break;
- case(2): //正转
- gear=1;break;
- case(3): //反转
- gear=2;break;
- case(4): //加速
- PWM_TIME_H+=Data;
- if(PWM_TIME_H>Total_PWM) PWM_TIME_H=Total_PWM;
- break;
- case(5): //减速
- PWM_TIME_H-=Data;
- if(PWM_TIME_H<0) PWM_TIME_H=0;
- break;
- case(6): //pwm
- if(Data>100) PWM_TIME_H=100;
- else PWM_TIME_H=Data;
- break;
- case(7): //PID目标速度
- if(Data>70) SetPoint=70;
- else SetPoint=Data;
- Pid_flag=1;
- break;
- }
- }
- }
- }
- }
- }
- void Count_EX0(void) interrupt 0 //外部中断0的中断函数
- {
- count++; //脉冲计数
- }
- void timer0(void) interrupt 1 //定时器T0的中断函数
- {
- TH0=(65536-T0_time)/256; //TH0=(2^16-t)/256 晶振12MHZ t单位us
- TL0=(65536-T0_time)/256; //TL0=(2^16-t)%256 晶振12MHZ t单位us
-
- PWM++;
- if(PWM==Total_PWM) PWM=0;
-
- int_time++;
- if(int_time==500) //每500次(500ms)T0中断,测速一次
- {
- int_time=0; //重新赋值0
- speed=count; //读取速度
- if(gear==1)
- angle+=count; //读取角度正转+
- if(gear==2)
- angle-=count; //反转-
- count=0; //计数清零
- /******PID***********/
- if(key>=5&&key<=8||Pid_flag)
- if((speed-SetPoint>1) || (speed-SetPoint<-1))
- {
- PWM_TIME_H+=PID(speed);
- if(PWM_TIME_H>Total_PWM) PWM_TIME_H=Total_PWM;
- }
- /*************************/
- }
- Motor();
- speed_out();
-
- }
- void ChooseFunction(void)
- {
- Pid_flag=0; //每次先关闭pid调速
- switch(key) //每个按键对应相应的功能
- {
- case(1): //选择正反转,1正转,2反转
- if(gear==1) gear=2;
- else if(gear==2) gear=1;
- else gear=0;
- break;
- case(2): //加占空比
- PWM_TIME_H+=10;
- if(PWM_TIME_H>Total_PWM) PWM_TIME_H=Total_PWM;
- break;
- case(3): //减占空比
- PWM_TIME_H-=10;
- if(PWM_TIME_H<0) PWM_TIME_H=0;
- break;
- case(4): //开关
- if(gear==1||gear==2) gear=0;
- else gear=1;
- break;
- case(5): //PID目标速度40
- SetPoint=40;
- break;
- case(6): //PID目标速度50
- SetPoint=50;
- break;
- case(7): //PID目标速度60
- SetPoint=60;
- break;
- case(8): //PID目标速度70
- SetPoint=70;
- break;
- }
- }
- void KeyDown(void)
- {
- char a=0;
- GPIO_KEY=0x0f;
- if(GPIO_KEY!=0x0f)//读取按键是否按下
- {
- delay(100);//延时1ms进行消抖
- if(GPIO_KEY!=0x0f)//再次检测键盘是否按下
- {
- //测试列
- GPIO_KEY=0X0F;
- switch(GPIO_KEY)
- {
- case(0X07): key=1;break;
- case(0X0b): key=2;break;
- case(0X0d): key=3;break;
- case(0X0e): key=4;break;
- }
- //测试行
- GPIO_KEY=0XF0;
- switch(GPIO_KEY)
- {
- case(0X70): key=key;break;
- case(0Xb0): key=key+4;break;
- case(0Xd0): key=key+8;break;
- case(0Xe0): key=key+12;break;
- }
- if(key==16) key=0;
- ChooseFunction();
- while((a<50)&&(GPIO_KEY!=0xf0)) //检测按键松手检测
- {
- delay(100);
- a++;
- }
- }
- }
- }
- void speed_out()//数码管显示速度与档位
- {
- u8 speed_3=speed%1000/100; //速度百位数字
- u8 speed_2=speed%100/10; //速度十位数字
- u8 speed_1=speed%10; //速度个位数字
- u8 PWM_TIME_H_2=PWM_TIME_H/10; //档位十位数字
- u8 PWM_TIME_H_1=PWM_TIME_H%10; //档位个位数字
-
- speed_show_time++;
- if(speed_show_time==7)
- speed_show_time=0;
- P0=0x00; //消影
- switch(speed_show_time)
- {
- case(0):
- LSA=0;LSB=0;LSC=0;
- P0=smgduan[speed_1];
- break;
- case(1):
- LSA=1;LSB=0;LSC=0;
- P0=smgduan[speed_2];
- break;
- case(2):
- LSA=0;LSB=1;LSC=0;
- P0=smgduan[speed_3];
- break;
- case(3):
- LSA=0;LSB=0;LSC=1;
- P0=smgduan[PWM_TIME_H_1];
- break;
- case(4):
- LSA=1;LSB=0;LSC=1;
- P0=smgduan[PWM_TIME_H_2];
- break;
- case(5):
- LSA=0;LSB=1;LSC=1;
- P0=smgduan_direction[gear];
- break;
- case(6):
- LSA=1;LSB=1;LSC=1;
- P0=smgduan[key];
- break;
- }
- }
- void Motor(void) //电机驱动
- { switch(gear)
- {
- case(0): //电机停止
- Int2=Int1=0;
- break;
- case(1): //电机正转
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
所有资料51hei提供下载:
程序源代码.zip
(2.29 MB, 下载次数: 212)
|