前言:
前面我們說過,之前LCD1602模塊有點難,但是現在,我們通過幾遍博客的學習,今天來講一下LCD1602的原理
演示視頻:
LCD1602流動
源代碼:
main.c
#include <STC89C5xRC.H>
#include "LCD1602.h"
#include "Delay.h"void main()
{LCD_Init(); //LCD初始化LCD_ShowChar(1,1,'A'); //在1行1列顯示字符ALCD_ShowString(1,3,"Hello"); //在1行3列顯示字符串HelloLCD_ShowNum(1,9,66,2); //在1行9列顯示數字66,長度為2LCD_ShowSignedNum(1,12,-88,2); //在1行12列顯示有符號數字-88,長度為2LCD_ShowHexNum(2,1,0xA5,2); //在2行1列顯示十六進制數字0xA5,長度為2LCD_ShowBinNum(2,4,0xA5,8); //在2行4列顯示二進制數字0xA5,長度為8LCD_ShowChar(2,13,0xDF); //在2行13列顯示編碼為0xDF的字符LCD_ShowChar(2,14,'C'); //在2行14列顯示字符CLCD_ShowString(1,16,"I Love You");while(1){LCD_WriteCommand(0x18);Delay(500);}
}
?LCD1602.c
#include <STC89C5xRC.H>//引腳配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0//函數定義:
/*** @brief LCD1602延時函數,12MHz調用可延時1ms* @param 無* @retval 無*/
void LCD_Delay() //@11.0592MHz
{unsigned char i, j;i = 11;j = 190;do{while (--j);} while (--i);
}/*** @brief LCD1602寫命令* @param Command 要寫入的命令* @retval 無*/
void LCD_WriteCommand(unsigned char Command)
{LCD_RS=0;LCD_RW=0;LCD_DataPort=Command;LCD_EN=1;LCD_Delay();LCD_EN=0;LCD_Delay();
}/*** @brief LCD1602寫數據* @param Data 要寫入的數據* @retval 無*/
void LCD_WriteData(unsigned char Data)
{LCD_RS=1;LCD_RW=0;LCD_DataPort=Data;LCD_EN=1;LCD_Delay();LCD_EN=0;LCD_Delay();
}/*** @brief LCD1602設置光標位置* @param Line 行位置,范圍:1~2* @param Column 列位置,范圍:1~16* @retval 無*/
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{if(Line==1){LCD_WriteCommand(0x80|(Column-1));}else if(Line==2){LCD_WriteCommand(0x80|(Column-1+0x40));}
}/*** @brief LCD1602初始化函數* @param 無* @retval 無*/
void LCD_Init()
{LCD_WriteCommand(0x38);//八位數據接口,兩行顯示,5*7點陣LCD_WriteCommand(0x0c);//顯示開,光標關,閃爍關LCD_WriteCommand(0x06);//數據讀寫操作后,光標自動加一,畫面不動LCD_WriteCommand(0x01);//光標復位,清屏
}/*** @brief 在LCD1602指定位置上顯示一個字符* @param Line 行位置,范圍:1~2* @param Column 列位置,范圍:1~16* @param Char 要顯示的字符* @retval 無*/
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{LCD_SetCursor(Line,Column);LCD_WriteData(Char);
}/*** @brief 在LCD1602指定位置開始顯示所給字符串* @param Line 起始行位置,范圍:1~2* @param Column 起始列位置,范圍:1~16* @param String 要顯示的字符串* @retval 無*/
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{unsigned char i;LCD_SetCursor(Line,Column);for(i=0;String[i]!='\0';i++){LCD_WriteData(String[i]);}
}/*** @brief 返回值=X的Y次方*/
int LCD_Pow(int X,int Y)
{unsigned char i;int Result=1;for(i=0;i<Y;i++){Result*=X;}return Result;
}/*** @brief 在LCD1602指定位置開始顯示所給數字* @param Line 起始行位置,范圍:1~2* @param Column 起始列位置,范圍:1~16* @param Number 要顯示的數字,范圍:0~65535* @param Length 要顯示數字的長度,范圍:1~5* @retval 無*/
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{unsigned char i;LCD_SetCursor(Line,Column);for(i=Length;i>0;i--){LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');}
}/*** @brief 在LCD1602指定位置開始以有符號十進制顯示所給數字* @param Line 起始行位置,范圍:1~2* @param Column 起始列位置,范圍:1~16* @param Number 要顯示的數字,范圍:-32768~32767* @param Length 要顯示數字的長度,范圍:1~5* @retval 無*/
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
{unsigned char i;unsigned int Number1;LCD_SetCursor(Line,Column);if(Number>=0){LCD_WriteData('+');Number1=Number;}else{LCD_WriteData('-');Number1=-Number;}for(i=Length;i>0;i--){LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');}
}/*** @brief 在LCD1602指定位置開始以十六進制顯示所給數字* @param Line 起始行位置,范圍:1~2* @param Column 起始列位置,范圍:1~16* @param Number 要顯示的數字,范圍:0~0xFFFF* @param Length 要顯示數字的長度,范圍:1~4* @retval 無*/
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{unsigned char i,SingleNumber;LCD_SetCursor(Line,Column);for(i=Length;i>0;i--){SingleNumber=Number/LCD_Pow(16,i-1)%16;if(SingleNumber<10){LCD_WriteData(SingleNumber+'0');}else{LCD_WriteData(SingleNumber-10+'A');}}
}/*** @brief 在LCD1602指定位置開始以二進制顯示所給數字* @param Line 起始行位置,范圍:1~2* @param Column 起始列位置,范圍:1~16* @param Number 要顯示的數字,范圍:0~1111 1111 1111 1111* @param Length 要顯示數字的長度,范圍:1~16* @retval 無*/
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{unsigned char i;LCD_SetCursor(Line,Column);for(i=Length;i>0;i--){LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');}
}
?LCD1602.h
#ifndef __LCD1602_H__
#define __LCD1602_H__//用戶調用函數:
void LCD_WriteCommand(unsigned char Command);
void LCD_Init();//初始化
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);//顯示單個字符
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);//顯示字符串
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);//顯示數字
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);//顯示帶符號數字
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);//顯示十進制數字
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);//顯示二進制數字#endif
?Delay.c
void Delay(unsigned int xms)
{unsigned char i, j;while(xms--){i = 2;j = 239;do{while (--j);} while (--i);}
}
?Delay.h
#ifndef __DELAY_H__
#define __DELAY_H__void Delay(unsigned int xms);#endif
?代碼解析與教程:
?Dealy模塊
- 包含源代碼與頭文件,不需要知道怎么實現的會用即可,后續使用,直接將頭文件和源代碼拿過來用即可;
xms是定義的毫秒,1000毫秒就是1秒;模版生成的是1毫秒的,因此xms等于1000
?LCD1602模塊
?
- LCD1602相關重要知識:
- LCD1602有兩上下兩行顯示屏,每行各有16個小顯示屏,如上圖中的LCD_ShowString(1,3,"Hello"),第一個參數是第一行還是第二行,第2個參數是對應第幾行的第幾個小顯示屏,最后一個是輸出的東西,同理,到LCD_ShowNum(1,9,123,3)里,前三個和前面一樣,最后一個參數是顯示的位數,不夠就在前面補0,例如輸入1,參數為4,顯示就是0001,輸入23,參數為3,顯示就是023
- 先看原理圖
VO是調節顯示亮度的,讓你的顯示屏顯示更清楚。
RS,WR,EN(E)是引腳定義,看單片機核心,對應著P25,P26,P27:(下述所有代碼WR都寫成了RW,不過不影響,引腳對就行)
再看D0-D7,也就是數據,看單片機核心可知,對應著P00-P07,也就是P0,因此宏定義LCD_DataPort=P0;
//引腳配置: sbit LCD_RS=P2^6; sbit LCD_RW=P2^5; sbit LCD_EN=P2^7; #define LCD_DataPort P0
LCD1602,屏幕是16*2的,每一個小格格就是CGRAM+CGROM(字模庫)組成,這個東西就是顯示數據的,這些數據是DDPAN(數據顯示區)來存儲的,然后映射到屏幕上,一一對應;但是DDRAM有40*2個小格格,因此,LCD1602,其實可以滾動顯示;然后DDRAM是由控制器來決定的,AC就是小格格的地址;
DDRAM部分
看第8個DDRAM部分:前兩個是00
上圖就是DDRAM的地址,也就是小格格的,如果是第一行顯示,A6前面那個等于0就行了,A6前面等于1就是第二行顯示,剩下的A6-A0就是小格格的地址,比如第一個,0000 0000,因此簡寫成00H,第二行第一個,0100?0000,0x40,簡寫40H,以此類推;
CGRAM+CGROM部分
這部分可以理解成二維數組,比如你想顯示A,在圖中找到A,A的列是0100,行是0001,把列放到行的前面組成二進制就是他的地址,0100 0001,就是0x41;
來看編碼表,A確實是0x41;
- 掌握上述知識,就可以寫顯示數據了,這里只講寫數據/指令:
寫指令/數據部分
可以看到,寫入一個數據要將RS變化(默認為1),R/W變化(默認為1),EN(E)也要變化,因此有:
/*** @brief LCD1602延時函數,12MHz調用可延時1ms* @param 無* @retval 無*/ void LCD_Delay() //@11.0592MHz {unsigned char i, j;i = 11;j = 190;do{while (--j);} while (--i); }/*** @brief LCD1602寫命令* @param Command 要寫入的命令* @retval 無*/ void LCD_WriteCommand(unsigned char Command) {LCD_RS=0;LCD_RW=0;LCD_DataPort=Command;LCD_EN=1;LCD_Delay();LCD_EN=0;LCD_Delay(); }/*** @brief LCD1602寫數據* @param Data 要寫入的數據* @retval 無*/ void LCD_WriteData(unsigned char Data) {LCD_RS=1;LCD_RW=0;LCD_DataPort=Data;LCD_EN=1;LCD_Delay();LCD_EN=0;LCD_Delay(); }
注意:EN(E)操作的時候需要時間,數據讀取需要時間,因此延時1ms;RS在寫數據和指令的時候不一樣,前者1,后者0;
屏幕顯示部分
由上控制指令,完成操作,就可以初始化屏幕:
/*** @brief LCD1602初始化函數* @param 無* @retval 無*/ void LCD_Init() {LCD_WriteCommand(0x38);//八位數據接口,兩行顯示,5*7點陣LCD_WriteCommand(0x0c);//顯示開,光標關,閃爍關LCD_WriteCommand(0x06);//數據讀寫操作后,光標自動加一,畫面不動LCD_WriteCommand(0x01);//光標復位,清屏 }
然后是顯示字符的操作,先用指令確定AC地址:
/*** @brief LCD1602設置光標位置* @param Line 行位置,范圍:1~2* @param Column 列位置,范圍:1~16* @retval 無*/ void LCD_SetCursor(unsigned char Line,unsigned char Column) {if(Line==1){LCD_WriteCommand(0x80|(Column-1));}else if(Line==2){LCD_WriteCommand(0x80|(Column-1+0x40));} }
然后發送數據:
字符:
/*** @brief 在LCD1602指定位置上顯示一個字符* @param Line 行位置,范圍:1~2* @param Column 列位置,范圍:1~16* @param Char 要顯示的字符* @retval 無*/ void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char) {LCD_SetCursor(Line,Column);LCD_WriteData(Char); }
確定AC地址,然后用函數直接寫數據;
字符串:
/*** @brief 在LCD1602指定位置開始顯示所給字符串* @param Line 起始行位置,范圍:1~2* @param Column 起始列位置,范圍:1~16* @param String 要顯示的字符串* @retval 無*/ void LCD_ShowString(unsigned char Line,unsigned char Column,char *String) {unsigned char i;LCD_SetCursor(Line,Column);for(i=0;String[i]!='\0';i++){LCD_WriteData(String[i]);} }
這部分就是C語言程序部分,看看代碼很好理解
數字:
/*** @brief 返回值=X的Y次方*/ int LCD_Pow(int X,int Y) {unsigned char i;int Result=1;for(i=0;i<Y;i++){Result*=X;}return Result; }/*** @brief 在LCD1602指定位置開始顯示所給數字* @param Line 起始行位置,范圍:1~2* @param Column 起始列位置,范圍:1~16* @param Number 要顯示的數字,范圍:0~65535* @param Length 要顯示數字的長度,范圍:1~5* @retval 無*/ void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length) {unsigned char i;LCD_SetCursor(Line,Column);for(i=Length;i>0;i--){LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');} }
這部分也是C語言代碼部分,將數字各位分開,例如:
這樣操作。
其他部分:
/*** @brief 在LCD1602指定位置開始以有符號十進制顯示所給數字* @param Line 起始行位置,范圍:1~2* @param Column 起始列位置,范圍:1~16* @param Number 要顯示的數字,范圍:-32768~32767* @param Length 要顯示數字的長度,范圍:1~5* @retval 無*/ void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length) {unsigned char i;unsigned int Number1;LCD_SetCursor(Line,Column);if(Number>=0){LCD_WriteData('+');Number1=Number;}else{LCD_WriteData('-');Number1=-Number;}for(i=Length;i>0;i--){LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');} }/*** @brief 在LCD1602指定位置開始以十六進制顯示所給數字* @param Line 起始行位置,范圍:1~2* @param Column 起始列位置,范圍:1~16* @param Number 要顯示的數字,范圍:0~0xFFFF* @param Length 要顯示數字的長度,范圍:1~4* @retval 無*/ void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length) {unsigned char i,SingleNumber;LCD_SetCursor(Line,Column);for(i=Length;i>0;i--){SingleNumber=Number/LCD_Pow(16,i-1)%16;if(SingleNumber<10){LCD_WriteData(SingleNumber+'0');}else{LCD_WriteData(SingleNumber-10+'A');}} }/*** @brief 在LCD1602指定位置開始以二進制顯示所給數字* @param Line 起始行位置,范圍:1~2* @param Column 起始列位置,范圍:1~16* @param Number 要顯示的數字,范圍:0~1111 1111 1111 1111* @param Length 要顯示數字的長度,范圍:1~16* @retval 無*/ void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length) {unsigned char i;LCD_SetCursor(Line,Column);for(i=Length;i>0;i--){LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');} }
和數字部分差不多,也是C語言程序,認真看代碼即可;
?main模塊
- 注釋寫的很清楚,這里不做解釋了
#include <STC89C5xRC.H> #include "LCD1602.h" #include "Delay.h"void main() {LCD_Init(); //LCD初始化LCD_ShowChar(1,1,'A'); //在1行1列顯示字符ALCD_ShowString(1,3,"Hello"); //在1行3列顯示字符串HelloLCD_ShowNum(1,9,66,2); //在1行9列顯示數字66,長度為2LCD_ShowSignedNum(1,12,-88,2); //在1行12列顯示有符號數字-88,長度為2LCD_ShowHexNum(2,1,0xA5,2); //在2行1列顯示十六進制數字0xA5,長度為2LCD_ShowBinNum(2,4,0xA5,8); //在2行4列顯示二進制數字0xA5,長度為8LCD_ShowChar(2,13,0xDF); //在2行13列顯示編碼為0xDF的字符LCD_ShowChar(2,14,'C'); //在2行14列顯示字符CLCD_ShowString(1,16,"I Love You");while(1){LCD_WriteCommand(0x18);Delay(500);} }
?注:該代碼是本人自己所寫,可能不夠好,不夠簡便,歡迎大家指出我的不足之處。如果遇見看不懂的地方,可以在評論區打出來,進行討論,或者聯系我。上述內容全是我自己理解的,如果你有別的想法,或者認為我的理解不對,歡迎指出!!!如果可以,可以點一個免費的贊支持一下嗎?謝謝各位彥祖亦菲!!!!!