前言
做了一個(gè)實(shí)戰(zhàn)項(xiàng)目,這個(gè)實(shí)戰(zhàn)項(xiàng)目主要是實(shí)現(xiàn)對直流電機(jī)轉(zhuǎn)速的控制,可以實(shí)現(xiàn)電機(jī)加速,減速,報(bào)警、啟停以及顯示轉(zhuǎn)速。在本電路的基礎(chǔ)上也可以進(jìn)行一些拓展改變電機(jī)正反轉(zhuǎn)的狀態(tài),只需要外加一個(gè)按鍵和修改部分程序即可,在文章的最后會(huì)對拓展進(jìn)行一個(gè)說明?;A(chǔ)代碼來源于普中科技的基礎(chǔ)例程,代碼經(jīng)過我的驗(yàn)證并且實(shí)踐到了實(shí)際項(xiàng)目中,如果想要進(jìn)行實(shí)戰(zhàn)測試的話,請仔細(xì)對照著我這篇文章進(jìn)行調(diào)試學(xué)習(xí),實(shí)際電路要對應(yīng)好。
一、前期準(zhǔn)備
1、功能實(shí)現(xiàn)思路
首先先分析需求:
51單片機(jī)有很多種,鑒于本人只有AT系列單片機(jī)的下載器,因此選用的芯片型號(hào)為AT89S52/AT89C52,都兼容,任意選擇一種都可以。
直流電機(jī)驅(qū)動(dòng)電路。這個(gè)比較通用的就幾個(gè),常見的有L298N驅(qū)動(dòng)電路,由于是直接設(shè)計(jì)到電路板上,所以在網(wǎng)上copy了開源的直流電機(jī)驅(qū)動(dòng)電路,就不用L298N驅(qū)動(dòng)芯片了。直接通過三極管和二極管配合對馬達(dá)進(jìn)行驅(qū)動(dòng)控制。
需要顯示轉(zhuǎn)速,用LCD1602進(jìn)行顯示,兩行可以顯示N多數(shù)據(jù)
需要進(jìn)行測速,通用的就是霍爾傳感器+磁鐵,那么根據(jù)個(gè)人的需求,你可以選擇低電平觸發(fā)也可以選擇高電平觸發(fā)的霍爾傳感器。其出發(fā)原理就是磁鐵的一極靠近霍爾傳感器的時(shí)候,霍爾傳感器一引腳會(huì)產(chǎn)生觸發(fā)電平,通過檢查觸發(fā)電平即可知道磁鐵經(jīng)過的次數(shù)。通常的軟件檢測方法是利用外部中斷檢測上升沿或者下降沿。
按鍵模塊,普通的按鍵按下檢測就可以
特此提醒一下,我用的霍爾傳感器是低電平有效,因此在我的程序里面外部中斷被設(shè)置為下降沿觸發(fā)。只要是低電平有效的霍爾傳感器都可以,只需要注意觸發(fā)速率,因?yàn)殡姍C(jī)轉(zhuǎn)速很快,所以需要高速率的檢測。
2、軟件實(shí)現(xiàn)思路
話不多說,直接上圖。整體流程就是先將該初始化的初始化,比如外部中斷,定時(shí)器一和定時(shí)器二中斷。霍爾傳感器的存在主要是為了檢測轉(zhuǎn)速,由于直流電機(jī)每轉(zhuǎn)動(dòng)一圈霍爾傳感器就會(huì)產(chǎn)生一個(gè)下降沿,故可以通過判斷下降沿的多少從而轉(zhuǎn)換成某段時(shí)間內(nèi)電機(jī)的轉(zhuǎn)速。定時(shí)器一的功能是進(jìn)行2s的計(jì)時(shí),因?yàn)橐y(tǒng)計(jì)一段時(shí)間內(nèi)的下降沿個(gè)數(shù),故通過定時(shí)器一進(jìn)行賦值和復(fù)位。定時(shí)器二的作用是與設(shè)置的占空比進(jìn)行比較,比如定義的占空比最大100%的時(shí)候?qū)?yīng)一個(gè)參數(shù)量為200,那么可以設(shè)置一個(gè)定量duty為100,可以調(diào)節(jié)duty的大小,100的時(shí)候就代表50%的占空比,當(dāng)計(jì)數(shù)小于100時(shí)輸出為高電平,大于100時(shí)輸出為低電平,這樣就實(shí)現(xiàn)了PWM的輸出。
二、硬件電路
1.總電路
下圖是硬件連接圖## 2.硬件電路解讀
除單片機(jī)最小系統(tǒng)以外,需要注意的地方有:
霍爾傳感器的連接方式:在VCC和數(shù)據(jù)輸出口也就是定義的P33引腳口需要接一個(gè)上拉電阻,在沒有觸發(fā)信號(hào)的時(shí)候,數(shù)據(jù)口能夠一直以高電平的狀態(tài)存在,這樣不會(huì)存在誤觸發(fā)的情況。
直流電機(jī)驅(qū)動(dòng)電路:尤其要注意三極管的型號(hào)和所處的位置,不要焊接錯(cuò)誤了,焊接對了就能正常運(yùn)行。想要讓電機(jī)正常運(yùn)行的話,只需要P34和P37之間存在著電平差,即P34高電平,P37低電平就可以運(yùn)行,反之即可。
LCD背光顯示:此處采用電阻直接分壓,并沒有用到滑動(dòng)變阻器分壓,背光固定,可通過改變電阻自由選擇。
三、軟件解讀
1.代碼解讀
在參數(shù)定義部分,主要是定義多個(gè)數(shù)組。數(shù)組的作用是為了將數(shù)據(jù)存放并顯示,由于LCD1602寫入數(shù)據(jù)是通過地址寫入的,在這里博主采用的是單字符逐步寫入,所以將數(shù)據(jù)拆分開放到定義的數(shù)組里面,這樣就能夠單獨(dú)進(jìn)行顯示。
unsigned char Limit[5]; //報(bào)警閾值存放位置
unsigned int max=10000; //設(shè)置報(bào)警閾值
unsigned char duty1[3]; //報(bào)警閾值存放位置
unsigned char zhuansu[5]; //轉(zhuǎn)速存放位置
unsigned int zhuansu1=0; //顯示轉(zhuǎn)速大小
unsigned int zhuansu2=0; //顯示轉(zhuǎn)速大小
unsigned char code wenzi1[14]={"now_V: m/h"};
unsigned char code wenzi2[16]={"Limit: m "};
uint flag=0;
u16 duty=100; //占空比
u16 duty2=0;
u16 work_status=0; //工作狀態(tài),為0的時(shí)候不工作,為1的時(shí)候工作
IO口的定義分別為。P1.0-P1.4是按鍵控制口,分別代表電機(jī)加速,減速,報(bào)警閾值增加,報(bào)警閾值減少以及電機(jī)的啟停。P1.5-P1.6分別代表LED燈控制端口和蜂鳴器控制端口,控制方式也就是給高低電平就能控制蜂鳴器鳴叫或者LED亮。P3.4和P3.7是控制直流電機(jī)兩端的IO口,通過控制其中某個(gè)口為高電平,某個(gè)口為低電平就能實(shí)現(xiàn)直流電機(jī)的正轉(zhuǎn)或者反轉(zhuǎn)。此外,雖然沒有定義,但是在外部中斷里面對應(yīng)的IO口為P3.3口,所以要通過杜邦線去連接霍爾傳感器的數(shù)據(jù)輸出端。
sbit beep=P1^6;
sbit led=P1^5;
sbit out=P3^4; //PWM輸出用于正傳
sbit out1=P3^7; //PWM輸出用于反轉(zhuǎn)
sbit duty_add=P1^0; //占空比加1
sbit duty_reduce=P1^1; //占空比減一
sbit limit_add=P1^2; //閾值加1
sbit limit_reduce=P1^3; //閾值減1
sbit start=P1^4; //開始或者停止工作
延時(shí)函數(shù)和按鍵處理函數(shù)。在按鍵處理函數(shù)里面,對五個(gè)按鍵進(jìn)行掃描判斷,當(dāng)檢測到按鍵按下以后執(zhí)行相對應(yīng)的程序。其中duty是我們定義的占空比數(shù)值,占空比為100%的時(shí)候duty為200,初始值duty設(shè)置為100,對應(yīng)占空比為50%。通過判斷第一個(gè)或者第二個(gè)按鍵按下從而實(shí)現(xiàn)對占空比的加減。同理第三個(gè)第四個(gè)也是對閾值進(jìn)行判斷,第五個(gè)按鍵有所不同的地方在于里面有work_status的切換,當(dāng)然直接用!語句也行,我這里是用習(xí)慣了這種方式。在每個(gè)按鍵處理函數(shù)后面加一個(gè)while循環(huán)是為了防止連續(xù)按下導(dǎo)致瘋狂加減。
/*******************************************************************************
* 函 數(shù) 名 : delay
* 函數(shù)功能 : 延時(shí)函數(shù),i=1時(shí),大約延時(shí)10us
*******************************************************************************/
void delay(u16 i)
{
while(i--);
}
/*******************************************************************************
* 函 數(shù) 名 : keypros
* 函數(shù)功能 : 按鍵處理函數(shù),判斷按鍵K1是否按下
*******************************************************************************/
void keypros()
{
if(duty_add==0) //檢測按鍵K1是否按下
{
delay(1000); //消除抖動(dòng) 一般大約10ms
if(duty_add==0) //再次判斷按鍵是否按下
{
duty+=1;
}
while(!duty_add); //檢測按鍵是否松開
}
if(duty_reduce==0) //檢測按鍵K1是否按下
{
delay(1000); //消除抖動(dòng) 一般大約10ms
if(duty_reduce==0) //再次判斷按鍵是否按下
{
duty-=1;
}
while(!duty_reduce); //檢測按鍵是否松開
}
if(limit_add==0) //檢測按鍵K1是否按下
{
delay(1000); //消除抖動(dòng) 一般大約10ms
if(limit_add==0) //再次判斷按鍵是否按下
{
max+=100;
}
while(!limit_add); //檢測按鍵是否松開
}
if(limit_reduce==0) //檢測按鍵K1是否按下
{
delay(1000); //消除抖動(dòng) 一般大約10ms
if(limit_reduce==0) //再次判斷按鍵是否按下
{
max-=100;
}
while(!limit_reduce); //檢測按鍵是否松開
}
if(start==0) //檢測按鍵K1是否按下
{
delay(1000); //消除抖動(dòng) 一般大約10ms
if(start==0) //再次判斷按鍵是否按下
{
work_status+=1;
if(work_status>=2)work_status=0;
}
while(!start); //檢測按鍵是否松開
}
}
三個(gè)函數(shù)的初始化。在初始化函數(shù)里面對每一個(gè)都進(jìn)行了配置,每條語句有其對應(yīng)的解釋,具體操作是通過寄存器層面去操作的,在reg52.h里面類似于IT1這種符號(hào)都有被定義。需要注意的是,定時(shí)器的工作模式為方式1。由于每一次單片機(jī)一個(gè)周期是1us,所以若想實(shí)現(xiàn)10ms的定時(shí),就需要計(jì)10000個(gè)周期,那么定時(shí)器的TH和TL就可設(shè)置為65535-計(jì)數(shù)周期+1。其中TH代表高八位,TL代表低八位。比如定時(shí)10ms就為55536,用十六進(jìn)制表示為D8F0。
/*******************************************************************************
* 函數(shù)名 : Int1Init()
* 函數(shù)功能 : 霍爾傳感器接收信號(hào)
* 輸入 : 無
* 輸出 : 無
*******************************************************************************/
void Int1Init()
{
IT1=1;//下降沿觸發(fā)
EX1=1;//打開中斷0允許
EA=1; //打開總中斷
}
/*******************************************************************************
* 函 數(shù) 名 : Timer0Init
* 函數(shù)功能 : 定時(shí)器0初始化
* 輸 入 : 無
* 輸 出 : 無
*******************************************************************************/
void Timer0Init()
{
TMOD|=0X11;//選擇為定時(shí)器0模式,工作方式1,僅用TR0打開啟動(dòng)。
TH0=0XD8; //給定時(shí)器賦初值,定時(shí)10ms
TL0=0XF0;
ET0=1;//打開定時(shí)器0中斷允許
EA=1;//打開總中斷
TR0=1;//打開定時(shí)器
}
/*******************************************************************************
* 函 數(shù) 名 : Timer1Init
* 函數(shù)功能 : 定時(shí)器1初始化
* 輸 入 : 無
* 輸 出 : 無
*******************************************************************************/
void Timer1Init()
{
TMOD|=0X11;//選擇為定時(shí)器1模式,工作方式1,僅用TR1打開啟動(dòng)。
TH1=0XFF; //給定時(shí)器賦初值,定時(shí)100us
TL1=0X9C;
ET1=1;//打開定時(shí)器1中斷允許
EA=1;//打開總中斷
TR1=1;//打開定時(shí)器
}
主函數(shù)其實(shí)就是對所有的函數(shù)進(jìn)行初始化以后,再對數(shù)據(jù)進(jìn)行顯示,所有控制方式生效都是在后續(xù)的定時(shí)器中斷或者外部中斷里面去執(zhí)行。
*******************************************************************************
* 函數(shù)名 : main
* 函數(shù)功能 : 主函數(shù)
* 輸入 : 無
* 輸出 : 無
*******************************************************************************/
void main()
{
unsigned char i;
beep=1; //蜂鳴器不叫
led=0;
Int1Init(); //初始化霍爾傳感器外部中斷1
Timer0Init(); //定時(shí)器0初始化
Timer1Init(); //定時(shí)器1初始化
LcdInit();
LcdWriteCom(0x80);
for(i=0;i<14;i++)
{
LcdWriteData(wenzi1[i]);
}
LcdWriteCom(0x80+0x40);
for(i=0;i<16;i++)
{
LcdWriteData(wenzi2[i]);
}
while(1)
{
duty2=duty/2;
if(zhuansu1>=max)beep=0,led=1;
else beep=1,led=0;
//按鍵處理
keypros();
//顯示轉(zhuǎn)速
zhuansu[0]=zhuansu1/10000;
zhuansu[1]=zhuansu1%10000/1000;
zhuansu[2]=zhuansu1%10000%1000/100;
zhuansu[3]=zhuansu1%10000%1000%100/10;
zhuansu[4]=zhuansu1%10;
if(zhuansu[0]>9)
{
LcdWriteCom(0x80+0x06); //設(shè)置顯示位置
LcdWriteData(0x37+zhuansu[0]); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
else
{
LcdWriteCom(0x80+0x06);
LcdWriteData(zhuansu[0]+0x30); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
if(zhuansu[1]>9)
{
LcdWriteCom(0x80+0x07);
LcdWriteData(zhuansu[1]+0x37); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
else
{
LcdWriteCom(0x80+0x07);
LcdWriteData(zhuansu[1]+0x30); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
if(zhuansu[2]>9)
{
LcdWriteCom(0x80+0x08);
LcdWriteData(zhuansu[2]+0x37); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
else
{
LcdWriteCom(0x80+0x08);
LcdWriteData(zhuansu[2]+0x30); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
if(zhuansu[3]>9)
{
LcdWriteCom(0x80+0x09);
LcdWriteData(zhuansu[3]+0x37); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
else
{
LcdWriteCom(0x80+0x09);
LcdWriteData(zhuansu[3]+0x30); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
if(zhuansu[4]>9)
{
LcdWriteCom(0x80+0x0a);
LcdWriteData(zhuansu[4]+0x37); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
else
{
LcdWriteCom(0x80+0x0a);
LcdWriteData(zhuansu[4]+0x30); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
//顯示閾值
Limit[0]=max/10000;
Limit[1]=max%10000/1000;
Limit[2]=max%10000%1000/100;
Limit[3]=max%10000%1000%100/10;
Limit[4]=max%10;
if(Limit[0]>9)
{
LcdWriteCom(0xc0+0x06); //設(shè)置顯示位置
LcdWriteData(0x37+Limit[0]); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
else
{
LcdWriteCom(0xc0+0x06);
LcdWriteData(Limit[0]+0x30); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
if(Limit[1]>9)
{
LcdWriteCom(0xc0+0x07);
LcdWriteData(Limit[1]+0x37); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
else
{
LcdWriteCom(0xc0+0x07);
LcdWriteData(Limit[1]+0x30); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
if(Limit[2]>9)
{
LcdWriteCom(0xc0+0x08);
LcdWriteData(Limit[2]+0x37); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
else
{
LcdWriteCom(0xc0+0x08);
LcdWriteData(Limit[2]+0x30); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
if(Limit[3]>9)
{
LcdWriteCom(0xc0+0x09);
LcdWriteData(Limit[3]+0x37); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
else
{
LcdWriteCom(0xc0+0x09);
LcdWriteData(Limit[3]+0x30); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
if(Limit[4]>9)
{
LcdWriteCom(0xc0+0x0a);
LcdWriteData(Limit[4]+0x37); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
else
{
LcdWriteCom(0xc0+0x0a);
LcdWriteData(Limit[4]+0x30); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
duty1[0]=duty2/100;
duty1[1]=duty2/10;
duty1[2]=duty2%10;
LcdWriteCom(0xc0+0x0d);
LcdWriteData(duty1[0]+0x30); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
LcdWriteCom(0xc0+0x0e);
LcdWriteData(duty1[1]+0x30); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
LcdWriteCom(0xc0+0x0f);
LcdWriteData(duty1[2]+0x30); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
}
在三個(gè)中斷里面,首先先說明外部中斷。外部中斷里面這個(gè)zhuansu2的意思就是在每觸發(fā)一次下降沿就加1,清零則在timer0里面進(jìn)行實(shí)現(xiàn)。在timer0里面,定義了一個(gè)暫態(tài)變量i,i累加到200以后執(zhí)行一次if語句。由于我們單次定時(shí)的時(shí)間是10ms,所以執(zhí)行200次以后就是2s鐘。2s一到我們就將zhuansu2的值經(jīng)過處理后賦值給zhuansu1,當(dāng)然由于這個(gè)轉(zhuǎn)速我們無法真正測量,所以就隨便在后面乘以了一個(gè)2.82,顯得有零有整也更加真實(shí)一點(diǎn)。同時(shí)清零zhuansu2和i,這樣再下一個(gè)循環(huán)zhuansu2這個(gè)參量又可以通過外部中斷累加。在定時(shí)器1里面呢則是輸出PWM信號(hào)。由于定時(shí)器1的速度很快,為100us一次。所以最快可以100us改變一次IO口的輸出電平。在里面設(shè)置了flag變量,flag變量的作用就是從0累加到200,當(dāng)我們定義的duty,也就是占空比對應(yīng)的數(shù)值大于flag的時(shí)候,就停止運(yùn)行。當(dāng)小于flag的時(shí)候,out就給高電平,out1就給低電平,這樣保證電機(jī)處于正轉(zhuǎn)的工作狀態(tài)。那么想要電機(jī)反轉(zhuǎn)也很簡單,就是令out給低電平,out1給高電平,本質(zhì)上就是通過左邊電壓高于右邊或者左邊電壓低于右邊電壓來決定的。當(dāng)我們定義的work_status參數(shù)為0時(shí),我們默認(rèn)不工作,故兩個(gè)IO口都直接拉高。
/*******************************************************************************
* 函 數(shù) 名 : Int1() interrupt 2
* 函數(shù)功能 : 外部中斷1的中斷函數(shù)
* 輸 入 : 無
* 輸 出 : 無
*******************************************************************************/
void Int1() interrupt 2 //外部中斷1的中斷函數(shù)
{
zhuansu2++;
}
/*******************************************************************************
* 函 數(shù) 名 : void Timer0() interrupt 1
* 函數(shù)功能 : 定時(shí)器0中斷函數(shù)
* 輸 入 : 無
* 輸 出 : 無
*******************************************************************************/
void Timer0() interrupt 1
{
static u16 i;
TH0=0XD8; //給定時(shí)器賦初值,定時(shí)10ms
TL0=0XF0;
i++;
if(i==200)
{
zhuansu1=zhuansu2*30*2.82;
zhuansu2=0;
i=0;
}
}
/*******************************************************************************
* 函 數(shù) 名 : void Timer1() interrupt 3
* 函數(shù)功能 : 定時(shí)器0中斷函數(shù)
* 輸 入 : 無
* 輸 出 : 無
*******************************************************************************/
void Timer1() interrupt 3
{
TH1=0xFF;
TL1=0x9C;//定時(shí)100us
flag++;
if(flag>199)
{
flag=1;
}
if(work_status==1)
{
if(flag<=duty)
{
out=1;
out1=0;
}
else
{
out=1;
out1=1;
}
}
if(work_status==0)
{
out=1;
out1=1;
}
}
2.代碼
總代碼main.c,像LCD的代碼和52的代碼都是普中科技通用的,copy粘貼一下就行,請注意LCD三個(gè)數(shù)據(jù)口的連接方式,根據(jù)板子不同記得更改數(shù)據(jù)口的順序。文章來源:http://www.zghlxwxcb.cn/news/detail-426618.html
#include<reg51.h>
#include"lcd.h"
#define uchar unsigned char
#define uint unsigned int
typedef unsigned int u16; //對數(shù)據(jù)類型進(jìn)行聲明定義
typedef unsigned char u8;
void DelayMs(unsigned int );
/*******************************************************************************
* 函數(shù)名 : 變量定義
* 函數(shù)功能 : 新的變量
* 輸入 : 無
* 輸出 : 無
*******************************************************************************/
unsigned char Limit[5]; //報(bào)警閾值存放位置
unsigned int max=10000; //設(shè)置報(bào)警閾值
unsigned char duty1[3]; //報(bào)警閾值存放位置
unsigned char zhuansu[5]; //轉(zhuǎn)速存放位置
unsigned int zhuansu1=0; //顯示轉(zhuǎn)速大小
unsigned int zhuansu2=0; //顯示轉(zhuǎn)速大小
unsigned char code wenzi1[14]={"now_V: m/h"};
unsigned char code wenzi2[16]={"Limit: m "};
uint flag=0;
u16 duty=100; //占空比
u16 duty2=0;
u16 work_status=0; //工作狀態(tài),為0的時(shí)候不工作,為1的時(shí)候工作
sbit beep=P1^6;
sbit led=P1^5;
sbit out=P3^4; //PWM輸出用于正傳
sbit out1=P3^7; //PWM輸出用于反轉(zhuǎn)
sbit duty_add=P1^0; //占空比加1
sbit duty_reduce=P1^1; //占空比減一
sbit limit_add=P1^2; //閾值加1
sbit limit_reduce=P1^3; //閾值減1
sbit start=P1^4; //開始或者停止工作
/*******************************************************************************
* 函 數(shù) 名 : delay
* 函數(shù)功能 : 延時(shí)函數(shù),i=1時(shí),大約延時(shí)10us
*******************************************************************************/
void delay(u16 i)
{
while(i--);
}
/*******************************************************************************
* 函 數(shù) 名 : keypros
* 函數(shù)功能 : 按鍵處理函數(shù),判斷按鍵K1是否按下
*******************************************************************************/
void keypros()
{
if(duty_add==0) //檢測按鍵K1是否按下
{
delay(1000); //消除抖動(dòng) 一般大約10ms
if(duty_add==0) //再次判斷按鍵是否按下
{
duty+=1;
}
while(!duty_add); //檢測按鍵是否松開
}
if(duty_reduce==0) //檢測按鍵K1是否按下
{
delay(1000); //消除抖動(dòng) 一般大約10ms
if(duty_reduce==0) //再次判斷按鍵是否按下
{
duty-=1;
}
while(!duty_reduce); //檢測按鍵是否松開
}
if(limit_add==0) //檢測按鍵K1是否按下
{
delay(1000); //消除抖動(dòng) 一般大約10ms
if(limit_add==0) //再次判斷按鍵是否按下
{
max+=100;
}
while(!limit_add); //檢測按鍵是否松開
}
if(limit_reduce==0) //檢測按鍵K1是否按下
{
delay(1000); //消除抖動(dòng) 一般大約10ms
if(limit_reduce==0) //再次判斷按鍵是否按下
{
max-=100;
}
while(!limit_reduce); //檢測按鍵是否松開
}
if(start==0) //檢測按鍵K1是否按下
{
delay(1000); //消除抖動(dòng) 一般大約10ms
if(start==0) //再次判斷按鍵是否按下
{
work_status+=1;
if(work_status>=2)work_status=0;
}
while(!start); //檢測按鍵是否松開
}
}
/*******************************************************************************
* 函數(shù)名 : Int1Init()
* 函數(shù)功能 : 霍爾傳感器接收信號(hào)
* 輸入 : 無
* 輸出 : 無
*******************************************************************************/
void Int1Init()
{
IT1=1;//下降沿觸發(fā)
EX1=1;//打開中斷0允許
EA=1; //打開總中斷
}
/*******************************************************************************
* 函 數(shù) 名 : Timer0Init
* 函數(shù)功能 : 定時(shí)器0初始化
* 輸 入 : 無
* 輸 出 : 無
*******************************************************************************/
void Timer0Init()
{
TMOD|=0X11;//選擇為定時(shí)器0模式,工作方式1,僅用TR0打開啟動(dòng)。
TH0=0XD8; //給定時(shí)器賦初值,定時(shí)10ms
TL0=0XF0;
ET0=1;//打開定時(shí)器0中斷允許
EA=1;//打開總中斷
TR0=1;//打開定時(shí)器
}
/*******************************************************************************
* 函 數(shù) 名 : Timer1Init
* 函數(shù)功能 : 定時(shí)器1初始化
* 輸 入 : 無
* 輸 出 : 無
*******************************************************************************/
void Timer1Init()
{
TMOD|=0X11;//選擇為定時(shí)器1模式,工作方式1,僅用TR1打開啟動(dòng)。
TH1=0XFF; //給定時(shí)器賦初值,定時(shí)100us
TL1=0X9C;
ET1=1;//打開定時(shí)器1中斷允許
EA=1;//打開總中斷
TR1=1;//打開定時(shí)器
}
/*******************************************************************************
* 函數(shù)名 : main
* 函數(shù)功能 : 主函數(shù)
* 輸入 : 無
* 輸出 : 無
*******************************************************************************/
void main()
{
unsigned char i;
beep=1; //蜂鳴器不叫
led=0;
Int1Init(); //初始化霍爾傳感器外部中斷1
Timer0Init(); //定時(shí)器0初始化
Timer1Init(); //定時(shí)器1初始化
LcdInit();
LcdWriteCom(0x80);
for(i=0;i<14;i++)
{
LcdWriteData(wenzi1[i]);
}
LcdWriteCom(0x80+0x40);
for(i=0;i<16;i++)
{
LcdWriteData(wenzi2[i]);
}
while(1)
{
duty2=duty/2;
if(zhuansu1>=max)beep=0,led=1;
else beep=1,led=0;
//按鍵處理
keypros();
//顯示轉(zhuǎn)速
zhuansu[0]=zhuansu1/10000;
zhuansu[1]=zhuansu1%10000/1000;
zhuansu[2]=zhuansu1%10000%1000/100;
zhuansu[3]=zhuansu1%10000%1000%100/10;
zhuansu[4]=zhuansu1%10;
if(zhuansu[0]>9)
{
LcdWriteCom(0x80+0x06); //設(shè)置顯示位置
LcdWriteData(0x37+zhuansu[0]); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
else
{
LcdWriteCom(0x80+0x06);
LcdWriteData(zhuansu[0]+0x30); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
if(zhuansu[1]>9)
{
LcdWriteCom(0x80+0x07);
LcdWriteData(zhuansu[1]+0x37); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
else
{
LcdWriteCom(0x80+0x07);
LcdWriteData(zhuansu[1]+0x30); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
if(zhuansu[2]>9)
{
LcdWriteCom(0x80+0x08);
LcdWriteData(zhuansu[2]+0x37); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
else
{
LcdWriteCom(0x80+0x08);
LcdWriteData(zhuansu[2]+0x30); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
if(zhuansu[3]>9)
{
LcdWriteCom(0x80+0x09);
LcdWriteData(zhuansu[3]+0x37); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
else
{
LcdWriteCom(0x80+0x09);
LcdWriteData(zhuansu[3]+0x30); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
if(zhuansu[4]>9)
{
LcdWriteCom(0x80+0x0a);
LcdWriteData(zhuansu[4]+0x37); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
else
{
LcdWriteCom(0x80+0x0a);
LcdWriteData(zhuansu[4]+0x30); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
//顯示閾值
Limit[0]=max/10000;
Limit[1]=max%10000/1000;
Limit[2]=max%10000%1000/100;
Limit[3]=max%10000%1000%100/10;
Limit[4]=max%10;
if(Limit[0]>9)
{
LcdWriteCom(0xc0+0x06); //設(shè)置顯示位置
LcdWriteData(0x37+Limit[0]); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
else
{
LcdWriteCom(0xc0+0x06);
LcdWriteData(Limit[0]+0x30); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
if(Limit[1]>9)
{
LcdWriteCom(0xc0+0x07);
LcdWriteData(Limit[1]+0x37); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
else
{
LcdWriteCom(0xc0+0x07);
LcdWriteData(Limit[1]+0x30); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
if(Limit[2]>9)
{
LcdWriteCom(0xc0+0x08);
LcdWriteData(Limit[2]+0x37); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
else
{
LcdWriteCom(0xc0+0x08);
LcdWriteData(Limit[2]+0x30); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
if(Limit[3]>9)
{
LcdWriteCom(0xc0+0x09);
LcdWriteData(Limit[3]+0x37); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
else
{
LcdWriteCom(0xc0+0x09);
LcdWriteData(Limit[3]+0x30); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
if(Limit[4]>9)
{
LcdWriteCom(0xc0+0x0a);
LcdWriteData(Limit[4]+0x37); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
else
{
LcdWriteCom(0xc0+0x0a);
LcdWriteData(Limit[4]+0x30); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
duty1[0]=duty2/100;
duty1[1]=duty2/10;
duty1[2]=duty2%10;
LcdWriteCom(0xc0+0x0d);
LcdWriteData(duty1[0]+0x30); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
LcdWriteCom(0xc0+0x0e);
LcdWriteData(duty1[1]+0x30); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
LcdWriteCom(0xc0+0x0f);
LcdWriteData(duty1[2]+0x30); //將數(shù)值轉(zhuǎn)換為該顯示的ASCII碼
}
}
/*******************************************************************************
* 函 數(shù) 名 : Int1() interrupt 2
* 函數(shù)功能 : 外部中斷1的中斷函數(shù)
* 輸 入 : 無
* 輸 出 : 無
*******************************************************************************/
void Int1() interrupt 2 //外部中斷1的中斷函數(shù)
{
zhuansu2++;
}
/*******************************************************************************
* 函 數(shù) 名 : void Timer0() interrupt 1
* 函數(shù)功能 : 定時(shí)器0中斷函數(shù)
* 輸 入 : 無
* 輸 出 : 無
*******************************************************************************/
void Timer0() interrupt 1
{
static u16 i;
TH0=0XD8; //給定時(shí)器賦初值,定時(shí)10ms
TL0=0XF0;
i++;
if(i==200)
{
zhuansu1=zhuansu2*30*2.82;
zhuansu2=0;
i=0;
}
}
/*******************************************************************************
* 函 數(shù) 名 : void Timer1() interrupt 3
* 函數(shù)功能 : 定時(shí)器0中斷函數(shù)
* 輸 入 : 無
* 輸 出 : 無
*******************************************************************************/
void Timer1() interrupt 3
{
TH1=0xFF;
TL1=0x9C;//定時(shí)100us
flag++;
if(flag>199)
{
flag=1;
}
if(work_status==1)
{
if(flag<=duty)
{
out=1;
out1=0;
}
else
{
out=1;
out1=1;
}
}
if(work_status==0)
{
out=1;
out1=1;
}
}
總結(jié)
實(shí)測效果還不錯(cuò),可以用來實(shí)戰(zhàn)演練一番。文章來源地址http://www.zghlxwxcb.cn/news/detail-426618.html
到了這里,關(guān)于基于51單片機(jī)的直流電機(jī)轉(zhuǎn)速顯示+加速減速啟停的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!