#include <reg52.h> |
| |
| #include <string.h> |
| |
| |
| |
| typedef unsigned char uchar; |
| typedef unsigned int uint; |
| |
| sbit m1 = P2^0; //pwm信號1 |
| sbit m2 = P2^1; //pwm信號2 |
| |
| sbit key0 = P3^3; //反接制動 |
| sbit key1 = P3^4; //方向切換及啟動 |
| sbit key2 = P3^5; //能耗制動 |
| sbit key3 = P3^6; //加速 |
| sbit key4 = P3^7; //減速 |
| |
| sbit BUTTON0 = P3^2; //外部中斷0 |
| //sbit BUTTON1 = P3^3; //外部中斷1 |
| |
| sbit RS = P0^2; |
| sbit RW = P0^1; |
| sbit EN = P0^0; |
| sbit relay = P0^3; |
| sbit led = P2^7; |
| |
| unsigned char flag=1,sflag=0; //flag:轉(zhuǎn)向標(biāo)志,1為正轉(zhuǎn)、0為翻轉(zhuǎn) |
| //sflag:啟動標(biāo)志,1為轉(zhuǎn)動狀態(tài)、0為停止?fàn)顟B(tài) |
| unsigned int t1=0; //t1:定時器中斷計數(shù) |
| int time=10; //time:占空比(0~10) |
| int freq,num; // num是外部中斷計數(shù)值,freq保存外部中斷的次數(shù) |
| char cnt=0; // 定時器0 1s計數(shù)值 |
| uint pp; // 定時器0 1s計數(shù)值,根據(jù)程序修改,本程序取pp=20時定時滿1s |
| |
| void delayms(unsigned int xms); //微秒級延時函數(shù) |
| void key(); //按鍵功能函數(shù) |
| void Initial(); //初始化函數(shù),包括定時器0(中斷),定時器1,外部中斷 |
| void Read_Busy(); //讀寫檢查函數(shù) |
| void Write_Cmd(uchar cmd); //寫指令函數(shù) |
| void Write_Dat(uchar dat); //寫入數(shù)據(jù) |
| void LCD1602_Init(); //LCD初始化 |
| void PrintStr(char *str); // LCD輸出字符串 |
| void DisplayNum(int m); // LCD顯示數(shù)值 |
| void delay(unsigned int x); |
| |
| /*****************主函數(shù)***********************/ |
| void main() |
| { |
| |
| m1=1; |
| m2=1; |
| |
| Initial(); // 初始化定時器0,1,外部中斷 |
| LCD1602_Init(); // 初始化LCD1602 |
| relay = 0; // 正常工作情況下繼電器不能得電 |
| led = 0; |
| while(1) |
| { |
| key(); |
| |
| Write_Cmd(0x80 | 0x00); // 顯示第1行 |
| PrintStr("Speed:"); |
| |
| DisplayNum(freq); |
| |
| PrintStr(" rpm"); |
| Write_Cmd(0xc0| 0x00); // 顯示第二行 |
| PrintStr("Duty:"); |
| DisplayNum(time*10); |
| Write_Dat('%'); |
| |
| } |
| } |
| |
| |
| |
| /************初始化函數(shù)**************** |
| * |
| * 功能描述:實現(xiàn)對定時器0,定時器1,外部中斷1中斷 |
| * |
| ************************************/ |
| void Initial() |
| { |
| TMOD=0X11; //設(shè)置定時器0 和 定時器1,工作方式1,16為定時 |
| |
| TH1 = 0XFC; //定時器0初值1ms |
| TL1 = 0X66; |
| IP = 0X00; // 中斷優(yōu)先級控制 |
| |
| //定時器1初值50ms |
| TH0 = 0x4c; //高8位 |
| TL0 = 0X00; //低8位 |
| |
| EX0 = 1; // 開啟外部中斷0,默認中斷優(yōu)先級為0 |
| EX1 = 1; // 開啟外部中斷0,默認中斷優(yōu)先級為2 |
| IT0 = 1; // 外部中斷觸發(fā)方式為脈沖觸發(fā) |
| TR0 = 1; // 定時器0啟動由后面啟動 |
| //TR1 = 1; // 定時器1用來參數(shù)PWM波,按下啟動按鈕后才啟動 |
| ET0 = 1; // 開定時器0中斷 |
| ET1 = 1; // 開定時器1中斷 |
| EA=1; // 開總中斷 |
| } |
| |
| /******************************************** |
| * |
| * 函數(shù)描述:定時器1中斷函數(shù),默認中斷編號3 |
| * |
| * t1 PWM波 |
| |-----| |-----| |
| | | | | |
| | | | | |
| ----- | |-----------| |--------- |
| |<--------------->| |
| time |
| ********************************************/ |
| |
| void timer1() interrupt 3 |
| { |
| TH1=0XFC; |
| TL1=0X66; |
| t1++; |
| if(t1<=time) |
| { |
| if(flag==1) //正轉(zhuǎn),P2^0 輸出PWM |
| { |
| m1=1; |
| m2=0; |
| } |
| else //反轉(zhuǎn),P2^1 輸出PWM |
| { |
| m1=0; |
| m2=1; |
| } |
| } |
| else |
| { |
| m1=1; |
| m2=1; |
| } |
| if(t1==10) //定時滿 1ms |
| { |
| t1=0; |
| } |
| } |
| |
| /** |
| * |
| * 函數(shù)描述:定時器0中斷函數(shù),默認中斷編號1,處理 |
| * 外部中斷的數(shù)值 |
| * |
| */ |
| |
| void timer0() interrupt 1 |
| { |
| TH0 = 0x4C; //定時器1初值50ms |
| TL0 = 0X00; |
| |
| pp++; |
| |
| if(pp ==20) //計時滿 1s |
| { |
| freq = num/6-25; //獲取1s內(nèi)中斷計數(shù)的值num,并進行數(shù)值處理,這個根據(jù)個人不同需求修改 |
| if(freq<=0) |
| freq=0; |
| num = 0; |
| //cnt++; |
| //led = ~led; |
| pp = 0; |
| } |
| } |
| |
| /** |
| * @brief 外部中斷0,P3^2口每來一次脈沖就計數(shù)值加1 |
| 記錄特定時間內(nèi)的脈沖數(shù),可用作頻率計 |
| * |
| */ |
| |
| void extern_int0(void) interrupt 0 //外部中斷0 |
| { |
| //led = ~led; |
| num ++; // 外部中斷計數(shù) |
| } |
| |
| /** |
| * @brief 外部中斷1,控制反接制動,反接約2s(軟件延時) |
| * |
| */ |
| |
| void extern_int1(void) interrupt 2 //外部中斷1 |
| { |
| TR1 = 0; //關(guān)閉定時器1,即關(guān)閉PWM輸出 |
| |
| if(flag) //判斷是由正轉(zhuǎn)停止還是由反轉(zhuǎn)狀態(tài)下停止, |
| { |
| m1 = 0; |
| m2 = 1; //反接制動 |
| delayms(2000); //延時2s |
| m1 = 1; //停止時m1,m2都輸出高電平 |
| sflag=0; |
| } |
| else if(!flag) |
| { |
| m1 = 1; |
| m2 = 0; |
| delayms(2000); |
| m2 = 1; |
| sflag=0; |
| } |
| } |
| |
| /* |
| //判斷液晶忙,如果忙則等待,因為1602也是一個CPU,要處理原來的指令,如果不判斷會導(dǎo)致數(shù)據(jù)紊亂 |
| void Read_Busy() //讀寫檢查函數(shù) |
| { |
| uchar busy; |
| P1 = 0xFF; //P0口作為數(shù)據(jù)端 |
| RS = 0; |
| RW = 1; //讀狀態(tài)的操作時序為 RS=L,RW=H,E=H,D0~D7輸出狀態(tài)字 |
| do |
| { |
| EN = 1; |
| busy = P1; |
| EN = 0; |
| }while(busy & 0x80); |
| //狀態(tài)字為busy(8位2進制數(shù))的最高位, |
| //若為1則禁止讀寫,為0則允許讀寫,該狀態(tài)用busy&0x80的結(jié)果表示 |
| } |
| |
| */ |
| |
| |
| /******************************************* |
| * |
| * 函數(shù)描述:寫指令函數(shù) |
| * |
| *******************************************/ |
| void Write_Cmd(uchar cmd) //寫指令函數(shù) |
| { |
| //Read_Busy(); //對控制器每次進行讀寫操作都要判斷是否正忙,即要進行讀寫檢測 |
| P1 = cmd; //寫入十六進制形式的指令(command) |
| RS = 0; |
| EN = 0; |
| delay(10); |
| |
| EN = 1; //寫指令的操作時序:RS=0,RW=0,EN=高脈沖 |
| delay(10); |
| EN = 0; //獲得高脈沖后使能端重新置零 |
| } |
| |
| |
| void Write_Dat(uchar dat) //寫入數(shù)據(jù) |
| { |
| // Read_Busy(); //寫入數(shù)據(jù)前進行讀寫檢測 |
| P1 = dat; //P0口寫入數(shù)據(jù) |
| RS = 1; |
| EN = 0; |
| |
| delay(10); |
| |
| EN = 1; //寫數(shù)據(jù)操作時序:RS=0,RW=0,EN=高脈沖 |
| delay(10); |
| EN = 0; //獲得高脈沖后使能端重新置零 |
| } |
| |
| void LCD1602_Init() |
| { |
| RW = 0; |
| Write_Cmd(0x38);//設(shè)置16*2顯示 |
| delay(8); |
| Write_Cmd(0x0f);//開顯示 顯示光標(biāo),光標(biāo)閃爍 |
| delay(8); |
| Write_Cmd(0x01);//清屏 |
| delay(8); |
| Write_Cmd(0x06);//地址指針移位命令 |
| delay(8); |
| //Write_Cmd(0x80 | 0x00);//顯示地址,0x80是第一行的的首地址。0x80|0x06表示數(shù)據(jù)從第一行第7個字符位置開始顯示 |
| |
| } |
| |
| /** |
| * @brief LCD1602打印字符串的函數(shù),使用到了strlen函數(shù),需要引入string.h頭文件 |
| * |
| */ |
| |
| void PrintStr(char *str) // LCD輸出字符串 |
| { |
| |
| char i,len; |
| len = strlen(str); // 獲取字符串長度 |
| for(i=0;i<len;i++) |
| { |
| Write_Dat(*str); |
| str++; |
| } |
| } |
| |
| /** |
| * @brief LCD1602顯示整數(shù),顯示4位數(shù) |
| * @note |
| * 希望補充顯示浮點型數(shù)值,未完成功能 |
| */ |
| void DisplayNum(int m) // LCD顯示數(shù)值 |
| { |
| |
| int disdata[4]; // 顯示占空比的數(shù)值,存到此數(shù)組 |
| disdata[0] = m/1000+0x30; |
| disdata[1] = m%1000/100+0x30; |
| disdata[2] = m%100/10+0x30; |
| disdata[3] = m%10+0x30; |
| |
| if(disdata[0]==0x30) //如果千位為0,讓LCD不顯示,0x30和0x20可以查詢ACSII碼表 |
| { |
| disdata[0]=0x20; |
| if( disdata[1]==0x30) //如果百位為0,讓LCD不顯示,0x30和0x20可以查詢ACSII碼表 |
| { |
| disdata[1]=0x20; |
| if( disdata[2]==0x30) //如果百位為0,讓LCD不顯示,0x30和0x20可以查詢ACSII碼表 |
| { |
| disdata[2]=0x20; |
| } |
| } |
| } |
| |
| Write_Dat(disdata[0]); |
| delay(4); |
| Write_Dat(disdata[1]); |
| delay(4); |
| Write_Dat(disdata[2]); |
| delay(4); |
| Write_Dat(disdata[3]); |
| delay(4); |
| |
| |
| } |
| |
| /** |
| * |
| * @brief 按鍵功能函數(shù),包括啟動/反轉(zhuǎn),能耗制動,加速,減速 |
| * |
| */ |
| void key() |
| { |
| if(key1==0) //轉(zhuǎn)向及啟動 |
| { |
| delayms(5); |
| if(key1==0) |
| { |
| while(key1==0); |
| if(sflag==1) //為了實現(xiàn)停止后再啟動保持之前的轉(zhuǎn)向 |
| { |
| flag=!flag; |
| TR1=1; //開啟定時器1,即開始PWM波輸出 |
| } |
| else |
| { |
| TR1=1; |
| sflag=1; |
| } |
| } |
| } |
| else if(key2==0) //停止 |
| { |
| delayms(5); |
| if(key2==0) |
| { |
| while(key2==0); |
| relay=1; //能耗制動 |
| TR1=0; //關(guān)閉定時器1,即關(guān)閉PWM輸出 |
| m1=1; |
| m2=1; |
| sflag=0; |
| } |
| } |
| else if(key3==0) //加速 |
| { |
| delayms(5); |
| if(key3==0) |
| { |
| while(key3==0); |
| if(time>=10) |
| time=10; |
| else |
| time++; |
| } |
| } |
| else if(key4==0) //減速 |
| { |
| delayms(5); |
| if(key4==0) |
| { |
| while(key4==0); |
| if(time==0) |
| time=0; |
| else |
| time--; |
| } |
| } |
| /* |
| else if(key0==0) // 按下反接制動 |
| { |
| delayms(5); //軟件消抖 |
| if(key0==0) //再次檢測到按下 |
| { |
| while(key0==0); |
| TR1 = 0; //關(guān)閉定時器1,即關(guān)閉PWM輸出 |
| |
| if(flag) //判斷 是由正轉(zhuǎn)停止還是由反轉(zhuǎn)狀態(tài)下停止 |
| { |
| m1 = 0; |
| m2 = 1; //反接制動 |
| // delayms(10); //延時1.5s |
| m1 = 1; //停止時m1,m2都輸出高電平 |
| sflag=0; |
| } |
| else if(!flag) |
| { |
| m1 = 1; |
| m2 = 0; |
| // delayms(150); |
| m2 = 1; |
| } |
| } |
| } |
| */ |
| |
| } |
| |
| |
| /** |
| * @brief 軟件延時函數(shù) |
| * |
| */ |
| void delayms(unsigned int xms) |
| { |
| unsigned int i,j; |
| for(i=xms;i>0;i--) |
| for(j=110;j>0;j--); |
| } |
| |
| /** |
| * @brief 軟件延時函數(shù) |
| * |
| */ |
| |
| void delay(unsigned int x) |
| { |
| unsigned int a,b; |
| for(a=x;a>0;a--) |
| for(b=10;b>0;b--); |
| } |