十四.128X64 液晶显示器的基本应用
[实验任务]
利用128X64点阵液晶显示屏显示图片,字符,汉字,画点,实现其基本显示
功能。
[硬件电路图]
[实验原理]
关于液晶显示的原理请用户自行其查找资料,这里只介绍 128X64 点阵液晶
显示屏的具体应用。驱动程序为用户提供了一个应用框架,大家只要直接应用驱
动程序提供的功能将可以了。在编程序前要先用液晶字模提取软件提取字模复制到 hzzi.h 文档,再在主程序里面编写程序。我们使用的液晶没有自带字库,必须提取字模到程序里。5V稳压电源,所以没有点亮液晶的背光。
[C语言源程序]
//注意:以下提供程序并没有包含128X64 液晶显示驱动程序,只有主程序。
#include<reg52.h>
#include<lcd12864.h> //包含128X64 驱动程序
#include<hzzi.H> //包含图片和汉字库
void delay(int x) //延时程序
{
int i,j;
for(i=0;i<600;i++)
for(j=0;j<x;j++);
}
void main(void)
{
unsigned char lie; //定义列
unsigned char hang; //定义行
lcd_init(); //初始化液晶驱动硬件
lcd_clr(); //清屏
while(1)
{
lie=15;//列的值可以是0--127 任意一个
hang=0;//行的值视情况而定
lcd_clr();
Disp_Img(yema);//显示一张128X64 的点阵的图片
delay(200); //延时等待
lcd_clr(); //清屏使残留的点不影响后面的显示
hz_disp(lie+0, hang, da);//在第15 列,第0 行显示汉字'大'
hz_disp(lie+16,hang, jia);//显示汉字'家'
hz_disp(lie+32,hang, yi);//显示汉字'一'
hz_disp(lie+48,hang, qi);//显示汉字'起'
hz_disp(lie+64,hang, lai);//显示汉字'来'
hz_disp(lie+80,hang, xue);//显示汉字'学'
hang=2;//换行 一行有8 个点阵 一列只有一个
hz_disp(lie+24,hang, dan );//显示汉字'单'
hz_disp(lie+40,hang, pian);//显示汉字'片'
hz_disp(lie+56,hang, ji);//显示汉字'机'
hang=4;//换行
hz_disp(lie+0, hang, huan);
hz_disp(lie+16,hang, ying);
hz_disp(lie+32,hang, jia1);
hz_disp(lie+48,hang, ru);
hz_disp(lie+64,hang, qq);
hz_disp(lie+80,hang, qun);
lie=32; hang=7;//换行.换列.
delay(50);
lcd_putchar8x8(lie+0, hang, 1+'0');//显示8X8 字符
delay(50);//延时 达到一个字一个字往外蹦的效果
lcd_putchar8x8(lie+8, hang, 9+'0');delay(50);
lcd_putchar8x8(lie+16,hang, 3+'0');delay(50);
lcd_putchar8x8(lie+24,hang, 0+'0');delay(50);
lcd_putchar8x8(lie+32,hang, 5+'0');delay(50);
lcd_putchar8x8(lie+40,hang, 2+'0');delay(50);
lcd_putchar8x8(lie+48,hang, 5+'0');delay(50);
lcd_putchar8x8(lie+56,hang, 5+'0');
delay(200);//延时显示
lcd_clr();
hang=0;
for(lie=0;lie<128;lie++)
{//画点时 行取值0--64,列取值0--128
set_point(lie,hang);hang++;
if(hang==32){hang=0;}
delay(5);
}
delay(200);
hz_disp128x32(0,0,qian33);//显示128X32 的图片
hz_disp128x32(0,4,dpy);
delay(300);
}
}
除了以上的例子外,还可以显示12X12.32X32.120X2.点阵图形///
///用法和上面的例子差不多,大家实践几次就可以熟练应用了/
---------------------------------------------------------------------------------------------------------------------------------
十五.标准键盘 PS/2与单片机通信
[实验任务]
标准键盘 PS2 向单片机输入数字.字母.字符等,用 128X64 液晶显示器显示
出来。
[硬件电路图]
[实验原理]
键盘通过时钟线和数据线和单片机通信,键盘和系统的相互通信都是采用
11 位格式的串行方式。第 1 位是起始位 0;第 2 到 9 位是 8 位数据位,第 10 位
是奇偶校验位。第11位停止位。时序图如下
[C语言源程序]
//注意 与第十三个实验128X64液晶显示器的基本应用一样,以下提供程序并没
//有包含128X64 液晶显示驱动程序,只有主程序和PS2 键盘通信的驱动程序。
//请大家到QQ 群:19305255,资源共享里面去下
//以下程序只有单片机接收PS2 键盘程序,没有单片机向PS2 发送命令程序。
//还有键盘数据处理上不是很完善,主要是为用户提供一个参考程序。
//如果把此实验看作是一个系统的话,那么这一个系统就是一个漏洞百出,充满
//Bug 系统。大家在用的时侯可以对它多作改进。
#include<reg52.h>
#include<lcd12864.h>//包含128X64 驱动程序
#include<hzzi.H> //包含图片和汉字库
sbit Key_Data =P2^0;//定义Keyboard 数据端口引脚
sbit Key_CLK=P3^3; //中断端口,时钟线
static unsigned char KeyV=0X00; //键值
static unsigned char BF = 0; //标识是否有字符被收到
static unsigned char IntNum = 0; //中断次数计数
unsigned char lie,hang;//lie 为列值, hang 为行值
bit dx=0; //大小写标志 dx==1 时大写状态
void Keyboard_out(void) interrupt 2//键盘中断处理 键值存储在 KeyV 中
{
if ((IntNum>0) && (IntNum <9))
{
KeyV = KeyV >> 1; //因键盘数据是低>>高,结合上一句所以右移一位
if (Key_Data==1) //当键盘数据线为1 时
{KeyV = KeyV | 0x80;} //存储一位
}
IntNum++; //中断次数加一(中断一次接收一位数据)
if (IntNum > 10) //中断11 次后数据发送完毕
{
IntNum=0; //当中断11 次后表示一帧数据收完,清变量准备下一次接收
BF = 1; //标识有字符输入完了
EA = 0; //关中断等显示完后再开中
}
}
void Decode() //键值处理
{
unsigned char data TempCyc;
signed char data k;
TempCyc=KeyV;
if(BF==1) //接收完一个有效数据时
{
BF=0; //准备下一次接收
switch ( TempCyc ) //键值与显示字符的对应关系
{ //键值// //对应字符//
case 0x8A: k=0; break; //0 case 0x3C: k=2; break; //2
case 0x2C: k=1; break; //1 case 0x4C: k=3; break; //3
case 0x4A: k=4; break; //4 case 0x88: k=24; break;
case 0x5C: k=5; break; //5 case 0x9A: k=25; break;
case 0x6C: k=6; break; //6 case 0x2A: k=26; break;
case 0x7A: k=7; break; //7 case 0x5A: k=27; break;
case 0x7C: k=8; break; //8 case 0x36: k=28; break;
case 0x8C: k=9; break; //9 case 0x58: k=29; break;
case 0x38: k=10; break; //a case 0x78: k=30; break;
case 0x64: k=11; break; //b case 0x54: k=31; break;
case 0x42: k=12; break; //c case 0x3A: k=32; break;
case 0x46: k=13; break; //d case 0x44: k=33; break;
case 0x48: k=14; break; //e case 0x6A: k=34; break;
case 0x56: k=15; break; //f case 0x34: k=35; break;
case 0x68: k=16; break; //g case 0x98: k=63; break;
case 0x66: k=17; break; //h case 0xAA: k=65; break
case 0x86: k=18; break; //i case 0xF2: k=68; break;
case 0x76: k=19; break; //j case 0x52: k=-16;break; //空
case 0x84: k=20; break; //k case 0xB0: k=101;brea
case 0x96: k=21; break; //l 大小写控制键Caps lock
case 0x74: k=22; break; //m }
case 0x62: k=23; break; //n
if(k==101) {dx=!dx;} //按下大小写控制键时 大小写标志取反
if(k==-16) //空格键按下时
{
lcd_putchar8x8(lie, hang, -16+'0'); //清除光标
lcd_putchar8x8(lie+8, hang, 79+'0');//光标移一位
}
if(dx==0) //小写状态时显示
{
lcd_putchar8x8(lie, hang, k+'0');//小写字符
lcd_putchar8x8(lie+8, hang, 79+'0');//光标
}
if(dx==1)//大写状态时显示
{
if(k>9 && k<=35)
{
lcd_putchar8x8(lie, hang, (k+26)+'0');//大写字符
lcd_putchar8x8(lie+8, hang, 79+'0');//光标
}
if(k>=0 && k<=9)
{
lcd_putchar8x8(lie, hang, (k-10)+'0');//数字键对应的符号
lcd_putchar8x8(lie+8, hang, 79+'0');//光标
}
}
if(lie==120) //写满一行
{lie=0;hang=hang+1;//换行
lcd_putchar8x8(lie, hang, 79+'0');}//光标下移
else {lie=lie+8;}
EA=1;
}
}
void delay(int x) //延时程序
{ int i,j;
for(i=0;i<600;i++)
for(j=0;j<x;j++); }
void wlcome() //开机画面和欢迎界面
{
lcd_init(); //初始化液晶驱动硬件 hz_disp(lie+24,hang, shu );//'输'
lcd_clr(); //清屏 hz_disp(lie+40,hang, ru);//'入'
Disp_Img(yema);//显示一张图片 hz_disp(lie+56,hang, xi);//'系'
delay(200); //延时等待 hz_disp(lie+72, hang, tong);//'统'
lie=20; hang=1; delay(200);lcd_clr();
lcd_clr(); lie=8; hang=0;
hz_disp(lie+0, hang, huan);//'欢' hz_disp(lie+16,hang, qing);// '请'
hz_disp(lie+16,hang, ying);//'迎' hz_disp(lie+32,hang, shu);//'输'
hz_disp(lie+32,hang, shi);//'使' hz_disp(lie+48,hang, ru);//'入'
hz_disp(lie+48,hang, yong);//'用' hz_disp(lie+64,hang, zi);//'字'
hz_disp(lie+64,hang, DP);//'DP' hz_disp(lie+80,hang, fu);//'符'
hz_disp(lie+80,hang, Y);//'Y' for(lie=0;lie<128;lie++)//画一条直线
lie=8;hang=4; {set_point(lie,15);}
}
void main()
{
wlcome() ; //调用开机画面和欢迎界面子程序
IT1 = 1; //设外部中断1 为下降沿触发
EA = 1; //开总中断
EX1=1; //开中断 1
hang=2; lie=0;//输入的字符从第 2 行 第0 列开始显示
while(1)
{
Decode();
delay(50);
}
}
-------------------------------------------------------------------------------------------------------------------------------------
十六,128X64无字库液晶4X4键盘输入使用(密码锁)
引脚 | 标号 | 功能说明 | 备注 |
1 | Vss | 逻辑负电源输入引脚,0V | |
2 | Vdd | 逻辑正电源输入引脚,+5V | |
3 | Vo | LCD驱动电源输入引脚,大小可调LCD显示对比度 | 一般接0V |
4 | RS | 数据/指令寄存器选择引脚 RS=“H” :数据D0-D7 与数据寄存器通信 RS=“L” :数据D0-D7 与指令寄存器通信 | |
5 | R/W | 读/写选择引脚 高电平:读数据 低电平:写数据 | 若不须要读操 作功能,该引脚 可直接接地 |
6 | E | 读写使能引脚 高电平有效,下降沿锁定数据 | |
7~14 | D0~D7 | 8 位数据线引脚 | 4 位总线模式 下,D0~D3 引 脚断开 |
15 | A | 背光电源输入引脚,+5V | 不带背光的模 块无此引脚 |
16 | K | 背光电源输入引脚,0V |
#include<reg52.h>
#include<math.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define data_IO P2
sbit rs=P3^0; //指令和数据寄存器 “1是数据,” “0是指令”
sbit rw=P3^1; //读写控制,“1读” “0写”
sbit e=P3^2; //片选信号
sbit p=P2^7;
sbit deng=P0^0 ; ///响音乐的端口
sbit md=P0^1; ///修改密码时的灯
uchar pwflag; //密码是否正确的标志位
uchar count; //
uchar gg=0 ; //只有输入正确的密码才能修改密码
uchar cs=3 ; //输入密码的错误次数
uchar m[]={1,2,3,4,5,6}; ///初始密码
static uchar mbuf[6];///输入的密码
char d[32]={' ','I','M','P','O','R','T',' ','C','I','P','H','E','R',':',' ',
' ',' ','_',' ',' ','_','_','_','_','_','_',' ',' ',' ',' ',' '};//输入密码
code char ks[32]={'C','O','N','G','R','A','T','U','L','A','T','E',' ','Y','O','U',
' ','O','P','E','N','I','N','G',' ',' ','L','O','C','K','!',' '};开锁
code char cw[32]={' ','C','I','P','H','E','R',' ',' ','E','R','R','O','R',' ',' ',
'~','~','~','~','~','~','~','~','~','~','~','~','~','~','~','~' };错误
code char xc[32]={' ',' ','A','M','E','N','D',' ','S','U','C','C','E','E','D',' ',
' ',' ',' ',' ',' ','!','!','!','!','!','!',' ',' ',' ',' ',' '};//修改成功
code char xg[32]={' ','A','M','E','N','D',' ',' ','C','I','P','H','E','R',':',' ',
' ',' ',' ',' ',' ','_','_','_','_','_','_',' ',' ',' ',' ',' '};///修改密码*/
void yanshi(uint n)///延时函数///
{
uint i;
for(i=0;i<n;i++){};
}
void delay(uint n)///延时函数///
{
uint i,j;
for(i=0;i<1000;i++)
{for(j=0;j<n;j++){}}
}
void busy() 判断是否忙
{data_IO=0xff;
rs=0; //写指令
rw=1; //表示读状态 // 三个的状态表示 //
e=1; //下降延// // 判忙状态 //
while(!p);
// e=0;
}
void xiezl(uchar shuju) /*写指令*/
{
busy();/*yanshi(6500);*/
data_IO=shuju;
rs=0; //写指令
rw=0; //表示写状态 // 三个的状态表示 //
e=1; //下降延// // 写指令 //
e=0; /
}
void w_dat(uint n)//写数据//
{
busy(); /*yanshi(6500) ;*/
data_IO=n;
rs=1; //写数据
rw=0; //表示写状态 // 三个的状态表示 //
e=1; //下降延// //写数据 //
e=0; /
// return;
}
void xianshi(uchar js[]) //显示函数///
{
uchar h,v;
xiezl(0x01); //清屏显示
yanshi(2000) ;
xiezl(0x80); // DDRAM地址的设置
for(h=0;h<16;h++)
{w_dat(js[h]); ///n表示有写几位数据
yanshi(100) ;
}
xiezl(0xc0);//换行
for(v=(16);v<32;v++)
{w_dat(js[v]); ///n表示有写几位数据
yanshi(100) ;
}
}
void chushihua(void)///*液晶模块初始化*/
{ uchar i;
rs=0; //写指令
rw=0; //表示写状态
e=0; //使能
for(i=0;i<3;i++)
{
xiezl(0x38); //功能设置,8位,一行显示,5*7点阵
yanshi(1000);
}
xiezl(0x38); //两行显示
xiezl(0x0f); //显示开关控制位
xiezl(0x18); //移位控制,光标和显示一起左移
xiezl(0x06); //设置输入模式
xiezl(0x01); //清屏显示
xiezl(0x80); // DDRAM地址的设置
}
bit pwcmp(void)
{
bit flag;
uchar i;
for (i=0;i<6;i++)
{
if (m[i]==mbuf[i]) flag = 1; //*密码正确*/
else { flag = 0; i=6; } //*密码错误*/
}
return(flag);
}
void gb(void)/转移光标
{ uchar c;
xiezl(0xc0);//换行
yanshi(3000) ;
for(c=0;c<5;c++)
{w_dat(' ');///n表示有写几位数据
yanshi(2000) ;
}
}
uchar getkey(void)///得到键值
{ uchar h,l,k;
while(P1!=0x0f)
{
h=P1&0x0f;
P1=0xf0;
l=P1&0xf0;
k=h|l;
return(k);
}
}
void diaoyong(uchar i)///调用各键的函数//输入密码
{ uchar lq;
switch(i)
{
case 0x7e: if (count<6) { mbuf[count]=1; count++; w_dat('*');} break; // 01111110 1
case 0xbe: if (count<6) { mbuf[count]=2; count++; w_dat('*');}break; // 10111110 2
case 0xde: if (count<6) { mbuf[count]=3; count++; w_dat('*');} break; // 11011110 3
case 0xee: if (count<6) { mbuf[count]=4; count++; w_dat('*');} break; // 11101110 4
case 0x7d: if (count<6) { mbuf[count]=5; count++; w_dat('*');} break; // 01111101 5
case 0xbd: if (count<6) { mbuf[count]=6; count++; w_dat('*');} break; // 10111101 6
case 0xdd: if (count<6) { mbuf[count]=7; count++; w_dat('*');} break; // 11011101 7
case 0xed: if (count<6) { mbuf[count]=8; count++; w_dat('*');} break; // 11101101 8
case 0x7b: if (count<6) { mbuf[count]=9; count++; w_dat('*');} break; // 01111011 9
case 0xbb: if (count<6) { mbuf[count]=0; count++; w_dat('*');}break; // 10111011 0
case 0xdb: if (count==6) { pwflag = pwcmp();} else pwflag = 0;// 只有输入6个密码后按确认键才作密码比较
if(pwflag) {deng=0; xianshi(ks);gg=1; } else { cs--;deng=1; xianshi(cw); delay(200); xianshi(d);gb();count = 0; }
break; // 11011011 a
case 0xeb: count = 0;deng=1; xianshi(d); gb();gg=0; /*取消键*/
break; // 11101011 b
case 0x77: if(gg==1){ count=0;xianshi(xg); gb();} //修该密码
break; // 01110111 c
case 0xb7: if((count==6)&&(gg==1)) { count=0;for (lq=0;lq<6;lq++){ m[lq]=mbuf[lq]; yanshi(10000);} md=0; xianshi(xc); delay(200);md=1; xianshi(d);yanshi(2000);gb();yanshi(200);gg=0;}//保存密码
break; // 10110111 d
/*case 0xd7: sr[jm]='e'; break; // 11010111 e
case 0xe7: sr[jm]='f'; break; // 11100111 f */
default: break;
}
}
void main(void)
{uchar key;
chushihua();
xianshi(d); //显示函数
gb(); //移光标到第二行第六位
while(cs)
{
P1=0x0f;
if(P1!=0x0f)
{
yanshi(20);
key=getkey();
diaoyong(key);
yanshi(20000);
}
}while(1);
}
------------------------------------------------------------------------------------------------------------------------------------------------------------
十七、串口下载线
十八步进电机控制程序:
原理图参考:单片机控制实训书44页
#include<reg52.h>
#define uchar unsigned char
uchar a,b;
int k;
uchar zdzt=0x0c;
uchar zsgw=0x02;
uchar zsdw=0x00;
uchar yxsj=0x11;
uchar zs=20;
uchar zsscgw=0x1f;
uchar zsscdw=0x00;
void key(void);
void delay();
void delays();
code uchar tab[13]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39};
code uchar zssc[2]={0x1f,0x00};
main()
{
while(1)
{key();
if(zdzt==0x0c)
P1=0xff;
else if(zdzt==0x0a)
{P1=yxsj;
deleys();
yxsj=yxsj<<1|yxsj>>7;
}
else if(zdzt==0x0b)
{P1=yxsj;
delays();
yxsj=yxsj<<7|yxsj>>1;
}
}
}
void key(void)
{
if(!(P2&0x01))
{delay();
while(!(P2&0x01))
zdzt=0x0a;
}
else if(!(P2&0x02))
{
delay();
while(!(P2&0x02))
zdzt=0x0b;
}
else if(!(P2&0x04))
{
delay();
while(!(P2&0x04))
zdzt=0x0c;
}
}
void delay()
{
for(k=0;k<1200;k++);
}
void delays()
{
a=zssc[0];
while(a--)
{b=zssc[1];
while(b--);
}
}
#include<reg52.h> /*闪烁灯*/
int k;
void delay()
{
for(k=0;k<2000;k++);
}
main()
{
while(1)
{
P1=0x01;
delay();
P1=0x04;
delay();
P1=0x02;
delay();
}
}
#include<reg52.h>
#define uchar unsigned char
code uchar zz[]={0x08,0x01,0x04,0x02};
code uchar fz[]={0x08,0x02,0x04,0x01};
sbit start=P3^0;
sbit stop=P3^2;
void delay(uchar a)
{
uchar b,c;
for(b=0;b<a;b++)
for(c=0;c<100;c++);
}
void run(uchar a)
{
uchar b,c;
for(b=0;b<6;b++)
for(c=0;c<4;c++);
{if(a==1) P1=zz[c];
else P1=fz[c];
delay(0x10);
}
}
in0()interrupt0 using 1
{P1=0xff;
while(start);
}
void main(void)
{IE=0x81;
while(start);
while(1)
{
uchar a=4;
uchar b=3;
while(a--)
run(1);
while(b--)
run(2);
}
}