書接上回,我們完成了步進(jìn)電機(jī)和按鍵掃描的組合,接下來就是要實(shí)現(xiàn)智能電梯控制系統(tǒng)的各相任務(wù)需求了。
為了方便閱讀,硬件介紹和軟硬件原理圖我再Ctrl C V一下(并沒有水字?jǐn)?shù))。
任務(wù)需求
2019年安徽省機(jī)器人大賽單片機(jī)與嵌入式系統(tǒng)應(yīng)用技能競賽試題
- 設(shè)計(jì)并制作智能電梯控制系統(tǒng),開機(jī)后屏幕第一行顯示"ZNDTKZQ",第二行顯示四位數(shù)字,并自下而上滾動(dòng),3秒后停止?jié)L動(dòng)。
- 使用4x4矩陣鍵盤模擬電梯轎廂內(nèi)的樓層選擇按鈕。當(dāng)按鍵按下時(shí),電梯控制系統(tǒng)記錄對(duì)應(yīng)樓層(建筑共9層樓高)。
- 使用步進(jìn)電機(jī)驅(qū)動(dòng)模塊控制步進(jìn)電機(jī)的轉(zhuǎn)動(dòng),順時(shí)針轉(zhuǎn)動(dòng)表示電梯上升,逆時(shí)針表示電梯下降。電機(jī)每轉(zhuǎn)一圈表示電梯升降一個(gè)樓層。
- 使用LCD12864顯示電梯所在的樓層信息。
- 當(dāng)電梯空閑時(shí)(3秒內(nèi)鍵盤未有按鍵按下),電梯停留到5樓。
- 當(dāng)電梯啟動(dòng)前和電梯停止后,使用LED燈和蜂鳴器實(shí)現(xiàn)1S聲光提示。
- 設(shè)置電梯具有互鎖功能(運(yùn)行時(shí),門開不了;門開狀態(tài),不能運(yùn)行)。使用繼電器模塊模擬電梯門狀態(tài)互鎖。門開時(shí),LED燈亮電機(jī)停止;電梯門關(guān)閉,LED燈滅,電機(jī)運(yùn)行。
- 設(shè)置電梯按鍵具有記憶功能。電梯在運(yùn)行時(shí)可以及時(shí)響應(yīng)各樓層按鍵的呼叫信號(hào),以先方向后距離的優(yōu)先原則(即當(dāng)電梯在5樓到6樓的過程中同時(shí)按下3樓和9樓的按鍵,電梯到達(dá)6樓后運(yùn)行方向不變,會(huì)繼續(xù)上升到9樓后再下降到達(dá)4樓)進(jìn)行判斷,自動(dòng)優(yōu)化運(yùn)行路徑,運(yùn)行過程具備不可逆響應(yīng)功能,任何反方向的呼叫均無效。應(yīng)符合實(shí)際電梯的運(yùn)行模式。
硬件環(huán)境介紹
1. 開發(fā)平臺(tái)套件介紹
本練習(xí)所采用的開發(fā)套件為單片機(jī)與嵌入式系統(tǒng)競賽實(shí)訓(xùn)平臺(tái)。
單片機(jī)與嵌入式競賽實(shí)訓(xùn)平臺(tái)擁有豐富的板載資源,一共分為公共資源去和四個(gè)實(shí)訓(xùn)場景,實(shí)訓(xùn)場景分別為智慧農(nóng)業(yè)、智能音箱、智能小車以及工業(yè)互聯(lián)網(wǎng)。在每個(gè)場景中都有豐富的傳感器以及執(zhí)行器,例如溫濕度傳感器、超聲波測距傳感器、步進(jìn)電機(jī)以及直流電機(jī)等。
同時(shí),該競賽實(shí)訓(xùn)平臺(tái)提供了三種不同的核心板——STC51核心板、STM21核心板以及FPGA核心板,可以通過核心板的插拔實(shí)現(xiàn)不同單片機(jī)核心的切換,大大提高利用率。
該實(shí)訓(xùn)平臺(tái)的場景切換只需要撥動(dòng)核心板上的撥碼開關(guān)到對(duì)應(yīng)的編碼即可實(shí)現(xiàn)元器件的鏈接和切換,不需要再使用杜邦線進(jìn)行連接,更加美觀簡潔。
本次項(xiàng)目練習(xí)為51單片機(jī)為核心的聯(lián)系項(xiàng)目,因此所采用的是STC51核心板作為實(shí)訓(xùn)平臺(tái)的核心控制模塊。
2. 主控制單片機(jī)介紹
STC51核心板的核心芯片采用的是宏晶科技的STC15W4K56S4,板載256Kb外置SRAM存儲(chǔ)器以及2個(gè)100P BTB高速連接器用于和底板連接。
在本實(shí)訓(xùn)平臺(tái)中所使用的晶振值為24MHz。
在本次練習(xí)實(shí)驗(yàn)中,串口測試波特率為9600。
3. 相關(guān)元器件介紹
3.1 LCD12864液晶顯示屏
LCD12864液晶顯示屏是一種具有4位/8位并行、2線或3線串行多種接口方式的點(diǎn)陣圖形液晶
顯示模塊,這里使用的是8位并行總線驅(qū)動(dòng)。
引腳連接:
數(shù)據(jù)端(D0~7) --------------------> P0
RS --------------------------------------> P20
RW -------------------------------------> P21
EN --------------------------------------> P22
電路原理圖如下:
對(duì)于LCD的操作指令以及時(shí)序圖,可以看一下51單片機(jī)練習(xí)1中的介紹,更為詳細(xì),在此就不再贅述。
3.2 28BYJ-48 型步進(jìn)電機(jī)
28BYJ-48型步進(jìn)電機(jī)是一款4相永磁減速步進(jìn)電機(jī),其內(nèi)部結(jié)構(gòu)示意圖如下圖所示。其中中間帶有0~5數(shù)字標(biāo)號(hào)的為“轉(zhuǎn)子”,外側(cè)連接導(dǎo)線標(biāo)有ABCD的為“定子”,其中“定子”一般與外殼固定,對(duì)定子上的線圈通電和斷電即可通過產(chǎn)生的磁場吸引轉(zhuǎn)子轉(zhuǎn)動(dòng)。
3.2.1 步進(jìn)電機(jī)轉(zhuǎn)動(dòng)原理
28BYJ-48 型步進(jìn)電機(jī)的接線一共有紅、橙、黃、粉、藍(lán)五根,其中紅色線為公共端用于外接5V電源,橙、黃、粉、藍(lán)則是對(duì)應(yīng)A、B、C、D四相,如果需要其中一相導(dǎo)通只需要將其對(duì)應(yīng)的那根線接地即可。通過各相的不斷導(dǎo)通、關(guān)閉從而產(chǎn)生對(duì)應(yīng)的磁場用來“吸”和“推”動(dòng)轉(zhuǎn)子轉(zhuǎn)動(dòng),為了使步進(jìn)電機(jī)處于最佳工作模式發(fā)揮其最大工作性能,一般使用八拍模式來驅(qū)動(dòng)步進(jìn)電機(jī)工作。
八拍模式的繞組控制順序表如下:
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
---|---|---|---|---|---|---|---|---|
P1-紅 | VCC | VCC | VCC | VCC | VCC | VCC | VCC | VCC |
P2-橙 | GND | GND | GND | |||||
P3-黃 | GND | GND | GND | |||||
P4-粉 | GND | GND | GND | |||||
P5-藍(lán) | GND | GND | GND |
因此只需要按照上表中的八拍模式,不斷的將對(duì)應(yīng)的相位控制線進(jìn)行置低操作,即可保證步進(jìn)電機(jī)的旋轉(zhuǎn)。由于單片機(jī)的IO引腳輸出的電流較小,一般僅為幾mA,而步進(jìn)電機(jī)的驅(qū)動(dòng)電流會(huì)高達(dá)幾百mA。為了保證步進(jìn)電機(jī)的穩(wěn)定工作,在本實(shí)訓(xùn)平臺(tái)中加入了ULN2003驅(qū)動(dòng)芯片用來放大驅(qū)動(dòng)電流,通過ULN2003與單片機(jī)的IO口相連,引腳連接如下表所示:
ULN2003 | 單片機(jī)IO口 |
---|---|
ULN-O1 | P11 |
ULN-O2 | P12 |
ULN-O3 | P13 |
ULN-O4 | P14 |
由八拍繞組控制順序表可知,想要使步進(jìn)電機(jī)轉(zhuǎn)動(dòng)起來就需要按照順序?qū)λ鶎?duì)應(yīng)相位的單片機(jī)IO口進(jìn)置低操作,由于在本實(shí)訓(xùn)平臺(tái)中,各相的控制端口為P11~14,那個(gè)口輸出低電平則導(dǎo)通對(duì)應(yīng)的相位,所以對(duì)步進(jìn)電機(jī)的八拍節(jié)拍的IO控制代碼數(shù)組如下:
unsigned char code BeatCode1[8] = { //步進(jìn)電機(jī)反轉(zhuǎn)節(jié)拍對(duì)應(yīng)的 IO 控制代碼
0x1C, 0x18, 0x1A, 0x12, 0x16, 0x6, 0xE, 0xC
};
只要按照上述數(shù)組按照一定的頻率進(jìn)行輸出,即可驅(qū)動(dòng)步進(jìn)電機(jī)旋轉(zhuǎn)。各位可以針對(duì)自己的步進(jìn)電機(jī)控制引腳修改。
3.2.2 28BYJ-48 型步進(jìn)電機(jī)相關(guān)參數(shù)解讀
在3.2.1中說到如果想驅(qū)動(dòng)步進(jìn)電機(jī)旋轉(zhuǎn),需要按一定頻率對(duì)IO口進(jìn)行控制代碼數(shù)組的輸出,那這個(gè)“一定頻率”是多少呢?此時(shí)要借助一位“古人”所言,“有疑問?那就讀手冊(cè)!”,是的,你想知道的一切都在廠商所給的手冊(cè)當(dāng)中,作為一個(gè)嵌入式工程師,手冊(cè)就是你的“新華字典”。
28BYJ-48 型步進(jìn)電機(jī)的參數(shù)如下圖所示:
在上圖中我們可以看到啟動(dòng)頻率所給的參數(shù)為 ≥550P.P.S,P.P.S即每秒脈沖數(shù)。按照廠商所給參數(shù),那只要保證每秒至少給出550個(gè)步進(jìn)脈沖就可以啟動(dòng)步進(jìn)電機(jī),那通過一些列初中除法運(yùn)算就換算得出單節(jié)拍持續(xù)時(shí)間大于1.8毫秒的情況下就能保證有550P.P.S以上的輸出,那我們只要保證輸出間隔為2ms,那步進(jìn)電機(jī)就一定可以轉(zhuǎn)起來。
在解釋了啟動(dòng)頻率之后,接下來最重要的一個(gè)參數(shù)就是減速比。各位如果真的參考我下面所寫的各模塊測試中的步進(jìn)電機(jī)旋轉(zhuǎn)一周測試,并且真的編碼測試后你會(huì)發(fā)現(xiàn)步進(jìn)電機(jī)轉(zhuǎn)一圈的時(shí)間比較長,大概在7-8秒左右,但按照我們八拍的工作模式來看,轉(zhuǎn)子轉(zhuǎn)動(dòng)一圈所需要的節(jié)拍數(shù)只有8*8 = 64拍,而剛剛我們算了一個(gè)節(jié)拍只要2ms,那就是說其實(shí)轉(zhuǎn)一圈只要64 * 2 = 128ms就夠了,但實(shí)際上我們?nèi)庋劭吹降氖?-8秒才轉(zhuǎn)了一圈。此時(shí)就是“減速比”干的好事了。
我們先看一下25BYJ-48步進(jìn)電機(jī)的內(nèi)部拆解圖:
如圖所示,我們看到中間紅色方框框起來的才是真的轉(zhuǎn)子,而我們?cè)谕饷嫒庋鬯吹降氖墙?jīng)過多級(jí)齒輪傳動(dòng)后所連接的一個(gè)傳動(dòng)軸,因此實(shí)際上我們所看到的步進(jìn)電機(jī)轉(zhuǎn)一圈是在經(jīng)過多級(jí)齒輪進(jìn)行降速后的一圈。那按照廠商所給參數(shù)來看,減速比為1:64,即紅色框中的轉(zhuǎn)子轉(zhuǎn)動(dòng)64圈后外面的大傳動(dòng)軸才轉(zhuǎn)動(dòng)一圈,即需要64 *64 = 4096個(gè)節(jié)拍才行,那所要的時(shí)間就是轉(zhuǎn)子轉(zhuǎn)動(dòng)一圈的時(shí)間就是128ms * 63 = 8192ms,差不多就是8秒左右。另外在減速比參數(shù)旁還有一個(gè)參數(shù)叫步進(jìn)角度的參數(shù),其值為5.625/64,將這個(gè)值分子分母各乘64就會(huì)發(fā)現(xiàn)是360/4096,剛好是一個(gè)節(jié)拍轉(zhuǎn)動(dòng)的角度,這個(gè)角度就叫步進(jìn)角度。
這樣與我們本次練習(xí)實(shí)驗(yàn)相關(guān)的步進(jìn)電機(jī)參數(shù)也就介紹完畢。
在本次實(shí)驗(yàn)中,步進(jìn)電機(jī)驅(qū)動(dòng)原理圖如下圖所示:
3.3 繼電器模塊
在本實(shí)訓(xùn)平臺(tái)中,繼電器模塊電路由三極管控制并驅(qū)動(dòng)繼電器,繼電器模塊控制原理圖如下圖所示。其中三極管的基極與單片機(jī)的IO口相連接。
繼電器的控制引腳為P12。
3.4 4X4矩陣鍵盤
4x4矩陣鍵盤電路原理圖:
引腳分配圖:
3.5 LED燈&蜂鳴器
LED的電路原理圖如下所示,LED與單片機(jī)P53引腳連接。
蜂鳴器的電路原理圖如下說是,蜂鳴器與單片機(jī)的P55引腳連接。
4.硬件連接示意圖
本次練習(xí)實(shí)驗(yàn)所需要的元器件與單片機(jī)的引腳連接示意圖如下圖所示,以此可以參考元器件的引腳連接。
5.軟件流程圖
對(duì)于完成任務(wù)需求,軟件的大致流程如下圖所示:
6.任務(wù)需求實(shí)現(xiàn)
6.1 開機(jī)后屏幕第一行顯示"ZNDTKZQ",第二行顯示四位數(shù)字,并自下而上滾動(dòng),3秒后停止?jié)L動(dòng)。
這個(gè)要求和在之前的練習(xí)1中是相同的,就是初始化LCD12864屏幕后使用for循環(huán)完成三次位置變換,每次延遲1S,結(jié)束for循環(huán)后再次顯示。
代碼如下:
for(i; i>0; i--)
{
LCD12864_ShowStr(i - 1, 0, "DCFZBJQ");
LCD12864_ShowStr(i, 0, "8957");
//i--;
Delay_ms(1000);
LCD12864_WriteCmd(0x01);
}
LCD12864_ShowStr(2, 0, "DCFZBJQ");
LCD12864_ShowStr(3, 0, "8957");
6.2 使用4x4矩陣鍵盤模擬電梯轎廂內(nèi)的樓層選擇按鈕
這個(gè)需求在上一篇的模塊測試中就已經(jīng)完成,通過中斷函數(shù)每毫秒掃描一次矩陣鍵盤,將鍵盤的狀態(tài)位映射到功能表上,在對(duì)各按鍵功能進(jìn)行switch挨個(gè)確定,就能實(shí)現(xiàn)按下幾,就去幾,同時(shí)在LCD12864上顯示目前所在樓層和目標(biāo)樓層。
部分功能函數(shù)代碼如下:
unsigned char code KeyCodeMap[4][4] = { //矩陣按鍵編號(hào)到標(biāo)準(zhǔn)鍵盤鍵碼的映射表
{ 0x31, 0x32, 0x33, 0x26 }, //數(shù)字鍵 1、數(shù)字鍵 2、數(shù)字鍵 3、向上鍵
{ 0x34, 0x35, 0x36, 0x25 }, //數(shù)字鍵 4、數(shù)字鍵 5、數(shù)字鍵 6、向左鍵
{ 0x37, 0x38, 0x39, 0x28 }, //數(shù)字鍵 7、數(shù)字鍵 8、數(shù)字鍵 9、向下鍵
{ 0x30, 0x1B, 0x0D, 0x27 } //數(shù)字鍵 0、ESC 鍵、 回車鍵、 向右鍵
};
unsigned char KeySta[4][4] = { //全部矩陣按鍵的當(dāng)前狀態(tài)
{1, 1, 1, 1},
{1, 1, 1, 1},
{1, 1, 1, 1},
{1, 1, 1, 1}
};
//按鍵動(dòng)作函數(shù),設(shè)置按鍵對(duì)應(yīng)功能
void KeyAction(unsigned char keycode)
{
static bit dirMotor = 0; //電機(jī)轉(zhuǎn)動(dòng)方向 0:正轉(zhuǎn) 1:反轉(zhuǎn)
if((keycode >= 0x30) && (keycode <= 0x39)) //控制電機(jī)轉(zhuǎn)動(dòng)1-9圈
{
num = keycode - loucen;
UartSendStr("num:");
UartSendInt(num);
UartSendStr("\r\n");
StartMotor(360 * num);
}
else if(keycode == 0x26) //向上鍵,控制電機(jī)正轉(zhuǎn)
{
dirMotor = 0;
}
else if(keycode == 0x28) //向下鍵,控制電機(jī)反轉(zhuǎn)
{
dirMotor = 1;
}
else if(keycode == 0x25) //向左鍵,正轉(zhuǎn)90°
{
StartMotor(90);
}
else if(keycode == 0x27) //向右鍵,反轉(zhuǎn)90°
{
StartMotor(-90);
}
else if(keycode == 0x1B) //停止鍵
{
StopMotor();
}
}
//按鍵驅(qū)動(dòng)函數(shù),檢測按鍵動(dòng)作
void KeyDriver()
{
unsigned char i, j, index;
static unsigned char backup[4][4] = { //按鍵值備份,保存前一次的值
{1, 1, 1, 1},
{1, 1, 1, 1},
{1, 1, 1, 1},
{1, 1, 1, 1}
};
for(i = 0; i < 4; i++)
{
for(j = 0; j < 4; j++)
{
if(backup[i][j] != KeySta[i][j]) //檢測按鍵動(dòng)作
{
if(backup[i][j] == 0) //按鍵按下時(shí)執(zhí)行的操作
{
if(IfRun)
{
if(jiyiindex < 3)
{
jiyi[jiyiindex] = KeyCodeMap[i][j];
jiyiindex ++;
}
else
{
LCD12864_ShowStr(2, 0, "記憶已滿");
}
}
else
{
//if(IfNull)
{
KeyAction(KeyCodeMap[i][j]); //調(diào)用按鍵動(dòng)作函數(shù)
UartSendByte(KeyCodeMap[i][j]);
UartSendStr("\r\n");
LCD12864_SetWindow(1, 5);
LCD12864_WriteData(KeyCodeMap[i][j]);
}
}
}
backup[i][j] = KeySta[i][j]; //刷新前一次的備份值
}
}
}
}
//按鍵掃描函數(shù)
void KeyScan()
{
unsigned char i, j = 0;
static unsigned char keyout = 0; //矩陣鍵盤掃描輸出索引
static unsigned char keybuf[4][4] = { //矩陣按鍵掃描緩沖區(qū)
{0xFF, 0xFF, 0xFF, 0xFF},
{0xFF, 0xFF, 0xFF, 0xFF},
{0xFF, 0xFF, 0xFF, 0xFF},
{0xFF, 0xFF, 0xFF, 0xFF}
};
//將一列的四個(gè)按鍵移入緩沖區(qū)
keybuf[0][keyout] = (keybuf[0][keyout] << 1) | KEY_IN_4;
keybuf[1][keyout] = (keybuf[1][keyout] << 1) | KEY_IN_3;
keybuf[2][keyout] = (keybuf[2][keyout] << 1) | KEY_IN_2;
keybuf[3][keyout] = (keybuf[3][keyout] << 1) | KEY_IN_1;
//消除抖動(dòng)后更新按鍵狀態(tài)
for (i=0; i<4; i++) //每行 4 個(gè)按鍵,所以循環(huán) 4 次
{
if ((keybuf[i][keyout] & 0x0F) == 0x00)
{ //連續(xù) 4 次掃描值為 0,即 4*4ms 內(nèi)都是按下狀態(tài)時(shí),可認(rèn)為按鍵已穩(wěn)定的按下
KeySta[i][keyout] = 0;
}
else if ((keybuf[i][keyout] & 0x0F) == 0x0F)
{ //連續(xù) 4 次掃描值為 1,即 4*4ms 內(nèi)都是彈起狀態(tài)時(shí),可認(rèn)為按鍵已穩(wěn)定的彈起
KeySta[i][keyout] = 1;
}
}
//執(zhí)行下一次的掃描輸出
keyout ++;
keyout &= 0x03; //索引值到4后自動(dòng)歸0
switch(keyout)
{
case 0:KEY_OUT_4 = 1; KEY_OUT_1 = 0; break;
case 1:KEY_OUT_1 = 1; KEY_OUT_2 = 0; break;
case 2:KEY_OUT_2 = 1; KEY_OUT_3 = 0; break;
case 3:KEY_OUT_3 = 1; KEY_OUT_4 = 0; break;
default:break;
}
}
6.3 使用步進(jìn)電機(jī)驅(qū)動(dòng)模塊控制步進(jìn)電機(jī)的轉(zhuǎn)動(dòng),順時(shí)針轉(zhuǎn)動(dòng)表示電梯上升,逆時(shí)針表示電梯下降。
是不是發(fā)現(xiàn)在進(jìn)行單獨(dú)模塊測試后,寫需求的速度和方便性越來越高,這就是萬事俱備,現(xiàn)在再次融合一下就是“東風(fēng)”。那就不再多說,直接上電機(jī)控制相關(guān)的代碼。
//啟動(dòng)電機(jī)
void StartMotor(signed long angle)
{
EA = 0; //在計(jì)算前先把中斷關(guān)閉
beats = (angle * 4080) / 360; //實(shí)測4080拍轉(zhuǎn)動(dòng)一圈
EA = 1;
}
//電機(jī)轉(zhuǎn)動(dòng)控制函數(shù)
void TurnMotor()
{
unsigned char tmp;
static unsigned char index = 0, index_jiyi; //節(jié)拍輸出索引
unsigned char code BeatCode1[8] = { //步進(jìn)電機(jī)反轉(zhuǎn)節(jié)拍對(duì)應(yīng)的 IO 控制代碼
0x1C, 0x18, 0x1A, 0x12, 0x16, 0x6, 0xE, 0xC
};
unsigned char code BeatCode[8] = { //步進(jìn)電機(jī)正轉(zhuǎn)節(jié)拍對(duì)應(yīng)的 IO 控制代碼
0xC, 0xE, 0x6, 0x16, 0x12, 0x1A, 0x18, 0x1C
};
//只要電機(jī)開始運(yùn)轉(zhuǎn),按鍵數(shù)據(jù)都扔到數(shù)組里 數(shù)組為空再開啟正常啟動(dòng)
if(beats != 0) //如果節(jié)拍數(shù)不為0,就產(chǎn)生一個(gè)驅(qū)動(dòng)節(jié)拍
{
IfRun = 1; //運(yùn)行狀態(tài)設(shè)置為1 表示電機(jī)進(jìn)入工作狀態(tài)
time = 0; //只要電機(jī)轉(zhuǎn)動(dòng) 就不計(jì)時(shí)
if(beats > 0) //節(jié)拍數(shù)大于0 實(shí)現(xiàn)正轉(zhuǎn)
{
index ++;
index = index & 0x07;
beats --;
if((beats % 4080) == 0)
{
loucen += 1;
LCD12864_SetWindow(0, 5);
LCD12864_WriteData(loucen);
if(loucen >= 0x39)
loucen = 0x39;
}
tmp = P1; //將P1口的狀態(tài)暫存
tmp &= 0xE1; //將P11-14置0
tmp |= BeatCode[index]; //按位將IO控制碼設(shè)置到P11-14
}
else //節(jié)拍數(shù)小于0,實(shí)現(xiàn)反轉(zhuǎn)
{
index ++;
index = index & 0x07;
beats ++;
if((beats % 4080) == 0)
{
loucen -= 1;
LCD12864_SetWindow(0, 5);
LCD12864_WriteData(loucen);
if(loucen <= 0x31)
loucen = 0x31;
}
tmp = P1; //將P1口的狀態(tài)暫存
tmp &= 0xE1; //將P11-14置0
tmp |= BeatCode1[index]; //按位將IO控制碼設(shè)置到P11-14
}
P1 = tmp; //將設(shè)置好的P1口參數(shù)寫出
}
else
{
P1 |= 0x1E; //若節(jié)拍數(shù)為0,關(guān)閉所有電機(jī)的相位
IfRun = 0;
if(IfNull(jiyi, 3))
{
time ++; //電機(jī)不轉(zhuǎn) 默認(rèn)按鍵沒有按下 開始計(jì)時(shí)等待
if(time == 1500)
{
KeyAction(KeyCodeMap[1][1]);
LCD12864_SetWindow(1, 5);
LCD12864_WriteData(KeyCodeMap[1][1]);
}
}
else
{
for(index_jiyi = 0; index_jiyi < 3; index_jiyi++)
{
if(jiyi[index_jiyi] != 0x00)
{
KeyAction(jiyi[index_jiyi]);
LCD12864_SetWindow(1, 5);
LCD12864_WriteData(jiyi[index_jiyi]);
jiyi[index_jiyi] = 0x00;
}
}
}
}
}
6.4使用LCD12864顯示電梯所在的樓層信息
實(shí)現(xiàn)方式:
使用LCD12864顯示樓層信息這個(gè)功能,我認(rèn)為的難點(diǎn)在于如何實(shí)現(xiàn)步進(jìn)電機(jī)旋轉(zhuǎn)一圈后樓層上下剛好改變一層。我實(shí)現(xiàn)的方式是將總節(jié)拍數(shù)和旋轉(zhuǎn)一周所要的節(jié)拍數(shù)4080進(jìn)行取余判斷,如果取余結(jié)果為0,那就說明已經(jīng)剛好轉(zhuǎn)過一周,那就控制樓層數(shù)加一或是減一操作。
重點(diǎn)展示在電機(jī)運(yùn)行過程中如何對(duì)LCD顯示的操作代碼:
if(beats > 0) //節(jié)拍數(shù)大于0 實(shí)現(xiàn)正轉(zhuǎn)
{
index ++;
index = index & 0x07;
beats --;
if((beats % 4080) == 0) //將總節(jié)拍數(shù)和旋轉(zhuǎn)一周所要節(jié)拍數(shù)進(jìn)行取余判斷
{
loucen += 1; //將樓層數(shù)加一
LCD12864_SetWindow(0, 5); //顯示
LCD12864_WriteData(loucen);
if(loucen >= 0x39) //防止過9,實(shí)際與總節(jié)拍數(shù)相關(guān),不會(huì)超過
loucen = 0x39;
}
tmp = P1; //將P1口的狀態(tài)暫存
tmp &= 0xE1; //將P11-14置0
tmp |= BeatCode[index]; //按位將IO控制碼設(shè)置到P11-14
}
else //節(jié)拍數(shù)小于0,實(shí)現(xiàn)反轉(zhuǎn)
{
index ++;
index = index & 0x07;
beats ++;
if((beats % 4080) == 0) //將總節(jié)拍數(shù)和旋轉(zhuǎn)一周所要節(jié)拍數(shù)進(jìn)行取余判斷
{
loucen -= 1; //將樓層數(shù)加一
LCD12864_SetWindow(0, 5);
LCD12864_WriteData(loucen);
if(loucen <= 0x31)
loucen = 0x31;
}
tmp = P1; //將P1口的狀態(tài)暫存
tmp &= 0xE1; //將P11-14置0
tmp |= BeatCode1[index]; //按位將IO控制碼設(shè)置到P11-14
}
6.5 當(dāng)電梯空閑時(shí)(3秒內(nèi)鍵盤未有按鍵按下),電梯停留到5樓
實(shí)現(xiàn)方式:
因?yàn)榘存I按下就會(huì)自動(dòng)掃描開始驅(qū)動(dòng)電機(jī)進(jìn)行轉(zhuǎn)動(dòng),那如果電機(jī)沒轉(zhuǎn)也就意味著并沒有按鍵按下。由于電機(jī)轉(zhuǎn)動(dòng)的函數(shù)是在T0中斷中執(zhí)行,本身就有計(jì)時(shí)的效果在,因此就不需要再寫一個(gè)計(jì)時(shí)或者是延時(shí)觸發(fā)函數(shù),所以我就可以在T0中斷函數(shù)中執(zhí)行電機(jī)轉(zhuǎn)動(dòng)TurnMotor()函數(shù)中加入一個(gè)計(jì)時(shí)變量time用來判斷是否達(dá)到3秒。因?yàn)橹袛嗍敲?毫秒觸發(fā)一次,而電機(jī)的啟動(dòng)間隔需要1.8毫秒,因此我在中斷中加入了二分法,通過一個(gè)div變量只有它為1時(shí)才執(zhí)行電機(jī)轉(zhuǎn)動(dòng),這樣剛好就是2ms間隔。
如何實(shí)現(xiàn)計(jì)時(shí)3秒呢,那就是對(duì)那個(gè)計(jì)時(shí)變量time進(jìn)行自增操作,不管電機(jī)是否要轉(zhuǎn)動(dòng)TurnMotor()函數(shù)固定每2ms要執(zhí)行一次,那就是在沒有節(jié)拍數(shù)傳入的時(shí)候每2ms對(duì)time進(jìn)行自增操作,只要自增到1500,更好就是1500 * 2 = 3000 ms也就是3s。如果在等待過程中有按鍵按下,那在執(zhí)行電機(jī)轉(zhuǎn)動(dòng)前,直接將time清零直到再次沒有按下開始重新自增計(jì)時(shí)。
對(duì)應(yīng)代碼:
time ++; //電機(jī)不轉(zhuǎn) 默認(rèn)按鍵沒有按下 開始計(jì)時(shí)等待
if(time == 1500)
{
KeyAction(KeyCodeMap[1][1]);//到3秒自動(dòng)傳入到5樓的按鍵功能碼
LCD12864_SetWindow(1, 5);
LCD12864_WriteData(KeyCodeMap[1][1]);
}
6.6 當(dāng)電梯啟動(dòng)前和電梯停止后,使用LED燈和蜂鳴器實(shí)現(xiàn)1S聲光提示
這個(gè)只需要在啟動(dòng)電機(jī)前和電機(jī)旋轉(zhuǎn)完成后進(jìn)行一次LED燈以及蜂鳴器的操作即可。
代碼:
void Led_Bee_Relay()
{
LED = 0;
BEEP = ~BEEP;
delay(500);
LED = 1;
if(IfRun = 1) //運(yùn)行過程中 繼電器關(guān)
{
relay = 0;
}
else
{
relay = 1;
}
}
6.7 置電梯按鍵具有記憶功能,電梯在運(yùn)行時(shí)可以及時(shí)響應(yīng)各樓層按鍵的呼叫信號(hào),以先方向后距離的優(yōu)先原則進(jìn)行判斷,自動(dòng)優(yōu)化運(yùn)行路徑,運(yùn)行過程具備不可逆響應(yīng)功能
該部分的功能,我只實(shí)現(xiàn)了記憶功能,通過一個(gè)數(shù)組,在電機(jī)運(yùn)行過程中將所有的按鍵掃描所得到的按鍵保留在數(shù)組中,當(dāng)電機(jī)停下時(shí)對(duì)數(shù)組進(jìn)行一次非零判斷,只要數(shù)組中有樓層數(shù)據(jù),那就繼續(xù)執(zhí)行對(duì)應(yīng)的樓層,執(zhí)行完畢后將對(duì)應(yīng)的數(shù)組元素清零,最后再次判斷。如果數(shù)組已經(jīng)為零,那就開始執(zhí)行3S按鍵等待,到3秒后自動(dòng)???樓。
關(guān)于以先方向后距離的判斷原則還在調(diào)試中,后續(xù)會(huì)保持更新,如果各位有更好的idea還請(qǐng)不吝賜教。
實(shí)現(xiàn)代碼:文章來源:http://www.zghlxwxcb.cn/news/detail-455701.html
unsigned char jiyi[3] = {0x00, 0x00, 0x00}; //實(shí)現(xiàn)電梯按鍵記憶
//判斷數(shù)組是否為空
unsigned char IfNull(unsigned char *jiyi, unsigned char len)
{
unsigned char i;
unsigned char num;
for(i = 0; i < len; i++)
{
num += jiyi[i];
}
if(num != 0x00)
{
return 1;
}
else
return 0;
}
if(IfRun)
{
if(jiyiindex < 3)
{
jiyi[jiyiindex] = KeyCodeMap[i][j];
jiyiindex ++;
}
else
{
LCD12864_ShowStr(2, 0, "記憶已滿");
}
}
else
{
KeyAction(KeyCodeMap[i][j]); //調(diào)用按鍵動(dòng)作函數(shù)
UartSendByte(KeyCodeMap[i][j]);
UartSendStr("\r\n");
LCD12864_SetWindow(1, 5);
LCD12864_WriteData(KeyCodeMap[i][j]);
}
效果演示:
按鍵演示文章來源地址http://www.zghlxwxcb.cn/news/detail-455701.html
到了這里,關(guān)于【51單片機(jī)練習(xí)3——智能電梯控制系統(tǒng)2】的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!