一、实验目的- 学习掌握Proteus仿真软件;
- 熟悉C51编程;
- 掌握按键、LED显示综合编程。
二、实验设备和器件
三、实验原理图图1 采用单片机I/O端口实现的键盘显示接口电路
实际应用中经常采用单片机的I/O端口实现矩阵键盘及LED数码管显示接口功能,具体电路如图3所示。单片机P3口用于矩阵键盘接口,P3.0~P3.3作为行扫描输出线,P3.4~P3.7作为读列输入线;P0口和P2口用于LED数码管显示接口,从P0口输出显示段码,P2口输出显示数位。 四、实验内容- 将按键内容显示在最右边的LED上。
- 初始显示0~7,实现按键右移显示。即;初始显示01234567,按1后,显示10123456,按2后显示21012345,以此类推。
- 自主设计一种按键+显示程序。
五.实验代码及结果5.1问题一代码及结果
- #include <reg51.h>
- #include <absacc.h>
- #define uchar unsigned char
- #define uint unsigned int
- uchar key1=16;//全局变量,key1为键码,定义为16是为了让初始时灯灭
- uchar code value[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,
- 0x5e,0x79,0x71,0x00}; //0~F的字段码表
- //延时函数
- void delay(uint i)
- {
- uint j;
- for(i=0;j<i;j++){}
- }
- //判断是否按键
- uchar checkkey()
- {
- uchar key;
- P3 = 0xF0;//
- key = ~P3 & 0xff;//无键按下返回0fh
- return ( key);
- }
- //显示函数
- void display(void)
- {
- P2=0x7f; //仅亮第8个灯
- P0=value[key1]; //键值
- }
- //求按键值,没有按键返回0ff,按键返回键值
- unsigned char key(void)
- {
- unsigned char row,col=0,k=0xff,dd,scan;// 定义行、列、返回值
- scan=0xfe; // 行扫描码
- for(row=0;row<4;row++) // 行扫描
- {
- P3=scan; dd=P3/16; // 行扫描值送P3
- if(dd!=0x0f) // 列线不全为1 ,进入列扫描
- {
- switch(dd&0x0f)//用case语句求键值
- {
- case(0x0e):k=0x00+row*4; break;
- case(0x0d):k=0x01+row*4; break;
- case(0x0b):k=0x02+row*4; break;
- case(0x07):k=0x03+row*4; break;
- }
- }
- scan=scan*2+1; // 左移1位
- }
- return k; // 返回键值
- }
- void main(void)
- {
- while(1)
- {
- while(checkkey()==0x0f)//没有按键则显示当前的数字
- {
- display();
- }
- key1=key(); //有按键求键值
- }
- }
复制代码
5.2问题二结果及代码
- <font color="rgb(0, 0, 0)">#include <reg51.h>
- #include <absacc.h>
- #include <intrins.h>
- #define uchar unsigned char
- #define uint unsigned int
- uchar key1=16;//全局变量,key1为键码,定义为16是为了让初始时灯灭
- uchar code value[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,
- 0x5e,0x79,0x71,0x00}; //0~F的字段码表
- uchar buf[8]={0,1,2,3,4,5,6,7};
- //延时函数
- void delay(uint i)
- {
- uint j;
- for(i=0;j<i;j++){}
- }
- //判断是否按键
- uchar checkkey()
- {
- uchar key;
- P3 = 0xF0;//
- key = ~P3 & 0xff;//无键按下返回0fh
- return ( key);
- }
- //显示函数
- void display(void)
- {
- uchar i,p,scan=0xfe;
- for(i=0;i<8;i++)
- {
- p=buf[i];
- P2=scan;
- P0=value[buf[i]];
- delay(1000);
- scan=_crol_(scan,1);
- }
- }
- //求按键值,没有按键返回0ff,按键返回键值
- unsigned char key(void)
- {
- unsigned char row,col=0,k=0xff,dd,scan;// 定义行、列、返回值
- scan=0xfe; // 行扫描码
- for(row=0;row<4;row++) // 行扫描
- {
- P3=scan; dd=P3/16; // 行扫描值送P3
- if(dd!=0x0f) // 列线不全为1 ,进入列扫描
- {
- switch(dd&0x0f)//用case语句求键值
- {
- case(0x0e):k=0x00+row*4; break;
- case(0x0d):k=0x01+row*4; break;
- case(0x0b):k=0x02+row*4; break;
- case(0x07):k=0x03+row*4; break;
- }
- }
- scan=scan*2+1; // 左移1位
- }
- while(checkkey()!=0x0f);
- return k; // 返回键值
- }
- void main(void)
- {
- while(1)
- {
- key1=key();
- if(key1!=0xff)
- {
- buf[7]=buf[6];
- buf[6]=buf[5];
- buf[5]=buf[4];
- buf[4]=buf[3];
- buf[3]=buf[2];
- buf[2]=buf[1];
- buf[1]=buf[0];
- buf[0]=key1;
- }
- display();
- }
- }</font>
复制代码
5.3问题三结果及代码
实现功能为:计算并显示个位数的一次减法。手动按键,前10个键为数字1-9,第11个键为减号,第12个键为等号。当按键时,第一个灯会显示相应的数,例如输入按键‘8-2=’,第一个灯会依次显示按键对应的字符,当再按‘=’时,就会显示减法结果。弊端是只能算个位减法,仅能算一次,只有第一个灯可以显示输入的数值,不能动态显示。
- #include <reg51.h>
- #include <absacc.h>
- #include <intrins.h>
- #define uchar unsigned char
- #define uint unsigned int
- uchar key1=12;//全局变量,key1为键码,定义为16是为了让初始时灯灭
- uchar key2,key3;//全局变量,key1为键码,定义为16是为了让初始时灯灭
- uchar code value[13]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40,0x09,0x00};//0-9,减号,等号
- uchar buf[13]={0,1,2,3,4,5,6,7,9,10,11,12};
- //延时函数
- void delay(uint i)
- {
- uint j;
- for(i=0;j<i;j++){}
- }
- //判断是否按键
- uchar checkkey()
- {
- uchar key;
- P3 = 0xF0;//
- key = ~P3 & 0xff;//无键按下返回0fh
- return ( key);
- }
- //显示函数
- void display(void)
- {
- uchar scan=0xfe;
- P2=scan;
- P0=value[key1];
- }
- //求按键值,没有按键返回0ff,按键返回键值
- unsigned char key(void)
- {
- unsigned char row,col=0,k=0xff,dd,scan;// 定义行、列、返回值
- scan=0xfe; // 行扫描码
- for(row=0;row<4;row++) // 行扫描
- {
- P3=scan; dd=P3/16; // 行扫描值送P3
- if(dd!=0x0f) // 列线不全为1 ,进入列扫描
- {
- switch(dd&0x0f)//用case语句求键值
- {
- case(0x0e):k=0x00+row*4; break;
- case(0x0d):k=0x01+row*4; break;
- case(0x0b):k=0x02+row*4; break;
- case(0x07):k=0x03+row*4; break;
- }
- }
- scan=scan*2+1; // 左移1位
- }
- while(checkkey()!=0x0f);
- return k; // 返回键值
- }
- void main(void)
- { uchar i=0,j=0;
- while(1)
- {
- key1=key();
- if(key1!=0xff)//如果有键按下
- {
- if(i==0)//如果被减数按下,键值赋给key2
- {key2=key1;}
- if(i==2)
- {key3=key1;}//如果减数按下,键值赋给key3
- if(i==4)
- {
- key1=key2-key3;//如果(被减数-减数=)操作完成,则再按=,显示减法结果
- }
- display();
- i++;
- }
- }
- }
复制代码
6.实验总结
我认为实验比较难的地方是按键会有延时,而机器的处理速度太快,这就导致预期的结果和实际显示的效果不一致。因此在编辑代码时,一定要考虑到手按键会有延时的影响。
在求按键值的子程序里,什么时候把按键值返回需要根据不同的实验做相应的改变,例如:按键结束后返回按键值,和按键时返回键值的效果是不一样的,这也导致在主程序中判断按键是否产生的不同。在问题二中,我就是因为没有在按键结束后返回键值,导致不能产生正确效果。
If里边不能嵌套for语句,在实验一中扫描列时,我嵌套了for,导致程序不能进入for循环。后来我改成了case语句才成功。
以上的Word格式文档51黑下载地址:
实验10.docx
(219.4 KB, 下载次数: 7)
|