仿真原理圖如下(proteus仿真工程文件可到本帖附件中下載)
單片機源程序如下:
- #include <intrins.h> //引用程序目錄的相對路徑中的頭文件
- #include <reg52.h> //引用編譯器的類庫路徑里面的頭文件
- #define LCD P2 //LCD2004數據接口
- sbit RS=P1^2; //設置RS引腳接口,RS=0,指令寄存器;RS=1,數據寄存器
- sbit RW=P1^1; //設置R/W引腳接口,R/W=0,寫;R/W=1,讀
- sbit E=P1^0; //設置E引腳接口,E允許信號
- unsigned char RPM_R[]="000"; //右電機轉速,H整型轉換為字符型,定義數組長度。
- unsigned char RPM_L[]="000"; //左電機轉速,H整型轉換為字符型,定義數組長度。
- unsigned char V_R[]="000"; //右電機時速,H整型轉換為字符型,定義數組長度。
- unsigned char V_L[]="000"; //左電機時速,H整型轉換為字符型,定義數組長度。
- unsigned int rpm_r=0; //初始化右電機轉速
- unsigned int rpm_l=0; //初始化左電機轉速
- unsigned int v_r=0; //初始化右電機時速
- unsigned int v_l=0; //初始化左電機時速
- unsigned int D=770; //直徑
- unsigned char cnt=0; //中斷次數倍數,50ms為單位,若20倍,組成1秒
- unsigned char flag=0; //時鐘標志位
- /******************************
- LCD忙檢測函數子程序
- ******************************/
- void CheckBusy(void)
- {
- unsigned int nTimeOut=0;
- RS=0;
- RW=1;
- E=0;
- E=1;
- while((LCD&0x80)&&(++nTimeOut !=0));
- E=0;
- RS=0;
- RW=1;
- }
-
- /******************************
- LCD發送命令或數據子程序
- ******************************/
- void SendCmdorData(unsigned char byCmdorData,bit DI)
- {
- CheckBusy();
- RS=DI; //為寄存器選擇腳,高電平時選擇數據寄存器、低電平時選擇指令寄存器
- RW=0; //為讀、寫信號線,低電平時進行寫操作
- E=0; //E端為使能端,當E端由高電平跳變為低電平時,液晶模塊執行命令
- LCD=byCmdorData; //送數據
- _nop_(); //空操作,給硬件反應時間
- _nop_(); //空操作,給硬件反應時間
- E=1;
- _nop_(); //空操作,給硬件反應時間
- _nop_(); //空操作,給硬件反應時間
- E=0; //E引腳要有一個下降沿,才能把數據線上數據,命令送入1602
- RW=1; //為讀、寫信號線,高電平時進行讀操作
- RS=0; //為寄存器選擇腳,低電平時選擇指令寄存器
- }
- /******************************
- 延時1毫秒
- ******************************/
- void Delay(unsigned int nDelay)
- {
- unsigned int i;
- for(;nDelay>0;nDelay--)
- {
- for(i=124;i>0;i--);
- }
- }
- /******************************
- LCD初始化子程序
- ******************************/
- void Init(void)
- {
- SendCmdorData(0x38,0); //寫命令,設置16*2顯示,5*7點陣,8位數據接口
- Delay(50); //50ms延時,給硬件反應時間
- SendCmdorData(0x01,0); //寫命令,顯示清屏:1、數據指針清零 2、所有顯示清零
- Delay(50); //50ms延時,給硬件反應時間
- SendCmdorData(0x06,0); //寫命令,當讀或寫一個字符后地址指針加一,且光標加一
- Delay(50); //50ms延時,給硬件反應時間
- SendCmdorData(0x0c,0); //寫命令,開顯示、不顯示光標、光標不顯示
- Delay(50); //50ms延時,給硬件反應時間
- }
- /******************************
- 地址轉換子程序
- x為行號 y為列號
- ******************************/
- void SetAddress(unsigned char x,y)
- {
- unsigned char byAddress;
- switch(x)
- {
- case 1:byAddress=0x80+y;break; //第一行首地址
- case 2:byAddress=0xC0+y;break; //第二行首地址
- case 3:byAddress=0x94+y;break; //第三行首地址
- case 4:byAddress=0xD4+y;break; //第四行首地址
- default:break; //default就是如果沒有符合的case就執行它,default并不是必須的.
- }
- SendCmdorData(byAddress,0); //執行發送指令子程序
- }
- /******************************
- 發送字符串到LCD子程序
- ******************************/
- void PutString(unsigned char x,y,unsigned char *pData)
- {
- SetAddress(x,y); //執行地址轉換子程序
- while(*pData !='\0') //表示顯示內容不為空時,執行循環體的代碼段,
- {
- SendCmdorData(*pData++,1); //發送命令子程序,*就是聲明他的類型,是一個指向整型數據的指針
- }
- }
- /******************************
- 4位數的H整型轉換為字符型, 加48為轉ASCII。
- *就是聲明他的類型,是一個指向整型數據的指針
- ******************************/
- void Inttochar4(unsigned int a,unsigned char *chx)
- {
- chx[0]=a/1000+48; //高電平千位
- chx[1]=(a/100)%10+48; //高電平百位
- chx[2]=(a/10)%10+48; //高電平十位
- chx[3]=a%10+48; //高電平個位
- }
- /******************************
- 3位數的H整型轉換為字符型,加48為轉ASCII。
- *就是聲明他的類型,是一個指向整型數據的指針
- ******************************/
- void Inttochar3(unsigned int a,unsigned char *chx)
- {
- chx[0]=a/100+48; //百分數百位
- chx[1]=(a/10)%10+48; //百分數十位
- chx[2]=a%10+48; //百分數個位
- }
- /******************************
- LCD數據顯示子程序
- ******************************/
- void Display(void)
- {
- Inttochar3(rpm_r,(unsigned char *)RPM_R); //右電機轉速,H整型轉換為字符型。*就是聲明他的類型,是一個指向整型數據的指針
- Inttochar3(rpm_l,(unsigned char *)RPM_L); //左電機轉速,H整型轉換為字符型。*就是聲明他的類型,是一個指向整型數據的指針
- Inttochar3(v_r,(unsigned char *)V_R); //右電機速度,H整型轉換為字符型。*就是聲明他的類型,是一個指向整型數據的指針
- Inttochar3(v_l,(unsigned char *)V_L); //左電機速度,H整型轉換為字符型。*就是聲明他的類型,是一個指向整型數據的指針
- PutString(1,4,"R:"); //字體,2字節
- PutString(1,7,RPM_R); //RPM_R為右電機轉速的ASCII數組,3字節
- PutString(1,11,"r/min"); //字體,5字節
- PutString(2,4,"L:"); //字體,2字節
- PutString(2,7,RPM_L); //RPM_L為左電機轉速的ASCII數組,3字節
- PutString(2,11,"r/min"); //字體,5字節
- PutString(3,4,"R:"); //字體,2字節
- PutString(3,7,V_R); //V_R為右電機速度的ASCII數組,3字節
- PutString(3,11,"km/h"); //字體,4字節
- PutString(4,4,"L:"); //字體,2字節
- PutString(4,7,V_L); //V_L為左電機速度的ASCII數組,3字節
- PutString(4,11,"km/h"); //字體,4字節
- }
- /******************************
- 單片機初始化
- ******************************/
- void Initial()
- {
- TMOD=0x55; //定時器T0、T1工作于計數器模式1;解釋:C/T=1時為計數功能:加1計數器對來自輸入引腳T0(P3.4)和T1(P3.5)的外信號脈沖進行計數;M1=0、M0=1,方式1:16位定時器/計數器
- RCAP2H=(65536-50000)/256; //定時/計數器2陷阱寄存器高字節,50000次溢出一次產生中斷
- RCAP2L=(65536-50000)%256; //定時/計數器2陷阱寄存器低字節,50ms中斷
- ET2=1; //打開定時器中斷
- TR2=1; //打開定時器開關
- EA=1; //打開總中斷
- TR0=1; //打開定時器開關
- TR1=1; //打開定時器開關
- }
- /******************************
- 主程序
- ******************************/
- void main()
- {
- Init(); //LCD初始化子程序
- Initial(); //單片機初始化
- while(1)
- {
- TH0=0; //定時器T0高八位的初值
- TL0=0; //定時器T0低八位的初值
- TH1=0; //定時器T1高八位的初值
- TL1=0; //定時器T1低八位的初值
- flag=0; //時鐘標志位
- while(flag==0); // 時間未滿等待
- rpm_r=(TH0*256+TL0)*60/20; //計算轉速,乘以60秒,除以每周產生20個脈沖,單位為r/min
- v_r=D*3.14*(TH0*256+TL0)/20*3.6/1000; //v=2π*R*n,線速度為v,單位為m/s,轉速為n,單位為r/s,1m/s=3.6km/h
- rpm_l=(TH1*256+TL1)*60/20; //計算轉速,除以每周產生20個脈沖,單位為r/s
- v_l=D*3.14*(TH1*256+TL1)/20*3.6/1000; //v=2π*R*n,線速度為v,單位為m/s,轉速為n,單位為r/s,1m/s=3.6km/h
- Display();
- }
- }
- /******************************
- 中斷0(P3.2),C1接收個數累加
- ******************************/
- void time2() interrupt 5//定時器T2中斷服務程序
- {
- TF2=0; //定時器2溢出標志位,注意!定時器2必須由軟件對溢出標志位清零,硬件不能清零,這里與定時器0和定時器1不同。
- cnt++; //中斷次數倍數,50ms為單位
- if(cnt==20) //中斷20次,每次50ms秒,累加1s。
- {
- flag=1; //時鐘標志位
- cnt=0; //中斷次數倍數
- }
- }
復制代碼
Keil代碼下載:
OPG測速1.rar
(84.35 KB, 下載次數: 21)
2022-3-26 04:22 上傳
點擊文件名下載附件
|