一、我的构想: 如何为编程爱好者设计一款好玩的智能硬件(一)——即插即用、积木化、功能重组的智能硬件模块构想
二、别人家的孩子: 如何为编程爱好者设计一款好玩的智能硬件(二)——别人是如何设计硬件积木的!
三、MCU选型: 如何为编程爱好者设计一款好玩的智能硬件(三)——该选什么样的MCU呢?
四、温湿度传感器DHT11驱动封装(上): 如何为编程爱好者设计一款好玩的智能硬件(四)——初尝试·把温湿度给收集了(上)!
五、温湿度传感器DHT11驱动封装(中): 如何为编程爱好者设计一款好玩的智能硬件(五)——初尝试·把温湿度给收集了(中)!
六、温湿度传感器DHT11驱动封装(下): 如何为编程爱好者设计一款好玩的智能硬件(六)——初尝试·把温湿度给收集了(下)!
前几节我们封装好了一个可以采集数据的传感器驱动,接下来两节将介绍一个非常简单的LCD液晶屏,即显示模块的驱动封装。——有采集有显示,才好!考虑刚开始,所以本节介绍一种最常用的液晶屏:LCD1602
该模块总共有16个引脚,显示字符为16X2行。1602液晶模块内部的字符发生存储器(CGROM)已经存储了160个不同的点阵字符图形,这些字符有:阿拉伯数字、英文字母的大小写、常用符号和日文假名等,每一个字符都有一个固定的代码,比如大写的英文字母'A'的代码是41H,显示时模块把地址41H中的点阵字符图形显示出来,我们就能看到字母'A'了。因为1602识别的是ASCII码,可以直接用ASCII码直接赋值。
456为控制线,DB0~7为8位数据线,3为为调节对比度的(过小会导致文本不清晰,过大会导致背景掩盖文本)
无论是TFT/LCD/OLCD等都会有一个驱动器,简单理解就是屏幕和控制CPU直接的一个桥梁,该桥梁规定发送什么格式的命令能达到某种效果~此外,一般这种驱动对于类似的显示器时相似的!这里用的是HD44780驱动芯片。
1.1 读状态:输入:RS=L,RW=H,E=H 输出:D0~D7=状态字 1.2 写状态:输入:RS=L,RW=L,D0~D7=指令码,E=高脉冲 输出:无 1.3 读数据:输入:RS=H,RW=H,E=H 输出:D0~D7=数据 1.4 写数据:输入:RS=H,RW=L,D0~D7=数据,E=高脉冲 输出:无
注:对控制器每次进行读写操作之前,都必须进行读写检测,确保STA7为0
控制器内部带80X8位(80字节)的RAM缓冲区,对应下图关系为:(因为这个是16X2行的,所以只用了其中一部分)
显示模式设置: 00111000 设置16X2显示,5X7点阵,8位数据接口
显示开关光标设置: 00001DCB D=1 开显示;D=0 关显示
C=1 显示光标;C=0 不显示光标
B=1 光标闪烁;B=0 光标不闪
000001NS N=1 当读或者写一个字符后地址指针加一,且光标加一
N=0 当读或者写一个字符后地址指针减一,且光标减一
S=1 当写一个字符,整屏显示左移(N=1)或右移(N=0),以得到光标不移动而整个屏幕移动的效果
S=0 当写一个字符,整个屏幕不移动
数据控制: 控制器内部设有一个数据地址指针,用户可通过它们来访问内部全部80字节RAM
数据指针设置: 80H+地址码(0-27H,40H-67H)
其他设置: 01H 显示清屏
02H 显示回车
初始化过程(复位过程): ① 延时15ms
② 写指令38H(不检测忙信号)
③ 延时5ms
④ 写指令38H(不检测忙信号)
⑤ 延时5ms
⑥ 写指令38H(不检测忙信号)
⑦ (以后每次写指令、读/写数据操作之前均需要忙检测信号)
⑧ 写指令38H:显示模式设置
⑨ 写指令08H:显示关闭
© 写指令01H:显示清屏
® 写指令06H:显示光标移动设置
〇 写指令0CH:显示开及光标设置
读操作时序图
写操作时序图
时序参数表
下面是基于51平台LCD1602显示静态文本的例子,其连线按照“ 引脚与功能 ”左图的方式进行连接,效果如下:
注:看下面代码,注意重点看我加粗的地方~不同颜色表示不同功能块的部分~
1 /**********************BST-V51实验开发板例程************************ 2 * 平台:BST-V51 + Keil U3 + STC89C52 3 * 名称:1602基本驱动的代码 4 * 公司:深圳市亚博软件开发有限公司 5 * 淘宝:bstmcu.taobao.com 6 * 日期:2012-8-12 7 * 晶振:11.0592MHZ 8 * 说明:免费开源,不提供源代码分析. 9 ******************************************************************/ 10 11 //实验目的: 12 /*----------------------------------------------- 13 名称:LCD1602 14 内容:通过标准程序静态显示字符 15 引脚定义如下:1-VSS 2-VDD 3-V0 4-RS 5-R/W 6-E 7-14 DB0-DB7 15-BLA 16-BLK 16 ------------------------------------------------*/ 17 18 19 #include<reg52.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义 20 #include<intrins.h> 21 22 sbit RS = P1 ^ 0; //定义端口 23 sbit RW = P1 ^ 1; 24 sbit EN = P2 ^ 5; 25 26 27 #define RS_CLR RS=0 28 #define RS_SET RS=1 29 30 #define RW_CLR RW=0 31 #define RW_SET RW=1 32 33 #define EN_CLR EN=0 34 #define EN_SET EN=1 35 36 #define DataPort P0 37 38 /*------------------------------------------------ 39 uS延时函数,含有输入参数 unsigned char t,无返回值 40 unsigned char 是定义无符号字符变量,其值的范围是 41 0~255 这里使用晶振12M,精确延时请使用汇编,大致延时 42 长度如下 T=tx2+5 uS 43 ------------------------------------------------*/ 44 void DelayUs2x(unsigned char t) 45 { 46 while(--t); 47 } 48 /*------------------------------------------------ 49 mS延时函数,含有输入参数 unsigned char t,无返回值 50 unsigned char 是定义无符号字符变量,其值的范围是 51 0~255 这里使用晶振12M,精确延时请使用汇编 52 ------------------------------------------------*/ 53 void DelayMs(unsigned char t) 54 { 55 56 while(t--) 57 { 58 //大致延时1mS 59 DelayUs2x(245); 60 DelayUs2x(245); 61 } 62 } 63 /*------------------------------------------------ 64 判忙函数 65 ------------------------------------------------*/ 66 bit LCD_Check_Busy(void)//蓝色的几个忙检测、写数据和写命令是根据上面《驱动器接口说明》中的第一条和读写时序图写成的 67 { 68 DataPort = 0xFF; 69 RS_CLR; 70 RW_SET; 71 EN_CLR; 72 _nop_(); 73 EN_SET; 74 return (bit)(DataPort & 0x80); 75 } 76 /*------------------------------------------------ 77 写入命令函数 78 ------------------------------------------------*/ 79 void LCD_Write_Com(unsigned char com) 80 { 81 while(LCD_Check_Busy()); //忙则等待 82 RS_CLR; 83 RW_CLR; 84 EN_SET; 85 DataPort = com; 86 _nop_(); 87 EN_CLR; 88 } 89 /*------------------------------------------------ 90 写入数据函数 91 ------------------------------------------------*/ 92 void LCD_Write_Data(unsigned char Data) 93 { 94 while(LCD_Check_Busy()); //忙则等待 95 RS_SET; 96 RW_CLR; 97 EN_SET; 98 DataPort = Data; 99 _nop_(); 100 EN_CLR; 101 } 102 103 /*------------------------------------------------ 104 清屏函数 105 ------------------------------------------------*/ 106 void LCD_Clear(void) 107 { 108 LCD_Write_Com(0x01); 109 DelayMs(5); 110 } 111 /*------------------------------------------------ 112 写入字符串函数 113 ------------------------------------------------*/ 114 void LCD_Write_String(unsigned char x, unsigned char y, unsigned char *s) 115 { 116 if (y == 0) 117 { 118 LCD_Write_Com(0x80 + x); //表示第一行 119 } 120 else 121 { 122 LCD_Write_Com(0xC0 + x); //表示第二行 123 } 124 while (*s) 125 { 126 LCD_Write_Data( *s); 127 s ++; 128 } 129 } 130 /*------------------------------------------------ 131 写入字符函数 132 ------------------------------------------------*/ 133 void LCD_Write_Char(unsigned char x, unsigned char y, unsigned char Data) 134 { 135 if (y == 0)//根据Y的值确定显示在哪一行,不同行RAM地址不一样 136 { 137 LCD_Write_Com(0x80 + x); 138 } 139 else 140 { 141 LCD_Write_Com(0xC0 + x); 142 } 143 LCD_Write_Data( Data); 144 } 145 /*------------------------------------------------和《4、指令说明》的启动阶段描述一样 146 初始化函数 147 ------------------------------------------------*/ 148 void LCD_Init(void) 149 { 150 LCD_Write_Com(0x38); /*显示模式设置*/ 151 DelayMs(5); 152 LCD_Write_Com(0x38); 153 DelayMs(5); 154 LCD_Write_Com(0x38); 155 DelayMs(5); 156 LCD_Write_Com(0x38); 157 LCD_Write_Com(0x08); /*显示关闭*/ 158 LCD_Write_Com(0x01); /*显示清屏*/ 159 LCD_Write_Com(0x06); /*显示光标移动设置*/ 160 DelayMs(5); 161 LCD_Write_Com(0x0C); /*显示开及光标设置*/ 162 } 163 164 /*------------------------------------------------ 165 主函数 166 ------------------------------------------------*/ 167 void main(void) 168 { 169 LCD_Init(); 170 LCD_Clear();//清屏 171 while (1) 172 { 173 LCD_Write_Char(7, 0, 'o'); 174 LCD_Write_Char(8, 0, 'k'); 175 LCD_Write_String(1, 1, "Hard Work"); 176 while(1); 177 } 178 }
下一节将把LCD1602的驱动改写成便于移植的版本,同时讨论一些稍微炫一点的效果——滚动、光标等待等。两周内计划是:再研究一个按键的驱动、一个通信的驱动之后就着手写我们的“X-积木”OS了。