自己动手做个智能小车(6)
——给小车装个脸(显示屏)
现在轮子可以由程序控制了,但总感觉少点啥,程序在跑,但不知道里面的情况,就象一台电脑没有显示器一样。所以我们也来组小车安装个小显示器。
选什么屏呢,对于小的屏幕,就当然是比较流程的1602LCD了:
1602字符型LCD专门用于显示数字、字母、图形符号和少量的自定义符号。这类显示器的LCD控制器、点阵驱动器、字符存储器等做在一块板上,再与液晶屏一起组成一个显示模块,这类显示器的安装和使用非常简单。
目前字符型LCD常用的有16字行、16字X2行、20字X2行、20字X4行等液晶模块,型号通常用XXX1602、XXX1604、X2002、XXX2004等其中为厂家商标名称16代表液晶每行可以显示16个字符,02代表共有2行,也就是说这个液晶一共可以显示32字符。
如何连接呢,比较容易,连接图如下:
图中,
第1脚:vss为地电源,
第2脚:VDD接5V正电源"
第3脚:VL为液晶显示器对比度调整端,接正电源时对比度最弱,接地时对比度最高,对比度过高时会产生"鬼影",使用时可以通过一个10K的电位器调整对此度,
第4脚:RS为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器"
第5脚;R/W,为读写信号线,高电平时进行读操作,低电平时进行写操作。当RS和R/V共同为低电平时可以写入指令或者显示地址,当RS为低电平R/w为高电平时可以读忙信号,当RS为高电平R/w为低电平时可以写入数据,
第6脚:E端为使能端,当E端由高电平跳变成低电平时,液晶模块执行命令。
第7~14脚:DO—D7为8位双向数据线,实际过程中,为了减少接口的使用(多留些给以后扩展用),所以我们采用4根线的(即用D0~D3),就是一个8位数据通过4根线传输2次。
第15脚:背光源正极,
第16脚:背光源负极。
小车中连接后的效果如下:
好了,连接好了硬件后,就开始软件了,为了方便管理,代码增加一个LCD.c类:
同时,为了方便调用,对外,我们提供两个函数:
LcdInitiate() 用于对液晶片初步化;
Print(字符串) 用于将字符串显示在屏上,跟C语言习惯相似。
好了,上代码:
/*******************************************************************
* LCD.c 描述:
* LCD1602可以分为8位和4位控制方式,8位控制方式是用D0-D7数据线
* 来传送控制命令及数据。4位控制方式是用D4-D7数据线来传送控制命令
* 及数据。使用4位数据线做控制时,需要分两次来传送,先送出高4位数
* 据,再送出低4位数据。可以节省单片机的4根端口线。
*
*******************************************************************/
#include "common.h"
sfr LCD_Data = 0x80; //P0 显示接入P0口的高4位 P4 P5 P6 P7
sbit LCD_RS=P0^3; //寄存器选择位,将RS位定义为P2.0引脚
sbit LCD_BF=P0^7; //忙碌标志位,,将BF位定义为P0.7引脚
sbit LCD_RW=P2^6; //读写选择位,将RW位定义为P2.1引脚
sbit LCD_EN=P2^7; //使能信号位,将E位定义为P2.2引脚
/*********************************************************
* 5us 延时子程序
*********************************************************/
void delayNOP()
{
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
}
/*********************************************************
* 检查LCD忙状态
* lcd_busy为1时,忙,等待。
* lcd-busy为0时,闲,可写指令与数据
*********************************************************/
bit lcd_busy()
{
bit result;
LCD_RS = 0;
LCD_RW = 1;
LCD_EN = 1;
delayNOP();
result = LCD_BF;
LCD_EN = 0;
return(result);
}
/*********************************************************
* 写指令或数据
* start=0, 写入命令; start=1, 写入数据
*********************************************************/
void lcd_write(bit start, uchar in_data)
{
uchar Hdata,Ldata;
while(lcd_busy());
Hdata=in_data&0xf0; //取高四位
Ldata=(in_data<<4)&0xf0; //取低四位
if(start==0)
LCD_RS = 0; //写入命令
else
LCD_RS = 1; //写入数据
LCD_RW = 0;
LCD_EN = 0;
delayNOP();
//发送高四位
LCD_Data = LCD_Data & 0x0F;
LCD_Data = Hdata | LCD_Data;
LCD_EN = 1;
delayNOP();
LCD_EN = 0;
delayNOP();
//发送低四位
LCD_Data = LCD_Data & 0x0F;
LCD_Data = Ldata | LCD_Data;
LCD_EN = 1;
delayNOP();
LCD_EN = 0;
delayNOP();
}
/*************************************************************
* LCD初始化设定
*************************************************************/
void LcdInitiate()
{
Delay(15);
lcd_write(0,0x28); //16*2显示,5*7点阵,4位数据
Delay(5);
lcd_write(0,0x28);
Delay(5);
lcd_write(0,0x28);
Delay(5);
lcd_write(0,0x0c); //显示开,关光标
Delay(5);
lcd_write(0,0x06); //移动光标
Delay(5);
lcd_write(0,0x01); //清除LCD的显示内容
Delay(25); //延时
}
/**********************************************************
* 设定显示位置
**********************************************************/
void lcd_pos(uchar pos)
{
lcd_write(0,pos|0x80); //数据指针=80+地址变量
}
/**********************************************************
* 显示字符串
* 示例: print("Hello World!") print("aaa\rbbb")
**********************************************************/
void print(unsigned char *str)
{
unsigned char i;
lcd_write(0,0x01); //清除LCD的显示内容
Delay(10);
lcd_pos(0); // 设置显示位置为第一行的第1个字
i = 0;
while(*str != '\0') //'\0'是数组结束标志
{
//超过一行时,另起一行
if (i == 16 || str[i] == '\r')
lcd_pos(0x40); //设置显示位置为第二行
if (*str == '\r')
{
i++;
str++;
continue;
}
lcd_write(1,*str);
i++;
str++;
}
}
有了这个显示函数(print),我们就很方便在主函数中调一下,比如print("Hello")之类的进行测试。 同时也可以将给小车的PWM值显示出来。