六、温湿度传感器DHT11驱动封装(下):如何为编程爱好者设计一款好玩的智能硬件(六)——初尝试·把温湿度给收集了(下)!
七、点阵字符型液晶显示模块LCD1602驱动封装(上):如何为编程爱好者设计一款好玩的智能硬件(七)——LCD1602点阵字符型液晶显示模块驱动封装(上)
八、LCD1602点阵字符型液晶显示模块驱动封装(中):如何为编程爱好者设计一款好玩的智能硬件(八)——LCD1602点阵字符型液晶显示模块驱动封装(中)
九、LCD1602点阵字符型液晶显示模块驱动封装(下)
在上文中我们终于实现了一个简单版的无线滚动屏!本节对其工程进行详细讲解——
工程概述
keil u5 PK51IDE
无线显示屏采用蓝牙串口透传模块和LCD1602液晶显示模块
单片机采用STC89C51单片机
实现上位机通过串口助手发送一行msg,其在LCD屏上显示出来
要求msg长度小于32
更多详情请见前两节内容
1、LCD1602封装——LCD1602.C内部封装(一般不要改动)用的时候只需要根据平台重新修改.h内的宏定义即可
下面3个函数是基础通信函数,分别负责忙检测、写命令和写数据。具体细节可以参考——如何为编程爱好者设计一款好玩的智能硬件(七)——LCD1602点阵字符型液晶显示模块驱动封装(上))
1 //------------------------------------------------ 2 //base communite function 3 t_uc LCD1602_CheckBusy(void)//check busy 4 { 5 t_c temp_data; 6 LCD1602_DATA_PORT_WRITE(0xFF); 7 LCD1602_RS_PIN_CLEAR; 8 LCD1602_RW_PIN_SET; 9 LCD1602_EN_PIN_CLEAR; 10 LCD1602_NOP; 11 LCD1602_EN_PIN_SET; 12 LCD1602_DATA_PORT_READ(&temp_data); 13 return (temp_data & 0x80); 14 } 15 16 void LCD1602_WriteCom(t_uc com)//write command 17 { 18 while(LCD1602_CheckBusy()); //if busy wait 19 LCD1602_RS_PIN_CLEAR; 20 LCD1602_RW_PIN_CLEAR; 21 LCD1602_EN_PIN_SET; 22 LCD1602_DATA_PORT_WRITE(com); 23 LCD1602_NOP; 24 LCD1602_EN_PIN_CLEAR; 25 } 26 27 void LCD1602_WriteData(t_uc temp_data)//write data 28 { 29 while(LCD1602_CheckBusy()); //if busy wait 30 LCD1602_RS_PIN_SET; 31 LCD1602_RW_PIN_CLEAR; 32 LCD1602_EN_PIN_SET; 33 LCD1602_DATA_PORT_WRITE(temp_data); 34 LCD1602_NOP; 35 LCD1602_EN_PIN_CLEAR; 36 }
下面的LCD1602初始化函数负责对LCD显示模式进行设置,如设置是否有光标、设置memory指针的方向...关于初始化为什么这样以及这些命令表示什么意思,可以参考——如何为编程爱好者设计一款好玩的智能硬件(七)——LCD1602点阵字符型液晶显示模块驱动封装(上))
1 //------------------------------------------------ 2 //initialization function 3 void LCD1602_Init(void) 4 { 5 LCD1602_WriteCom(0x38); /*display mode settings*/ 6 LCD1602_DELAY_MS(5); 7 LCD1602_WriteCom(0x38); 8 LCD1602_DELAY_MS(5); 9 LCD1602_WriteCom(0x38); 10 LCD1602_DELAY_MS(5); 11 LCD1602_WriteCom(0x38); 12 LCD1602_WriteCom(0x08); /*display close*/ 13 LCD1602_WriteCom(0x01); /*display clear*/ 14 LCD1602_WriteCom(0x06); /*display cursor movement settings*/ 15 LCD1602_DELAY_MS(5); 16 LCD1602_WriteCom(0x0C); /*display and cursor settings*/ 17 }
下面是一些基于LCD1602基本通信函数封装的功能函数:
void LCD1602_Clear(void)//clear screen 是清屏函数
void LCD1602_WriteChar(t_uc x,t_uc y,t_uc temp_data)//(x,y),data,ascill 是控制在16X2的LCD显示屏上某个位置(x,y)显示一个字符temp_data的函数
void LCD1602_WriteString(t_uc x,t_uc y,t_uc *s)//(x,y),string data 是在第一行(y==0)或在第二行(y==1)的第x个位置显示一个字符串s,不支持自动换行
void LCD1602_ShowMessage(t_uc from,t_uc *s,t_uc delay_ms)//from(0~31),msg,each char delay time 是从0~31显示屏的某个位置开始显示完字符串s,并且显示每个字符间隔时间delay_ms,这里字符串不能超出屏的范围!
写入某个位置某个内容参见——如何为编程爱好者设计一款好玩的智能硬件(七)——LCD1602点阵字符型液晶显示模块驱动封装(上))的内存映射和指令说明小节
1 //------------------------------------------------ 2 //Function 3 void LCD1602_Clear(void)//clear screen 4 { 5 LCD1602_WriteCom(0x01); 6 LCD1602_DELAY_MS(5); 7 } 8 9 void LCD1602_WriteChar(t_uc x,t_uc y,t_uc temp_data)//(x,y),data,ascill 10 { 11 if (y == 0)//the first line 12 { 13 LCD1602_WriteCom(0x80 + x); 14 } 15 else//the second line 16 { 17 LCD1602_WriteCom(0xC0 + x); 18 } 19 LCD1602_WriteData(temp_data); 20 } 21 22 void LCD1602_WriteString(t_uc x,t_uc y,t_uc *s)//(x,y),string data 23 { 24 if (y == 0)//the first line 25 { 26 LCD1602_WriteCom(0x80 + x); 27 } 28 else//the second line 29 { 30 LCD1602_WriteCom(0xC0 + x); 31 } 32 while (*s) 33 { 34 LCD1602_WriteData( *s); 35 s ++; 36 } 37 } 38 39 void LCD1602_ShowMessage(t_uc from,t_uc *s,t_uc delay_ms)//from(0~31),msg,each char delay time 40 { 41 t_uc i; 42 t_uc to=from+strlen((t_c*)s)-1; 43 if(from<0 || from>31 || to<0 || to>31)return;//shouldn't out the 32 datas 44 if(to<16){//only the first line 45 LCD1602_WriteCom(0x80 + from); 46 for(i=from;i<=to;i++){ 47 LCD1602_WriteData(s[i]); 48 LCD1602_DELAY_MS(delay_ms); 49 } 50 }else if(from>15){//only the sencond line 51 LCD1602_WriteCom(0xC0 + from); 52 for(i=from;i<=to;i++){ 53 LCD1602_WriteData(s[i]); 54 LCD1602_DELAY_MS(delay_ms); 55 } 56 }else{//both lines 57 LCD1602_WriteCom(0x80 + from); 58 for(i=from;i<16;i++){ 59 LCD1602_WriteData(s[i]); 60 LCD1602_DELAY_MS(delay_ms); 61 } 62 LCD1602_WriteCom(0xC0 + from); 63 for(i=16;i<=to;i++){ 64 LCD1602_WriteData(s[i]); 65 LCD1602_DELAY_MS(delay_ms); 66 } 67 } 68 }
2、LCD1602封装——LCD1602.h根据平台重新修改.h内的宏定义适应不同硬件平台
下面是根据AT89C52的平台特性对宏进行的修改,由于51单片机引脚操作比较简单,且支持读写,无需切换属性~因此下面部分宏定义的功能可以不定义~但是对于STM32就比较复杂了!正因如此,我STM32的封装也没想到一个比较好的处理方式,在我的工程里有基于STM32宏定义修改,不过存在问题,如果今后要用,一定要修改好!!!
1 #define MCU_AT89C52 2 3 ////////////////////////////////////////////////////////////////////////////////////////// 4 //MCU_AT89C52 5 ////////////////////////////////////////////////////////////////////////////////////////// 6 #ifdef MCU_AT89C52 7 8 #include "FUNC/delay.h" 9 #include <intrins.h> 10 #include <string.h> 11 12 //some typedef need to do 13 typedef unsigned char t_uc; 14 typedef unsigned short t_us; 15 typedef unsigned int t_ui; 16 typedef char t_c; 17 typedef short t_s; 18 typedef int t_i; 19 20 sbit sLCD1602_RS_PIN = P1^0; 21 sbit sLCD1602_RW_PIN = P1^1; 22 sbit sLCD1602_EN_PIN = P2^5; 23 24 25 #define LCD1602_DELAY_MS(x) DelayMs((x)) 26 #define LCD1602_NOP _nop_() 27 28 29 #define LCD1602_RS_PIN sLCD1602_RS_PIN 30 #define LCD1602_RS_PIN_SET LCD1602_RS_PIN=1 31 #define LCD1602_RS_PIN_CLEAR LCD1602_RS_PIN=0 32 #define LCD1602_RS_PIN_OUT 33 34 #define LCD1602_RW_PIN sLCD1602_RW_PIN 35 #define LCD1602_RW_PIN_SET LCD1602_RW_PIN=1 36 #define LCD1602_RW_PIN_CLEAR LCD1602_RW_PIN=0 37 #define LCD1602_RW_PIN_OUT 38 39 #define LCD1602_EN_PIN sLCD1602_EN_PIN 40 #define LCD1602_EN_PIN_SET LCD1602_EN_PIN=1 41 #define LCD1602_EN_PIN_CLEAR LCD1602_EN_PIN=0 42 #define LCD1602_EN_PIN_OUT 43 44 #define LCD1602_DATA_PORT_GPIO P0 45 #define LCD1602_DATA_PORT_IN 46 #define LCD1602_DATA_PORT_OUT 47 #define LCD1602_DATA_PORT_READ(x) (*(x))=LCD1602_DATA_PORT_GPIO 48 #define LCD1602_DATA_PORT_WRITE(x) LCD1602_DATA_PORT_GPIO=(x) 49 50 51 void LCD1602_WriteCom(t_uc com);//write command 52 void LCD1602_WriteData(t_uc temp_data);//write data 53 void LCD1602_Init(void);//initialization function 54 void LCD1602_Clear(void);//clear screen 55 void LCD1602_WriteChar(t_uc x,t_uc y,t_uc temp_data);//(x,y),data,ascill 56 void LCD1602_WriteString(t_uc x,t_uc y,t_uc *s);//(x,y),string data 57 void LCD1602_ShowMessage(t_uc from,t_uc *s,t_uc delay_ms);//from(0~31),msg,each char delay time 58 59 #endif
3、工程整体逻辑简单梳理
main函数中不断检测串口是否发来有效数据(暂且把一行当为有效数据),一旦有效数据到来就调用ShowMessage显示出来~
1 /*------------------------------------------------ 2 主函数 3 ------------------------------------------------*/ 4 void main (void) 5 { 6 InitUART(); 7 LCD1602_Init(); 8 LCD1602_Clear();//ÇåÆÁ 9 while (1) 10 { 11 //LCD1602_ShowMessage(0,"hello world! I'm beautifulzzzz.",1000); 12 if(flag==1) 13 { 14 flag=0; 15 SendStr(getByte); 16 LCD1602_Clear(); 17 LCD1602_ShowMessage(0,getByte,1000); 18 } 19 // LCD1602_WriteChar(7, 0, 'o'); 20 // LCD1602_WriteChar(8, 0, 'k'); 21 // LCD1602_WriteString(3, 1, "Hard Work"); 22 //while(1); 23 } 24 }
串口中断是每收到一行置flag标志位为1,一旦point超过getByte大小就从0开始填充~
1 /*------------------------------------------------ 2 串口中断程序 3 ------------------------------------------------*/ 4 void UART_SER (void) interrupt 4 //串行中断服务程序 5 { 6 if(RI){ //判断是接收中断产生 7 RI=0; //标志位清零 8 getByte[point]=SBUF; //读入缓冲区的值 9 if((point>0) && (getByte[point-1]==0x0d) && (getByte[point]==0x0a)){ 10 getByte[point-1]=0x00; 11 flag=1; 12 point=0; 13 }else{ 14 point++; 15 if(point==40){ 16 point=0; 17 } 18 } 19 } 20 }
小结&接下来计划:
终于,我们把LCD1602的驱动封装好了!并且修改了之前模块化模块的想法,引入新的设计方式——模块化功能组件的方式(功能组件一般有单片机、通信模块加传感器、显示器、按键或者机械装置组成)。
模块化模块:之前目标是对每个模块封装,使模块灵活适应各种组合(MCU+POWER+X1+X2+...)
模块化功能块:现在是分出基础部分(MCU+POWER+radio)+一个变动部分=构成功能块
因此,接下来我们将会涉足"X-OS"比较重要的一块——基础部分中的无线通信基础部分。而我们首先尝试的将是最赤裸的24L01无线2.4G通信模块驱动的封装!请持续关注~
链接:http://pan.baidu.com/s/1pJMPuJL
[三个关键文件夹说明]
第一个是:LCD1602封装上参考的几个例程
第二个是:(上)参考的datasheet
第三个是:(下)中的工程
@beautifulzzzz
2015-10-02 持续更新中~