字符型液晶显示器用于显示数字、字母、图形符号。这类显示器均把LCD控制器、点阵驱动器、字符存储器等做在一块板上,再与液晶屏一起组成一个显示模块,因此,这类显示器的安装与使用都较简单。
图1是一块仿真实验板上字符型液晶的接口电路。要求编写程序从该板的第二行第1列开始显示“Hello World!”。由于市面上常见的字符型液晶驱动器均由HD44780或其兼容芯片构成,因此,这类液晶屏的驱动程序具有一定的通用性,这里给出用C语言写的驱动程序。在设置字符的起始行、列后,直接调用驱动程序提供的WriteString函数即可将字符串显示在指定的位置,使用非常简单。在熟悉了程序后,略作改动,便可用于2002、2004等型号的液晶屏。

#include “reg51.h”
#include<absacc.h>
#include <intrins.h>
#define DPORT P0
#define uchar unsigned char
sbit RS = P2^5;
sbit RW = P2^6;
sbit E = P2^7;
uchar Xpos; //列方向地址指针
uchar Ypos; //行方向地址指针
#define NoDisp 0关显示
#define NoCur 1无光标
#define CurNoFlash 2有光标但不闪烁
#define CurFlash 3有光标且闪烁
void LcdWcn(uchar);
void LcdWc(uchar);
void WriteChar(uchar);
void LcdPos();
void LcdWd(uchar);
void LcdWdn(uchar);
*延时程序由Delay参数确定延迟时间*/
void mDelay(unsigned int Delay)
{ ...}
*光标设置命令Cur 为参数 */
void SetCur(uchar Cur)
{ ...}
*清屏命令 */
void ClrLcd()
{ LcdWc(0x01);}
*在指定的行与列显示 */
void WriteChar(uchar c)
{ LcdPos();
LcdWd(c);}
*正常读写操作之前检测LCD控制器*/
void WaitIdle()
{ ...... }
*不检测忙的写字符子程序*/
void LcdWdn(uchar c)
{ ...... }
*带忙检测的写字符子程序*/
void LcdWd(uchar c)
{ WaitIdle();
LcdWdn(c);}
*不检测忙信号的送控制字子程序*/
void LcdWcn(uchar c)
{ ......}
*检测忙信号的送控制字子程序*/
void LcdWc(uchar c)
{ WaitIdle();
LcdWcn(c);}
void LcdPos() //定位
{ uchar tmp;
Xpos&=0x0f;
Ypos&=0x01;
tmp=Xpos;
if(Ypos==1)
tmp+=0x40;
tmp|=0x80;
LcdWc(tmp);}
void RstLcd() /*LCD的复位程序*/
{ ......}
void WriteString(char s[])
{ ......}
void main()
{ uchar s1[]=“Hello World!”;
RstLcd(); //复位LCD
ClrLcd();
SetCur(CurFlash); //光标显示且闪烁
Xpos=2;
Ypos=1;
WriteString(s1);
for(;;){;}}
限于篇幅,这里的程序没有完整给出,在本期配刊光盘的“本期程序”文件夹中有完整的程序。
程序分析:
本程序中大量使用了函数,在此对函数的功能作一个简介。
C语言程序是由一个个函数构成的,从函数定义的形式上划分,函数有三种形式: 无参数函数、有参数函数和空函数。
无参数函数的定义形式为:
返回值类型识别符 函数名(){函数体语句}
如本例中的void WaitIdle(){ ...... }就是一个无参数函数。
有参数函数的定义形式为:
返回值类型识别符 函数名(形式参数列表){函数体语句}
如本例中的void LcdWdn(uchar c){ ...... }就是一个有参数的函数。
函数可以返回一个值,也可以什么值也不返回,如果函数要返回一个值,在定义这个函数时要定义好这个值的数据类型,这里所说的数据类型就是指前面课程中介绍到的int、char、float等类型。如果在定义函数时没有定义返回值的类型,系统默认为返回一个int型的值。如果明确地知道一个函数将没有返回值,可以将其定义为void型,这样,如果在调用函数时错误地使用了“变量名=函数名”的方式来调用函数,编译器就能发现这一错误并指出。本例中就大量地应用到了void型函数。
C语言采用函数之间的参数传递方式,这使得一个函数能对不同的变量进行功能相同的处理,使函数具有了通用性。定义函数时,写在函数名括号中的称之为形式参数,而在实际调用函数时写在函数括号中的称之为实际参数。本例中:
void SetCur(uchar Cur)
{ ...}
函数中Cur就是一个形式参数,而在主函数中调用时写的:
SetCur(CurFlash);
其中CurFlash就是一个用符号常量表示的实际参数,在执行该函数时该值被传递到函数内部并执行。
每一个程序所调用的函数必须已被定义,否则就会出现语法错误,因此程序中一般要求在程序的开头对程序中用到的函数进行统一的说明,然后再分别定义有关函数,本例中有:
void WriteChar(uchar);
void LcdWdn(uchar);
就是首先在程序的前方写一个有关函数的说明,而真正的函数定义则放在程序后部。但细心的读者可能发现有一些函数并未写其说明,而是直接在程序中定义了,如mDelay函数,这是为何呢?这是因为这些函数出现在程序的前面,在还没有任何函数调用它们之前它们就被定义了,因此就不需要再单独写一个函数说明。读者如果将mDelay函数的定义移到程序的后面位置,再次编译就会出错。当然,好的编程习惯是不论函数在何处被定义,总是在前面写一个函数说明。
通过有关内容的学习,我们已经可以使用C语言进行一些实际的工程开发工作,大家可以在工作中继续学习有关C语言的知识。
(文/周坚)