法做简单计算器　2021-04-17　09:41:35　　80C　51单片机　逐行　扫描　法的　实现　+简易计算器的功能　实现　。其中keyscan函数是逐行　扫描　函数,act是功能函数。　正在学习郭天祥《　51单片机　C语言教程(第2版)》第4章,　键盘　检测原理。矩阵　键盘　检测部分的代码又长又啰嗦,所以修改了下。　权当个记录。　问题描述:　在实验板TX-1C上　实现　如下描述,实验板上电时,数码管不显示,顺序...　正在学习郭天祥《51单片机C语言教程(第2版)》第4章,键盘检测原理。矩阵键盘检测部分的代码又长又啰嗦,所以修改了下。　权当个记录。　问题描述:　在实验板TX-1C上实现如下描述,实验板上电时,数码管不显示,顺序按下矩阵键盘后,在数码管上依次显示0-F,6个数码管同时静态显示即可。　当前代码实现的是:按键按下后,数码管亮起;手放下,不按,数码管关闭不亮。　尤其说明,只有按键状态变化时,才会重新扫描,数码管的亮灭状态才会变化,而不是连续重复扫描,数码管持续高速亮灭变化。　矩阵键盘扫描方法有两种,书中采用的是　逐行扫描　。　在此尝试用　行列扫描:学习板上,行连接的是P3的低4位,列连接的是P3的高4位。所以,当P3口高4位输出高电平,低4位输出低电平,若这4行按键里有按键按下了,那么那一列对应的I/O电平就会拉低,我们就可知道按键的列坐标。类似地,高4位输出低电平,低4位输出高电平,可以得到按键的行坐标。　(上面一段话引用自文章《矩阵键盘的原理及应用》,链接:　link　.其中因为按键的接线不同,而有些说法不同。　)　代码如下:　#include　<　reg52　.　h　>　sbit　dula　=　P2　^　6　;　sbit　wela　=　P2　^　7　;　unsigned　char　code　table　[　]　=　{　0x3f　,　0x06　,　0x5b　,　0x4f　,　0x66　,　0x6d　,　0x7d　,　0x07　,　0x7f　,　0x6f　,　0x77　,　0x7c　,　0x39　,　0x5e　,　0x79　,　0x71　}　;　int　delayms　(　unsigned　int　)　;　int　LED_on　(　unsigned　int　P0we　,　unsigned　int　P0du　)　;　unsigned　int　matrixkeyscn　(　)　;　int　main　(　void　)　{　unsigned　int　num　,　num0　=　16　,　temp　;　while　(　1　)　{　num　=　matrixkeyscn　(　)　;　if　(　num　!=　num0　)　//　按键状态有变,则(才)需要操作　{　if　(　num　<　16　)　//　按了不同的按键　{　LED_on　(　0xc0　,　table　[　num　点亮对应的数码管　P3　=　0x0f　;　temp　=　P3　;　while　(　temp　!=　0x0f　)　//　等放开按键　{　temp　=　P3　;　}　}　else　//　先前按了,现在不按了　{　LED_on　(　0xc0　,　0x00　)　;　//　关闭数码管　P3　=　0x0f　;　temp　=　P3　;　while　(　temp　==　0x0f　)　//　等再按下按键　{　temp　=　P3　;　}　}　num0　=　num　;　}　}　return　0　;　}　unsigned　int　matrixkeyscn　(　)　//　键盘阵列,行列扫描　{　unsigned　char　temp　;　unsigned　int　hang　,　lie　,　key　=　16　;　P3　=　0x0f　;　temp　=　P3　;　if　(　temp　!=　0x0f　)　{　delayms　(　10　)　;　//　去抖延时　P3　=　0x0f　;　temp　=　P3　;　if　(　temp　!=　0x0f　)　{　P3　=　0x0f　;　temp　=　P3　;　switch　(　temp　)　{　case　0x0e　:　hang　=　1　;　break　;　case　0x0d　:　hang　=　2　;　break　;　case　0x0b　:　hang　=　3　;　break　;　case　0x07　:　hang　=　4　;　break　;　}　P3　=　0xf0　;　temp　=　P3　;　switch　(　temp　)　{　case　0xe0　:　lie　=　1　;　break　;　case　0xd0　:　lie　=　2　;　break　;　case　0xb0　:　lie　=　3　;　break　;　case　0x70　:　lie　=　4　;　break　;　}　key　=　(　hang　-　1　)　*　4　+　lie　-　1　;　}　}　return　key　;　}　int　LED_on　(　unsigned　int　P0we　,　unsigned　int　P0du　)　{　wela　=　1　;　P0　=　P0we　;　wela　=　0　;　P0　=　0xff　;　//　消影　dula　=　1　;　P0　=　P0du　;　dula　=　0　;　return　0　;　}　int　delayms　(　unsigned　int　xms　)　{　unsigned　int　i　,　j　;　for　(　i　=　0　;　i　<　xms　;　i　++　)　for　(　j　=　0　;　j　<　110　;　j　++　)　;　return　0　;　}　首次涉及　51单片机　矩阵　键盘扫描　的新手　采用线　扫描　的方式　实现键盘　识别,所采用　键盘　为4*4　矩阵　键盘　在MCS　51单片机　上　实现键盘扫描　,并控制LCD显示的程序.　包含线反转法和　扫描　法两种矩阵　键盘的实现　,含proteus仿真原理图及完整代码,可运行　实现　C51　单片机　矩阵　键盘扫描　去抖程序　 　最近有一个C51的项目,用的是新华龙的C51　F020　单片机　。项目中要　实现　4*5的矩阵　键盘　。矩阵电路图如下如示　 　其中,四条列线接在F020的P2~P5口线上,5条行线接在P5口线上...　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　20　extern　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;　#endif 　key.c 　文件内容　#include　#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;　//行线全部置为0　EX1　=　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<=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;span　style="font-family:　'Times　New　Roman';　font-size:　14px;　background-color:　rgb(255,　255,　255);"> 　在main.c　中的调用方法为　if(Key_Pressed　==　1)　{　//Key_Pressed　=　0;　Scan_Key();　}　if(Key_Released　==　1)　{　Key_Released　=　0;　Ack_Key();　}　其中　Ack_Key()　函数为具体的键盘响应程序,就不列出了。　我在另外使用　Arm9　的项目中,　linux　底层扫描键盘的驱动中,也使用了这种去抖方法,同样表现良好。　以　键盘的　某个角作为坐标原点建立平面直角坐标系,如下图(图为我设计计算器的矩阵键盘),从而,矩阵　键盘的　思路就是,给x方向(水平方向)赋值为1,y方向(竖直方向)赋值为0,不断　扫描　判断x方向是否有等于0的,若判断到...　Author:　Manba　Cople　专业:IOT　说明:记录和输出学习内容　文章目录　前言　介绍写矩阵键盘的一种思路和具体实现代码　思路　以键盘的某个角作为坐标原点建立平面直角坐标系,如下图(图为我设计计算器的矩阵键盘),从而,矩阵键盘的思路就是,给x方向(水平方向)　赋值为1,y方向(竖直方向)赋值为0,不断扫描判断x方向是否有等于0的,若判断到某行为0就说明该行有按键按下,因为,当有按键按下时,　按键导通,y方向的0就给了x方向;由于矩阵键盘是二维的,还需要判断按键的列号才能确定一个按键的位置,判断列,首先给x方向复制为0,y方向赋值为1,不断扫描,当有按键按下时,x方向的0,就会导通给y方向,从而确定按键的(x,y)。另外,关于矩阵键盘的扫描,可以在主程序中实现,也可以用利用定时器做。　具体代码　unsigned　char　keyvalue　=　0　;　bit　keyflag　=　0　;　//0无按键按下,1有按键按下　void　MatrixKey　(　)　{　unsigned　char　ky　=　0　,　kx　=　0　,　i　,　j　;　if　(　keyflag　==　0　)　//没有按键按下执行扫描程序　{　P3　=　0x0f　;　for　(　i　=　0　;　i　<　4　;　i　++　)　{　if　(　(　P3　&　(　0x01　<<　i　0x01　<<　i　)　)　//通过for+移位运算不断的判断是否有0值出现　ky　=　i　+　1　;　}　P3　=　0xf0　;　for　(　j　=　0　;　j　<　4　;　j　++　)　{　if　(　(　P3　&　(　0x10　<<　j　0x10　<<　j　)　)　kx　=　j　+　1　;　}　}　if　(　kx　==　0　)　//排除没有按键按下就计算键值　{　keyflag　=　0　;　}　else　//有按键按下　{　keyvalue　=　kx　+　4　*　(　ky　-　1　)　;　//计算键值　keyflag　=　1　;　//标志位置1　}　}　总结　利用坐标系的思想实现矩阵键盘思路较为清晰,另外,代码利用循环+移位运算降低了代码量。继续优化的话,在于按键消抖的问题。　矩阵　键盘　采用行和列　扫描　的方式进行判断那个按键被按下了　先进行　扫描　或先进行列　扫描　都可以　行　扫描　的时候,先将行所在的引脚置一,列所在的引脚置0,然后判断行所在引脚的电平的值,随后进行列　扫描　8×8点阵　8×8...　欢迎关注公众号,获取更多信息　一.　实验所需模块　4×4矩阵键盘,8×8点阵,定时器0　二.　模块简介　4×4矩阵键盘　矩阵键盘采用行和列扫描的方式进行判断那个按键被按下了　先进行扫描或先进行列扫描都可以　行扫描的时候,先将行所在的引脚置一,列所在的引脚置0,然后判断行所在引脚的电平的值,随后进行列扫描　8×8点阵　8×8点阵共由64个发光二极管组成,且每个发光二极管是放置在行线和列线的交叉点上。　当某一行置1,某一列置0时,对应的二极管就会点亮。　与动态数码类似,利用视觉残留效果,即可实现动态依次点亮的效果　定时器0　16位定时器由高8位和低8位的两个寄存器组成TH0和TL0。　每来一个脉冲,定时器的值就会加一,当达到最大的时候,就会溢出清零,并产生中断信号。　预先设置TH0和TL0的值,可以得到我们所需的生产中断信号的间隔。　三.　点亮一个灯　这个很简单,就是把某一行线置1,并且把某一列线置0,其他的行线全部为0,列线全部为1.　void　Led　(　u8　dat　,　u8　dat2　)　//dat为行线值,dat2为列线值　{　u16　i　;　RCLKS　=　1　;　SRCLK　=　1　;　for　(　i　=　0　;　i　<　8　;　i　行线的输入是由74HC595模块输入的,　//通过时钟的上升沿把每一位的数据输入即可,高位优先　SET　=　dat　>>　7　;　dat　=　dat　<<　1　;　SRCLK　=　0　;　SRCLK　=　1　;　}　RCLKS　=　0　;　RCLKS　=　1　;　P0　=　dat2　;　//列线由P0端口输入　}　这里令dat　=　0x20,dat2=fb的时候,一个发光二极管就被点亮啦!　四.　一个灯的移动　前面我们已经知道了,行线可以控制那一行亮那一行不亮,列线也同样如此。　假设当我们的列线不变,行线左移一位或者右移一位,是不是我们的灯向上或者向下移动了一个!　行线不变时,列线的移动同样如此,但是要注意,列线是为0点亮,每一次左移或右移,低位或高位就会多出来一个0,这时,我们还需要加上0x01或者0x80以消掉这个多出来的0　1.向上移动　列线不变,行线左移一位即可　if　(　Rows　[　0　]　!=　0x80　)　//防止移过头了　Rows　[　0　]　<<=　1　;　2.向下移动　列线不变,行线右移一位即可　if　(　Rows　[　0　]　!=　0x01　)　Rows　[　0　]　>>=　1　;　3.向左移动　行线不变,列线左移一位加0x01即可　if　(　Cols　[　0　]　!=　0x7F　)　{　Cols　[　0　]　<<=　1　;　Cols　[　0　]　+　=　1　;　}　向右移动　行线不变,列线右移一位加0x80即可　if　(　Cols　[　0　]　!=　0xFE　)　{　Cols　[　0　]　>>=　1　;　Cols　[　0　]　+　=　0x80　;　}　自此,一个灯的上下左右的移动我们已经完成了,接下来蛇的移动了　五.　贪吃蛇　认真看玩过贪吃蛇的朋友应该都清楚,蛇身是随着蛇头的移动而移动的。其中不难发现。　当前蛇的某一节的位置是它前面一节蛇的上一个状态的位置　,知道了这个规律之后,我们就可以很方便地更新蛇的状态了。　由于8×8点阵显示有限,我就只设置了蛇的最大长度为5,防止闪烁。　1.蛇的存储　这里我采取的是数组的方式,存储每一节的行线值和列线值　u8　Rows　[　5　]　;　//行线值　u8　Cols　[　5　]　;　//列线值　2.蛇的更新　前面说过,蛇的当前蛇的某一节的位置是它前面一节蛇的上一个状态的位置,也就是说,Rows[n-1]　=　Rows[n],Cols[n-1]　=　Cols[n]当然这里的Rows[n],和Cols[n]是上一个状态的值了　void　Up　(　u8　len　)　//当前蛇的长度　{　u8　i　;　u8　tmp　=　Rows　[　0　]　;　u8　rr　,　cc_1　,　cc_2　;　if　(　Rows　[　0　]　!=　0x80　)　Rows　[　0　]　<<=　1　;　cc_1　=　Cols　[　0　]　;　//后一节依次等于前一节的上一个状态的值　for　(　i　=　1　;　i　<　len　;　i　++　)　{　rr　=　Rows　[　i　]　;　//　保存上一个状态　Rows　[　i　]　=　tmp　;　//Rows[i]为当前状态　tmp　=　rr　;　cc_2　=　Cols　[　i　]　;　//　保存上一个状态　Cols　[　i　]　=　cc_1　;　cc_1　=　cc_2　;　}　}　这里就只拿了向上移动的代码作为参考,其他方向的移动类型,基本上一样,这里蛇的移动也完成了。　3.食物　食物的行线与列线同样用两个变量存储食物的位置是随机的,这里我们用rand产生随机数并对8求余数,这样就得到了0-7的随机数,然后对0x01进行相应的左移,就得到了选定的行,取反就得到了选定的列。　Food_col　=　~　(　0x01　<<　rand　(　)　%　8　)　;　Food_row　=　0x01　<<　rand　(　)　%　8　;　4.吃到食物　这也是很好办的事,只需要判断蛇头的Row和Col是否等于食物的Row和Col,如果相等,则更新食物的位置,蛇身加一.　if　(　(　Rows　[　0　]　==　Food_row　)　&&　(　Cols　[　0　]　==　Food_col　)　)　//　判断是否吃到食物　{　if　(　len　<　5　)　//判断蛇长是否达到最大值　{　Rows　[　len　]　=　Rows　[　len　-　1　]　;　Cols　[　len　]　=　Cols　[　len　-　1　]　;　len　随机更新食物的位置　Food_col　=　~　(　0x01　<<　rand　(　)　%　8　)　;　Food_row　=　0x01　<<　rand　(　)　%　8　;　}　自此,贪吃蛇可以说已经基本完成了,剩下的就是用键盘来控制蛇的移动方向了　六.　蛇方向的控制　方向的控制我把它放在中断里面,这样可以解决如下问题　如果不用延迟,蛇移动得太快,根本看不清楚蛇的移动。　如果用延迟来控制蛇移动的速度,那么键盘的读取就会变动不灵敏,　要按下许久之后,才能读取,游戏效果不好。　因此我决定把它放在定时器中断中,通过设定初值,以极小的时间差,来读取键盘的内容,即可达到实时的效果,而且延时对这个完全没有干扰。　void　Time_0　(　)　interrupt　1　{　u8　key　;　key　=　KEY　(　)　;　if　(　key　!=　-　1　)　{　if　(　key　==　1　)　{　//Up(len);　direct　=　0　;　delay　(　10000　)　;　//　不用也没有关系,不会造成影响　}　if　(　key　==　9　)　{　//Down(len);　direct　=　1　;　delay　(　10000　)　;　}　if　(　key　==　4　)　{　//Left(len);　direct　=　2　;　delay　(　10000　)　;　}　if　(　key　==　6　)　{　//Right(len);　direct　=　3　;　delay　(　10000　防止p过大　if　(　p　>　8　*　100　)　p　=　0　;　p　++　;　//每8次移动一下,这是合理的,由于每一次的时间差极小　//8次加起来的时间差也是非常小的,　//该时间差小于先后按下两个不同方向的时间差,因为这是合理的　if　(　p　%　8　==　0　)　{　switch　(　direct　)　{　case　0　:　Up　(　len　)　;　break　;　case　1　:　Down　(　len　)　;　break　;　case　2　:　Left　(　len　)　;　break　;　case　3　:　Right　(　len　)　;　break　;　}　}　TH0　=　0x0c　;　TL0　=　0x0c　;　}　七.　最后就是main函数啦　这部分也是非常简单的。　void　main　(　)　{　u8　i　;　//u8　len　=　1;　//　初始化长度,这个放到全局变量中了　u8　Food_row　=　0x20　;　u8　Food_col　=　0xfb　;　//u8　direct　=　0;//　初始化方向,这个放到全局变量中了　Rows　[　0　]　=　Row　;　//初始化,蛇头的位置　Cols　[　0　]　=　Col　;　Init_time_0　(　)　;　//配置定时器0,开启中断　while　(　1　)　{　//判断蛇头是否到达食物的位置　if　(　(　Rows　[　0　]　==　Food_row　)　&&　(　Cols　[　0　]　==　Food_col　)　)　{　if　(　len　<　5　)　{　Rows　[　len　]　=　Rows　[　len　-　1　]　;　Cols　[　len　]　=　Cols　[　len　-　1　]　;　len　随机更新食物的位置　Food_col　=　~　(　0x01　<<　rand　(　)　%　8　)　;　Food_row　=　0x01　<<　rand　(　)　%　8　;　}　Led　(　Food_row　,　Food_col　)　;　//显示食物　for　(　i　=　0　;　i　<　len　;　i　++　)　Led　(　Rows　[　i　]　,　Cols　[　i　显示蛇　//这里用延时来控制速度的话,容易产生闪烁。　}　}　至此贪吃蛇就完成啦!!!!　完整代码如下　#　include　　typedef　unsigned　int　u16　;　typedef　unsigned　char　u8　;　sbit　RCLKS　=　P3　^　5　;　sbit　SRCLK　=　P3　^　6　;　sbit　SET　=　P3　^　4　;　//Row为1亮,Col为0亮u8　Row　=　0x08　;　u8　Col　=　0xF7　;　//最大长度为5　,防止过长出现闪烁　u8　Rows　[　5　]　;　u8　Cols　[　5　]　;　u8　len　=　1　;　u8　direct　=　0　;　u16　p　=　0　;　//每8次中断检测一次　void　Init_time_0　(　)　{　TMOD　=　0x01　;　TH0　=　0x0c　;　TL0　=　0x0c　;　ET0　=　1　;　EA　=　1　;　TR0　=　1　;　}　void　delay　(　u16　i　)　{　while　(　i　void　Led　(　u8　dat　,　u8　dat2　)　{　u16　i　;　RCLKS　=　1　;　SRCLK　=　1　;　for　(　i　=　0　;　i　<　8　;　i　++　)　{　SET　=　dat　>>　7　;　dat　=　dat　<<　1　;　SRCLK　=　0　;　SRCLK　=　1　;　}　RCLKS　=　0　;　RCLKS　=　1　;　P0　=　dat2　;　}　u16　KEY　(　)　{　u16　key　=　-　1　;　P1　=　0x0f　;　if　(　P1　!=　0x0f　)　{　delay　(　500　)　;　if　(　P1　!=　0x0f　)　{　P1　=　0x0f　;　switch　(　P1　)　{　case　(　0x07　)　:　key　=　0　;　break　;　case　(　0x0b　)　:　key　=　1　;　break　;　case　(　0x0d　)　:　key　=　2　;　break　;　case　(　0x0e　)　:　key　=　3　;　break　;　}　P1　=　0xf0　;　switch　(　P1　)　{　case　(　0x70　)　:　key　+　=　0　;　break　;　case　(　0xb0　)　:　key　+　=　4　;　break　;　case　(　0xd0　)　:　key　+　=　8　;　break　;　case　(　0xe0　)　:　key　+　=　12　;　break　;　}　}　}　return　key　;　}　void　Up　(　u8　len　)　{　u8　i　;　u8　tmp　=　Rows　[　0　]　;　u8　rr　,　cc_1　,　cc_2　;　if　(　Rows　[　0　]　!=　0x80　)　Rows　[　0　]　<<=　1　;　cc_1　=　Cols　[　0　]　;　//后一节依次等于前一节的值　for　(　i　=　1　;　i　<　len　;　i　++　)　{　rr　=　Rows　[　i　]　;　Rows　[　i　]　=　tmp　;　tmp　=　rr　;　cc_2　=　Cols　[　i　]　;　Cols　[　i　]　=　cc_1　;　cc_1　=　cc_2　;　}　}　void　Down　(　u8　len　)　{　u8　i　;　u8　tmp　=　Rows　[　0　]　;　u8　rr　,　cc_1　,　cc_2　;　if　(　Rows　[　0　]　!=　0x01　)　Rows　[　0　]　>>=　1　;　cc_1　=　Cols　[　0　]　;　for　(　i　=　1　;　i　<　len　;　i　++　)　{　rr　=　Rows　[　i　]　;　Rows　[　i　]　=　tmp　;　tmp　=　rr　;　cc_2　=　Cols　[　i　]　;　Cols　[　i　]　=　cc_1　;　cc_1　=　cc_2　;　}　}　void　Left　(　u8　len　)　{　u8　i　;　u8　tmp　=　Cols　[　0　]　;　u8　cc　,　rr_1　,　rr_2　;　if　(　Cols　[　0　]　!=　0x7F　)　{　Cols　[　0　]　<<=　1　;　Cols　[　0　]　+　=　1　;　}　rr_1　=　Rows　[　0　]　;　for　(　i　=　1　;　i　<　len　;　i　++　)　{　cc　=　Cols　[　i　]　;　Cols　[　i　]　=　tmp　;　tmp　=　cc　;　rr_2　=　Rows　[　i　]　;　Rows　[　i　]　=　rr_1　;　rr_1　=　rr_2　;　}　}　void　Right　(　u8　len　)　{　u8　i　;　u8　tmp　=　Cols　[　0　]　;　u8　cc　,　rr_1　,　rr_2　;　if　(　Cols　[　0　]　!=　0xFE　)　{　Cols　[　0　]　>>=　1　;　Cols　[　0　]　+　=　0x80　;　}　rr_1　=　Rows　[　0　]　;　for　(　i　=　1　;　i　<　len　;　i　++　)　{　cc　=　Cols　[　i　]　;　Cols　[　i　]　=　tmp　;　tmp　=　cc　;　rr_2　=　Rows　[　i　]　;　Rows　[　i　]　=　rr_1　;　rr_1　=　rr_2　;　}　}　void　main　(　)　{　u8　i　;　u16　key　;　//u8　len　=　1;　u8　Food_row　=　0x20　;　u8　Food_col　=　0xfb　;　//u8　direct　=　0;　Rows　[　0　]　=　Row　;　Cols　[　0　]　=　Col　;　Init_time_0　(　)　;　while　(　1　)　{　//　key　=　KEY();　//　if(key　!=　-1)if(key　==　1)Up(len)direct　=　0;　//　delay(20000)if(key　==　9)Down(len);　//　//direct　=　1;　//　delay(20000)if(key　==　4)Left(len);　//　//direct　=　2;　//　delay(20000)if(key　==　6)Right(len);　//　//direct　=　3;　//　delay(20000)switch(direct)case　0:　Up(len);break;　//　case　1:　Down(len);break;　//　case　2:　Left(len);break;　//　case　3:　Right(len);break;判断蛇头是否到达食物的位置　if　(　(　Rows　[　0　]　==　Food_row　)　&&　(　Cols　[　0　]　==　Food_col　)　)　{　if　(　len　<　5　)　{　Rows　[　len　]　=　Rows　[　len　-　1　]　;　Cols　[　len　]　=　Cols　[　len　-　1　]　;　len　随机更新食物的位置　Food_col　=　~　(　0x01　<<　rand　(　)　%　8　)　;　Food_row　=　0x01　<<　rand　(　)　%　8　;　}　Led　(　Food_row　,　Food_col　)　;　for　(　i　=　0　;　i　<　len　;　i　++　)　Led　(　Rows　[　i　]　,　Cols　[　i　void　Time_0　(　)　interrupt　1　{　u8　key　;　key　=　KEY　(　)　;　if　(　key　!=　-　1　)　{　if　(　key　==　1　)　{　//Up(len);　direct　=　0　;　delay　(　10000　)　;　}　if　(　key　==　9　)　{　//Down(len);　direct　=　1　;　delay　(　10000　)　;　}　if　(　key　==　4　)　{　//Left(len);　direct　=　2　;　delay　(　10000　)　;　}　if　(　key　==　6　)　{　//Right(len);　direct　=　3　;　delay　(　10000　防止p过大　if　(　p　>　8　*　100　)　p　=　0　;　p　++　;　if　(　p　%　8　==　0　)　{　switch　(　direct　)　{　case　0　:　Up　(　len　)　;　break　;　case　1　:　Down　(　len　)　;　break　;　case　2　:　Left　(　len　)　;　break　;　case　3　:　Right　(　len　)　;　break　;　}　}　TH0　=　0x0c　;　TL0　=　0x0c　;　}　Thank　for　your　reading　!!!　用89C　51单片机　的I/O口　实现　非编码行列式　键盘的　功能。　2.学习掌握系统中8255扩展键盘显示接口的工作原理和编程的方法。　二.　实验内容:　掌握行列式　键盘的　设计应用　三.　实验要求:　1.　行列式键盘接口的编程方法,用89C...　在上篇文章【　51单片机　】〈C语言+Keil5+Proteus仿真〉矩阵键盘逐行　扫描　法-20210414中,提到了矩阵　键盘的　线反转法,但是在仿真上出现了一些问题,导致没能做出来。当时都已经开始怀疑自己,课本上的虽然是汇编写的代码...　采用s51　实现扫描键盘　键盘输入,然后数码管显示按下的键。其中的芯片是74HC595　.　当有按键按下时,将其键值显示出来,同时有...要求P1口使用灌电流方式驱动一位共阳型7段数码管,P2口则以行列　扫描　的方法连接16个按键,为了能在有按键按下时发出声音提示,使用P0.0引脚通过NPN三极管驱动一个蜂鸣器。　用　单片机实现　数字时钟,关于时间显示,是用的1602液晶,C51单片机,然后再加一个定时器,每到一秒就动态的更新一下液晶的时间显示,在更新的时候也要计算相应的分针和时针的变化,还要注意边界问题.为了能够达到一个最好的...　单片机　的　键盘扫描　c语言程序,以及proteus仿真的　实现　本例子是应用模块化编程的思想　将几个模块连接在一起来　实现　键盘ps/2协议的　扫描　,按下　键盘的　键以后,用1602显示出键值,例如,按下A会显示A,　最重要的是本例子给了初学者一个　学习模块化编程的模版!!!　能做计算器的单片机　...它主要由　51单片机　的数码管,　键盘　等模块组成。本计算器是将　键盘　输入信息经处理通过缓存,送入数码管显示,数码管采用动态　扫描　方式,计算功能通过软件　实现　,用C语言对单片机可编芯片进行编程...　本计算器是以MCS-　51单片机　控制,　实现　对4*4　键盘扫描　进行实时的按键检测,并由LCD1602显示屏将过程与结果显示出来。　我们知道,在拨号是,每拨一位数字,前边拨的数字就要向左挪一位,我们可以用一个一位数组,通过移动数组中数字的移动和8位数码管的动态　扫描　来　实现　位置的移动。　代码如下:　#include　"reg52.h"　//此...　导读:本方案中所设计的温度控制器,采用AT89C　51单片机　作为内核,采用DS18B20作为温度传感器,通过四位LED显示,通过循环　扫描实现　了两路温度的采集与显示。　1.引言　目前,温度控制器存在的问题是如何缩减成本...　在Proteus仿真环境下搭建了L298N直流电机驱动电路、矩阵　键盘扫描　电路以及LCD12864显示电路。　实现　了直流电机的启动、加速、正转、反转、制动等功能。同时,采用PID控制算法可　实现　电机速度在特定的场合　实现　自动切换。　目标是　实现　根据矩阵　键盘　输入内容显示对应的数字(0到f),如按下S1->S8会显示0->7八个数字,在上述情况下按下S9后会显示1->8八位数,再按下S10后会显示2->9;按S16清除数码管显示内容;　出现问题:当八位数码管都有...　导读:本方案中所设计的温度控制器,采用AT89C　51单片机　作为内核,采用DS18B20作为温度传感器,通过四位LED显示,通过循环　扫描实现　了两路温度的采集与显示。　1.引言　目前,温度控制器存在的问题是如何缩减成本...　利用　51单片机实现　65535以内的加减乘除　…………内含　扫描键盘的　pcb和全电路仿真　上讲介绍并应用了　单片机　动态　扫描　驱动数码管,并给出了实例。这一讲将重点介绍　单片机　如何通过捕获来　实现　对红外遥控器解码。通过该讲,读者可以掌握红外遥控器的编码原理以及如何通过　单片机　对遥控器进行解码。　二...　本次设计就是设计一款万年历,以AT89S52　单片机　为核心,配备数码管显示模块、按键等功能模块。分别采用A/D转换器TLC1549和温度...软件用汇编语言来　实现　,主要包括主程序、　键盘扫描　子程序、时间设置子程序等软件模块。　并显示计时状态和结果　,软件代码采用C语言编写程序,包括显示程序,初始化子程序,　键盘扫描　程序,中断服务程序,延时子程序等,并在keil中调试运行,硬件系统利用　单片机　电路板强大的功能来　实现　,操作简单且视觉效果...　介绍了PS/2协议及PS/2标准　键盘的　第2套　扫描　码和命令集,给出了在　单片机　系统中支持PS/2　键盘的　硬件连接方式以及利用Ke订C51语言　实现　的驱动程序设计和部分代码。驱动程序在　单片机　系统中　实现　了对PS/2标准104　键盘的　支持;...　云龙　51单片机　视频教程,目前国内公认的最好的入门视频教程　云龙　51单片机　视频教程如果觉得好,请回复支持一下,让更多人看到,谢谢!　目前国内公认的最好的视频教程,通俗易懂,容易上手,非常适合初学者,被大量的...