實驗(六)16x2 LCM顯示
History Key
- New content
Removed content
Recent Versions
Choose two versions to compare, or click the link to view it.
實驗(六) LCM 模組控制
實驗目的:
本節在實現LCM模組。
實驗○:
在LCM上 顯示出Welcome to FPPA's World 字樣
實驗一:
在LCM上 動態跑馬顯示出Welcome to FPPA's World 字樣
I/O腳位定義:
/// LCMen equ pe.0;
/// LCMrw equ pe.1;
/// LCMrs equ pe.2;
/// LCMPort equ pg;
模組函式規畫:
/// ======== START 共享變數-由主程式宣告 ========
extern word lcm_share_str; /// 作為 PUTS 傳入的字串
/// ======== END 共享變數 ========
/// ======== START Public 函式 ========
void Initial_LCM( void ); /// 初始化 IO
void LCM_line1( void ); /// LCM 歸位至第一行
void LCM_line2( void ); /// LCM 歸位至第二行
void LCM_putc( void ); /// LCM 輸出單一字元 a
void LCM_puts_HI( void ); /// 傳入字串長度 a,將 ROM 中,位址 lcm_share_str 開始的字串 PUT 出。(從 HI BYTE 開始)
void LCM_puts_LO( void ); /// 傳入字串長度 a,將 ROM 中,位址 lcm_share_str 開始的字串 PUT 出。(從 LO BYTE 開始)
#define LCM_puts() LCM_puts_LO();
void LCM_clear( void ); /// 清除 LCM
/// -------- 簡易巨集 --------
#define _LCM_puts_HI(str,n) \ /// 將長度 n 的字串 str 從 LCM 印出。(從 HI BYTE 開始)
lcm_share_str=str;\
a=n;\
LCM_puts_HI();
#define _LCM_puts_LO(str,n) \ /// 將長度 n 的字串 str 從 LCM 印出。(從 LO BYTE 開始)
lcm_share_str=str;\
a=n;\
LCM_puts_LO();
#define _LCM_puts(str,n) \ /// 將長度 n 的字串 str 從 LCM 印出。(從 LO BYTE 開始)
lcm_share_str=str;\
a=n;\
LCM_puts_LO();
#define _LCM_putc(c) \ /// 將字元 c 從 LCM 印出。
a=c;\
LCM_putc();
/// ======== END Public 函式 ========
模組函式設計:
操作函式設計:...................略。
LCM模組是一個很方便的輸出模組,可以拿來作各種資訊的顯示輸出,跟LED或七字節是屬於同性質的元件,差別只在單價LED<七字節<LCM跟底層控制的複雜度。
在這邊我們規畫了一些易用的函式作為這個模組的服務窗口,讓使用者可以把LCM模組當作像一個螢幕輸出文字來使用,查看模組的原始碼(.c)我們還發現幾個底層的函式沒有開放出來給外部使用:
void LCM_WriteCommand( void )void LCM_WriteData( void )
這也是模組設計的考量,並不是所有的函式都需要開放給使用者使用,模組底層的計算、運作有可能會非常複雜,但是使用者不需要知道這些細節,系統設計師關心的是「有哪些可以用」、「怎麼用才正確」、「用起來效能怎樣」...等等整合層面的問題。
另外一個與之前模組不同的地方是,多了一個外部變數的宣告:
extern word lcm_share_str; /// 作為 PUTS 傳入的字串位址
正如同外部函式的意義一樣,模組在宣告這個變數時並不會佔用實體變數的記憶體空間,但是可以在模組裡面使用,真正的宣告是在系統使用,使用外部變數的目的在於讓系統能過透過這個變數來跟模組傳遞參數,這是由於Miini-C無法像一般的C語言一樣能在調用函式的時候把參數傳進去或回傳,因此需要一個全域變數來達到這個目的,若是爾後Mini-C有支援,自然還是以傳統C的寫法比較適合。
最後我們還設計了一些簡易巨集:
#define _LCM_puts_HI(str,n)...#define _LCM_puts_LO(str,n)...#define _LCM_puts(str,n)...#define _LCM_putc(c)...
這些函式用來取代原本無法傳遞參數的函式,使巨集就可以使用代換的方式來作到類似參數傳遞的功能,這樣在使用上會更方便。
控制函式的實作:
void LCM_WriteCommand( void )
{
LCMPort = a;
LCMen = 1; ///En = 1
DelayEN;
LCMen = 0; /// En= 0, Falling edge active
delay 249;
delay 249;
delay 249;
delay 249;
}
void LCM_WriteData( void )
{
LCMPort = a;
LCMen = 1; ///En = 1
DelayEN;
LCMen = 0; /// En= 0, Falling edge active
DelayRW;
}
LCM_WriteCommand() 跟LCM_WriteData() 是LCM模組最底層的函式,用來跟LCM模組作溝通、傳遞命命或資料,兩個函式其實執行的動作完全一樣,差別只在於LCM_WriteCommand() 後面多了些延時的指令碼,是由於LCM模組資料傳輸的規範所要求的延時不同而不同,而其餘的函式都是由這兩個函式衍生出來的,也就是按照其Datasheet的通訊協定來現實每個不同的功能,初始化LCM、游標定位、輸出字元...等等(請參閱其Datasheet)。
其中比較繁雜的是LCM的初始化步驟,需要照著Datasheet一步一步流程照作才能動作正常,要注意的是若系統時脈不同,所需的延時就會有所不同,需要再自行調整。
void Initial_LCM( void ) /// 初始化 IO
{
/// I/O初始化...略;
//-- write 0x30 for High Nibble --
a = 0b00110000;
LCM_WriteCommand();
//-- write 0x30 for High Nibble --
a = 0b00110000;
LCM_WriteCommand();
//-- write 0x30 for High Nibble --
a = 0b00110000;
LCM_WriteCommand();
//-- write 0x3x for High Nibble -- // 8-Bit Data Mode
a = 0b00111000; // two Row display module and 5x7 segments
LCM_WriteCommand();
a = 0b00001100; // Set Display Mode = Display On, Cursor Off , and No blinking
LCM_WriteCommand();
a = 0b00000001; // Clear Display
LCM_WriteCommand();
a = 0b00000010; // Cursor go Home
LCM_WriteCommand();
a = 0b00000110; // Set Entry Mode
LCM_WriteCommand();
a = 0b10000000; // Set DD RAM Address=0
LCM_WriteCommand();
}
實驗實作:
實驗○:
在LCM上 顯示出Welcome to FPPA's World 字樣
void FPPA0 (void)
{
/// 初始化...略
LCM_clear();
lcm_share_str = str_hello; /// 字串位址
a = 16; /// 字串長度
LCM_puts();
goto $;
}
若是使用簡易巨集,可以寫成底下這樣:
void FPPA0 (void)
{
/// 初始化...略
LCM_clear();
_LCM_puts (str_hello, 16 ); /// 字串位址
goto $;
}
實驗一:
在LCM上 動態跑馬顯示出Welcome to FPPA's World 字樣。略。