基于51单片机的人机接口电路设计一、功能描述键盘和显示是单片机应用系统中实现人机对话的一种基本形式,两种接口设计的好坏,直接影响到人机接口的友好程度。
在对一个系统进行操作时,往往离不开人与机器的对话,人机接口界面可以满足人与机器之间的交流。
可以通过按键将所需要信号与信息输入给系统,经过系统处理后,所期待的效果又可以通过屏幕来显示出来,这样就可以很好的达到人与机器的交流目的。
二、硬件电路图基于51单片机的人机接口电路如图1.1所示。
电路结构包括基本的复位电路、晶振电路、串口程序下载电路、键盘电路及屏幕显示电路。
图1.1 基于51单片机的人机接口电路设计显示电路键盘控制AT89C51图1 人机接口电路结构框图复位电路 晶振电路三、接口定义接口定义说明包括单片机的I/O 口的定义、中断的选择。
在键盘电路中引入了外部中断方式0,减少了CPU 的工作强度。
屏幕接口电路采用的是并行工作方式,51单片的的I/O 口较多,采用并行方式可以增大数据传输的速度,可以将信息实时显示。
具体接口定义如表1.1所示。
表1 A T89C51接口定义I/O 口 定义引脚号 引脚名 接口说明 备注 1~8 P1口 接矩阵键盘 10 RXD 接MAX232 11TXD 接MAX23212 /INT0 接74ls13四输入与非门输出引入中断21 P2.0 接屏幕的RST 22 P2.1 接屏幕的RS 23 P2.2 接屏幕的RW 24 P2.3 接屏幕的E32~38 P0口接屏幕的数据口DB0~DB7 中断类型 中断方式 按键中断中断方式0四、程序流程图1、主程序在主程序中,执行两个任务:1)初始化,键盘初始化,屏幕初始化;2)判断中断是否发生。
程序开始,进行初始化,若有中断发生,则屏幕有相应的显示;若无中断发生,则屏幕不显示或保留原显示,继续等待中断发生。
主程序流程图如图2.1所示。
2、初始化初始化函数主要包括键盘初始化和屏幕初始化。
键盘的初始化:1)设置中断标志位flag 初值为0,表示无中断产生,若有中断产生,则中断标志位flag 变为1;2)给P1口赋初值,若外部有键被按下,则P1口的值发生改变,引发外部中断;3)设置外部中开始 初始化中断发生?Y N屏幕显示 结束图2.1 主程序流程图断0的触发方式为下降沿触发,然后开启外部中断0,最后开启总中断。
屏幕初始化主要是对显示地址的初始化。
程序流程图分别如图2.2,2.3所示。
4、中断进入中断以后,中断标志位置1。
然后将外部中断0关闭,避免同时按下两个键时产生干扰;外部中断响应后开始进行键盘扫描;最后再给P1口重新赋初值,将之前关闭的外部中断打开,等待下一次的中断服务。
程序流程图如图2.4所示。
5、按键扫描按键扫描子函数实现的功能是判断哪一个按键被按下。
扫描开始后,通过行列检测的方式检测是否有按键被按下;确认按键被按下后,读取P1口的值,判断出哪个按键被按下,屏幕显示相应的内容。
程序流程图如图2.5所示。
6、屏幕写指令写指令函数程序流程图如图2.6所示。
该函数的功能是向控制器写入操作指令。
首先判断控制器的状态是的忙,如果忙则继续等待,不忙则进行下一步。
再将读写控制端读取键值 屏幕显示消抖重新检测扫描开始 扫描结束图2.5 按键扫描程序流程按键检测 按键按下? NYY键盘扫描 开外部中断 进入中断 退出中断图2.4 中断程序流程图关外部中断 flag=1 P1口赋初值中断标志位赋初值初始化开始中断配置 结束图2.2 按键初始化程序流程图图2.3 屏幕初始化流程图初始化开始 屏幕复位 写清屏指令 写开显示指令结束写基本指令集R/W 置0,使控制器为写的状态,再将RS 置低,然后向P0口送入指令数据,指令等待接收。
当使能端E 形成一个下降沿时,指令被接收。
控制器完成相应的指令动作 7、屏幕写数据写数据函数程序流程图如图7所示。
该函数的功能是向控制器写入显示数据。
首先判断控制器的状态是的忙,如果忙则继续等待,不忙则进行下一步。
再将读写控制端R/W 置0,使控制器为写的状态,再将RS 置高,然后向P0口送入数据,数据等待接收。
当使能端E 形成一个下降沿时,数据被接收,在屏幕上进行相应的显示。
五、程序1)主函数#include <reg51.h> #include<12864.h> #include<KEY .h> void main() { Lcm_init(); key_init(); while(flag==1) { Lcm_display(); } }图2.6 写指令流程图开始 测忙? RS=0 将指令送入P0口 将使能端置高E=1 将使能端置低E=0结束YN 读状态R/W=0 图2.7 写数据流程图开始 测忙? RS=1 将数据送入P0口 将使能端置高E=1 将使能端置低E=0结束YN读状态R/W=02)、12864.c#include<12864.h>uchar S1[]= "2012年7 月20 号";uchar S2[]= "文理学院";uchar S3[]= "第三实验楼";uchar S4[]= "1 楼112";/*****************延时函数*********************/ void delay_1ms(uint x){uint i,j;for(j=0;j<x;j++)for(i=0;i<110;i++);}/*****************写指令函数*********************/ void write_cmd(uchar cmd){RS=0;RW=0;E =0;P0=cmd;delay_1ms(5);E =1;delay_1ms(5);E =0;}/*****************写数据函数*********************/ void write_date(uchar date){RS=1;RW=0;E =0;P0=date;delay_1ms(5);E =1;delay_1ms(5);E =0;}/*****************显示位置函数*********************/ void Lcm_pos(uchar *ptr,uchar ddram){uchar i,j=0,x;if(ddram<0x88)Line=0; //定位行地址:第一行else if(ddram<0xA0)Line=2; //定位行地址:第三行else if(ddram<0xA8)Line=1; //定位行地址:第二行elseLine=3; //定位行地址:第四行Col=0x0f&ddram; //定位列地址if(Col>0x07)Col=Col-0x08;x=Col*2;write_cmd(ddram); // 定位显示起始地址while ((ptr[j])!='\0')j++; //判断数组ptr中字符的个数for (i=0;i<j;i++){write_date(ptr[i]); //输出单个字符x++;if (x==0x10){x=0;Line++;switch (Line){case 0:write_cmd(0x80);break;case 1:write_cmd(0xA0);break;case 2:write_cmd(0x88);break;case 3:write_cmd(0xA8);break;}if (Line>3){write_cmd(0x80);Line=0;}}}}/*****************初始化函数*******************/ void Lcm_init(){RST=0;delay_1ms(10);RST=1;delay_1ms(10);write_cmd(0x30);delay_1ms(10);write_cmd(0x0c);delay_1ms(10);write_cmd(0x01);delay_1ms(10);}/*****************显示函数*******************/ void Lcm_display(){Lcm_pos(S1,0X80);delay_1ms(10);Lcm_pos(S2,0X90);delay_1ms(10);Lcm_pos(S3,0X88);delay_1ms(10);Lcm_pos(S4,0X98);delay_1ms(10);}3)、12864.h#include<reg51.h>#define uint unsigned int#define uchar unsigned charuchar Col,Line;sbit E = P2^0;sbit RS = P2^1;sbit RW = P2^2;sbit RST= P2^3;void delay_1ms(uint x);void write_cmd(uchar cmd);void write_date(uchar date);void Lcm_pos(uchar *ptr,uchar ddram);void Lcm_init();void Lcm_display();4)、key.c#include <reg51.h>#include <KEY.h>/*****************延时函数*********************/ void delay_1ms(uint x){uint i,j;for(j=0;j<x;j++)for(i=0;i<110;i++);}/*****************初始化函数*******************/void key_init(){flag=0; //中断未发生,标志位初值设置为0;P1=0x0f; //给P1口赋初值,检测是否产生外部中断;TI=0; //数据允许发送标志位清0,允许数据发送;IT0=1; //外部中断0为下降沿触发;EX0=1; //开外部中断;EA=1; //开总中断;}/****************外部中断函数*****************/void jianpan() interrupt 0{flag=1; //中断产生,标志位置1;EX0=0; //关外部中断,避免干扰;keyscan(); //外部中断产生后,进行键盘扫描;P1=0x0f; //重新给P1口赋值;EX0=1; //重新打开外部中断0;}/*****************按键扫描函数*******************/void keyscan(){P1=0xfe;temp=P1;temp=temp&0xf0;if(temp!=0xf0) //消抖检测;{delay_1ms(10); temp=P1;temp=temp&0xf0;if(temp!=0xf0){temp=P1;switch(temp){case 0x7e: key=0; break;case 0xbe: key=1; break;case 0xde: key=2; break;case 0xee: key=3; break;}while(temp!=0xf0) //按键松手检测;{temp=P1;temp=temp&0xf0;}}}P1=0xfd;temp=P1;temp=temp&0xf0;if(temp!=0xf0){delay_1ms(10);temp=P1;temp=temp&0xf0;if(temp!=0xf0){temp=P1;switch(temp){case 0x7d: key=4; break;case 0xbd: key=5; break;case 0xdd: key=6; break;case 0xed: key=7; break;}while(temp!=0xf0){temp=P1;temp=temp&0xf0;}}}P1=0xfb;temp=P1;temp=temp&0xf0;if(temp!=0xf0){delay_1ms(10);temp=P1;temp=temp&0xf0;if(temp!=0xf0){temp=P1;switch(temp){case 0x7b: key=8; break;case 0xbb: key=9; break;case 0xdb: key=10; break;case 0xeb: key=11; break;}while(temp!=0xf0){temp=P1;temp=temp&0xf0;}}}P1=0xf7;temp=P1;temp=temp&0xf0;if(temp!=0xf0){delay_1ms(10);temp=P1;temp=temp&0xf0;if(temp!=0xf0){temp=P1;switch(temp){case 0x77: key=12; break;case 0xb7: key=13; break;case 0xd7: key=14; break;case 0xe7: key=15; break;}while(temp!=0xf0){temp=P1;temp=temp&0xf0;}}}}5)、key.h#include<reg51.h>#define uint unsigned int#define uchar unsigned charuchar temp,flag;uint key;void key_init();void keyscan();void delay_1ms(uint x);。