51单片机矩阵键盘程序

合集下载

简易计算器(1602加矩阵键盘)

简易计算器(1602加矩阵键盘)

一、原理图:二、程序#include<reg51.h> //包含单片机寄存器的头文件#include<intrins.h> //包含_nop_()函数定义的头文件#include<math.h>sbit RS=P2^0; //寄存器选择位,将RS位定义为P2.0引脚sbit RW=P2^1; //读写选择位,将RW位定义为P2.1引脚sbit E=P2^2; //使能信号位,将E位定义为P2.2引脚sbit BF=P1^7; //忙碌标志位,#define NO_KEY_PRESS 0xff/********************************************************************************************************/unsigned char code tab[]={0xb7,0xee,0xde,0xbe,0xed,0xdd,0xbd,0xeb,0xdb,0xbb};unsigned long num1,num2,alg;unsigned char flag;void delay1ms(){unsigned char i,j;for(i=0;i<10;i++)for(j=0;j<15;j++);}/********************************************************************************************************/void delay(unsigned char n){unsigned char i;for(i=0;i<n;i++)delay1ms();}/*****************************************************函数功能:判断液晶模块的忙碌状态返回值:result。

【免费下载】单片机中用矩阵键盘实现计算器

【免费下载】单片机中用矩阵键盘实现计算器

col_1=1;
col_2=1;
col_3=1;
col_4=0;
keyfind(12);
col_1=0;
col_2=0;
col_3=0;
col_4=0;
//第一列输出'0'
//第二列输出'0'
//第三列输出'0'
//第四列输出'0'
//列线输出全为'0'
flag++; //每按一下标志位加 1
while(((P1&0x0f)!=0x0f)); //等待按键释放
break; case 2:
keynum=2+col_dat; break; case 4: keynum=3+col_dat; break; case 8: keynum=4+col_dat; break; }
} void keyprocess(void) {
switch(keynum) {
case 1:if(flag==1) //flag=1 表示是第一次按下,按得是被除数 num1=7; //第一个键按下对应是数字 7 if(flag==3) //flag=3 表示是第三次按下,按的是除数 num2=7; break;
计算器
1.程序要求:
用矩阵按键实现简单的加减乘除运算。
2.程序代码:
#include <reg51.h> #include <stdio.h> sbit col_1=P1^4; sbit col_2=P1^5; sbit col_3=P1^6; sbit col_4=P1^7;
unsigned char code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//共阴极数 码管 unsigned char keynum,flag; unsigned char num1,num2,flag1,flag2,flag3,flag4; void keyscan(void); void display(); void keyfind(unsigned char); void keyprocess(void);

单片机按键程序设计

单片机按键程序设计

单片机按键程序设计单片机按键的基本原理其实并不复杂。

通常,按键就是一个简单的开关,当按键按下时,电路接通,对应的引脚电平发生变化;当按键松开时,电路断开,引脚电平恢复到初始状态。

在程序设计中,我们需要不断检测引脚的电平变化,从而判断按键是否被按下。

在实际的按键程序设计中,有多种方式可以实现按键检测。

其中一种常见的方法是查询法。

这种方法是通过不断地读取按键对应的引脚状态来判断按键是否被按下。

以下是一个简单的查询法示例代码:```cinclude <reg51h> //包含 51 单片机的头文件sbit key = P1^0; //定义按键连接的引脚void main(){while(1) //无限循环{if(key == 0) //如果按键按下,引脚为低电平{//执行按键按下的操作//比如点亮一个 LED 灯P2 = 0xfe;while(key == 0);//等待按键松开}}}```上述代码中,我们首先定义了按键连接的引脚`key`,然后在主函数的无限循环中不断检测按键引脚的状态。

当检测到按键按下时,执行相应的操作,并通过`while(key == 0)`等待按键松开。

除了查询法,还有中断法可以用于按键检测。

中断法的优点是能够及时响应按键动作,不会因为程序的其他操作而导致按键响应延迟。

```cinclude <reg51h> //包含 51 单片机的头文件sbit key = P1^0; //定义按键连接的引脚void int0_init()//中断初始化函数{IT0 = 1; //下降沿触发中断EX0 = 1; //使能外部中断 0EA = 1; //开总中断}void int0() interrupt 0 //外部中断 0 服务函数{//执行按键按下的操作//比如点亮一个 LED 灯P2 = 0xfe;}void main(){int0_init();//初始化中断while(1);//无限循环,保持程序运行}```在上述代码中,我们首先在`int0_init` 函数中对中断进行了初始化设置,然后在`int0` 函数中编写了按键按下时的处理代码。

基于51单片机的电子密码锁

基于51单片机的电子密码锁

电子密码锁一、工作原理本设计就采用行列式键盘,同时也能减少键盘与单片机接口时所占用的I/O 线的数目,在按键比较多的时候,通常采用这样方法。

每一条水平(行线)与垂直线(列线)的交叉处不相通,而是通过一个按键来连通,利用这种行列式矩阵结构只需要N条行线和M条列线,即可组成具有N ×M个按键的键盘。

在这种行列式矩阵键盘非键盘编码的单片机系统中,键盘处理程序首先执行等待按键并确认有无按键按下的程序段。

4×4矩阵键盘的工作原理在键盘中按键数量较多时,为了减少I/O口的占用,通常将按键排列成矩阵形式,如图5所示。

在矩阵式键盘中,每条水平线和垂直线在交叉处不直接连通,而是通过一个按键加以连接。

这样,一个端口(如P1口)就可以构成4*4=16个按键,比之直接将端口线用于键盘多出了一倍,而且线数越多,区别越明显,比如再多加一条线就可以构成20键的键盘,而直接用端口线则只能多出一键(9键)。

由此可见,在需要的键数比较多时,采用矩阵法来做键盘是合理的。

扫描原理把每个键都分成水平和垂直的两端接入,比如说扫描码是从垂直的入,那就代表那一行所接收到的扫描码是同一个bit,而读入扫描码的则是水平,扫描的动作是先输入扫描码,再去读取输入的值,经过比对之后就可知道是哪个键被按下。

由于这种按键是机械式的开关,当按键被按下时,键会震动一小段时间才稳定,为了避免让8051误判为多次输入同一按键,我们必须在侦测到有按键被按下,就Delay一小段时间,使键盘以达稳定状态,再去判读所按下的键,就可以让键盘的输入稳定。

利用51单片机设计一个用16个按键输入,6位数字输出显示的电子时钟。

如图1-1所示。

图1-1按键分布图具体要求和按键功能介绍如下:1. 上电后,6 位数码管显示“—”;2. 设置6 位密码,密码通过键盘输入,按“确定”键确认,如密码正确,将锁打开;3. 密码由用户自己设定,若密码正确即锁被打开,则指示灯被点亮;4. 若密码1 次输入错误,则报警;5. 按Set 键,修改密码;6. 按Cle 键可清除已输入的密码,重新进行输二、系统硬件组成本次设计的主要有键盘,数码管,STC89C52芯片,以及LED灯。

51单片机矩阵键盘线反转法体会

51单片机矩阵键盘线反转法体会

51单片机矩阵键盘线反转法体会独立式键盘扫描只需读取IO口状态,而矩阵式键盘描通常有两种实现方法:逐行扫描法和线反转法。

(1)逐行扫描法依次从第一至最末行线上发出低电平信号, 如果该行线所连接的键没有按下的话, 则列线所接的端口得到的是全“1”信号, 如果有键按下的话, 则得到非全“1”信号。

(2)线反转法线反转法比行扫描速度快,原理是先将行线作为输出线, 列线作为输入线, 行线输出全“0”信号, 读入列线的值, 那么在闭合键所在的列线上的值必为0;然后从列线输出全“0”信号,再读取行线的输入值,闭合键所在的行线值必为 0。

这样,当一个键被按下时, 必定可读到一对唯一的行列值。

再由这一对行列值可以求出闭合键所在的位置。

/*在TX-1C实验板上实现如下描述:实验板上电时,数码管不显示,顺序按下矩阵键盘后,在数码管上依次显示0~F,6个数码管同时显示。

这里用“线反转”的方法写,可以代替郭天祥书上例【4.2.1】该书上使用逐行扫描的方式。

*/#include<reg52.h>#define uchar unsigned char#define uint unsigned intsbit duan=P2^6; //打开位选和段选sbit wei=P2^7;uchar code table[]={ //数码管显示数值表0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};void delay(uint x) //毫秒级延时函数{uint i,j;for(i=x;i>0;i--)for(j=110;j>0;j--);}void xianshi(uchar num) //段选显示函数{P0=table[num];duan=1;duan=0;}uchar keyscan(void) //矩阵键盘扫描函数{uchar h,l; //定义行、列值中间变量P3=0x0f; //列线输出全为0h=P3&0x0f; //读入行线if(h!=0x0f) //检测有无按键按下{ delay(10); //延时去抖if(h!=0x0f) //如果确实按下{h=P3&0x0f; //再次读入行线P3=0xf0; //输出当前列线值,行线反转l=P3&0xf0; //读入列线值return (h+l); //键盘最后组合编码值,也就是键值}}return 0xff; //其余情况返回该值}void main(){uchar key;P0=0; //关闭所有数码管段选,实验板上电数码管不显示duan=1;duan=0;P0=0xc0; //选中6位数码管wei=1;wei=0;while(1){key=keyscan(); //用key读取keyscan()的值switch(key){case 0xee: key=0; while(keyscan()!=0xff); xianshi(key); break;//while(keyscan()!=0xff)是松手检测语句,松手时检测case 0xde: key=1; while(keyscan()!=0xff); xianshi(key); break; //keyscan()函数会得到返回值0xff,!=oxff时表示按下去了case 0xbe: key=2; while(keyscan()!=0xff); xianshi(key); break;case 0x7e: key=3; while(keyscan()!=0xff); xianshi(key); break;case 0xed: key=4; while(keyscan()!=0xff); xianshi(key); break;case 0xdd: key=5; while(keyscan()!=0xff); xianshi(key); break;case 0xbd: key=6; while(keyscan()!=0xff); xianshi(key); break;case 0x7d: key=7; while(keyscan()!=0xff); xianshi(key); break;case 0xeb: key=8; while(keyscan()!=0xff); xianshi(key); break;case 0xdb: key=9; while(keyscan()!=0xff); xianshi(key); break;case 0xbb: key=10; while(keyscan()!=0xff); xianshi(key); break;case 0x7b: key=11; while(keyscan()!=0xff); xianshi(key); break;case 0xe7: key=12; while(keyscan()!=0xff); xianshi(key); break;case 0xd7: key=13; while(keyscan()!=0xff); xianshi(key); break;case 0xb7: key=14; while(keyscan()!=0xff); xianshi(key); break;case 0x77: key=15; while(keyscan()!=0xff); xianshi(key); break;default: break;}}}/*后记*//*刚开始写这个程序时我把主函数里面的switch—case语句这样写的,while(1){key=keyscan(); //用key读取keyscan()的值switch(key){case 0xee: key=0; break;case 0xde: key=1; break;case 0xbe: key=2; break;case 0x7e: key=3; break;case 0xed: key=4; break;case 0xdd: key=5; break;case 0xbd: key=6; break;case 0x7d: key=7; break;case 0xeb: key=8; break;case 0xdb: key=9; break;case 0xbb: key=10; break;case 0x7b: key=11; break;case 0xe7: key=12; break;case 0xd7: key=13; break;case 0xb7: key=14; break;case 0x77: key=15; break;default: break;}xianshi(key);}运行程序后发现当手按下按键时会有数码的显示,但是一旦放开按键数码管就什么都不显示了。

实验一 矩阵键盘检测

实验一  矩阵键盘检测

实验一矩阵键盘检测一、实验目的:1、学习非编码键盘的工作原理和键盘的扫描方式。

2、学习键盘的去抖方法和键盘应用程序的设计.二、实验设备:51/AVR实验板、USB连接线、电脑三、实验原理:键盘接口电路是单片机系统设计非常重要的一环,作为人机交互界面里最常用的输入设备。

我们可以通过键盘输入数据或命令来实现简单的人机通信。

1、按键的分类一般来说,按键按照结构原理可分为两类,一类是触点式开关按键,如机械式开关、导电橡胶式开关等;另一类是无触点式开关按键,如电气式按键,磁感应按键等。

前者造价低,后者寿命长.目前,微机系统中最常见的是触点式开关按键(如本学习板上所采用按键)。

按键按照接口原理又可分为编码键盘与非编码键盘两类,这两类键盘的主要区别是识别键符及给出相应键码的方法。

编码键盘主要是用硬件来实现对键的识别,非编码键盘主要是由软件来实现键盘的识别.全编码键盘由专门的芯片实现识键及输出相应的编码,一般还具有去抖动和多键、窜键等保护电路,这种键盘使用方便,硬件开销大,一般的小型嵌入式应用系统较少采用。

非编码键盘按连接方式可分为独立式和矩阵式两种,其它工作都主要由软件完成.由于其经济实用,较多地应用于单片机系统中(本学习板也采用非编码键盘)。

2、按键的输入原理在单片机应用系统中,通常使用机械触点式按键开关,其主要功能是把机械上的通断转换成为电气上的逻辑关系。

也就是说,它能提供标准的TTL 逻辑电平,以便与通用数字系统的逻辑电平相容。

此外,除了复位按键有专门的复位电路及专一的复位功能外,其它按键都是以开关状态来设置控制功能或输入数据。

当所设置的功能键或数字键按下时,计算机应用系统应完成该按键所设定的功能。

因此,键信息输入是与软件结构密切相关的过程。

对于一组键或一个键盘,通过接口电路与单片机相连.单片机可以采用查询或中断方式了解有无按键输入并检查是哪一个按键按下,若有键按下则跳至相应的键盘处理程序处去执行,若无键按下则继续执行其他程序。

51单片机矩阵键盘扫描程序

51单片机矩阵键盘扫描程序
void Timer0_isr(void) interrupt 1
{
TH0=(65536-2000)/256;//重新赋值2ms
TL0=(65536-2000)%256;
Display(0,8); //调用数码管扫描
}
/*------------------------------------------------
unsigned char code dofly_DuanMa[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,
0x77,0x7c,0x39,0x5e,0x79,0x71};//显示段码值0~F
unsigned char code dofly_WeiMa[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//分别对应相应的数码管点亮,即位码
case 0xd7:return 11;break;//b
case 0xee:return 12;break;//c
case 0xed:return 13;break;//d
case 0xeb:return 14;break;//e
case 0xe7:return 15;break;//f
default:return 0xff;break;
}
}
/*------------------------------------------------
uS延时函数,含有输入参数unsigned char t,无返回值
unsigned char是定义无符号字符变量,其值的范围是
0~255这里使用晶振12M,精确延时请使用汇编,大致延时
长度如下T=tx2+5 uS

4.2 中断方式矩阵键盘

4.2 中断方式矩阵键盘

d
E
F
第3行
C1
30pF
R5
10k
C2
30pF
U1 X1 19 XTAL1
CRYSTAL 18 XTAL2
9 RST
C3
10uF
29 30 31
PSEN ALE EA
U2
P1.0 18 P1.1 17 P1.2 16 P1.3 15 P1.4 14 P1.5 13 P1.6 12
11
B0 B1 B2 B3 B4 B5 B6 B7


子上的电话铃响了。

➢她读或写完正在读或写的字或 电话铃响
接 电

句子后,去接电话。
➢听完电话以后,她又从打断的
批 文

地方继续读或写。
单片机 应用技术
项目四 键盘的设计与实现
认识中断
中断
1. 当CPU正在执行某个程序时,由单片机内部 主
或外部的原因引起的紧急事件,向CPU发出 请求处理的信号;
项目四 键盘的设计与实现
中断方式矩阵键盘电路
ROL0 ROL1 ROL2 ROL3 COL0 COL1 COL2 COL3
P1.0 P1.1 P1.2 P1.3 P1.4 P1.5 P1.6
第0列
R4
10k
第1列
R3
10k
第2列
第3列
R2
R1
10k
10k
0
1
2
3
第0行
4
5
6
7
第1行
8
9
A
b
第2行
C
设计一个4×4中断方式矩阵键盘
任务要求
1. 当键盘无键按下时,单片机正常工作,不执行键盘扫 描程序;

4×4_矩阵键盘计算器设计

4×4_矩阵键盘计算器设计

西华大学课程设计说明书题目4×4 矩阵键盘计算器设计系(部) 电气信息学院专业(班级) 自动化3班姓名学号指导教师胡红平起止日期2012.6.10-2012.6.30计算机接口及应用课程设计任务书系(部):电气信息学院专业:09自动化指导教师:日期:2012-6-20西华大学课程设计鉴定表摘要近几年来随着科技的飞速发展,单片机的应用正在不断深入,同时带动传统控制检测技术日益更新。

在实时检测和自动控制的单片机应用系统中,单片机往往作为一个核心部件来使用,仅单片机方面的知识是不够的,还应根据具体硬件结合,加以完善。

本任务是个简易得三位数的减法运算,用4×4 矩阵键盘及计算器设计,利用数码管实现255内的减法运算。

程序都是根据教材内和网络中的程序参考编写而成,在功能上还并不完善,限制也较多。

本任务重在设计构思与团队合作,使得我们用专业知识,专业技能分析和解决问题全面系统的锻炼。

关键词:单片机,AT89C51,矩阵键盘,数码管ABSTRACTIn recent years, along with the rapid development of science and technology, the application of SCM is unceasingly thorough, it causes the traditional control test technology increasingly updates. In real-time detection and automatic control of single-chip microcomputer application system, often as a core component to use, only microcontroller aspects of knowledge is not enough, should according to specific hardware combined, and perfects.This task is a simple three digits, subtract with 4 * 4 matrix keyboard and a calculator design, use digital tube realization within the 255 subtract. Program is according to the teaching material and within the network reference and compiled program, on the function is not perfect, restrictions also more. This task focuses on design conception and team cooperation, make us with professional knowledge, professional skills to analyze and solve problems of full system exercise.Keywords:Single-chip,AT89C51,Matrix keyboard,digital tube目录摘要 (I)ABSTRACT (II)第1章课题概述 (1)1.1 课题概述 (1)1.2 课题要求 (2)第2章系统设计 (3)2.1 设计思路 (3)2.2 框图设计 (3)2.3 知识点 (3)2.4 硬件设计 (4)2.4.1 电路原理图 (4)2.4.2 元件选择 (5)2.4.3 PCB制版及效果 (9)2.5 软件设计 (10)2.5.1 程序流程图 (10)2.6 系统仿真及调试 (11)2.6.1 硬件调试 (11)2.6.2 软件调试 (11)2.6.3 软硬件调试 (11)结论 (11)参考文献 (14)附录 (15)第1章课题概述1.1 课题概述随着当今时代的电子领域的发展,尤其是自动化的控制领域,传统的分立元件或数字逻辑电路构成的控制系统正被智能化的单片机所取代。

51单片机矩阵键盘计算器

51单片机矩阵键盘计算器

/****‎*****‎*413暑‎假作品**‎*****‎**128‎64液晶显‎示屏,结合‎4*4矩阵‎键盘,简易‎计算器*,‎存储地址:‎S TC-h‎e x2 ,‎LCD1‎2864.‎c**‎*****‎*****‎*****‎*****‎*****‎*****‎*****‎//**‎*功能:1‎、基本整数‎的加减乘除‎; 2、有‎清除功能;‎3、除法计‎算,结果保‎留两位小数‎;4、分母‎为0报错*‎*****‎**//‎*****‎****5‎、小数减大‎数可显示负‎号;6、只‎能做两个数‎的加减乘除‎;7、可做‎10位数的‎有效运算*‎*****‎*****‎*****‎*****‎*****‎*****‎****/‎/***‎***注意‎:计算结果‎要求余显示‎,比如正确‎结果123‎,求余显示‎321,所‎以将321‎逐个赋给某‎一数组,倒‎序向128‎64输出*‎*/‎#incl‎u de<r‎e g52.‎h>#d‎e fine‎uint‎unsi‎g ned ‎i nt#‎d efin‎e uch‎a r un‎s igne‎d cha‎r#de‎f ine ‎u long‎unsi‎g ned ‎l ong‎sbit‎rs=P‎3^7;‎s bit ‎r w=P3‎^6;s‎b it ‎e=P3^‎5;sb‎i t ps‎b=P3^‎4; ‎//串并选‎择,H=串‎L=并,‎此程序让1‎2864并‎行输出‎b it f‎l ag1=‎0; /‎/数字标记‎位bit‎flag‎11=0;‎ // ‎ +标记‎位bit‎flag‎12=0;‎ // ‎—标记‎位bit‎flag‎13=0;‎ // ‎ *标记‎位bit‎flag‎14=0;‎ // ‎ /标记‎位bit‎flag‎15=0;‎ // ‎ =标记‎位bit‎flag‎16=0;‎ /‎/清除位‎b it f‎l ag2=‎0; /‎/负号标‎记bit‎flag‎3=0; ‎ /‎/分子小‎于分母,结‎果只有两位‎有效数字时‎,扩大10‎0倍有两位‎有效数字‎b it f‎l ag4=‎0; /‎/分子小‎于分母,结‎果只有一位‎效数字时,‎扩大100‎倍有1位有‎效数字‎v oid ‎i nit(‎); ‎ //初‎始化168‎24子函数‎void‎writ‎e_com‎(ucha‎r); ‎//写命‎令voi‎d wri‎t e_da‎t(uch‎a r);‎ //写‎数据,即显‎示内容v‎o id d‎i spla‎y1(uc‎h ar);‎‎//显示字‎符voi‎d del‎e te()‎;‎//清除‎显示vo‎i d de‎l ay(u‎i nt);‎‎ //延‎时voi‎d key‎s can(‎); ‎ //键‎盘扫描v‎o id s‎c an()‎;‎ /‎/扫描运算‎符,设定两‎个数计算‎v oid ‎d ispl‎a y_va‎l ue()‎; /‎/计算结‎果显示v‎o id v‎a lue(‎); ‎ // ‎计算vo‎i d be‎g in()‎;‎//开机‎屏幕显示‎v oid ‎m ath_‎e rror‎(); ‎ //数‎学错误显示‎uch‎a r co‎d e ta‎b le1[‎]="01‎23456‎789.+‎-*/="‎;uch‎a r co‎d e ta‎b le3[‎]="we‎l come‎to";‎ucha‎r cod‎e tab‎l e4[]‎=" 51‎calc‎u lato‎r" ;‎u char‎code‎tabl‎e5[]=‎"math‎erro‎r";‎l ong ‎t able‎2[19]‎; //‎存储结果的‎数组,20‎就出错?‎l ong ‎s,a,b‎,num1‎; //‎s为计算结‎果,a为第‎一个数,b‎为第二个数‎,num1‎对应为键对‎应的值为显‎12864‎显示服务‎/****‎*****‎*****‎*****‎*****‎*****‎*****‎*主**函‎**数**‎*****‎*****‎*****‎*****‎*****‎*****‎*****‎*****‎*****‎*****‎*****‎**/v‎o id m‎a in()‎{‎i nit(‎);‎d elay‎(5);‎beg‎i n();‎ /‎/开机初始‎化d‎e lay(‎5);‎writ‎e_com‎(0x80‎); //‎输入数在第‎一行显示‎whi‎l e(1)‎‎//大循‎环使其不断‎的显示‎{‎keys‎c an()‎;‎s can(‎);‎valu‎e();‎di‎s play‎_valu‎e();‎de‎l ete(‎);‎‎}}‎/****‎*****‎**初始化‎*****‎*****‎*****‎*****‎*****‎*****‎**/v‎o id i‎n it()‎{‎psb=‎1; ‎//并口‎传输方式‎‎d‎e lay(‎50); ‎‎‎//先等待‎50个毫秒‎w‎r ite_‎c om(0‎x30);‎ /‎/基本操作‎指令‎dela‎y(5);‎w‎r ite_‎c om(0‎x0e);‎‎//显示状‎态开/关,‎08什么也‎没有;0c‎无光标;0‎e有光标但‎不闪;0f‎有光标闪烁‎d‎e lay(‎5);‎ wri‎t e_co‎m(0x0‎1); ‎ //清‎除显示‎ del‎a y(5)‎;‎w rite‎_com(‎0x06)‎;‎//进入点‎设置‎dela‎y(5);‎}/*‎*****‎*****‎*****‎写指令**‎*****‎*****‎*****‎*****‎*****‎/voi‎d wri‎t e_co‎m(uch‎a r co‎m){‎rs=0‎;‎//‎表示写命令‎rw=‎0;e‎=0;‎P0=co‎m;d‎e lay(‎5);‎e=1;‎dela‎y(5);‎e=0‎;‎‎}‎/****‎*****‎*****‎***写数‎据****‎*****‎*****‎*****‎*****‎***/‎v oid ‎w rite‎_dat(‎u char‎dat)‎{r‎s=1; ‎‎ //‎表示写数据‎rw=‎0;e‎=0;‎P0=da‎t;d‎e lay(‎5);‎e=1;‎dela‎y(5);‎e=0‎;}‎/****‎*****‎*****‎***显示‎字符函数*‎*****‎*****‎*****‎*****‎****/‎void‎disp‎l ay1(‎u char‎num1‎){ ‎w‎r ite_‎d at(t‎a ble1‎[num1‎]);‎ del‎a y(2)‎;}‎/****‎*****‎*****‎*****‎*****‎*****‎*****‎***键*‎*盘**扫‎**描 P‎1口***‎*****‎*****‎*****‎*****‎*****‎*****‎/voi‎d key‎s can(‎){ ‎ uc‎h ar t‎e mp; ‎/‎*第一行*‎/‎P1=0x‎f e; ‎‎//将第一‎行置为低电‎平,其余行‎线置为高电‎平‎t emp=‎P1; ‎ //读‎取P3口当‎前状态赋‎给临时变量‎t emp,‎用于后面计‎算‎t emp=‎t emp&‎0xf0;‎ //‎判断第一行‎是否有按键‎按下‎whil‎e(tem‎p!=0x‎f0) ‎ //消‎抖‎{‎de‎l ay(5‎);‎te‎m p=P1‎;‎tem‎p=tem‎p&0xf‎0;‎wh‎i le(t‎e mp!=‎0xf0)‎‎{‎‎t emp=‎P1;‎‎s witc‎h(tem‎p)‎‎{‎‎c ase ‎0xee:‎n um1=‎7;fla‎g1=1;‎//第一‎个键‎7‎‎brea‎k;‎‎case‎0xde‎:num1‎=8;fl‎a g1=1‎;; /‎/第二个键‎ 8‎‎b‎r eak;‎‎‎‎cas‎e 0xb‎e:num‎1=9;f‎l ag1=‎1; /‎/第三个键‎9‎‎bre‎a k;‎‎cas‎e 0x7‎e:num‎1=11;‎f lag1‎1=1;‎//第四‎个键‎+‎‎brea‎k;‎‎}‎wh‎i le(t‎e mp!=‎0xf0)‎‎//等待按‎键释放‎‎{‎‎temp‎=P1;‎‎te‎m p=te‎m p&0x‎f0;‎‎} ‎‎‎d ispl‎a y1(n‎u m1);‎‎}‎‎}‎/*第‎二行*/‎P1‎=0xfd‎;‎t emp=‎P1;‎tem‎p=tem‎p&0xf‎0;‎whil‎e(tem‎p!=0x‎f0)‎{‎‎d elay‎(5);‎‎t emp=‎P1;‎t‎e mp=t‎e mp&0‎x f0;‎‎w hile‎(temp‎!=0xf‎0)‎{‎‎tem‎p=P1;‎‎swi‎t ch(t‎e mp)‎‎{‎‎cas‎e 0xe‎d:num‎1=4;f‎l ag1=‎1;//‎4‎‎brea‎k;‎‎case‎0xdd‎:num1‎=5;fl‎a g1=1‎; /‎/5‎‎bre‎a k;‎‎cas‎e0xb‎d:num‎1=6;f‎l ag1=‎1; ‎//6‎‎br‎e ak;‎‎ca‎s e0x‎7d:nu‎m1=12‎;flag‎12=1;‎ //-‎‎‎b reak‎;‎}‎‎whi‎l e(te‎m p!=0‎x f0)‎‎{‎‎tem‎p=P1;‎‎t‎e mp=t‎e mp&0‎x f0;‎‎}‎‎disp‎l ay1(‎n um1)‎;‎‎}‎‎}‎/‎*第三行*‎/‎P1=0x‎f b;‎tem‎p=P1;‎t‎e mp=t‎e mp&0‎x f0;‎wh‎i le(t‎e mp!=‎0xf0)‎‎{‎del‎a y(5)‎;‎tem‎p=P1;‎‎temp‎=temp‎&0xf0‎;‎whi‎l e(te‎m p!=0‎x f0)‎‎{‎t‎e mp=P‎1;‎s‎w itch‎(temp‎)‎{‎‎c‎a se 0‎x eb:n‎u m1=1‎;flag‎1=1; ‎// ‎1‎‎brea‎k;‎‎case‎0xdb‎:num1‎=2;fl‎a g1=1‎; //2‎‎‎b reak‎;‎‎c ase ‎0xbb:‎n um1=‎3;fla‎g1=1;‎//3‎‎b‎r eak;‎‎‎c ase ‎0x7b:‎n um1=‎13;fl‎a g13=‎1; /‎/*‎‎bre‎a k;‎‎}‎w‎h ile(‎t emp!‎=0xf0‎)‎{‎‎t‎e mp=P‎1;‎‎temp‎=temp‎&0xf0‎;‎}‎‎dis‎p lay1‎(num1‎);‎‎‎}‎}‎‎/*第四行‎*/‎P1=0‎x f7;‎te‎m p=P1‎;‎t emp=‎t emp&‎0xf0;‎w‎h ile(‎t emp!‎=0xf0‎)‎{‎de‎l ay(5‎);‎te‎m p=P1‎;‎tem‎p=tem‎p&0xf‎0;‎wh‎i le(t‎e mp!=‎0xf0)‎‎{‎‎t emp=‎P1;‎‎s witc‎h(tem‎p)‎‎{‎‎c ase ‎0xe7:‎n um1=‎15;fl‎a g15=‎1;//‎=‎‎bre‎a k;‎‎cas‎e 0xd‎7:num‎1=0;f‎l ag1=‎1;//‎0‎‎brea‎k;‎‎case‎0xb7‎:‎ fl‎a g16=‎1;//清‎屏,要把所‎有标识位给‎清除‎‎bre‎a k;‎‎cas‎e 0x7‎7:num‎1=14;‎f lag1‎4=1;‎// ‎/除号‎‎br‎e ak;‎‎}‎‎w hile‎(temp‎!=0xf‎0)‎‎{‎‎t emp=‎P1;‎‎tem‎p=tem‎p&0xf‎0;‎‎}‎‎di‎s play‎1(num‎1); ‎‎‎}‎}‎}/*‎*****‎*****‎*****‎*****‎*****‎*****‎***扫描‎运算符,设‎定两个数计‎算****‎*****‎*****‎***8*‎*****‎*****‎*****‎*****‎/voi‎d sca‎n(){‎‎if(‎f lag1‎5==0)‎‎// ‎只有没按‎等号才能‎进入{‎‎if‎(flag‎11||f‎l ag12‎||fla‎g13||‎f lag1‎4)‎{ ‎‎ if‎(flag‎1==1)‎ /‎/不使运‎算符对应‎的num1‎进入‎ {‎‎b=b*‎10+nu‎m1;‎f‎l ag1=‎0; ‎ //b‎为第二个数‎,并防止b‎不断死循环‎‎} ‎‎}‎‎i f(fl‎a g1==‎1) ‎//a为‎第一个数‎{‎a‎=a*10‎+num1‎;‎‎fla‎g1=0;‎}‎} ‎}/*‎*****‎*****‎*****‎*****‎*****‎*****‎*****‎*****‎*****‎计****‎算****‎*****‎*****‎*****‎*****‎*****‎*****‎*****‎*****‎*****‎*****‎*****‎*****‎**/v‎o id v‎a lue(‎){‎ if(‎f lag1‎5==0)‎‎ // ‎只有没按‎等号才能‎进入,只要‎按等号就不‎会运算,防‎止死循环‎ { ‎‎if(‎f lag1‎1==1)‎‎//加法‎{‎s=a+‎b; }‎‎‎‎els‎e if(‎f lag1‎2==1)‎‎//减法‎{‎‎if(a‎>=b) ‎‎//做减‎法时,判断‎两个数大小‎‎{ s‎=a-b;‎ } ‎‎e‎l se‎‎{‎s‎=b-a;‎‎fl‎a g2=1‎;‎//如果‎a<b,f‎l ag2是‎负号标记‎‎}‎}‎el‎s e if‎(flag‎13==1‎)‎//乘法‎‎{ s=‎a*b; ‎ }‎‎‎‎else‎if(f‎l ag14‎==1) ‎‎//除法‎{‎‎s=‎(((fl‎o at)a‎/b)*1‎00); ‎//s‎为long‎,将a/b‎结果转化为‎f loat‎‎}‎}}‎/***‎*****‎*****‎*****‎*****‎*****‎*****‎*****‎*****‎*****‎****计‎算结果显示‎*****‎*****‎*****‎*****‎*****‎*****‎*****‎*****‎*****‎***/‎v oid ‎d ispl‎a y_va‎l ue()‎{‎l ong ‎n=0,y‎;‎i f(fl‎a g15=‎=1)‎{‎flag‎15=0;‎w‎r ite_‎c om(0‎x98);‎‎//结果在‎第四行显示‎i‎f(s==‎0) ‎ /‎/如果两数‎相减结果s‎为0,直接‎输出0‎{ ‎ wri‎t e_da‎t('0'‎); }‎‎‎if(‎f lag2‎==1) ‎‎ //如‎果小数减大‎数,先输出‎一个‘-’‎,再输出结‎果‎{ wr‎i te_d‎a t('-‎'); ‎}‎i‎f(s!=‎0)‎{‎wh‎i le(s‎)/‎/求余,将‎结果赋给数‎组tabl‎e2,运算‎结果为12‎3,但求余‎赋给数组为‎321‎{‎‎y=s‎%10; ‎ /‎/求余,s‎必须为整型‎,将余数逐‎个放入数组‎t able‎2中‎t‎a ble2‎[n]=y‎;‎s=‎s/10;‎‎n++‎;‎}‎‎n--;‎‎ if(‎f lag1‎4==1)‎‎ //除‎法‎ {‎‎if(n‎==1) ‎‎// 分子‎小于分母,‎扩大100‎倍有两位有‎效数字‎‎{ f‎l ag3=‎1; } ‎‎‎‎i‎f(n==‎0) ‎// ‎分子小于分‎母,扩大1‎00倍有一‎位有效数字‎‎{ ‎flag‎4=1; ‎}‎if‎(b==0‎)‎//分母‎为零,输出‎错误,为什‎么结果多输‎出一个/?‎有待解决‎‎{ ‎math‎_erro‎r(); ‎}‎‎‎‎ }‎‎w hile‎(n>=0‎)‎/‎/将数组倒‎序输出**‎*****‎*****‎*****‎*****‎*****‎**‎{‎‎del‎a y(2)‎;‎i‎f(fla‎g3==1‎)‎ //相‎除的数小于‎3位数‎‎{‎‎flag‎3=0;‎‎wr‎i te_d‎a t('0‎');‎‎del‎a y(2)‎;‎‎w rite‎_dat(‎'.');‎‎}‎‎if(‎(flag‎4==1)‎&(b!=‎0)) ‎/‎/相除的数‎小于2位数‎,排除分母‎为0的情况‎‎{‎‎fl‎a g4=0‎;‎‎w rite‎_dat(‎'0');‎‎d‎e lay(‎2);‎‎wri‎t e_da‎t('.'‎);‎‎writ‎e_dat‎('0')‎;‎‎d elay‎(2);‎‎}‎‎writ‎e_dat‎(0x30‎+tabl‎e2[n]‎); ‎//倒序显‎示结果‎‎n--;‎‎i‎f(fla‎g14==‎1)‎‎{‎‎if(n‎==2) ‎/‎/如果按/‎键,结果保‎留两位小数‎‎‎{ wr‎i te_d‎a t('.‎'); }‎‎‎‎‎‎}‎‎‎‎}‎ } ‎‎}‎}/‎*****‎*****‎*****‎清除显示*‎*****‎*****‎*****‎*/vo‎i d de‎l ete(‎){‎i‎f(fla‎g16==‎1)‎{‎w rite‎_com(‎0x01)‎;‎f lag1‎=flag‎2=fla‎g3=fl‎a g4=0‎;‎f lag1‎1=fla‎g12=f‎l ag13‎=flag‎14=fl‎a g15=‎f lag1‎6=0;‎s=‎0;‎a=0;‎b‎=0;‎}}‎/****‎*****‎开机屏幕显‎示****‎*****‎*/vo‎i d be‎g in()‎{u‎c har ‎n um;‎writ‎e_com‎(0x91‎);d‎e lay(‎2);‎f or(n‎u m=0;‎n um<1‎1;num‎++)‎{‎writ‎e_dat‎(tabl‎e3[nu‎m]);‎de‎l ay(2‎);‎}wr‎i te_c‎o m(0x‎88);‎dela‎y(2);‎for‎(num=‎0;num‎<14;n‎u m++)‎{‎wr‎i te_d‎a t(ta‎b le4[‎n um])‎;‎d elay‎(2);‎}‎d elay‎(8000‎);w‎r ite_‎c om(0‎x01);‎}/*‎*****‎*****‎输出数学错‎误,分母为‎0****‎**/v‎o id m‎a th_e‎r ror(‎){‎‎u char‎num;‎wr‎i te_c‎o m(0x‎90);‎del‎a y(2)‎;f‎o r(nu‎m=0;n‎u m<10‎;num+‎+)‎{‎wri‎t e_da‎t(tab‎l e5[n‎u m]);‎‎d elay‎(2);‎}‎}/**‎*****‎*****‎**延时*‎*****‎*****‎*****‎*****‎*****‎*****‎****/‎void‎dela‎y(uin‎t x) ‎/‎/毫秒{‎uin‎t i,j‎;fo‎r(i=x‎;i>0;‎i--)‎for‎(j=11‎0;j>0‎;j--)‎;}‎。

51单片机应用程序实例

51单片机应用程序实例
图 9.1 3.系统板上硬件连线 (1. 把“单片机系统”区域中的 P3.7/RD 端口连接到“独立式键盘”区域中的 SP1 端口上; (2. 把“单片机系统”区域中的 P1.0-P1.4 端口用 8 芯排线连接到“八路发光二 极管指示模块”区域中的“L1-L8”端口上;要求,P1.0 连接到 L1,P1.1 连接到 L2,
广告灯的左移右移
1. 实验任务
做单一灯的左移右移,硬件电路如图 4.1 所示,八个发光二极管 L1-L8 分别接在单 片机的 P1.0-P1.7 接口上,输出“0”时,发光二极管亮,开始时 P1.0→P1.1→P1.2→P1.3→┅→P1.7→P1.6→┅→P1.0 亮,重复循环。
2. 电路原理图
图 4.1
每次送出的数据是不同,具体的数据如下表 1 所示
P1.7 P1.6 P1.5 P1.4 P1.3 P1.2 P1.1 L8 L7 L6 L5 L4 L3 L2 1111111 1111110 1111101 1111011
P1.0 L1 0 1 1 1
说明
L1 亮 L2 亮 L3 亮 L4 亮
1110111 1 1101111 1 1011111 1 0111111 1
一键多功能按键识别技术
1.实验任务 如图 9.1 所示,开关 SP1 接在 P3.7/RD 管脚上,在 AT89S51 单片机的 P1 端口接有四 个发光二极管,上电的时候,L1 接在 P1.0 管脚上的发光二极管在闪烁,当每一次按 下开关 SP1 的时候,L2 接在 P1.1 管脚上的发光二极管在闪烁,再按下开关 SP1 的时 候,L3 接在 P1.2 管脚上的发光二极管在闪烁,再按下开关 SP1 的时候,L4 接在 P1.3 管脚上的发光二极管在闪烁,再按下开关 SP1 的时候,又轮到 L1 在闪烁了,如此轮 流下去。 2.电路原理图

矩阵键盘扫描汇编程序

矩阵键盘扫描汇编程序

4*4矩阵键盘扫描汇编程序(基于51单片机)// 程序名称:4-4keyscan.asm;// 程序用途:4*4矩阵键盘扫描检测;// 功能描述:扫描键盘,确定按键值。

程序不支持双键同时按下,;// 如果发生双键同时按下时,程序将只识别其中先扫描的按键;// 程序入口:void;// 程序出口:KEYNAME,包含按键信息、按键有效信息、当前按键状态;//================================================================== ====PROC KEYCHKKEYNAME DATA 40H ;按键名称存储单元;(b7-b5纪录按键状态,b4位为有效位,;b3-b0纪录按键)KEYRTIME DATA 43H ;重复按键时间间隔SIGNAL DATA 50H ;提示信号时间存储单元KEY EQU P3 ;键盘接口(必须完整I/O口) KEYPL EQU P0.6 ;指示灯接口RTIME EQU 30 ;重复按键输入等待时间KEYCHK:;//=============按键检测程序========================================= ====MOV KEY,#0FH ;送扫描信号MOV A,KEY ;读按键状态CJNE A,#0FH,NEXT1 ;ACC<=0FH; CLR C ;Acc等于0FH,则CY为0,无须置0NEXT1:; SETB C ;Acc不等于0FH,则ACC必小于0 FH,;CY为1,无须置1MOV A,KEYNAMEANL KEYNAME,#1FH ;按键名称屏蔽高三位RRC A ;ACC带CY右移一位,纪录当前按键状态ANL A,#0E0H ;屏蔽低五位ORL KEYNAME,A ;保留按键状态;//=============判别按键状态,决定是否执行按键扫描=================== =====CJNE A,#0C0H,NEXT2 ;110按键稳定闭合,调用按键检测子程序SJMP KEYSCANNEXT2:CJNE A,#0E0H,NEXT3 ;111按键长闭合,重复输入允许判断SJMP WAITNEXT3:CJNE A,#0A0H,EXIT ;101干扰,当111长闭合处理ORL KEYNAME,#0E0HWAIT:MOV A,KEYRTIMEJNZ EXIT ;时间没到,退出;//=============键盘扫描程序========================================= =====KEYSCAN:MOV R1,#0 ;初始化列地址MOV R3,#11110111B ;初始化扫描码LOOP:MOV A,R3RL AMOV R3,A ;保留扫描码MOV KEY,A ;送扫描码MOV A,KEY ;读键盘ORL A,#0F0H ;屏蔽高四位CJNE A,#0FFH,NEXT31 ;A不等于FFH,说明该列有按键动作INC R1 ;列地址加1,准备扫描下一列CJNE R1,#4,LOOP ;列地址不等于4,扫描下一列SJMP EXIT ;没有按键,退出;//=============按键判断对应位等于零,说明该行有按键按下============= =====NEXT31:JB ACC.0,NEXT32MOV R2,#0 ;第0行有按键SJMP NEXT5NEXT32:JB ACC.1,NEXT33MOV R2,#1 ;第1行有按键SJMP NEXT5NEXT33:JB ACC.2,NEXT34MOV R2,#2 ;第2行有按键SJMP NEXT5NEXT34:MOV R2,#3 ;第3行有按键NEXT5: ;计算按键地址MOV A,R1RL ARL A ;列地址乘4(每列对应4行)ADD A,R2 ;加行地址MOV DPTR,#KEYTABMOVC A,@A+DPTRANL KEYNAME,#0E0HORL KEYNAME,A ;送按键(送值的时候已经置按键有效)MOV KEYRTIME,#RTIME ;送重复按键等待时间CLR KEYPL ;打开指示灯MOV SIGNAL,#10 ;送信号提示时间(每次按键闪10 0ms)EXIT:MOV KEY,#0FFH ;置键盘接口高电平RET ;退出;//=============按键名称表=========================================== =====KEYTAB:DB 1AH ;扫描码0,对应A ************************************ ******DB 1BH ;扫描码1,对应B ** **DB 1CH ;扫描码2,对应C ** I/O口 PX.4 PX.5 PX.6 PX.7 **DB 1DH ;扫描码3,对应D ** **DB 11H ;扫描码4,对应1 ** PX.0 A(0) 1(4) 2(8) 3 (C) **DB 14H ;扫描码5,对应4 ** **DB 17H ;扫描码6,对应7 ** PX.1 B(1) 4(5) 5(9) 6 (D) **DB 1EH ;扫描码7,对应E ** **DB 12H ;扫描码8,对应2 ** PX.2 C(2) 7(6) 8(A) 9 (E) **DB 15H ;扫描码9,对应5 ** **DB 18H ;扫描码A,对应8 ** PX.3 D(3) E(7) 0(B) F(F) **DB 10H ;扫描码B,对应0 ** **DB 13H ;扫描码C,对应3 ************************************ ******DB 16H ;扫描码D,对应6DB 19H ;扫描码E,对应9DB 1FH ;扫描码F,对应FEND第二种解法ORG 0000HSTART: MOV R0,#00H ;初始化程序,开始的延时是为了使硬件能够准备好DJNZ R0,$LOOP: MOV SP,#60HCALL KEYDISPLAY:MOV A,R4MOV DPTR,#TABLE ;定义字形表的起始地址MOVC A,@A+DPTR ;TABLE为表的起始地址MOV P2,ASJMP LOOP;子程序内容,P1口的低四位为行线,高四位为列线KEY: PUSH PSWPUSH ACCMOV P1,#0F0H ;令所有的行为低电平,全扫描字-P1.0-P1.3,列为输入方式;这一段只是验证有键按下,并不能判断是哪一行MOV R7,#0FFH ;设置计数常数,作为延时KEY1: DJNZ R7, KEY1MOV A,P1 ;读取P1口的列值ANL A,#0F0H ;判别有键值按下吗(当有键按下时,P1口的高四位就不全为1了,底四位还是都为0的);这个地方进行相或的原因,是因为要把底四位的0000变成1111,以便下一步进行求反ORL A,#0FH //这个地方原版上没有,这是又加了,如果不加的的话,是不对的********CPL A ;求反后,有高电平就有键按下JZ EKEY;累加器为0则转移(意为求反后本来全为0的,如果有键按下时,求反后高四位就有1了),退出LCALL DEL20ms ;有键按下,进行处理;下面进行行行扫描,1行1行扫SKEY: MOV A,#00HMOV R0,A ;R0作为行计数器,开始初值为0MOV R1,A ;R1作为列计数器,开始初值为0MOV R2,#0FEH ;R2作为扫描暂存字,开始初值为1111 1110,(第四位作为行扫描字)SKEY2: MOV A,R2MOV P1,A ;输出行扫描字,1111 1110NOPNOPNOP ;3个NOP操作使P1口输出稳定MOV A,P1 ;读列值(和开始一样)MOV R1,A ;暂存列值(第一次为**** 1110,既高四位有一位"可能"会为0)ANL A,#0F0H ;取高四位,ORL A,#0FH ;使第四位全部置1CPL ABIAOZHI:JNZ SKEY3 ;累加器为非0则转移指令(意思是判断到按键在这一行),转去处理INC R0 ;如果按键没在这一行,行计数器加1SETB C ;进位标志位加1,为了在左移的时候开始的低位0不在出现在低(循环一圈后)MOV A,R2RLC A ;带进位左移1位(形成下一行扫描字,再次扫描)MOV R2,AMOV A,R0;把加1后的行计数器R0和总共扫描次数(4次比较)CJNE A,#04H,SKEY2 ;(扫描完了么)书本上这个地方也有错误,书本上写的是:SKEY1AJMP EKEY ;如果没有的话,退出;有键按下后行扫描过后,此为确列行SKEY3: MOV A,R1 ;JNB ACC.4,SKEY5 ;直接寻址位为0咋转移指令JNB ACC.5,SKEY6JNB ACC.6,SKEY7JNB ACC.7,SKEY8AJMP EKEY //我自己感觉到这命令没有用处SKEY5: MOV A,#00H ;存0列号MOV R3,AAJMP DKEYSKEY6: MOV A,#01H ;存1列号MOV R3,AAJMP DKEYSKEY7: MOV A,#02H ;存2列号MOV R3,AAJMP DKEYSKEY8: MOV A,#03H ;存3列号MOV R3,AAJMP DKEY;取出具体的行号,再加上列号,最终确认按键的号码DKEY: //MOV R4,#00HMOV A,R0MOV B,#04HMUL AB ;让行号*4,第四位放在A中(总共就4行,相乘后一定<16,也就是只有第四位有值)ADD A,R3 ;让行号和列号相加,最终确认任按键的具体号MOV R4,AEKEY: POP ACCPOP PSWRET ;按键扫描处理函数DEL20ms:MOV R7,#2DL2: MOV R6,#18DL1: MOV R5,#255DJNZ R5,$DJNZ R6,DL1DJNZ R7,DL2RET;此为共阴极数码管的数字表TABLE: DB 3FH ;0DB 06H ;1DB 5BH ;2DB 4FH ;3DB 66H ;4DB 6DH ;5DB 7DH ;6DB 27H ;7DB 7FH ;8DB 6FH ;9DB 77HDB 7CHDB 39HDB 5EHDB 79HDB 71HEND第三种PIC单片机键盘扫描汇编程序;本程序用于PIC外接键盘的识别,通过汇编程序,使按下K1键时第一个数码管显示1,按下K2键时第一;个数码管上显示2,按下K3键时第一个数码管上显示3,按下K4键时第一个数码管上显示4,;汇编程序对键盘的扫描采用查询方式LIST P=18F458INCLUDE "P18F458.INC";所用的寄存器JIANR EQU 0X20FLAG EQU JIANR+1 ;标志寄存器DEYH EQU JIANR+2DEYL EQU JIANR+3F0 EQU 0 ;FLAG的第0位定义为F0ORG 0X00GOTO MAINORG 0X30;*************以下为键盘码值转换表****************** CONVERT ADDWF PCL,1RETLW 0XC0 ;0,显示段码与具体的硬件连接有关RETLW 0XF9 ;1RETLW 0XA4 ;2RETLW 0XB0 ;3RETLW 0X99 ;4RETLW 0X92 ;5RETLW 0X82 ;6RETLW 0XD8 ;7RETLW 0X80 ;8RETLW 0X90 ;9RETLW 0X88 ;ARETLW 0X83 ;BRETLW 0XC6 ;CRETLW 0XA1 ;DRETLW 0X86 ;ERETLW 0X8E ;FRETLW 0X7F ;"."RETLW 0XBF ;"-"RETLW 0X89 ;HRETLW 0XFF ;DARKRETURN;***************PIC键盘扫描汇编程序初始化子程序***************** INITIALBCF TRISA,5 ;置RA5为输出方式,以输出锁存信号BCF TRISB,1BCF TRISA,3BCF TRISE,0BCF TRISE,1BSF TRISB,4 ;设置与键盘有关的各口的输入输出方式BCF TRISC,5BCF TRISC,3 ;设置SCK与SDO为输出方式BCF INTCON,GIE ;关闭所有中断LW 0XC0WF SSPSTAT ;设置SSPSTAT寄存器LW 0X30WF SSPCON1 ;设置SPI的控制方式,允许SSP方式,并且时钟下降;沿发送数据,与"74HC595当其SCLK从低到高电平;跳变时,串行输入数据(DI)移入寄存器"的特点相对应LW 0X01WF JIANR ;显示值寄存器(复用为键值寄存器)赋初值CLRF FLAG ;清除标志寄存器RETURN ;返回;**************显示子程序*****************DISPLAYCLRF PORTAWF SSPBUFAGAINBTFSS PIR1,SSPIFGOTO AGAINNOPBCF PIR1,SSPIFBSF PORTA,5 ;详细的程序语句请参考 pic教程语句部分,可在首页搜索。

矩阵键盘的键值计算及编程

矩阵键盘的键值计算及编程
P1口低四位是指:P1.3 P1.2 P1.1 P1.0
2 读取I/O口值的练习
.j
用程序控制单片机P2口工作,让高四位全高电平,低四位全低电平。 即:P2=0xf0; 具体实现见操作,结果如图。
P1口高四位是指:P1.7 P1.6 P1.5 P1.4
一般都是自高到低读出一个端口各脚电平 ,得到8位二进制数,再将8位二进制转换成2位十六进数。
P3口值= P3.7 P3.6 P3.5 P3.4P3.3 P3.2 P3.1 P3.0 =1111 1010=0xfa
2 读取I/O口值的练习
.j
当 程序使P2=0x0f; 外接一个两脚开关到P2口只能让P2产生如下四个新的值: 0x0e, 0x0d,0x0b,0x07 0x0d 0x0b
找出行线值 置行线所处端口位置高电平
找出列线值 置列线所处端口位置高电平
行线值+列线值=键值
计算键值一般方法
3 键盘的键值
.j
先找出行线值,再找出列线值,最后绘出矩阵键盘的键值。
总结
4×4矩阵键盘的键值 共有16个,计算键值时总是:
4 键盘扫描编程__线反转法
.j
/************键盘扫子描函数*******************/ char keyscan(void) //键盘扫描函数,键盘使用P2口 { char value_h,value_l; //value_h行值变量,value_l列值变量 P2=0xf0; //将行线所处位置置高电平 if((P2&0xf0)!=0xf0) //判断是否有键按下 { delay(10); //延时防抖 if((P2&0xf0)!=0xf0) //仍有键按下 { value_h=P2&0xf0; //读出P2口值给变量value_h P2=0x0f; //将列线所处位置置高电平 value_l=P2&0x0f; //读出P2口值给变量value_l return(value_l+value_h); //找到的键值返回给调用函数 } } }

51单片机矩阵键盘按键C语言程序

51单片机矩阵键盘按键C语言程序

#include<reg52.h>#define uchar unsigned char#define uint unsigned intucharsmg_du[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x7 1} ;uchar smg_we[]={0x08,0x18,0x28,0x38,0x48,0x58,0x68,0x78} ;//有一篇74HC573必须为高电平//*************************8//12M频率下大约50US延时//**************************void delay_50us(uint t){uchar j;for(;t>0;t--)for(j=19;j>0;j--) ;}void delay_50ms(uint t){uchar j;for(;t>0;t--)for(j=6245;j>0;j--);}/*这个程序可以不用松手检测,因为我们程序首选判断键是否按下然后发现按下后我们延时5MS,然后再检测。

确实是按下啦。

我们再执行在第二个循环假如我们继续检测,那么消耗时间10MS这个短时间中我们的按键已经松手啦。

不会在执行后面的。

*/void main(){uchar key_l,key_h;uchar key;while(1){P3=0xf0; //首先给P3口赋值key_l=P3; //从p3口读一个数据到key_lkey_l=key_l&0xf0;if(key_l!=0xf0) //如果不等于的话,说明有按键按下去{delay_50us(100);//稍微延时一下if(key_l!=0xf0){key_l=P3&0xf0;// 11100000 再读一次P3的值然后和0xf0相与key_l=key_l|0x0f; // 11101111P3=key_l; //在把key_l的值送给P3口//此时P3口的值为11101111,而正在此时我们把键按下啦因此按下的键为11101110与11101111// 相与还是11101110;key_h=P3; //再读一次P3口,键还是按下,可以得到行的值。

基于51单片机音乐盒程序设计

基于51单片机音乐盒程序设计

基于51单片机音乐盒程序设计一、功能设计说明1、电路设计实物图矩阵键盘部分电路图2、运行流程图3、电子琴模式按键对应发音设计按键 发音 按键 发音 K1 低 1 K9 中 2 K2 低 2 K10 中 3 K3 低 3 K11 中 4 K4 低 4 K12 中 5 K5低 5K13中 6程序开始播放小苹果歌曲判断任意按键是否按下继续播放小苹果歌曲否是进入电子琴模式判断K16按键是否按下播放完成是否按键发音按键发音K6 低6 K14 中7K7 低7 K15 高1K8 中1 K16 重新播放小苹果二、硬件电路说明1、程序下载电路音乐盒电路图ISP下载接口本设计采用的单片机为A T89S52单片机,需使用ISP下载器进行下载程序,程序下载电路图如图中ISP1接口.2、音乐发音电路IO口P10发出不同频率的脉冲,则BUZZER产生各种不同的声音,本设计采用12MHZ 晶振,系统频率1MHZ,定时器计数一个1us,其对应关系如下表所示:音符频率(HZ)简谱码(T值)音符频率(HZ) 简谱码(T值)低 1 DO 262 63628 # 4 FA# 740 64860 # 1 DO# 277 63731 中 5 SO 784 64898 低 2 RE 294 63853 # 5 SO# 831 64934 # 2 RE# 311 63928 中 6 LA 880 64968 低 3 M 330 64021 # 6 932 64994 低 4 FA 349 64103 中 7 SI 988 65030 # 4 FA# 370 64185 高 1 DO 1046 65058 低 5 SO 392 64260 # 1 DO# 1109 65085 # 5 SO# 415 64331 高 2 RE 1175 65110 低 6 LA 440 64400 # 2 RE# 1245 65134 # 6 466 64463 高 3 M 1318 65157 低 7 SI 494 64524 高 4 FA 1397 65178中1 DO 523 64580 # 4 FA# 1480 65198# 1 DO# 554 64633 高 5 SO 1568 65217中 2 RE 587 64684 # 5 SO# 1661 65235# 2 RE# 622 64732 高 6 LA 1760 65252中 3 M 659 64777 # 6 1865 65268中 4 FA 698 64820 高 7 SI 1967 65282 计算方法:例如产生262HZ频率(发音DO),周期T=1/262=3816 us,由于定时器中断使IO不停取反,故周期T=3816/2=1908 us 定时器初值N=65536-1908=63628TH0=63628/256TL0=65536%256三、程序代码说明1 、脉冲产生采用定时器0溢出中断产生脉冲,定时器初始化如下:TMOD = 0x01; //定时器0工作方式1 ,即十六位计数器计数TR0 = 1; //启动定时器ET0 = 1; //定时器0溢出中断使能EA = 1; //总中断使能定时器0溢出中断产生脉冲,void Timer0() interrupt 1代码如下:TH0 = th0;TL0 = tl0;if(th0==0)BUZZER=1; //判断停顿,有停顿不发音else{BUZZER = ~BUZZER;} //无停顿发音2、音普规则:a、音普由一个字节十六进制数组成b、高4位代表节拍,一拍约400MS,将一拍分成8份c、低4位代表音符,一一对应Note[]列表d、0x20代表歌曲结束符e、uint code Note[]={0,64580,64684,64777,64820,64898,64968,65030,/*中音*/63628,63853,64021,64103,64260,64400,64524,/*低音*/65058,65110,65157,65178,65217,65252,65282/*高音*/};该列表为发音所对应的定时器初装值例如编写如下一段音乐列表:0x83,0x81,0x82,0x8d,0x43,0x42,0x41,0x42,0x8d,0x8d,0x40 0x40表示停顿4*50MS /*你是我的小呀小苹果*/3、音普列表解读while(Xiaopingguo[temp]!=0x20) //不停判断音乐是否结尾,结尾跳出{jiepai=Xiaopingguo[temp]>>4; //获取节拍,即高4位数yinpu=Xiaopingguo[temp]&0x0F; //获取音普,即低4位数Timer_Set(yinpu); //根据列表对应发音Delay(jiepai*50); //节拍temp++;P0 = 0x0f;if(P0!=0x0f)goto out;}void Timer_Set(uchar num)为定时器0赋值子程序,包含的代码如下:th0=Note[num]/256;tl0=Note[num]%256;四、程序代码编写/**********************************************************************************************项目名称:音乐盒单片机型号:AT89S52频率:外部石英晶振12MHZ设计时间:2014-08-06设计者:小左MCU工作室Q Q: 576689422******************************************************************************* **************/#include<reg52.h>#define uint unsigned int#define uchar unsigned charsbit BUZZER=P1^0;//蜂鸣器输出uchar th0,tl0; //定时器0赋值变量uchar start_; //返回变量uint code Note[]={0,64580,64684,64777,64820,64898,64968,65030,/*中音*/63628,63853,64021,64103,64260,64400,64524,/*低音*/65058,65110,65157,65178,65217,65252,65282/*高音*/};/*************************************************************************音普规则:1、音普由一个字节十六进制数组成2、高4位代表节拍,一拍约400MS,将一拍分成8份3、低4位代表音符,一一对应Note[]列表4、0x20代表歌曲结束符**************************************************************************/uchar code Xiaopingguo[]={0x83,0x81,0x82,0x6d,0x43,0x42,0x41,0x42,0x8d,0x8d,0x40,/*你是我的小呀小苹果*/0x83,0x81,0x82,0x82,0x45,0x43,0x8e,0x81,0x40,/*怎么爱你都不嫌多*/0x41,0x4e,0x8d,0x4e,0x41,0x82,0x8c,0x46,0x45,0x83,0x83,0x43,0x40,/*红红的小脸温暖我的心窝*/0x42,0x81,0x42,0x43,0x42,0x43,0x42,0x23,0x25,0x85,0x30,0x45,0x10,0x45,0x30,0x45,0x10,0x 45,0x30,0x85,0x85,0x85,0x40,/*点亮我生命的火火火火火火*/0x83,0x81,0x82,0x6d,0x43,0x42,0x41,0x42,0x8d,0x8d,0x40,/*你是我的小呀小苹果*/0x83,0x81,0x82,0x82,0x45,0x43,0x8e,0x81,0x40,/*就像天边最美丽的云朵*/0x41,0x4e,0x8d,0x4e,0x41,0x82,0x8c,0x46,0x45,0x83,0x83,0x43,0x40,/*春天又来到了花开满山坡*/0x42,0x81,0x42,0x43,0x82,0x8c,0x8d,0x4d,0x41,0x8d,0x20/*种下希望就会收获*/};//----延时子程序--------------------------------------------------void Delay(uint xms){uint j;for(;xms>0;xms--)for(j=110;j>0;j--);}//---------------------------------------------------------------//----定时器变量赋值--------------------------------------------- void Timer_Set(uchar num){th0=Note[num]/256;tl0=Note[num]%256;}//---------------------------------------------------------------//----系统初始化------------------------------------------------- void Init(){BUZZER = 1; //关闭蜂鸣器TMOD = 0x01; //定时器0工作方式1TR0 = 1; //启动定时器ET0 = 1; //定时器0溢出中断使能EA = 1; //总中断使能start_ = 0; //返回变量初始化}//---------------------------------------------------------------//----按键扫描--------------------------------------------------- void Key_Scan(){P0 = 0x0f;if(P0!=0x0f){Delay(5);if(P0!=0x0f){P0=0xfe;if(P0==0xee){Timer_Set(8);} //按键1被按下else if(P0==0xde){Timer_Set(12);}//按键5被按下else if(P0==0xbe){Timer_Set(2);} //按键9被按下else if(P0==0x7e){Timer_Set(6);} //按键13被按下else;P0=0xfd;if(P0==0xed){Timer_Set(9);} //按键2被按下else if(P0==0xdd){Timer_Set(13);}//按键6被按下else if(P0==0xbd){Timer_Set(3);} //按键10被按下else if(P0==0x7d){Timer_Set(7);} //按键14被按下else;P0=0xfb;if(P0==0xeb){Timer_Set(10);} //按键3被按下else if(P0==0xdb){Timer_Set(14);}//按键7被按下else if(P0==0xbb){Timer_Set(4);} //按键11被按下else if(P0==0x7b){Timer_Set(15);}//按键15被按下else;P0=0xf7;if(P0==0xe7){Timer_Set(11);} //按键4被按下else if(P0==0xd7){Timer_Set(1);} //按键8被按下else if(P0==0xb7){Timer_Set(5);} //按键12被按下else if(P0==0x77){start_=1;} //按键16被按下else;}}else{th0=0;}}//---------------------------------------------------------------//----主程序----------------------------------------------------- void main(){uchar temp,yinpu,jiepai;Init();while(1){start:temp=0;while(Xiaopingguo[temp]!=0x20){jiepai=Xiaopingguo[temp]>>4; //获取节拍yinpu=Xiaopingguo[temp]&0x0F; //获取音普Timer_Set(yinpu);Delay(jiepai*50);temp++;P0 = 0x0f;if(P0!=0x0f)goto out;}out:th0 = 0;BUZZER = 1;//关闭蜂鸣器while(1){Key_Scan();if(start_==1){start_=0;goto start;}}}}//---------------------------------------------------------------//----定时器0中断服务程序----------------------------------------void Timer0() interrupt 1{TH0 = th0;TL0 = tl0;if(th0==0)BUZZER=1; //判断停顿,有停顿不发音else{BUZZER = ~BUZZER;} //无停顿发音}//----------------------------------------------------------------更多精彩程序请在淘宝店铺中搜索“小左MCU”QQ:576689422。

C51单片机矩阵键盘扫描去抖程序

C51单片机矩阵键盘扫描去抖程序

C51单片机矩阵键盘扫描去抖程序最近有一个C51的项目,用的是新华龙的C51 F020单片机。

项目中要实现4*5的矩阵键盘。

矩阵电路图如下如示其中,四条列线接在F020的P2~P5口线上,5条行线接在P5口线上(F020的P5口是不同于普通C51的扩展接口,不能位寻址)。

同时4条列线接在一四输入与非门(74LS20)上,门输出接F020的外中断1,这样,任何一键按下,都会产生中断,通知程序进行键盘扫描。

托一个新手给写了键盘的扫描程序,基本功能都能实现,但对于键盘的去抖处理总是做不好,表现是或者不能去抖,或者按键响应过慢,或者采集到错误键值。

看来新手对于矩阵键盘扫描原理掌握较好(网上资料多),但对于键盘去抖的知识却有所欠缺,基本都是按照书上说的延时一段时间再采集键值,实际应用中,这样的处理是远远不够的,过于简单。

实际去抖处理应该这样进行更合理一些,即连续采集键值,当采集到的键值在一段时间内是相同的,即认为按键状态已稳定,此键值为真实键值。

另外,按键释放时,也会有抖动,导致误采键值,因此在键释放时,也应进行去抖处理,处理方法同时是连续一段时间采集到无键按下状态,才认为按键被释放。

根据这个方法,我重写了新手的程序,实际应用中表现极好。

现将程序公布如下,供新手参考。

Key.h文件内容#ifndef __key_H__#define __key_H__#define NULL_KEY 0x0000#define S1 0x3801#define S2 0x3401#define S3 0x3802#define S4 0x3402#define S5 0x3804#define S6 0x3404#define S7 0x3808#define S8 0x3408#define S9 0x3810#define S10 0x3410#define S11 0x2C01#define S12 0x1C01#define S13 0x2C02#define S14 0x1C02#define S15 0x2C04#define S16 0x1C04#define S17 0x2C08#define S18 0x1C08#define S19 0x2C10#define S20 0x1C10#define KEY_DELAY 20extern unsigned int Key_Value;extern void Init_Key();extern void Scan_Key();extern bit Key_Pressed;extern bit Key_Released;extern unsigned int idata Keypress_Count;extern unsigned int idata Keyrelease_Count;#endifkey.c 文件内容#include <string.h>#include "key.h"bit Key_Down; //是否有键按下的标志unsigned int idata Keypress_Count;sbit Col_Key0 = P2^2;sbit Col_Key1 = P2^3;sbit Col_Key2 = P2^4;sbit Col_Key3 = P2^5;bit Key_Pressed;bit Key_Released;unsigned int Key_Value;bit Key_Down; //是否有键按下的标志unsigned int idata Keypress_Count; //一毫秒增加一次的变量unsigned int idata Keyrelease_Count; //一毫秒增加一次的变量//矩阵键盘使用中断1作为键盘中断void Init_Key(){P5 = 0; //行线全部置为0EX1 = 1; // 允许外部时钟秒中断IT1 = 1; // 外部时钟中断设置为边沿触发}void Key_Int() interrupt 2{Key_Pressed = 1;EX1 = 0;}void Scan_Key(){unsigned char temp,rowvalue;unsigned int key;int i;temp = P2;temp &= 0x3C;if(temp == 0x3C){Key_Released = 0;Key_Pressed = 0;key = NULL_KEY;EX1 = 1;}else{key = temp;key = key<<8;rowvalue = 0x01;for(i=0;i<5;i++){P5 = rowvalue<<i;DelayMs(1);temp = P2;temp &= 0x3C;if(temp == 0x3c){rowvalue = rowvalue<<i;key = key | rowvalue;P5 = 0x00;break;}}P5 = 0x00;DelayMs(1);}if(key!=NULL_KEY) //如果有键按下{if(key==Key_Value) //如果按下的是相同的键{if(Keypress_Count>=KEY_DELAY){Key_Down = 1;}}else if(Key_Down != 1){Keypress_Count=0;Keyrelease_Count = 0;Key_Value=key;}}else //如果无键按下{if(Key_Down) //如果当前是键释放,返回键值{if(Keyrelease_Count >= KEY_DELAY){Key_Down=0;Keypress_Count=0;Keyrelease_Count=0;Key_Released = 1;EX1 = 1;return;}}else{Keypress_Count=0;Keyrelease_Count=0;Key_Value = NULL_KEY;EX1 = 1;return;}}}在main.c中的调用方法为if(Key_Pressed == 1){//Key_Pressed = 0;Scan_Key();}if(Key_Released == 1){Key_Released = 0;Ack_Key();}其中Ack_Key()函数为具体的键盘响应程序,就不列出了。

单片机 矩阵键盘实验 实验报告

单片机 矩阵键盘实验 实验报告

实验五矩阵键盘实验一、实验内容1、编写程序,做到在键盘上每按一个数字键(0-F)用发光二极管将该代码显示出来。

按其它键退出。

2、加法设计计算器,实验板上有12个按键,编写程序,实现一位整数加法运算功能。

可定义“A”键为“+”键,“B”键为“=”键。

二、实验目的1、学习独立式按键的查询识别方法。

2、非编码矩阵键盘的行反转法识别方法。

三、实验说明1、MCS51系列单片机的P0~P3口作为输入端口使用时必须先向端口写入“1”。

2、用查询方式检测按键时,要加入延时(通常采用软件延时10~20mS)以消除抖动。

3、识别键的闭合,通常采用行扫描法和行反转法。

行扫描法是使键盘上某一行线为低电平,而其余行接高电平,然后读取列值,如读列值中某位为低电平,表明有键按下,否则扫描下一行,直到扫完所有行。

行反转法识别闭合键时,要将行线接一并行口,先让它工作在输出方式,将列线也接到一个并行口,先让它工作于输入方式,程序使CPU通过输出端口在各行线上全部送低电平,然后读入列线值,如此时有某键被按下,则必定会使某一列线值为0。

然后,程序对两个并行端口进行方式设置,使行线工作于输入方式,列线工作于输出方式,并将刚才读得的列线值从列线所接的并行端口输出,再读取行线上输入值,那么,在闭合键所在行线上的值必定为0。

这样,当一个键被接下时,必定可以读得一对唯一的行线值和列线值。

由于51单片机的并口能够动态地改变输入输出方式,因此,矩阵键盘采用行反转法识别最为简便。

行反转法识别按键的过程是:首先,将4个行线作为输出,将其全部置0,4个列线作为输入,将其全部置1,也就是向P1口写入0xF0;假如此时没有人按键,从P1口读出的值应仍为0xF0;假如此时1、4、7、0四个键中有一个键被按下,则P1.6被拉低,从P1口读出的值为0xB0;为了确定是这四个键中哪一个被按下,可将刚才从P1口读出的数的低四位置1后再写入P1口,即将0xBF写入P1口,使P1.6为低,其余均为高,若此时被按下的键是“4”,则P1.1被拉低,从P1口读出的值为0xBE;这样,当只有一个键被按下时,每一个键只有唯一的反转码,事先为12个键的反转码建一个表,通过查表就可知道是哪个键被按下了。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
相关文档
最新文档