六、温湿度传感器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();
  7. LCD1602_WriteCom(0x38);
  8. LCD1602_DELAY_MS();
  9. LCD1602_WriteCom(0x38);
  10. LCD1602_DELAY_MS();
  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();
  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();
  7. }
  8.  
  9. void LCD1602_WriteChar(t_uc x,t_uc y,t_uc temp_data)//(x,y),data,ascill
  10. {
  11. if (y == )//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 == )//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)-;
  43. if(from< || from> || to< || to>)return;//shouldn't out the 32 datas
  44. if(to<){//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>){//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<;i++){
  59. LCD1602_WriteData(s[i]);
  60. LCD1602_DELAY_MS(delay_ms);
  61. }
  62. LCD1602_WriteCom(0xC0 + from);
  63. for(i=;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^;
  21. sbit sLCD1602_RW_PIN = P1^;
  22. sbit sLCD1602_EN_PIN = P2^;
  23.  
  24. #define LCD1602_DELAY_MS(x) DelayMs((x))
  25. #define LCD1602_NOP _nop_()
  26.  
  27. #define LCD1602_RS_PIN sLCD1602_RS_PIN
  28. #define LCD1602_RS_PIN_SET LCD1602_RS_PIN=1
  29. #define LCD1602_RS_PIN_CLEAR LCD1602_RS_PIN=0
  30. #define LCD1602_RS_PIN_OUT
  31.  
  32. #define LCD1602_RW_PIN sLCD1602_RW_PIN
  33. #define LCD1602_RW_PIN_SET LCD1602_RW_PIN=1
  34. #define LCD1602_RW_PIN_CLEAR LCD1602_RW_PIN=0
  35. #define LCD1602_RW_PIN_OUT
  36.  
  37. #define LCD1602_EN_PIN sLCD1602_EN_PIN
  38. #define LCD1602_EN_PIN_SET LCD1602_EN_PIN=1
  39. #define LCD1602_EN_PIN_CLEAR LCD1602_EN_PIN=0
  40. #define LCD1602_EN_PIN_OUT
  41.  
  42. #define LCD1602_DATA_PORT_GPIO P0
  43. #define LCD1602_DATA_PORT_IN
  44. #define LCD1602_DATA_PORT_OUT
  45. #define LCD1602_DATA_PORT_READ(x) (*(x))=LCD1602_DATA_PORT_GPIO
  46. #define LCD1602_DATA_PORT_WRITE(x) LCD1602_DATA_PORT_GPIO=(x)
  47.  
  48. void LCD1602_WriteCom(t_uc com);//write command
  49. void LCD1602_WriteData(t_uc temp_data);//write data
  50. void LCD1602_Init(void);//initialization function
  51. void LCD1602_Clear(void);//clear screen
  52. void LCD1602_WriteChar(t_uc x,t_uc y,t_uc temp_data);//(x,y),data,ascill
  53. void LCD1602_WriteString(t_uc x,t_uc y,t_uc *s);//(x,y),string data
  54. void LCD1602_ShowMessage(t_uc from,t_uc *s,t_uc delay_ms);//from(0~31),msg,each char delay time
  55.  
  56. #endif

3、工程整体逻辑简单梳理

main函数中不断检测串口是否发来有效数据(暂且把一行当为有效数据),一旦有效数据到来就调用ShowMessage显示出来~

  1. /*------------------------------------------------
  2. 主函数
  3. ------------------------------------------------*/
  4. void main (void)
  5. {
  6. InitUART();
  7. LCD1602_Init();
  8. LCD1602_Clear();//ÇåÆÁ
  9. while ()
  10. {
  11. //LCD1602_ShowMessage(0,"hello world! I'm beautifulzzzz.",1000);
  12. if(flag==)
  13. {
  14. flag=;
  15. SendStr(getByte);
  16. LCD1602_Clear();
  17. LCD1602_ShowMessage(,getByte,);
  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 //串行中断服务程序
  5. {
  6. if(RI){ //判断是接收中断产生
  7. RI=; //标志位清零
  8. getByte[point]=SBUF; //读入缓冲区的值
  9. if((point>) && (getByte[point-]==0x0d) && (getByte[point]==0x0a)){
  10. getByte[point-]=0x00;
  11. flag=;
  12. point=;
  13. }else{
  14. point++;
  15. if(point==){
  16. point=;
  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 持续更新中~

如何为编程爱好者设计一款好玩的智能硬件(九)——LCD1602点阵字符型液晶显示模块驱动封装(下)的更多相关文章

  1. 如何为编程爱好者设计一款好玩的智能硬件(八)——LCD1602点阵字符型液晶显示模块驱动封装(中)

    六.温湿度传感器DHT11驱动封装(下):如何为编程爱好者设计一款好玩的智能硬件(六)——初尝试·把温湿度给收集了(下)! 七.点阵字符型液晶显示模块LCD1602驱动封装(上):如何为编程爱好者设计 ...

  2. 如何为编程爱好者设计一款好玩的智能硬件(七)——LCD1602点阵字符型液晶显示模块驱动封装(上)

    当前进展: 一.我的构想:如何为编程爱好者设计一款好玩的智能硬件(一)——即插即用.积木化.功能重组的智能硬件模块构想 二.别人家的孩子:如何为编程爱好者设计一款好玩的智能硬件(二)——别人是如何设计 ...

  3. 如何为编程爱好者设计一款好玩的智能硬件(十)——无线2.4G通信模块研究·一篇说完

    六.温湿度传感器DHT11驱动封装(下):如何为编程爱好者设计一款好玩的智能硬件(六)——初尝试·把温湿度给收集了(下)! 七.点阵字符型液晶显示模块LCD1602驱动封装(上):如何为编程爱好者设计 ...

  4. 如何为编程爱好者设计一款好玩的智能硬件(三)——该选什么样的MCU呢?

    一.我的构想:如何为编程爱好者设计一款好玩的智能硬件(一)——即插即用.积木化.功能重组的智能硬件模块构想 二.别人家的孩子:如何为编程爱好者设计一款好玩的智能硬件(二)——别人是如何设计硬件积木的! ...

  5. 程序员编程利器:20款最好的免费的IDEs和编辑器

    程序员编程利器:20款最好的免费的IDEs和编辑器 还没转眼明年可就大年三十了,忙的可真是晕头转了个向,看着亲朋好友们那让人欣羡的小肚腩,不禁感慨,岁月是一把猪饲料,绿了芭蕉,肥了那杨柳小蛮腰,可怜我 ...

  6. IOS开发入门教程-总结篇-写给狂热的编程爱好者们

    程序发轻狂,代码阑珊,苹果开发安卓狂!--写给狂热的编程爱好者们 写在前面的话 学习iOS应用程序开发已有一段时间,最近稍微闲下来了,正好也想记录一下前阶段的整个学习过程.索性就从最基础的开始,一步一 ...

  7. Java Socket 网络编程心跳设计概念

    Java Socket 网络编程心跳设计概念   1.一般是用来判断对方(设备,进程或其它网元)是否正常动行,一 般采用定时发送简单的通讯包,如果在指定时间段内未收到对方响应,则判断对方已经当掉.用于 ...

  8. 五款好玩又好用的Linux网络测试和监控工具

    五款好玩又好用的Linux网络测试和监控工具 [51CTO精选译文]在这篇介绍几款Linux网络测试实用工具的文章中,我们使用Bandwidthd.Speedometer.Nethogs.Darkst ...

  9. 如何设计一款优秀的短视频 SDK

    2017 年,短视频成为了创业的新风口,各种短视频 App 如雨后春笋般先后上线,视频越来越像文字.图片一样,成为每一个 App 不可或缺的一部分. 1. 包体一定要尽可能小 如何做到尽可能的减小 S ...

随机推荐

  1. [11]APUE:(文件)记录锁

    [a] 概念 建议锁:在遵循相同记录锁规则的进程间生效,通常用于保证某个程序自身多个进程间的数据一致性 强制锁:意在保证所有进程间的数据一致性,但不一定有效:如不能应对先 unlink 后建立同名副本 ...

  2. SQL Server 2008通过LinkServer操作ORACLE

    时光荏苒~~ 最近项目有需求需要通过SQL Server2008中的数据自动更新到ORACLE中,其实,一开始肯定会想到触发器,因为可以保证实时性. 方案一: 首先,我很确定的一件事情就是MSSQL中 ...

  3. Oracle 11g 服务器安装图解

    平常Oracle都是安装到本地的,没有安装到服务器过,今天找了个帖子是安装到服务器的图解 http://jingyan.baidu.com/album/948f5924373c04d80ff5f9f5 ...

  4. K/3 Cloud开发之旅--环境准备篇

    K/3 Cloud是金蝶软件新推出的一款产品,介绍我就不多说了,谁用谁知道啊,那么我们如果要基于它做开发需要什么环境呢 开发环境必备软件 1 操作系统Windows X86/X64 或者Windows ...

  5. 《photon中配置lite的相关问题》

    前几天在学习photon的时候发现了一个问题: 无论如何都找不到Lite文件夹,我是一个新手这也是写给那些新上手的朋友: 首先下载SDK以后配置完成后无论如何都找不到Lite文件夹和相关的Lite.d ...

  6. Oracle数据库备份 expdp/impdp导出导入命令

    使用EXPDP和IMPDP时应该注意的事项: EXP和IMP是客户端工具程序,它们既可以在客户端使用,也可以在服务端使用. EXPDP和IMPDP是服务端的工具程序,他们只能在ORACLE服务端使用, ...

  7. js数组去重的三种方法

    <script type="text/javascript"> /*// 第一种冒泡法删除 var arr=[1,2,2,78,3,456,456]; for(var ...

  8. ODBC,OLEDB,ADO,ADO.net,JDBC 理解

    一 .ODBC 开放式数据库互联(Open Database connectivity), 93年微软推出的实现应用程序 和关系数据库直接 通讯的借口标准.只能用于关系数据库 . 注意事项 : 必须先 ...

  9. #ing# CSS细节注意点

    目录: 常用简写 权重(优先级) Hack 常用简写 权重(优先级) Hack    etc

  10. invalidate()和postInvalidate()的使用与区别

    Android提供了Invalidate方法实现界面刷新,但是Invalidate不能直接在线程中调用,因为他是违背了单线程模型: Android UI操作并不是线程安全的,并且这些操作必须在UI线程 ...