• 沒有找到結果。

LCD 应用编程及与机器人的集成技术

LCD(Liquid Crystal Display)的应用很广泛,简单如手表上的液晶显示屏,仪表仪器 上的液晶显示器或者笔记本电脑上的液晶显示器,都用 LCD。在一般的办公设备上也很常 见,如传真机,复印件,以及一些娱乐器材玩具等也常常见到LCD 的踪影。本章应用 LCD 作为机器人状态显示窗口,使机器人在运行过程中能够向你显示信息。

LCD 显示器的介绍

本章使用的LCD 为字符型点阵式 LCD 模块(Liquid Crystal Display Module),简称 LCM,

或者是字符型LCD。

字符型液晶显示模块是一种专门用于显示字母、数字、符号等的点阵式液晶显示模块。

每一个显示的字符(或字母、数字等)是由5*7 或 5*11 点阵组成。点阵字符位之间有一空 点距的间隔,起到字符间距和行距的作用。

本章所使用的LCD 显示器可显示两行,每行由 16 个点阵字符组成,能显示所有 ASCII 字符,如图8-1 所示,每个字符由 5*7 点阵组成。

8-1 1602 LCD 实物图

任务一 认识LCD显示器

LCD 显示器连接

LCD1602 有八个数据引脚(D0~D7)与 AT89S52 相连,用于接收指令和数据;AT89S52 通过RS,RW 和 E 这三个端口控制 LCD 模块。表 8-1 为 LCD 的引脚说明,图 8-2 为 LCD 引脚与AT89S52 连接示意图。

8-1 LCD 显示器引脚说明

编 号 符 号 引脚说明 编 号 符 号 引脚说明 1 GND 电源地 9 D2 双向数据口 2 Vcc 电源正极 10 D3 双向数据口 3 V0 对比度调节 11 D4 双向数据口 4 RS 数据/命令选择 12 D5 双向数据口 5 R/W /写选择 13 D6 双向数据口 6 E 模块使能端 14 D7 双向数据口 7 D0 双向数据口 15 BLA 背光源正极 8 D1 双向数据口 16 BLK 背光源地

Vo:直接接地,对比度最高。

RS:MCU 写入数据或者指令选择端。MCU 要写入指令时,使 RS 为低电平;MCU 要 写入数据时,使RS 为高电平。

R/W:读写控制端。R/W 为高电平时,读取数据;R/W 为低电平时,写入数据。

E:LCD 模块使能信号控制端。写数据时,需要下降沿触发模块。

D0~D7:8 位数据总线,三态双向。该模块也可以只使用 4 位数据线 D4-D7 接口传送 数据。

BLA:需要背光时,BLA 串接一个限流电阻接 VCC,BLK 接地。

BLK:背光地端。

8-2 LCD 模块于 MCU 连接图

说明

实际上,是LCD模块与教学板相连,相关电路图见附件。

LCD 控制器接口说明 基本操作时序

在LCD 时序图中,在将 E 置高电平前,先设置好 RS 和 R/W 信号,在 E 下降沿到来之 前,准备好写入的命令字或数据。只需在适当的地方加上延时,就可以满足要求了。

读状态 输入:RS=L,RW=H,E=H 输出:DB0~DB7=状态字

写指令 输入:RS=L,RW=L,E=下降沿脉冲,DB0~DB7=指令码 输出:无

读数据 输入:RS=H,RW=H,E=H 输出:DB0~DB7=数据

写数据 输入:RS=H,RW=L,E=下降沿脉冲,DB0~DB7=数据 输出:无

状态字说明

STA7 STA6 STA5 STA4 STA3 STA2 STA1 STA0

D7 D6 D5 D4 D3 D2 D1 D0

8-3 LCD 内部 RAM 地址映射图

数据地址设置指令码:80H+地址码(0~27H,40~67)。

任务二 编写LCD模块驱动程序

在本任务中,你将通过编写程序来驱动LCD 显示器,并显示你的机器人所要显示的字 符或字符串,这样你就可以不需要调试终端的帮助而显示字符或者字符串。

元件清单:

(1)1602LCD 显示器

(2)跳线 线路连接

传统的连线是图8-2 介绍的八位数据线接法,而教材采用的是四位数据线传输方式来进 行LCD 显示。为什么只用四线传输?因为这样可以节省接口开销。

由于LCD 的指令和数据都是八位的,因此在传输时要传输两次才能完成一次操作。电 路的连接如图8-4 所示。

8-4 四口数据线连接 LCD 例程:LCDdisplay.c

z 接通主板电源

z 输入、保存并运行 LCDdisplay.c

z 连接 LCD 显示器模块,验证显示器是否显示字符串

#include <at89x52.h>

#include <BoeBot.h>

#define LCM_RW P2_1 //定义引脚

void Write_Data_LCM(unsigned char WDLCM);

void Write_Command_LCM(unsigned char WCLCM,BuysC);

void Read_Status_LCM(void);

void LCM_Init(void);

void Set_xy_LCM(unsigned char x, unsigned char y);

void Display_List_Char(unsigned char x, unsigned char y, unsigned char *s);

void main(void) {

void Read_Status_LCM(void) {

unsigned char read=0;

LCM_RW = 1;

while(read & Busy);

LCM_E = 0;

void Write_Data_LCM(unsigned char WDLCM) {

void Write_Command_LCM(unsigned char WCLCM,BuysC) //BuysC0时忽略忙检测 {

if (BuysC)

Read_Status_LCM(); //根据需要检测忙

LCM_RS = 0;

void LCM_Init(void) //LCM初始化 {

void Set_xy_LCM(unsigned char x, unsigned char y) {

unsigned char address;

if( x == 0 )

address = 0x80+y;

else

address = 0xc0+y;

Write_Command_LCM(address,1);

}

/*--- 函数名:Display_List_Char()

能:按指定位置显示一串字符 ---*/

void Display_List_Char(unsigned char x, unsigned char y, unsigned char *s) {

LCDdiaplay.c 是如何工作的?

整个工作分为两步:先对LCD 进行初始化,然后再显示。

研究初始化函数 void LCM_Init(void),你会发现,该函数完全是按照任务一 LCD 的初 始化要求来的。

初始化工作完成之后,主函数调用 Display_List_Char(unsigned char x, unsigned char y, unsigned char *s)来显示字符串。

在显示字符串之前,需用 Set_xy_LCM()确定光标的位置,根据数据地址设置指令要

对于一个内存单元来说,单元的地址即为指针,其中存放的数据才是该单元的内容。在C语

char string[]=”I love Robot!”;

printf("%s\n",string);

}

2.用字符串指针指向一个字符串。如:

main( ) {

char *string=”I love Robot!”;

printf("%s\n",string);

}

这里,string 是一个指向字符串的指针变量。程序并没有把整个字符串存入 string,而 是把字符串的首地址赋予 string。

函数Display_List_Char(0, 0, "www.depush.com");先给字符串定位(0,0);之后将字符 串"www.depush.com"首地址附给指针 s,并显示,随后加 1 ,指向下一个字符,直到显示全 部字符。

该你了

还记得第三章例程 NavigationWithSwitch.c 吗?当时,用数组 char Navigation[10] = {'F','L','F','F','R','B','L','B','B','Q'}来保存机器人的运行状态,指针同样可以完成该功能,动手

提供的标准库函数,也可以是你已经开发好的某些程序)进行预处理,然后再将预处理的结

这个指令教材在最开始就用了,如 #include <uart.h>。

所谓文件包含就是指一个源文件可以将另一个源文件的全部内容包含进来。但要注意的

void Read_Status_LCM(void) {

}

void Write_Data_LCM(unsigned char WDLCM) {

void Write_Command_LCM(unsigned char WCLCM,BuysC) //BuysC0时忽略忙检测 {

void LCM_Init(void) //LCM初始化

void Set_xy_LCM(unsigned char x, unsigned char y) {

Write_Command_LCM(address,1);

}

void Display_List_Char(unsigned char x, unsigned char y, unsigned char *s) {

下面的例程以第三章的例程NavigationWithSwitch.c 为模版,添加 LCD 显示部分。删除 串口显示部分。

例程:MoveWithLCDDisplay.c

#include <at89x52.h>

#include <BoeBot.h>

#include <LCD.h>

void Forward(void)

{

void Left_Turn(void) {

void Right_Turn(void) {

void Backward(void) {

int i;

for(i=1;i<=65;i++)

int main(void) {

char Navigation[10]={'F','L','F','F','R','B','L','B','B','Q'};

int address=0;

LCM_Init();

while(Navigation[address]!='Q') {

switch(Navigation[address]) {

case 'F':Forward();

Display_List_Char(0,0,"case:F");

Display_List_Char(1,0,"Forward ");

delay_nms(500);

break;

case 'L':Left_Turn();

Display_List_Char(0,0,"case:L");

Display_List_Char(1,0,"Turn Left ");

delay_nms(500);

break;

case 'R':Right_Turn();

Display_List_Char(0,0,"case:R");

Display_List_Char(1,0,"Turn Right");

delay_nms(500);

break;

case 'B':Backward();

Display_List_Char(0,0,"case:B");

Display_List_Char(1,0,"Backward ");

while(1);

}

MoveWithLCDDisplay.c 是如何工作的?

在理解第三章例程NavigationWithSwitch.c 的基础上,该例程不难理解:switch 处理每 个case 之后,调用 Display_List_Char( )函数在 LCD 的二行上显示了相关信息,之后做了 0.5s 的延时,为什么?因为如果不加延时,LCD 显示时间过短,实验效果不明显。

程序执行过程中的LCD 的部分显示可见图 8-5 和图 8-6。

8-5 前进时 LCD 显示

8-6 右拐时 LCD 显示 该你了

z 将主函数 main 之前的四个行走子函数做成头文件的形式加入程序,优化程序 z 思考为什么不将 LCD 初始化函数 LCM_Init()放在 while 循环体外

z 仔细研究 LCD 模块电路图(附录 D),你会发现电路中有四个按钮,它们分别与数据 端D4~D7 相连,可以起到触发输出的作用,如何完成这个功能呢?动手做一下!

z 思考为什么有的显示字符后面加了空格,比如:“Forward ”,没有写成“Forward”?

提示:该LCD 没有清行命令。

工程素质和技能归纳

1. LCD 作为终端显示与单片机编程实现 2. 指针的使用

3. C 语言编译预处理功能 4. 头文件的制作

科学精神的培养

1. 在介绍 LCD 数据总线时,说它是“三态双向”,第三态是什么?

2. 指针作为 C 语言重要的一种数据类型,还有许多用法,请查找相关资料,对指针用 法进行归纳总结。