這是樓主的課程作業,代碼寫的可能有點亂,見諒見諒。
可能后面串口部分代碼注釋不是很多,趕時間,沒辦法
移植注意了,我用的是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黑下載附件…………
復制代碼
0.png (46.58 KB, 下載次數: 66)
下載附件
2018-12-5 22:25 上傳
所有資料51hei提供下載:
程序源代碼.zip
(2.29 MB, 下載次數: 212)
2018-12-5 15:12 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
|