IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 单片机学习笔记(2) -> 正文阅读

[嵌入式]单片机学习笔记(2)

一.动态数码管

1.数码管介绍

  • 我的单片机上的显示器是液晶LED,液晶LED显示器可以分为:段显示(7段)和点阵(8*8)
  • 数码管静态显示是段显示,也就是7段加一个点,看上去像一个8字(如图)
  • 1-F的显示数字就根据图中a-g发光二极管的亮来调节;比如要1亮,那就b、c二极管发光,也就是1100 0000,转为16进制就是P0=0xf9

2.数码管静态显示原理

  • 静态显示:必须选择一个8位数据线来保持显示的字码形;输入的字码会一直保持到下一次再输入字码为止。
  • 动态显示:

  1. 动态驱动是将所有数码管的8个显示笔划"a,b,c,d,e,f,g,dp"的同名端连在一起,当单片机输出字形码时,所有数码管都接收到相同的字形码,但究竟是那个数码管会显示出字形,取决于单片机对位选通COM端电路的控制,所以我们只要将需要显示的数码管的选通控制打开,该位就显示出字形,没有选通的数码管就不会亮。通过分时轮流控制各个数码管的的COM端,就使各个数码管轮流受控显示,这就是动态驱动。在轮流显示过程中,每位数码管的点亮时间为1~2ms,由于人的视觉暂留现象及发光二极管的余辉效应,尽管实际上各位数码管并非同时点亮,但只要扫描的速度足够快,给人的印象就是一组稳定的显示数据,不会有闪烁感,动态显示的效果和静态显示是一样的,只不过动态显示的要比静态显示的暗,所以电流限制要比静态的电流大,也就是电阻阻值要比较大。(段选:P0口扫描 ,和9个LED是相接的;位选:8个共阳的的位的扫描,链接38译码器)

3.静态数码管模块电路

  • 8个电阻(排阻)作用:限流,防止二极管因为电流过大而被击穿
  • 每个段显示的8个二极管都是共阳的,要使某一个数码管显示某一个数字就要看下是那个二极管亮(P0口为1),然后转化为16进制令其等于P0

4.74HC138芯片

? ? ? ??

? ?

  • 这个输入把它当做二进制然后转化为十进制Y0-Y7(对应1-8个数码管)?;例如:100就是2,输出就是Y2,那就是第二个数码管输出。
  • 上边的A0、A1、A2对应下边原理图的A、B、C

5.代码

先位选确定哪一个数码管亮,再位选,确定亮的那个数码管要显示什么值

#include<reg52.h>

sbit LSA=P2^2;   //3转8输入确定哪一个灯亮
sbit LSB=P2^3;
sbit LSC=P2^4;

char code smgduan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
			0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//显示0~F的值,这个可以用软件直接转化

void delay(u16 i)
{
	while(i--);	
}

void Display()
{
	u8 i;
	for(i=0;i<8;i++)
	{
		switch(i)	 //位选,选择点亮的数码管,
		{
		   case(0):
				LSA=1;LSB=1;LSC=1; break;//显示第0位
			case(1):
				LSA=0;LSB=1;LSC=1; break;//显示第1位
			case(2):
				LSA=1;LSB=0;LSC=1; break;//显示第2位
			case(3):	
				LSA=0;LSB=0;LSC=1; break;//显示第3位
			case(4):
				LSA=1;LSB=1;LSC=0; break;//显示第4位
			case(5):
				LSA=0;LSB=1;LSC=0; break;//显示第5位
			case(6):
				LSA=1;LSB=0;LSC=0; break;//显示第6位
			case(7):
				LSA=0;LSB=0;LSC=0; break;//显示第7位	
		}
		P0=smgduan[i];//段选,发送段码
		delay(100); //间隔一段时间扫描	
		P0=0x00;//消隐
	}
}

void main()
{	
	while(1)
	{	
		Display();  //数码管显示函数	
	}		
}

二.矩阵按键

1.矩阵按键介绍

独立按键有4个占了4个 IO口,然而单片机也就只有8个IO口,如果有16个按键,那IO口就不够用了,所以就有了矩阵按键,利用8个IO口实现16个矩阵按键。

2.矩阵按键原理

行列扫描:高四位(P14-17)全部输出高电频,低四位(P10-13)全部输出低电频,当由按键按下的时候,低四位不全为低电频,然后通过接受的数值来判断那一列有按键按下;然后反过来高四位(P14-17)全部输出低电频,低四位(P10-13)全部输出高电频,然后通过接受的数值来判断那一行有按键按下;这样就确定了哪一个按键有按下。

3.代码

#include "reg52.h"	

#define GPIO_DIG P0
#define GPIO_KEY P1

char KeyValue;	//用来存放读取到的键值

void KeyDown(void)
{
	char a=0;
	GPIO_KEY=0x0f;//0000 1111
	if(GPIO_KEY!=0x0f)//读取按键是否按下
	{
		delay(1000);//延时10ms进行消抖
		if(GPIO_KEY!=0x0f)//再次检测键盘是否按下
		{	
			//测试列
			GPIO_KEY=0X0F;
			switch(GPIO_KEY)
			{
				case(0X07):	KeyValue=0;break;//0000 0111
				case(0X0b):	KeyValue=1;break;//0000 1011
				case(0X0d): KeyValue=2;break;//0000 1101
				case(0X0e):	KeyValue=3;break;//0000 1110
			}
			//测试行
			GPIO_KEY=0XF0;
			switch(GPIO_KEY)
			{
				case(0X70):	KeyValue=KeyValue;break;
				case(0Xb0):	KeyValue=KeyValue+4;break;
				case(0Xd0): KeyValue=KeyValue+8;break;
				case(0Xe0):	KeyValue=KeyValue+12;break;
			}
			
		}
	}
	while((a<50)&&(GPIO_KEY!=0xf0))	 //检测按键松手检测
	{
		delay(100);
		a++;
	}
}

三.作业

  • 【任务】

? ? ?1.按下独立按键1,特殊流水(此功能具体请看演示视频)
? ? ?2.按下独立按键2,数码管显示 7777 7777,再按数码管均灭(第三次按,再显示7777 7777)
? ? ?3.按下矩阵按键1,蜂鸣器响,第二次按,以第2种声音响,第三次按,以第3种声音响,(第四? ? ? ? ? ?次按,回到第一种声音)
? ? ?4.按下矩阵按键2,LED特殊闪烁(此功能具体请看演示视频)
? ? ?5.各个按键均可多次使用

  • ?? ?【思路】

?? ? ? ?1.解决独立按键和矩阵--用存放值来解决
?? ??? ?2.解决两个特殊流水灯--直接对P0口进行赋值即可
?? ??? ?3.解决数码管显示问题--因为显示的数值都一样,所以直接放松段码0x07即可
?? ??? ?4.三次不同的蜂鸣器响声--利用逻辑值判断进行筛选然后赋予键值即可

  • ?? ?【问题】

1. 延迟函数的改进,使得按键更为灵敏,但是由于for循环太快,不可能等到按键按下,所以不能转化

/*本来这里的延迟如果改为下边这个的话,那么反应会更加灵敏,
?? ??? ?但是for循环在几毫秒内已经运行完了,它不会再执行里面按键检测函数
?? ??? ?然后又不能在几秒内按下按键,所以他就不能够执行这个按键检测函数
?? ??? ?然后你按一下的话就没有效果
?? ??for(n=0;n<1000;n++) ?//改进:上边直接用delay延迟的话,可能按下按键的时候,它还在延迟中
?? ??? ??? ?{? ? ? ? ? ? ? ? ? ? ? ? ?//所以设置了每10ms就进行一次判断的程序,是功能切换更为灵敏
?? ??? ??? ? PD_DLkeyDown();?
? ? ? ? ? ? ?PD_JZKeyDown();?? ?
? ? ? ? ? ? ?if(k!=1) return;
?? ??? ??? ? delay(10);
?? ??? ??? ?}
?2. 矩阵按键的问题描述:按下矩阵按键2,执行的是3的程序,按下两次矩阵按键1,并不会执行1_2的程序
? 矩阵按键的问题分析:在逻辑值的判断上出现问题或者单片机硬件有问题(因为之前按键1、2是相反的

矩阵按键的问题解决:*/

#include<reg52.h>
#include<intrins.h>

#define led P2
#define GPIO_DIG P0  //矩阵按键
#define GPIO_KEY P1

sbit k1=P3^1;//定义独立按键的串口
sbit k2=P3^0;

sbit beep=P1^5;  //定义蜂鸣器

sbit LSA=P2^2;//定义数码管显示的3-8口
sbit LSB=P2^3;
sbit LSC=P2^4;

char key;	//用来存放矩阵按键读取到的键值
char k;//用于存放独立按键和矩阵按键的值,并进行判断

char code smgduan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
					0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//显示0~F的值

/******************************延迟函数*******************************************/
void delay(int i)
{
	while(i--);	
}

/*************************判断是否有独立按键的按下**********************************/
void PD_DLkeyDown()
{
	if(k1==0)		  //检测按键K1是否按下
	{	
		delay(1000);   //消除抖动 一般大约10ms
		if(k1==0)	 //再次判断按键是否按下
		{
				k=1;
		}
		while(!k1);	 //检测按键是否松开
	}	
  if(k2==0)		  //检测按键K1是否按下
	{	
		delay(1000);   //消除抖动 一般大约10ms
		if(k2==0)	 //再次判断按键是否按下
		{
				k=2;
		}
		while(!k2);	 //检测按键是否松开
	}			
}

/*************************判断是否有矩阵按键的按下**********************************/
//这里的独立按键只用到1和2,所以只需要测试第一行和第一二列
//矩阵按键1按下,返回key值3;2按下的话,key的值返回4
//由于我的单片机的按键1、2是相反的,所以等下我的键值也会是相反的
void PD_JZKeyDown()
{
	/*判断矩阵按键*/
		GPIO_KEY = 0x0f;       //  0000 1111
		if(GPIO_KEY!=0x0f)			//按键按下,有电位的变化			
		{
			switch(GPIO_KEY)
			{
				case 0x07:key = 3; break;	//第一列   0000 0111
				case 0x0b: k = 4 ; break;  	//第二列   0000 1011
			}
			if(key==3)
			{
			   if(k!=3&&k!=5)
					   k=3;
				   if(k==3)
					   k=5;
				   if(k==5)
					   k=6;
			}
			while(GPIO_KEY!=0x0f);//检测按键松开
			delay(1000);
		}
	}

/****************************按下独立按键1后执行的内容*****************************/
  void  DLkey_1()
{
  //int n;
	while(1)
	{
       led=0x7f;         //1111 1110
	     delay(50000);
		/*本来这里的延迟如果改为下边这个的话,那么反应会更加灵敏,
		但是for循环在几毫秒内已经运行完了,它不会再执行里面按键检测函数
		然后又不能在几秒内按下按键,所以他就不能够执行这个按键检测函数
		然后你按一下的话就没有效果
			 for(n=0;n<1000;n++)  //改进:上边直接用delay延迟的话,可能按下按键的时候,它还在延迟中
			{                       //所以设置了每10ms就进行一次判断的程序,是功能切换更为灵敏
		   PD_DLkeyDown(); 
		   PD_JZKeyDown();	
		   if(k!=1) return;
			delay(10);
			}
		*/
		   led=0xfe;
		   delay(50000);
		   PD_DLkeyDown(); 
		   PD_JZKeyDown();	
		   if(k!=1) return;
		   led=0xbf;
		   delay(50000);
		   PD_DLkeyDown(); 
		   PD_JZKeyDown();	
		   if(k!=1) return;
		   led=0xfd;         //1111 1110
	       delay(50000);
		   PD_DLkeyDown(); 
		   PD_JZKeyDown();	
		   if(k!=1) return;
		   led=0xdf;
		   delay(50000);
		   PD_DLkeyDown(); 
		   PD_JZKeyDown();	
		   if(k!=1) return;
		   led=0xfb;
		   delay(50000);
		   PD_DLkeyDown(); 
		   PD_JZKeyDown();	
		   if(k!=1) return;
		   led=0xef;
		   delay(50000);
		   PD_DLkeyDown(); 
		   PD_JZKeyDown();	
		   if(k!=1) return;
		   led=0xf7;
		   delay(50000);
		   PD_DLkeyDown(); 
		   PD_JZKeyDown();	
		   if(k!=1) return;
 }
}

/************************按下独立按键二后执行的内容*******************************/
void DLkey_2()
{
	char i;
	while(1)
	{
	for(i=0;i<8;i++)
	{
		switch(i)	 //位选,选择点亮的数码管,
		{
		   case(0):
				LSA=1;LSB=1;LSC=1; break;//显示第0位
			case(1):
				LSA=0;LSB=1;LSC=1; break;//显示第1位
			case(2):
				LSA=1;LSB=0;LSC=1; break;//显示第2位
			case(3):	
				LSA=0;LSB=0;LSC=1; break;//显示第3位
			case(4):
				LSA=1;LSB=1;LSC=0; break;//显示第4位
			case(5):
				LSA=0;LSB=1;LSC=0; break;//显示第5位
			case(6):
				LSA=1;LSB=0;LSC=0; break;//显示第6位
			case(7):
				LSA=0;LSB=0;LSC=0; break;//显示第7位	
		}
		P0=smgduan[7];//发送段码,显示7
		delay(100); //间隔一段时间扫描	
		P0=0x00;//消隐
	}
	  PD_DLkeyDown(); 
		PD_JZKeyDown();	
		if(k!=2) return;
 }
}

/************************按下矩阵按键一后执行的内容*******************************/
void JZkey2()
{
  while(1)
	{
	  led=0xaa;
		delay(50000);
		PD_DLkeyDown(); 
		PD_JZKeyDown();	
		if(k!=3) return;
		led=0x55;
		delay(50000);
		PD_DLkeyDown(); 
		PD_JZKeyDown();	
		if(k!=3) return;
	}
}

/************************按下矩阵按键二后执行的内容*******************************/
/*         第一次按下矩阵按键2              */
void JZkey_1_1()
{
    beep = ~beep;
	delay(10);
	PD_DLkeyDown(); 
	PD_JZKeyDown();	
	if(k!=4) return;
}
/*         第二次按下矩阵按键2               */
void JZkey_1_2()
{
    beep =~beep;
	delay(500);
	PD_DLkeyDown(); 
	PD_JZKeyDown();	
	if(k!=5) return;
}
/*         第二次按下矩阵按键2               */
void JZkey_1_3()
{
    beep =~beep;
	delay(1000);
	PD_DLkeyDown(); 
	PD_JZKeyDown();	
	if(k!=6) return;
}
/******************************主函数*******************************************/
void main()
{	

	while(1)
	{	
		PD_DLkeyDown(); //判断独立按键是否有按下
		PD_JZKeyDown();	//判断矩阵按键是否有按下
	
		switch(k)
		{
			case 1:
				     DLkey_1(); break;
			case 2:
				     DLkey_2();break;
			case 3:
				     JZkey_1_1();break;
			case 4:
			         JZkey2();break;
			case 5:
				     JZkey_1_2();break;
			case 6:
				     JZkey_1_3();break;
			
		}
		
	}		
}

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-08-11 12:35:13  更:2021-08-11 12:35:47 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/13 10:57:23-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码