|
由于上次諾基亞5110的液晶屏接觸不良,所以沒辦法用在我要做的自平衡小車上面.我主要是想用液晶屏顯示PID參數(shù),用兩個(gè)按鍵設(shè)置PID,方便平衡小車的調(diào)試.
我手中只剩下LCD1602這款液晶屏了,雖然一直很嫌棄它(驅(qū)動(dòng)IO多,顯示字符少)但也沒辦法.
本文使用四線驅(qū)動(dòng)LCD1602的方法,主要是八線驅(qū)動(dòng)太占用IO口.關(guān)于四線驅(qū)動(dòng),網(wǎng)上有很多例程可以參考,我也是參考網(wǎng)上的程序?qū)懙?但在編寫LCD1602驅(qū)動(dòng)程序時(shí),還是經(jīng)歷了很多困難,時(shí)序問題就不提了.網(wǎng)上的很多程序都是沒有判斷忙標(biāo)志位的,直接通過延時(shí)來實(shí)現(xiàn).這樣,延時(shí)時(shí)間多少合適成為一個(gè)問題,我改了好多次延時(shí),但發(fā)現(xiàn)延時(shí)時(shí)間都比較長,寫入一次數(shù)據(jù)的時(shí)間很長.這樣的液晶屏用著很鬧心,刷新一次時(shí)間那么,我的程序還有很多對時(shí)間要求比較苛刻的任務(wù)要執(zhí)行呢,這樣的速度可不行.
關(guān)于四線驅(qū)動(dòng)如何去判斷忙標(biāo)志位,我也不懂,只好去網(wǎng)上搜,很少有這方面的例程,但最后還是找到了一個(gè),照著寫,總算解決了.

上圖是單片機(jī)與LCD1602的接線圖,DB0~DB7為8條并行數(shù)據(jù)線.VL是調(diào)節(jié)液晶屏的對比度的,外接一個(gè)電位器到地,如果顯示不清晰,可以通過此電位器調(diào)節(jié)值最佳對比度.BLK,BLA接液晶背光.
除了8個(gè)數(shù)據(jù)線,和顯示控制有關(guān)的還有RS,RW,E三個(gè)端口,上圖是他們對應(yīng)的功能.

通過向LCD1602寫入命令和數(shù)據(jù)來控制顯示.讀狀態(tài)是為了判斷LCD1602此時(shí)是否處于忙的狀態(tài),如果忙,就只能等待不忙的時(shí)候再進(jìn)行寫操作.通過讀狀態(tài)時(shí)序,讀到一個(gè)八位數(shù)據(jù),最高位是忙標(biāo)志位,此位為1說明此時(shí)忙,為了表示空閑.
大概沒什么要講的了,LCD1602的一些設(shè)置指令比較重要,手上也沒找到詳細(xì)的配置說明.

下圖是LCD1602驅(qū)動(dòng)芯片的顯存,向?qū)?yīng)的顯存地址寫入數(shù)據(jù),就可以控制顯示字符.由于LCD1602自帶了一個(gè)ASCII碼字庫,所以一些常用的字符都可以直接顯示,不需要自己去用軟件生成字庫了.

四線驅(qū)動(dòng)時(shí),寫入的是0x28,八線驅(qū)動(dòng)是寫入的是0x38,如上圖.
四線驅(qū)動(dòng)的寫命令寫數(shù)據(jù)時(shí)序可以參考下面的例程.
本例程,使用STM8L的PB口驅(qū)動(dòng)LCD1602,正好用完P(guān)B口的八個(gè)IO.高四位是數(shù)據(jù)接口,寫入一字節(jié)數(shù)據(jù)時(shí),先寫高四位,再寫第四位.

- /*硬件連接*/
- // PB0 --> RS
- // PB1 --> RW
- // PB2 --> E
- // PB3 --> A(背光正極)
- // PB4 --> D4
- // PB5 --> D5
- // PB6 --> D6
- // PB7 --> D7
- // PD6 --> 按鍵+
- // PD7 --> 按鍵-
- #define RS_H PB_ODR_ODR0=1
- #define RS_L PB_ODR_ODR0=0
- #define RW_H PB_ODR_ODR1=1
- #define RW_L PB_ODR_ODR1=0
- #define EN_H PB_ODR_ODR2=1
- #define EN_L PB_ODR_ODR2=0
- /****************************************************************************************
- *開發(fā)環(huán)境:IAR for stm8 v6.5.3
- *硬件平臺(tái):STM8L-DISCOVERY
- *功能說明:LCD1602四線驅(qū)動(dòng)控制,檢測忙標(biāo)志位 第一行顯示一串字符,第二行顯示一個(gè)可以用按鍵改變大小的三位數(shù)字
- *作 者:茗風(fēng)
- ****************************************************************************************/
- #include"iostm8l152c6.h"
- #include"stdbool.h"
- #include"stdint.h"
- const uint8_t Num_to_Char[10]="0123456789";
- /******************************************************************************************************
- * 名 稱:void delay_100us(uint8_t x_us)
- * 功 能:延時(shí)100us
- * 入口參數(shù):無
- * 出口參數(shù):無
- * 說 明:
- * 范 例:無
- ******************************************************************************************************/
- void delay_100us(uint16_t x_us)
- {
- uint8_t j;
- while(x_us--)
- {
- for(j=0;j<33;j++);//2*40個(gè)指令周期
- }
- //delay_10ms共消耗 x_ms*2*255+2*x_ms個(gè)指令周期
- //*2*40+2*x_ms=80us+
- //16M/8/2=1M 一個(gè)指令周期為1us
- }
- ///******************************************************************** **********************************
- //* 功 能 :LCD1602端口初始化函數(shù)
- //* 入口參數(shù) :無
- //* 出口參數(shù) :無
- //* 說 明 :對LCD1602用的IO端口進(jìn)行初始化
- //* 范 例 :無
- //******************************************************************************************************/
- void LCD1602_GPIO_Init(void)
- {
-
- PB_DDR =0xFF;//PB設(shè)置為輸出
- PB_CR1 =0xFF;//PB設(shè)置為推挽輸出
- PB_CR2 =0xFF;//PB的IO輸出速率為10MHz
- PB_ODR =0x00;//PB輸出高電平
- PB_ODR |=0x08;
- }
- ///******************************************************************************************************
- //* 功 能 :LCD1602忙檢測,若不忙則退出,忙則等待
- //* 入口參數(shù) :無
- //* 出口參數(shù) :無
- //* 說 明 :
- //* 編寫日期 :2016年10月21日
- //* 作 者 :茗風(fēng)
- //******************************************************************************************************/
- void LCD1602_Busy_Check(void)
- {
- PB_CR1 &=0x7F;//浮空輸入
- PB_CR2 &=0x7F;//無中斷能力
- PB_DDR &=0x7F;
- PB_ODR |=0x80;
- RS_L;
- RW_H;
- EN_H;
- while(PB_IDR&0x80);
- PB_DDR |=0x80;//PB設(shè)置為輸出
- PB_CR1 |=0x80;//PB設(shè)置為推挽輸出
- PB_CR2 |=0x80;//PB的IO輸出速率為10MHz
- EN_L;
- }
- ///******************************************************************************************************
- //* 功 能 :LCD1602寫命令函數(shù)
- //* 入口參數(shù) :d 寫入的一字節(jié)命令
- //* 出口參數(shù) :無
- //* 說 明 :
- //* 編寫日期 :2016年10月21日
- //* 作 者 :茗風(fēng)
- //******************************************************************************************************/
- void LCD1602_Write_One_Byte_Cmd(uint8_t d)
- {
- LCD1602_Busy_Check();
-
- RW_L;//寫
- RS_L;//命令
-
- PB_ODR &=0x0F;//清高四位
- PB_ODR |=(d&0xF0);
- EN_H;//
- asm("nop");//200ns延時(shí)
- EN_L;
- asm("nop");//200ns延時(shí)
-
- d<<=4; //低四位移到到高四位
- PB_ODR &=0x0F;//清高四位
- PB_ODR |=(d&0xF0);
- EN_H;
- asm("nop");//200ns延時(shí)
- EN_L;
- asm("nop");//200ns延時(shí)
- }
- ///******************************************************************************************************
- //* 功 能 :LCD1602寫數(shù)據(jù)函數(shù)
- //* 入口參數(shù) :d 寫入的一字節(jié)數(shù)據(jù)
- //* 出口參數(shù) :無
- //* 說 明 :
- //* 編寫日期 :2016年10月21日
- //* 作 者 :茗風(fēng)
- //******************************************************************************************************/
- void LCD1602_Write_One_Byte_Data(char d)
- {
- LCD1602_Busy_Check();
- RS_H;//數(shù)據(jù)
- RW_L;//寫
-
- PB_ODR &=0x0F;//清高四位
- PB_ODR |=(d&0xF0);
- EN_H;
- asm("nop");
- EN_L;
- // asm("nop");
- // delay_100us(1500);
-
- d<<=4; //低四位移到到高四位
- PB_ODR &=0x0F;//清高四位
- PB_ODR |=(d&0xF0);
- EN_H;
- asm("nop");
- EN_L;
- asm("nop");
- // delay_100us(1500);
- }
- ///******************************************************************************************************
- //* 功 能 :LCD1602一串字符函數(shù)
- //* 入口參數(shù) :x x軸坐標(biāo),取值范圍(0~15)
- //* y y軸坐標(biāo),取值范圍(0~1),一共兩行
- //* *s 一串字符
- //* 出口參數(shù) :無
- //* 說 明 :
- //* 編寫日期 :2016年10月21日
- //* 作 者 :茗風(fēng)
- //******************************************************************************************************/
- uint8_t LCD1602_Display_String(uint8_t x,uint8_t y,uint8_t *s)
- {
- if(y==1)
- {
- LCD1602_Write_One_Byte_Cmd(0xC0+x);//設(shè)置寫入字符開始坐標(biāo)
- }
- else
- {
- LCD1602_Write_One_Byte_Cmd(0x80+x);//設(shè)置寫入字符開始坐標(biāo)
- }
- while(*s != '\0')
- {
- LCD1602_Write_One_Byte_Data(*s++);
- }
- return 0;
- }
- ///******************************************************************************************************
- //* 功 能 :LCD1602顯示兩位數(shù)字
- //* 入口參數(shù) :x x軸坐標(biāo),取值范圍(0~15)
- //* y y軸坐標(biāo),取值范圍(0~1),一共兩行
- //* *s 一串字符
- //* 出口參數(shù) :無
- //* 說 明 :
- //* 編寫日期 :2016年10月22日
- //* 作 者 :茗風(fēng)
- //******************************************************************************************************/
- void LCD1602_Display_Number(uint8_t x,uint8_t y,uint8_t number)
- {
- if(y==1)
- {
- LCD1602_Write_One_Byte_Cmd(0xC0+x);//設(shè)置寫入字符開始坐標(biāo)
- }
- else
- {
- LCD1602_Write_One_Byte_Cmd(0x80+x);//設(shè)置寫入字符開始坐標(biāo)
- }
- if(number<10)
- {
- LCD1602_Write_One_Byte_Data(' ');
- LCD1602_Write_One_Byte_Data(' ');
- LCD1602_Write_One_Byte_Data(Num_to_Char[number%10]);
- }
- else if(number<100)
- {
- LCD1602_Write_One_Byte_Data(' ');
- LCD1602_Write_One_Byte_Data(Num_to_Char[number/10]);
- LCD1602_Write_One_Byte_Data(Num_to_Char[number%10]);
- }
- else
- {
- LCD1602_Write_One_Byte_Data(Num_to_Char[number/100]);
- LCD1602_Write_One_Byte_Data(Num_to_Char[number%100/10]);
- LCD1602_Write_One_Byte_Data(Num_to_Char[number%10]);
- }
-
- }
- ///******************************************************************************************************
- //* 功 能 :LCD1602初始化配置
- //* 入口參數(shù) :無
- //* 出口參數(shù) :無
- //* 說 明 :
- //* 編寫日期 :2016年10月21日
- //* 作 者 :茗風(fēng)
- //******************************************************************************************************/
- void LCD1602_init(void)
- {
- LCD1602_GPIO_Init();
- LCD1602_Write_One_Byte_Cmd(0x28);//四線驅(qū)動(dòng)
- LCD1602_Write_One_Byte_Cmd(0x01);//清屏
- LCD1602_Write_One_Byte_Cmd(0x06);//這個(gè)是上面指令碼是 000001NS的設(shè)
- LCD1602_Write_One_Byte_Cmd(0x0C);//顯示開及光標(biāo)設(shè)置
- }
- ///******************************************************************************************************
- //* 功 能 :按鍵GPIO初始化配置
- //* 入口參數(shù) :無
- //* 出口參數(shù) :無
- //* 說 明 :
- //* 編寫日期 :2016年10月21日
- //* 作 者 :茗風(fēng)
- //******************************************************************************************************/
- void GPIO_Config(void)
- {
- //PE7 LED控制引腳
- PE_DDR_DDR7 =1;//輸出
- PE_CR1_C17 =1;//推挽輸出
- PE_CR2_C27 =1;//輸出速率10M
-
- //配置閥門到位檢測引腳PD6,PD7
- PD_DDR_DDR6 =0;
- PD_CR1_C16 =1;//帶上拉電阻輸入
- PD_CR2_C26 =1;//使能外部中斷
-
- PD_DDR_DDR7 =0;
- PD_CR1_C17 =1;//帶上拉電阻輸入
- PD_CR2_C27 =1;//使能外部中斷
-
- EXTI_CR3_PDIS =2;//PD口上升沿中斷
- /*00: Falling edge and low level
- 01: Rising edge only
- 10: Falling edge only
- 11: Rising and falling edge*/
- EXTI_CONF_PDHIS =1;//PD[7:4] are used for EXTID interrupt generation
-
- //設(shè)置中斷
- //CPU_CCR |=MASK_CPU_CCR_I1+MASK_CPU_CCR_I0;//啟用硬件優(yōu)先級,禁用軟件優(yōu)先級
- }
- uint8_t num=30;
- void main(void)
- {
- GPIO_Config();
- LCD1602_init();
- LCD1602_Display_String(0,0,"nannan wo ai ni!");
- LCD1602_Display_String(0,1,"NUM:");
- asm("rim"); //enable interrupts
- while(1)
- {
- LCD1602_Display_Number(4,1,num);
- PE_ODR ^=0x80;
- asm("wfi");
- //delay_100us(10000);
- }
- }
- #pragma vector=EXTID_vector
- __interrupt void EXTID_ISR(void)
- {
- delay_100us(100);//10ms延時(shí),暫時(shí)這么做
- if(PD_IDR_IDR6==0)//加
- {
- if(num>256)
- num=255;
- else
- num++;
- }
- else if(PD_IDR_IDR7==0)//減
- {
- if(num==0)
- num=0;
- else
- num--;
- }
- EXTI_SR2_PDF =1;//They are cleared by writing a ‘1’ by software
- }
復(fù)制代碼
|
|