PS:這是人生中的第一篇博客,記錄了我人生中的第一次實習工作。與其說是博客文章,這些更像是一個小白的流水賬日記,可能會有很多錯誤和有待優(yōu)化的地方,希望各位大佬可以多多提出。如有問題可以私信聯(lián)系。
行文過程中,欲說盡心中無限事,感慨萬千。不過各位“道友”,很高興見到你們,我們來日方長!
話不多說接下來就是正文內(nèi)容。。。
任務需求
2018年安徽省機器人大賽單片機與嵌入式系統(tǒng)應用技能競賽試題
需求1:開機后LCD12864屏幕第一行顯示"DFZBJQ",第二行顯示四位數(shù)字,并自下而上滾動,3秒后停止?jié)L動。
需求2:應用超聲波傳感器實現(xiàn)距離采集,并在LCD12864顯示屏上顯示。
需求3:能夠實現(xiàn)最遠最近距離存儲、查閱以及清除。
硬件環(huán)境介紹
1.開發(fā)套件介紹
本練習所采用的的開發(fā)套件為單片機與嵌入式系統(tǒng)競賽實訓平臺。
單片機與嵌入式競賽實訓平臺擁有豐富的板載資源,一共分為公共資源去和四個實訓場景,實訓場景分別為智慧農(nóng)業(yè)、智能音箱、智能小車以及工業(yè)互聯(lián)網(wǎng)。在每個場景中都有豐富的傳感器以及執(zhí)行器,例如溫濕度傳感器、超聲波測距傳感器、步進電機以及直流電機等。
同時,該競賽實訓平臺提供了三種不同的核心板——STC51核心板、STM21核心板以及FPGA核心板,可以通過核心板的插拔實現(xiàn)不同單片機核心的切換,大大提高利用率。
該實訓平臺的場景切換只需要撥動核心板上的撥碼開關到對應的編碼即可實現(xiàn)元器件的鏈接和切換,不需要再使用杜邦線進行連接,更加美觀簡潔。
由于本人是嵌入式學習的小白一枚,因此是從最簡單的STC51單片機開始,因此所使用的為STC51核心板。
2.單片機介紹
STC51核心板的核心芯片采用的是宏晶科技的STC15W4K56S4,板載256Kb外置SRAM存儲器以及2個100P BTB高速連接器用于和底板連接。
在本實訓平臺中所使用的晶振值為24MHz,串口測試波特率為115200.
3.所需元器件介紹
3.1 LCD12864液晶顯示屏
LCD12864液晶顯示屏是一種具有4位/8位并行、2線或3線串行多種接口方式的點陣圖形液晶
顯示模塊,這里使用的是8位并行總線驅動。
引腳連接:
數(shù)據(jù)端(D0~7) --------------------> P0
RS --------------------------------------> P20
RW -------------------------------------> P21
EN --------------------------------------> P22
電路原理圖如下:
對于LCD12864的所有操作可以總結為4中:
- 讀忙狀態(tài):讀忙的同時讀出指針地址內(nèi)容,在初始化之后對LCD12864的每次讀寫都要進行忙檢測。
- 寫命令:寫地址也是寫指令,所有的指令可以查看下方指令集。
- 寫數(shù)據(jù):操作對象為DDRAM(數(shù)據(jù)顯示RAM)、CGRAM(字符發(fā)生RAM)和GDRAM(圖形顯示RAM)。
- 讀數(shù)據(jù):操作對象與寫數(shù)據(jù)一致
3.1.1 LCD12864引腳介紹
LCD12864一共擁有20個引腳,引腳號以及引腳說明如下圖所示,其中我們需要重點關注的是RS、R/W、EN以及DB0~7這幾個引腳。
3.1.2 LCD12864時序圖
- 寫時序:
2.讀時序:
3.1.3 LCD12864常用指令集
指令集分為基本指令集和擴展指令集,在使用對應的指令集前需要先寫入對應指令,表明后續(xù)的所有指令都是該類指令。使用基本指令集時寫指令(0x30),使用擴展指令集時寫指令(0x34)。
- 基本指令集(RE = 0)
- 清屏指令(0x01)
- 回車指令(0x02/0x03)
- 顯示開、關光標(0x0c)
- 擴展指令集(RE = 1)
3.2 超聲波控制模塊
本實訓平臺所使用的超聲波模塊是以CS100A芯片為主的自研模塊,其具有兩個控制端口——TRIG和ECHO,TRIG端口用于觸發(fā)測距,至少需要給10us的高電平信號,接著模塊自動發(fā)送8個40KHz的方波,自動檢測是否有信號返回。如果有信號返回,通過ECHO輸出一個高電平,高電平持續(xù)的時間就是超聲波從發(fā)射到返回的時間。
超聲波測距時序圖:
由此可以得出:測試距離 = (高電平時間 * 聲速(340m/s))/ 2
本次實驗超聲波控制模塊與單片機引腳:
Trig ----------------------> P15
Echo --------------------->P34
超聲波模塊外圍電路圖:
3.3 4x4矩陣鍵盤
4x4矩陣鍵盤電路原理圖:
引腳分配圖:
硬件連接示意圖
總體程序流程圖
實現(xiàn)代碼
1. 需求1:LCD12864滾動顯示實現(xiàn)
實現(xiàn)思路及代碼:文章來源:http://www.zghlxwxcb.cn/news/detail-442846.html
1. 初始化LCD12864屏幕
/*******************************************************************************
* 函 數(shù) 名 : LCD12864_Init
* 函數(shù)功能 : 初始化LCD12864
* 輸 入 : 無
* 輸 出 : 無
*******************************************************************************/
void LCD12864_Init()
{
LCD12864_WriteCmd(0x30); //選擇基本指令操作
LCD12864_WriteCmd(0x0c); //顯示開,關光標
LCD12864_WriteCmd(0x01); //清除LCD12864的顯示內(nèi)容
}
2. 使用for循環(huán)完成三次位置變換,每次延遲1S,結束for循環(huán)后再次顯示(一定記得在循環(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");
2. 需求2:LCD12864顯示實時顯示超聲波測距實現(xiàn)
- 初始化LCD12864和超聲波模塊(LCD初始化見上方)
TRIG_IO = 1;
Delay10us(); //@24.000MHz,10微秒
TRIG_IO = 0;
Timer_Count_0 = 0;
while(ECHO_IO == 0 && Timer_Count_0 < 50); //500微秒超時
Timer_Count_0 = 0;
while(ECHO_IO == 1 && Timer_Count_0 < 2000); //20毫秒超時
- 根據(jù)公式計算距離,公式為:距離(毫米)=時間(ms)*速度(340mm/ms)/2,及時通過定時器0完成
Num_Distance = (int)((float)Timer_Count_0 / 100 * 340 / 2); //計算距離:距離(毫米)=時間(ms)*速度(340mm/ms)/2
void Timer0_Int (void) interrupt 1
{
Timer_Count_0++;
}
- 顯示數(shù)據(jù)
LCD12864_WriteCmd(0x01);
LCD12864_ShowStr(0, 0, "Distance:");
sprintf((char *)buf,"%d",Num_Distance);
LCD12864_ShowStr(0,5,&buf);
3. 需求3:記錄并顯示有效最大值最小值并實現(xiàn)清除
- 創(chuàng)建三個變量s(交換變量,用于臨時存儲距離值),max(最大值),min(最小值)。同時將min賦初值為測試輸出最大值2187,max賦值為0。并且在主循環(huán)中獲取距離值的時候不斷進行比較更新。
int min = 2187, max = 0, s;
s = Num_Distance;
if(s > max)
max = s;
if(s < min)
min = s;
- 在屏幕上顯示數(shù)據(jù)
LCD12864_ShowStr(1, 0, "Min:");
sprintf((char *)buf1,"%d",min);
LCD12864_ShowStr(1,2,&buf1);
LCD12864_ShowStr(1, 4, "Max:");
sprintf((char *)buf2,"%d",max);
LCD12864_ShowStr(1,6,&buf2);
- 按鍵掃描,判斷清除鍵是否按下,按下后將max和min兩個變量恢復初始值
void IO_KeyScan(void)
{
unsigned char j;
j = IO_KeyState1; //保存上一次狀態(tài)
P7 = 0xf0; //X低,讀Y
IO_KeyDelay();
IO_KeyState1 = P7 & 0xf0;
P7 = 0x0f; //Y低,讀X
IO_KeyDelay();
IO_KeyState1 |= (P7 & 0x0f);
IO_KeyState1 ^= 0xff; //取反
if(j == IO_KeyState1) //連續(xù)兩次讀相等
{
j = IO_KeyState;
IO_KeyState = IO_KeyState1;
if(IO_KeyState != 0) //有鍵按下
{
F0 = 0;
if(j == 0) F0 = 1; //第一次按下
else if(j == IO_KeyState)
{
if(++IO_KeyHoldCnt >= 20) //1秒后重鍵
{
IO_KeyHoldCnt = 18;
F0 = 1;
}
}
if(F0)
{
j = T_KeyTable[IO_KeyState >> 4];
if((j != 0) && (T_KeyTable[IO_KeyState& 0x0f] != 0))
{
KeyCode = (unsigned char)(((j - 1) * 4 )+ (T_KeyTable[IO_KeyState & 0x0f]) ); //計算鍵碼,17~32 + 16
}
}
}
else
IO_KeyHoldCnt = 0;
}
P7 = 0xff;
if(KeyCode>0)
{
serial_one_send_number(KeyCode);
serial_one_send_string("按鍵\r\n");
switch(KeyCode)
{
case 1:
{
serial_one_send_string("查詢最近值\r\n");
RememberMaxMin();
break;
}
case 2: {CleanMaxMin();break;}
}
KeyCode=0;
}
}
void CleanMaxMin()
{
LCD12864_WriteCmd(0x01);
serial_one_send_string("清除最大最小值\r\n"); //串口輸出測試
max = 0;
min = 2187;
Delay_ms(100);
}
總結
在完成這個練習之后,第一個感想,我在學校里真的學了51單片機嗎?
哦~原來是以前做的太簡單了,全程只有一個功能,難怪那會兒不知天高地厚,因為自己掌握了單片機的精髓,結果就這么一個練習就讓我費勁心思。
第二個感想,對于單片機的基礎知識一定要扎實扎實再扎實,所有的高端操作就離不開最簡單的“烹飪方式”,對于定時器、中斷以及串口的認識只停留在知道且了解的境地是不夠的,我們要做的是將單片機上的基礎資源和功能可以了然于胸,這些雖不是什么高深的功法,但沒有這些,后續(xù)任何高深的操作都會讓你“走火入魔”。
第三個感想,精進編程水平的精髓在于多敲!多敲!多敲!以及提前構思好代碼流程。由于一段時間沒有觸碰到C語言以及單片機,初上手一股陌生感油然而生,許多方法和語法都會和其他語言弄混(鄙人還在寫Java),因此導致這第一個練習讓我躊躇不前,一度懷疑自己是否適合做這個,但是在捋清楚思路和流程后,一步一步的實現(xiàn)和改正bug,最終讓我實現(xiàn)了這個功能。
最后,各位,一定要好好學習!天天向上!俺們下一篇“水文”見!文章來源地址http://www.zghlxwxcb.cn/news/detail-442846.html
到了這里,關于【51單片機練習1——超聲波測距+LCD12864顯示】的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!