如何为编程爱好者设计一款好玩的智能硬件(九)——LCD1602点阵字符型液晶显示模块驱动封装(下)
六、温湿度传感器DHT11驱动封装(下):如何为编程爱好者设计一款好玩的智能硬件(六)——初尝试·把温湿度给收集了(下)!
七、点阵字符型液晶显示模块LCD1602驱动封装(上):如何为编程爱好者设计一款好玩的智能硬件(七)——LCD1602点阵字符型液晶显示模块驱动封装(上)
八、LCD1602点阵字符型液晶显示模块驱动封装(中):如何为编程爱好者设计一款好玩的智能硬件(八)——LCD1602点阵字符型液晶显示模块驱动封装(中)
九、LCD1602点阵字符型液晶显示模块驱动封装(下)
在上文中我们终于实现了一个简单版的无线滚动屏!本节对其工程进行详细讲解——
工程概述

keil u5 PK51IDE
无线显示屏采用蓝牙串口透传模块和LCD1602液晶显示模块
单片机采用STC89C51单片机
实现上位机通过串口助手发送一行msg,其在LCD屏上显示出来
要求msg长度小于32
更多详情请见前两节内容
1、LCD1602封装——LCD1602.C内部封装(一般不要改动)用的时候只需要根据平台重新修改.h内的宏定义即可
下面3个函数是基础通信函数,分别负责忙检测、写命令和写数据。具体细节可以参考——如何为编程爱好者设计一款好玩的智能硬件(七)——LCD1602点阵字符型液晶显示模块驱动封装(上))

//------------------------------------------------
//base communite function
t_uc LCD1602_CheckBusy(void)//check busy
{
t_c temp_data;
LCD1602_DATA_PORT_WRITE(0xFF);
LCD1602_RS_PIN_CLEAR;
LCD1602_RW_PIN_SET;
LCD1602_EN_PIN_CLEAR;
LCD1602_NOP;
LCD1602_EN_PIN_SET;
LCD1602_DATA_PORT_READ(&temp_data);
return (temp_data & 0x80);
} void LCD1602_WriteCom(t_uc com)//write command
{
while(LCD1602_CheckBusy()); //if busy wait
LCD1602_RS_PIN_CLEAR;
LCD1602_RW_PIN_CLEAR;
LCD1602_EN_PIN_SET;
LCD1602_DATA_PORT_WRITE(com);
LCD1602_NOP;
LCD1602_EN_PIN_CLEAR;
} void LCD1602_WriteData(t_uc temp_data)//write data
{
while(LCD1602_CheckBusy()); //if busy wait
LCD1602_RS_PIN_SET;
LCD1602_RW_PIN_CLEAR;
LCD1602_EN_PIN_SET;
LCD1602_DATA_PORT_WRITE(temp_data);
LCD1602_NOP;
LCD1602_EN_PIN_CLEAR;
}
下面的LCD1602初始化函数负责对LCD显示模式进行设置,如设置是否有光标、设置memory指针的方向...关于初始化为什么这样以及这些命令表示什么意思,可以参考——如何为编程爱好者设计一款好玩的智能硬件(七)——LCD1602点阵字符型液晶显示模块驱动封装(上))

//------------------------------------------------
//initialization function
void LCD1602_Init(void)
{
LCD1602_WriteCom(0x38); /*display mode settings*/
LCD1602_DELAY_MS();
LCD1602_WriteCom(0x38);
LCD1602_DELAY_MS();
LCD1602_WriteCom(0x38);
LCD1602_DELAY_MS();
LCD1602_WriteCom(0x38);
LCD1602_WriteCom(0x08); /*display close*/
LCD1602_WriteCom(0x01); /*display clear*/
LCD1602_WriteCom(0x06); /*display cursor movement settings*/
LCD1602_DELAY_MS();
LCD1602_WriteCom(0x0C); /*display and cursor settings*/
}
下面是一些基于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点阵字符型液晶显示模块驱动封装(上))的内存映射和指令说明小节

//------------------------------------------------
//Function
void LCD1602_Clear(void)//clear screen
{
LCD1602_WriteCom(0x01);
LCD1602_DELAY_MS();
} void LCD1602_WriteChar(t_uc x,t_uc y,t_uc temp_data)//(x,y),data,ascill
{
if (y == )//the first line
{
LCD1602_WriteCom(0x80 + x);
}
else//the second line
{
LCD1602_WriteCom(0xC0 + x);
}
LCD1602_WriteData(temp_data);
} void LCD1602_WriteString(t_uc x,t_uc y,t_uc *s)//(x,y),string data
{
if (y == )//the first line
{
LCD1602_WriteCom(0x80 + x);
}
else//the second line
{
LCD1602_WriteCom(0xC0 + x);
}
while (*s)
{
LCD1602_WriteData( *s);
s ++;
}
} void LCD1602_ShowMessage(t_uc from,t_uc *s,t_uc delay_ms)//from(0~31),msg,each char delay time
{
t_uc i;
t_uc to=from+strlen((t_c*)s)-;
if(from< || from> || to< || to>)return;//shouldn't out the 32 datas
if(to<){//only the first line
LCD1602_WriteCom(0x80 + from);
for(i=from;i<=to;i++){
LCD1602_WriteData(s[i]);
LCD1602_DELAY_MS(delay_ms);
}
}else if(from>){//only the sencond line
LCD1602_WriteCom(0xC0 + from);
for(i=from;i<=to;i++){
LCD1602_WriteData(s[i]);
LCD1602_DELAY_MS(delay_ms);
}
}else{//both lines
LCD1602_WriteCom(0x80 + from);
for(i=from;i<;i++){
LCD1602_WriteData(s[i]);
LCD1602_DELAY_MS(delay_ms);
}
LCD1602_WriteCom(0xC0 + from);
for(i=;i<=to;i++){
LCD1602_WriteData(s[i]);
LCD1602_DELAY_MS(delay_ms);
}
}
}
2、LCD1602封装——LCD1602.h根据平台重新修改.h内的宏定义适应不同硬件平台
下面是根据AT89C52的平台特性对宏进行的修改,由于51单片机引脚操作比较简单,且支持读写,无需切换属性~因此下面部分宏定义的功能可以不定义~但是对于STM32就比较复杂了!正因如此,我STM32的封装也没想到一个比较好的处理方式,在我的工程里有基于STM32宏定义修改,不过存在问题,如果今后要用,一定要修改好!!!
#define MCU_AT89C52 //////////////////////////////////////////////////////////////////////////////////////////
//MCU_AT89C52
//////////////////////////////////////////////////////////////////////////////////////////
#ifdef MCU_AT89C52 #include "FUNC/delay.h"
#include <intrins.h>
#include <string.h> //some typedef need to do
typedef unsigned char t_uc;
typedef unsigned short t_us;
typedef unsigned int t_ui;
typedef char t_c;
typedef short t_s;
typedef int t_i; sbit sLCD1602_RS_PIN = P1^;
sbit sLCD1602_RW_PIN = P1^;
sbit sLCD1602_EN_PIN = P2^; #define LCD1602_DELAY_MS(x) DelayMs((x))
#define LCD1602_NOP _nop_() #define LCD1602_RS_PIN sLCD1602_RS_PIN
#define LCD1602_RS_PIN_SET LCD1602_RS_PIN=1
#define LCD1602_RS_PIN_CLEAR LCD1602_RS_PIN=0
#define LCD1602_RS_PIN_OUT #define LCD1602_RW_PIN sLCD1602_RW_PIN
#define LCD1602_RW_PIN_SET LCD1602_RW_PIN=1
#define LCD1602_RW_PIN_CLEAR LCD1602_RW_PIN=0
#define LCD1602_RW_PIN_OUT #define LCD1602_EN_PIN sLCD1602_EN_PIN
#define LCD1602_EN_PIN_SET LCD1602_EN_PIN=1
#define LCD1602_EN_PIN_CLEAR LCD1602_EN_PIN=0
#define LCD1602_EN_PIN_OUT #define LCD1602_DATA_PORT_GPIO P0
#define LCD1602_DATA_PORT_IN
#define LCD1602_DATA_PORT_OUT
#define LCD1602_DATA_PORT_READ(x) (*(x))=LCD1602_DATA_PORT_GPIO
#define LCD1602_DATA_PORT_WRITE(x) LCD1602_DATA_PORT_GPIO=(x) void LCD1602_WriteCom(t_uc com);//write command
void LCD1602_WriteData(t_uc temp_data);//write data
void LCD1602_Init(void);//initialization function
void LCD1602_Clear(void);//clear screen
void LCD1602_WriteChar(t_uc x,t_uc y,t_uc temp_data);//(x,y),data,ascill
void LCD1602_WriteString(t_uc x,t_uc y,t_uc *s);//(x,y),string data
void LCD1602_ShowMessage(t_uc from,t_uc *s,t_uc delay_ms);//from(0~31),msg,each char delay time #endif
3、工程整体逻辑简单梳理
main函数中不断检测串口是否发来有效数据(暂且把一行当为有效数据),一旦有效数据到来就调用ShowMessage显示出来~
/*------------------------------------------------
主函数
------------------------------------------------*/
void main (void)
{
InitUART();
LCD1602_Init();
LCD1602_Clear();//ÇåÆÁ
while ()
{
//LCD1602_ShowMessage(0,"hello world! I'm beautifulzzzz.",1000);
if(flag==)
{
flag=;
SendStr(getByte);
LCD1602_Clear();
LCD1602_ShowMessage(,getByte,);
}
// LCD1602_WriteChar(7, 0, 'o');
// LCD1602_WriteChar(8, 0, 'k');
// LCD1602_WriteString(3, 1, "Hard Work");
//while(1);
}
}
串口中断是每收到一行置flag标志位为1,一旦point超过getByte大小就从0开始填充~
/*------------------------------------------------
串口中断程序
------------------------------------------------*/
void UART_SER (void) interrupt //串行中断服务程序
{
if(RI){ //判断是接收中断产生
RI=; //标志位清零
getByte[point]=SBUF; //读入缓冲区的值
if((point>) && (getByte[point-]==0x0d) && (getByte[point]==0x0a)){
getByte[point-]=0x00;
flag=;
point=;
}else{
point++;
if(point==){
point=;
}
}
}
}
小结&接下来计划:
终于,我们把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点阵字符型液晶显示模块驱动封装(下)的更多相关文章
- 如何为编程爱好者设计一款好玩的智能硬件(八)——LCD1602点阵字符型液晶显示模块驱动封装(中)
六.温湿度传感器DHT11驱动封装(下):如何为编程爱好者设计一款好玩的智能硬件(六)——初尝试·把温湿度给收集了(下)! 七.点阵字符型液晶显示模块LCD1602驱动封装(上):如何为编程爱好者设计 ...
- 如何为编程爱好者设计一款好玩的智能硬件(七)——LCD1602点阵字符型液晶显示模块驱动封装(上)
当前进展: 一.我的构想:如何为编程爱好者设计一款好玩的智能硬件(一)——即插即用.积木化.功能重组的智能硬件模块构想 二.别人家的孩子:如何为编程爱好者设计一款好玩的智能硬件(二)——别人是如何设计 ...
- 如何为编程爱好者设计一款好玩的智能硬件(十)——无线2.4G通信模块研究·一篇说完
六.温湿度传感器DHT11驱动封装(下):如何为编程爱好者设计一款好玩的智能硬件(六)——初尝试·把温湿度给收集了(下)! 七.点阵字符型液晶显示模块LCD1602驱动封装(上):如何为编程爱好者设计 ...
- 如何为编程爱好者设计一款好玩的智能硬件(三)——该选什么样的MCU呢?
一.我的构想:如何为编程爱好者设计一款好玩的智能硬件(一)——即插即用.积木化.功能重组的智能硬件模块构想 二.别人家的孩子:如何为编程爱好者设计一款好玩的智能硬件(二)——别人是如何设计硬件积木的! ...
- 程序员编程利器:20款最好的免费的IDEs和编辑器
程序员编程利器:20款最好的免费的IDEs和编辑器 还没转眼明年可就大年三十了,忙的可真是晕头转了个向,看着亲朋好友们那让人欣羡的小肚腩,不禁感慨,岁月是一把猪饲料,绿了芭蕉,肥了那杨柳小蛮腰,可怜我 ...
- IOS开发入门教程-总结篇-写给狂热的编程爱好者们
程序发轻狂,代码阑珊,苹果开发安卓狂!--写给狂热的编程爱好者们 写在前面的话 学习iOS应用程序开发已有一段时间,最近稍微闲下来了,正好也想记录一下前阶段的整个学习过程.索性就从最基础的开始,一步一 ...
- Java Socket 网络编程心跳设计概念
Java Socket 网络编程心跳设计概念 1.一般是用来判断对方(设备,进程或其它网元)是否正常动行,一 般采用定时发送简单的通讯包,如果在指定时间段内未收到对方响应,则判断对方已经当掉.用于 ...
- 五款好玩又好用的Linux网络测试和监控工具
五款好玩又好用的Linux网络测试和监控工具 [51CTO精选译文]在这篇介绍几款Linux网络测试实用工具的文章中,我们使用Bandwidthd.Speedometer.Nethogs.Darkst ...
- 如何设计一款优秀的短视频 SDK
2017 年,短视频成为了创业的新风口,各种短视频 App 如雨后春笋般先后上线,视频越来越像文字.图片一样,成为每一个 App 不可或缺的一部分. 1. 包体一定要尽可能小 如何做到尽可能的减小 S ...
随机推荐
- 浅谈SDN和NFV之间的关系
一个行业固定设备的折旧周期很长,任何变革的发生都绝非易事,但是网络却一次性面临两项革新--软件定义网络(SDN)和网络功能虚拟化(NFV),在变革网络的过程中,二者若想取得成功可能会依赖彼此的技术,或 ...
- Oracle表空间数据文件移动的方法
最近遇到这样的一个问题,Oracle存放表空间文件的盘符 空间不够了,必须把部分表空间迁移出去, [转]http://www.jb51.net/article/77026.htm 实现把用户表空间中的 ...
- IE9下WebUploader上传图片跨域问题
作为前端,这一次踩到后台xml配置的坑. IE9下上传图片通过flash插件,一直发送http://192.168.0.8:8888/crossdomain.xml请求,状态码为404,原因是上传图片 ...
- ADO.net操作数据库
今天整理硬盘,发现2年前开始着手开始学习C#的学习日记.陆续整理,一是自己的知识梳理梳理,二是希望与大家多多交流,能给初学者带来一定帮助,当然是更高兴的啦. 断线对象 另一类是与数据源无关的断线对象, ...
- 攻破JAVA NIO技术壁垒
转载自攻破JAVA NIO技术壁垒 概述 NIO主要有三大核心部分:Channel(通道),Buffer(缓冲区), Selector.传统IO基于字节流和字符流进行操作,而NIO基于Channel和 ...
- 第一个jemter测试脚本
通过jmeter代理录制脚本后,会产生大量的无用的请求,尽管在代理中已经过滤了一部分图片或者CSS.JS文件. 手动查看主要的请求:这里主要关注登陆请求,要确定有效的URL请求 删除除/Login.a ...
- 关于L'Hopital法则
1.首先需要使用 罗尔定理 函数f(x)在闭区间[a,b]连续在开区间(a,b)可微,如果f(a)=f(b),那么至少存在一点c使函数导数f'(c)=0 注意需要再(a,b)可微,如果函数有角点,断点 ...
- 【Visual Lisp】块专题
;;关于块 ;;(0)模型空间→块表记录→块图元:顶层的是模型空间→模型空间下有很多图元和一些块表记录→块表记录又有很多图元(此时块表记录就相当于模型空间),一个块表记录可以有多个insert块→同一 ...
- android ProgressBar 进度条的进度两端是圆角的方法
转自 http://www.jianshu.com/p/6e7ea842d5ce 另外工作原理可以参考http://blog.csdn.net/lan603168/article/details/44 ...
- erlang日志功能。
用cowboy这个库,没有日志功能,所以研究了otp提供的日志功能. 1.启动SASL的方式 erl –boot start_sasl 默认配置文件下启动SASL, {env, [{sasl_erro ...