南山企业网站建设,自己做的网站 网站备案流程,电子工程网单片机,广告发布包括哪些51单片机之按键和数码管 ✍前言#xff1a;♐独立按键#x1f600;独立按键的原理#x1f600;软件实现按键控制LED灯的亮灭 ♐数码管#x1f60a;数码管显示数字或者字母的原理#x1f409;共阳极数码管#x1f409;共阴极极数码管#x1f409;4位1体数码管 #x1f6… 51单片机之按键和数码管 ✍前言♐独立按键独立按键的原理软件实现按键控制LED灯的亮灭 ♐数码管数码管显示数字或者字母的原理共阳极数码管共阴极极数码管4位1体数码管 静态数码管动态数码管动态数码管的原理延时的目的消影处理 ♐矩阵键盘️使用矩阵键盘控制数码管显示0~f ⭕总结 ✍前言
在学习了如何使用51单片机控制LED之后我们进一步来学习使用按键来控制LED。
♐独立按键
独立按键的原理
下图是我们普中单片机开发板A2的独立按键原理图 可以看到之所以称之为独立按键是因为每个按键单独占用一个I/O口。 默认的情况我们的P31口由于有上拉电阻会输出一个高电平当按下按键K1后P31那条支路回导通此时P31会输出低电平看下面这张图片它是51单片机的准双向IO口内部图可以帮助你更好的理解上面那段话 红色的框就是一个IO口当按键没有按下回路是一条断路由于有VCC和上拉电阻的存在会输出高电平但是当按键按下按键回路导通电压为0所以输出一个低电平。这里提一嘴单片机IO口输出的是电压。
通过软件编程判断与该按键对应的IO口的电平情况我们就可以完成一些功能。
软件实现按键控制LED灯的亮灭
先上代码
#includereg52.h
typedef unsigned int u16;
typedef unsigned char u8;sbit k1 P3^1;//设置按键K1对应的单片机IO口
sbit LED P2^0;void delay(u16 i)
{while(i--);
}
void key_scan()//按键扫描
{if(0 k1){delay(1000);//消抖10msif(0 k1){LED ~LED;}while(!k1); }
}void main()
{while(1){key_scan();}
}实验效果演示 由于按键按下的时候由于机械具有一定的弹性它不会马上按下去松开也是不会马上松开而是会有5~10ms的抖动。 上述程序是传统的消抖方法存在占用cpu过多的问题如果小伙伴有兴趣可以去学习一些更加优的消抖程序。
♐数码管
数码管显示数字或者字母的原理 我的开发板是八段的数码管8段数码管是由字母a,b,c,d,e,f,g,dp八段组成的数码管它比七段数码管多了一段也就是小数点dp8段对应8个LED想要显示相应的字母或者数字让相应的LED亮就可以了我们主要介绍一下8段数码管。 8段数码管按照这8个LED共同接的是阴极还是阳极又分为共阴数码管和共阳数码管下面我们来借助原理图具体的介绍一下他们两个它们显示不同的数字或者字符的段码该字符或者数字的二进制代码。
共阳极数码管 阳极就是正极共阳极意思就是标号a~dp的各个并联的支路是有一个共同的阳极如果你希望某个位置亮就应该给对应IO口输出低电平。 下面我们给出对应的段码以0来举例子 理解了0的共阳极16进制码其它的想必小伙伴们也能自己写出来下面我们给出0~f的段码 共阴极极数码管 共阴和共阳对应a~dp有一个共同的阴极。 我们以1为例子给出1的段码推导 0~f的共阴段码表为 4位1体数码管
我的开发板刚好就是共阴的这是它的原理图 红色的数字是网络标号相同代表连在一起。
我们的板子的数码管采用的是4个数码管封装在一起的模式简称四位一体如果用正常的方式来控制它们就需要8个IO口这太占用资源了我们单片机一共就只有32个IO口这里我们的板子用到了74138芯片这种芯片使用3个IO口就可以控制8个IO口。
4位一体中的8段数码管共用共同的a~dp由P00~P07控制其值我们通过改变P0改变码值。 通过上图我们可以得到这个74138由单片机的P22、P23、P24三个IO口控制通过控制这三个IO口的值我们就可以控制哪个位置的数码管点亮这是它的真值表 A2是高位A0是低位这个74138芯片还有E1、E2、E3三个引脚其中E1、E2上面有一个非的符号表示低电平有效E3表示高电平有效如果没有正确设置E1、E2、E3我们的输出LED1~LED8都是高电平数码管是不会工作的因为LED1~LED8实际上是数码管的阴极它和它控制的数码管的a~dp位置都是并联的每一个位置的LED方向已经确定指向阴极发光二极管的特性正向导通反向截止。但是说了这么多E1、E2、E3都不用我们设置板子在制的时候已经就接好了。
要怎么控制这个位码呢A2A1A0是二进制数它们十进制的值为iYi就为高电平取反就是它的输出为低电平。与LEDi1相连的数码管会显示对应的值。
上面的知识我们在软件编程里会用到的通过给74HC138的A0~A3管脚对应的IO口赋值控制哪一个位点亮然后通过给P0赋段码值控制点亮的内容。
静态数码管 程序实现的功能让最后一个数码管显示数字1 #include reg52.h // 引入 8051 单片机的头文件typedef unsigned int u16; // 定义无符号整型变量 u16
typedef unsigned char u8; // 定义无符号字符型变量 u8sbit LSA P2^2; // 定义 P2^2 引脚为 LSA
sbit LSB P2^3; // 定义 P2^3 引脚为 LSB
sbit LSC P2^4; // 定义 P2^4 引脚为 LSCu8 code smgduan[] { 0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};// 数码管段码数据表0~fu8 code Digital_tube_number[][3] {{0,0,0},{1,0,0},{0,1,0},{1,1,0},{0,0,1},{1,0,1},{0,1,1},{1,1,1}}; // 位码数据表// 数码管动态显示函数
void Dynamic_digital_tube(u8 wei,u8 duan)
{//设置数字或者字母显示的位置LSA Digital_tube_number[wei][0];LSB Digital_tube_number[wei][0];LSC Digital_tube_number[wei][0];P0 smgduan[duan];//设置P0为相应的段码值显示该数字或字母
}int main()
{while(1) // 主循环{Dynamic_digital_tube(0,1); // 调用动态数码管显示函数}return 0; // 返回 0表示正常结束
}效果演示 这段代码相信大家很容易看懂就是先设置位码再设置段码。
动态数码管 程序实现的功能让前面的几个数码管同时显示数字5201314 动态数码管的原理
相信大家会有疑惑明明74LS138一次只能输出一个位置为低电平如何让不同的位置同时显示数字呢其实这和之前我们LED不能正常闪烁的原理是一样的利用了人眼只能看到50HZ左右的变化太快了人眼是无法观测到的也就是说实际上是依次点亮的但是对于我们的眼睛来说就好像同时显示一样由于数码管点亮的位置一直在变所以又叫做动态数码管。
#include reg52.h // 引入 8051 单片机的头文件typedef unsigned int u16; // 定义无符号整型变量 u16
typedef unsigned char u8; // 定义无符号字符型变量 u8sbit LSA P2^2; // 定义 P2^2 引脚为 LSA
sbit LSB P2^3; // 定义 P2^3 引脚为 LSB
sbit LSC P2^4; // 定义 P2^4 引脚为 LSCu8 code smgduan[] {0x06,0x4f,0x06,0x66,0x6d,0x5b,0x3f}; // 数码管段码数据表1314520
u8 code Digital_tube_number[][3] {{0,0,0},{1,0,0},{0,1,0},{1,1,0},{0,0,1},{1,0,1},{0,1,1},{1,1,1}}; // 位码数据表// 延时函数参数 i1 为延时时间
void delay(u16 i1)
{while(i1--); // 空循环实现延时
}// 数码管动态显示函数
void Dynamic_digital_tube()
{u8 i;for(i 7; i 1; --i) // 从 7 到 1 循环{LSA Digital_tube_number[i][0]; // 设置 LSA 引脚的状态LSB Digital_tube_number[i][1]; // 设置 LSB 引脚的状态LSC Digital_tube_number[i][2]; // 设置 LSC 引脚的状态P0 smgduan[7-i]; // 在数码管显示对应的段码数据delay(100); // 延时 1000微秒1msP0 0x00; // 关闭所有段熄灭数码管}
}int main()
{while(1) // 主循环{Dynamic_digital_tube(); // 调用动态数码管显示函数}return 0; // 返回 0表示正常结束
}效果演示 动态数码管模块的几个关键的解释
延时的目的
细心的小伙伴可能会发现在我们的Dynamic_digital_tube函数中在设置位选和段选之后我们延时了1ms可能你不理解为什么要这样去做我们删除这个延时语句看效果 可以看到数字明显变暗了可能原因是你程序执行的太快了理想的二极管还没有稳定的导通就已经将段码清零了。
注意不能延时的太长否则数码管依次点亮的过程我们的眼睛就能察觉到了。
消影处理 我们动态扫描程序执行的顺序是设置位码-设置段码-设置位码-设置段码。 如果在执行一次之后不把段码清0都设置为低电平让其什么都不显示设置新的位码后由于程序执行到设置新的段码需要一定的时间新的数码管会显示之前的段码对应的数字就会出现重影。
不消影的效果 可以看到重影的情况还是非常严重所以一个位置显示之后必须把段码设置为0x00也就是让数码管什么都不显示。
♐矩阵键盘 有时候我们想使用很多按键但是没有那么多IO口这个时候就需要使用矩阵按键它的1行或者一列的按键只需要一个IO口来控制。 通常一个键盘是由两个IO口控制的行和列一个IO口控制一行或者列。所以一个矩阵键盘有多少个键是由IO口决定的即控制行的IO口 ∗ * ∗控制列的IO口。 我们的原理图就是采用的四行四列的模式。
那么问题来了我们该如何判断是否有按键按下呢我们以S1为例来解释一下 ️使用矩阵键盘控制数码管显示0~f 我们的程序是一行一行的点击按键依次显示0~f你也可以按照一列一列的来点击按键依次显示0~F更改一下keyValue值就可以。 #include reg52.h // 包含 8051 单片机的寄存器定义文件typedef unsigned int u16; // 定义无符号 16 位整数类型
typedef unsigned char u8; // 定义无符号 8 位整数类型sbit LSA P2^2; // 数码管位选引脚
sbit LSB P2^3; // 数码管位选引脚
sbit LSC P2^4; // 数码管位选引脚#define GPIO_DIG P0 // 数码管的数据端口
#define GPIO_KEY P1 // 按键的端口u8 KeyValue 16; // 按键值初始化为 16用于标识未按下任何按键
u8 code smgduan[] {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71}; // 数码管显示的数值对应的段码void delay(u16 i1) {while (i1--); // 延时函数
}// 检测按键函数
void KeyDown() {u8 a 0;GPIO_KEY 0x0f; // 设置高四位为低电平用于检测按键if (GPIO_KEY ! 0x0f) { // 如果按键有按下delay(1000); // 延时10msGPIO_KEY 0x0f; // 再次设置高四位为低电平用于检测按键的列位置if (GPIO_KEY ! 0x0f) {switch (GPIO_KEY) {case (0x07): KeyValue 0; break;case (0x0b): KeyValue 1; break;case (0x0d): KeyValue 2; break;case (0x0e): KeyValue 3; break;}}GPIO_KEY 0xf0; // 设置低四位为低电平用于检测按键的行位置if (GPIO_KEY ! 0x0f) {switch (GPIO_KEY) {case (0x70): KeyValue 0; break;case (0xb0): KeyValue 4; break;case (0xd0): KeyValue 8; break;case (0xe0): KeyValue 12; break;}}while (a 50 GPIO_KEY ! 0xf0) { // 延时和检测按键松开delay(1000);a;}}
}void main() {LSA 0;LSB 0;LSC 0;GPIO_DIG 0x00; // 初始化数码管和端口while (1) {KeyDown(); // 调用按键检测函数if (KeyValue 0 KeyValue 15) // 检测按键值范围GPIO_DIG smgduan[KeyValue]; // 在数码管显示按键对应的数字}
}演示效果 如果你希望一列一列的点击显示0~F程序可以这样改
#include reg52.h // 包含 8051 单片机的寄存器定义文件typedef unsigned int u16; // 定义无符号 16 位整数类型
typedef unsigned char u8; // 定义无符号 8 位整数类型sbit LSA P2^2; // 数码管位选引脚
sbit LSB P2^3; // 数码管位选引脚
sbit LSC P2^4; // 数码管位选引脚#define GPIO_DIG P0 // 数码管的数据端口
#define GPIO_KEY P1 // 按键的端口u8 KeyValue 16; // 按键值初始化为 16用于标识未按下任何按键
u8 code smgduan[] {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71}; // 数码管显示的数值对应的段码void delay(u16 i1) {while (i1--); // 延时函数
}// 检测按键函数
void KeyDown() {u8 a 0;GPIO_KEY 0x0f; // 设置高四位为低电平用于检测按键if (GPIO_KEY ! 0x0f) { // 如果按键有按下delay(1000); // 延时10msGPIO_KEY 0x0f; // 再次设置高四位为低电平用于检测列if (GPIO_KEY ! 0x0f) {KeyValue 0;//先初始化一下KeyValueswitch (GPIO_KEY) {case (0x07): KeyValue 0; break;case (0x0b): KeyValue 4; break;case (0x0d): KeyValue 8; break;case (0x0e): KeyValue 12; break;}}GPIO_KEY 0xf0; // 设置低四位为低电平用于检测行if (GPIO_KEY ! 0x0f) {switch (GPIO_KEY) {case (0x70): KeyValue 0; break;case (0xb0): KeyValue 1; break;case (0xd0): KeyValue 2; break;case (0xe0): KeyValue 3; break;}}while (a 50 GPIO_KEY ! 0xf0) { // 检测按键松开delay(1000);a;}}
}void main() {LSA 0;LSB 0;LSC 0;GPIO_DIG 0x00; // 初始化数码管和端口while (1) {KeyDown(); // 调用按键检测函数if (KeyValue 0 KeyValue 15) // 检测按键值范围GPIO_DIG smgduan[KeyValue]; // 在数码管显示按键对应的数字}
}效果演示 最后提一嘴软件里给矩阵键盘的IO口设置合适的值可以将其一行或者一列当成独立按键来使用哦判断方法也和独立按键判断的方法相似。
⭕总结
本篇博客主要讲了按键和数码管的相关知识下面是关于它的思维导图欢迎大家提出建议和指出不足指出谢谢希望本篇博客对小伙伴有所帮助。