国信长天单片机之led、数码管与按键

       

目录

一、LED模块

二、数码管模块

三、按键模块 

四、相关代码

config.h文件

config.c文件

main.c文件


         在蓝桥杯单片机比赛中,LED灯、数码管、按键这三个模块的重要性我就不明说了,总而言之,这三个模块都成该比赛的家常便饭了。下面就让小编带大家看看这三个模块吧!

一、LED模块

        国信长天单片机一共有8个LED灯,是一组连接着一块74HC573芯片的共阳LED灯。(原理图如下)

        这也就是说,每个LED灯是低电平有效(也就是0有效),因此,我们向我们需要点亮的LED灯引脚输入一个低电平就可点亮。又因为74HC573芯片的输出是等于输入的,因此我们只需要将P0的所有引脚全部至1即可关闭所有的LED灯;

二、数码管模块

        在讲述国信长天单片机8个数码管之前,我们先来看看八段数码管的构造:

        八段数码管有两种不同的形式:一种是八个发光二极管的阳极都连在一起的,称之为共阳极八段数码管;另一种是八个发光二极管的阴极都连在一起的,称之为共阴极八段数码管。国信长天单片机使用的就是一个共阳的八段数码管。这也就是说,我们想要那一段点亮直接至0就好,那么我们就可以有:

共阳极数码管码段表
字符码段值
00xc0
10xf9
20xa4
30xb0
40x99
50x92
60x82
70xf8
80x80
90x90
-0xBF
熄灭0xFF

        那么,现在我们回到我们的单片机数码管来,这显然是一个数码管组合,而且他们的段选引脚(a,b,c,……g,dp)全部是接在一起的,但位选引脚(com1-com8)是分开的。由此,只要让选择不同的数码管位选,再给予数码管的段选就能够使得数码管显示不同或相同的数据。

        既然如此,那又是如何做到数码管的动态刷新的呢?

        数码管的动态刷新,其本质就是以较快的速度对数码管的每一位数据进行刷新,因为在这个速度下,我们肉眼是看不到数码管一次次的刷新,因此我们我们就能够看到他们是同时稳定刷新的。

        接下来就让小编带大家看看小编自己数码管刷新思路吧:

        小编使用的是定时器定时刷新。定时器定时刷新的好处是:在写程序时,不用再考虑延时、刷新顺序等因素,也不用担心数码管刷新时会不会因频率过大或过小导致数码管刷新时出现闪烁或有重影;

        具体刷新的思路是,每次刷新时,首先使整个数码管都熄灭(消影),再分别进行段选与位选,最后再移动数码管的位选到下一个位置。

三、按键模块 

        国信长天单片机的按键分为两种,即矩阵按键(S4-S19)与独立按键(S4-S7),具体分布可见下图,这两者区别一是矩阵按键有16个,而独立按键只有4个;区别二是矩阵按键使用行列扫描法查找按键是否按下,而独立按键可以直接使用switch判断。

       

        当按键被按下的时候,电路导通接地,I/0口为低电平;当按键未被下时,电路断开,I/0口保持高电平的。但一般的按键所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。因而在闭合及断开的瞬间均伴随有一连串的抖动,假如不加以处理,会导致按键被识别为按下多次。如下面这个按键按下的波形图:

        为了不产生这种现象而作的措施就是按键消抖,下面就有一些常用的按键消抖措施:
                方法A:使用延时。  即,检测出键闭合后执行一个延时程序,让前沿抖动消失后再一次检测按键的状态,如果仍保持闭合状态电平,则确认为真正有键按下。
                方法B:检测多次。即,可以设定一个检测周期,如果在一个检测周期内,按键被检测为被按下达到了一定次数,则确认为真正被按下。

        但是小编这里使用的就是状态机消抖,即定义三个状态,分别是按键按下状态、按键有效按下状态,按键弹起状态,相关转态装换如下图:

四、相关代码

config.h文件

#include "intrins.h"
#include "STC15F2K60S2.H"

#ifndef _CONFIG_H
#define _CONFIG_H

#define kbd_io P3
#define state_0 0	  //是否按下
#define state_1 1 	  //是否是抖动
#define state_2 2	  //判断是否弹起
#define kbd_maskrow 0x0f	  //屏蔽不需要的IO
#define u8 unsigned char
#define u16 unsigned int

sbit relay=P0^4;//
sbit buzzer=P0^6;//蜂鸣器的引脚
//以下三个变量虽然是全局变量,但是实际上定义的地方不在此处,编译时需要查找定义的地方
extern unsigned int key_num;//按键的数值
extern unsigned int segbuff[];//可以控制数码管显示的位置
extern unsigned int segtab[];//数码管显示的数字
extern unsigned int ledtab[];//led的位置

void Delay1us0();
void delay_us0(unsigned int us);
void scanbtn();//独立按键函数
void scankbd();//矩阵按键函数
void segs(void);//数码管新时函数
void SysInit(unsigned char x);//初始化,关闭LED,数码管段选位选,蜂鸣器,还可以控制蜂鸣器是否工作
void LED_Select(unsigned char n);//LED选择函数

#endif

config.c文件

//包括矩阵按键函数、独立按键函数、数码管显示函数、LED显示函数、初始化函数
#include "config.h"

//以下定义全部都是全局变量
unsigned int key_num=16;//有按键的位置得到的数值

//数码管显示位置        管1 管2 管3 管4 管5 管6 管7 管8
unsigned int segbuff[]={10, 10, 10, 10, 10, 10, 10, 10};//可以相当于数码管的位选

// 显示数值            0     1    2   3    4    5    6    7    8    9    -    熄灭 
unsigned int segtab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xBF,0xFF,//共阳数码管段选带数值显示
//显示  0.   1.   2.   3.   4.   5.   6.   7.   8.   9.   -    熄灭
       0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0xBF,0xFF};//带小数点显示

//led显示位置            全灭 L1   L2   L3   L4   L5   L6   L7   L8   全亮
unsigned int ledtab[] = {0xff,0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f,0x00};

//初始化关闭LED、蜂鸣器、数码管
void SysInit(unsigned char x)
{
	//关闭LED
	P2=P2&0x1f|0x80;P0=0xff;P2&=0x1f;//先将P2口高三位强制置0,再或上值,强制选择Y4C输出,后关闭所有的LED,再去除P2高三位的值
	
	//关闭蜂鸣器
	P2=P2&0x1f|0xa0;relay=0;buzzer=x;P2&=0x1f;//先将P2口高三位强制置0,再或上值,强制选择Y5C输出,
	                                          //后使P0^4有效,关闭蜂鸣器,再去除P2高三位的值    
	//关闭数码管的段选
	P2=P2&0x1f|0xe0;P0=0xff;P2&=0x1f; //先将P2口高三位强制置0,再或上值,强制选择Y7C输出,
	                                  //后使P0口都有效,关闭共阳数码管段选,再去除P2高三位的值 
	//关闭数码管的位选
	P2=P2&0x1f|0xc0;P0=0x00;P2&=0x1f;//先将P2口高三位强制置0,再或上值,强制选择Y6C输出,
	                                  //后使P0口都无效,关闭共阳数码管位选,再去除P2高三位的值             
}

//延时
void Delay1us0()		//@12.000MHz
{
	_nop_();
	_nop_();
	_nop_();
	_nop_();
}

//延时
void delay_us0(unsigned int us) 
{
	while(us--)
	{
		Delay1us0();
	}
}

//LED选择闪烁
void LED_Select(unsigned char n)
{
	
	P2 = ( P2& 0x1f ) | 0x80;//先将P2的高三位强制置0,后或上一个数强制选择Y4C口
	P0 = n;//输入想要点亮的LED
	P2 = P2 & 0x8e;
	delay_us0(50000);//延时5毫秒
	
	P2 = ( P2& 0x1f ) | 0x80;//先将P2的高三位强制置0,后或上一个数强制选择Y4C口
	P0 = 0xff;//关闭所有LED灯
	P2 = P2 & 0x8e;
	delay_us0(50000);//延时
}

//矩阵按键
void scankbd()
{
	static char kbd_state = 0;//定义的三个状态
	unsigned char kbd_press;
	char row;//判断按键的行
	switch(kbd_state)
	{
		case state_0:  //是否按下  
			kbd_io=0x0f; P42=0; P44=0;
			kbd_press = kbd_io;   
			if(kbd_press != kbd_maskrow)
				kbd_state = state_1;//说明key_press不等于0x0f,跳转到1状态
			break;
			
		case state_1:   //是否是抖动   kbd_io-P3
			kbd_press = kbd_io;
			if(kbd_press != kbd_maskrow)
			{//按键不是需要屏蔽的状态
				//判断按键属于哪一行
				if((kbd_io&0x08)==0)  row=0;            
				if((kbd_io&0x04)==0)  row=1;              
				if((kbd_io&0x02)==0)  row=2;                   
				if((kbd_io&0x01)==0)  row=3;             
				
				kbd_io=0xf0; P42=1;P44=1; //将四列强制无效,再判断按键的列数
				
				//判断按键属于哪一列
				if(P44==0) key_num=row;
				if(P42==0) key_num=row+4;         
				if((kbd_io&0x20)==0) key_num=row+8;
				if((kbd_io&0x10)==0) key_num=row+12;		
				kbd_state = state_2;//跳转到2状态
			}else{//按键被屏蔽,跳转0状态
				kbd_state = state_0;
			}
			break;
			
		case state_2:   //判断是否弹起
			kbd_io=0x0f; P42=0; P44=0;//将按键强制有效
			kbd_press =kbd_io;//再获取端口的数值
			if(kbd_press == 0x0f)	kbd_state = state_0;//是需要被屏蔽的状态,需要跳转到0状态
			break; 
		
		default:        //屏蔽不需要的IO
			break;
	}
}

//数码管显示
void segs(void)
{
	static unsigned char segaddr=0;
	//首先全灭是为了消影
	P2=(0x1f&P2)|0xe0;//先将P2口高三位置零,再强制选择Y7C,段选控制
	P0=0xff;//将所有段选强制无效
	P2=0x1f&P2;//消除P2口高三位的影响
	
	P2=(0x1f&P2)|0xc0;//先将P2口高三位置零,再强制选择Y6C,位选控制
	P0=1<<segaddr;    //改变数码管现实的位置                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
	P2=0x1f&P2;//消除P2口高三位的影响
	
	P2=(0x1f&P2)|0xe0;//先将P2口高三位置零,再强制选择Y7C,段选控制
	P0=segtab[segbuff[segaddr]];//显示需要显示的数值
	P2=0x1f&P2;//消除数码管高三位的影响
	
	if(++segaddr==8) 
		segaddr=0;//让数码管每次只显示在八个数码管上
}

//独立按键
void scanbtn(){
	static char kbd_state = 0;//定义的三个状态
	unsigned char kbd_press;//判断按键的行
	switch(kbd_state)
	{
		case state_0:  //是否按下  
			kbd_io=0x0f; 
			kbd_press =kbd_io;   
			if(kbd_press != kbd_maskrow)
				kbd_state = state_1;//说明key_press不等于0x0f,跳转到1状态
			break;
			
		case state_1:   //是否是抖动   kbd_io-P3
			kbd_press =kbd_io;
			if(kbd_press != kbd_maskrow)
			{//按键不是需要屏蔽的状态
				//判断按键属于哪一行
				if((kbd_io&0x08)==0)  key_num=0;            
				if((kbd_io&0x04)==0)  key_num=1;              
				if((kbd_io&0x02)==0)  key_num=2;                   
				if((kbd_io&0x01)==0)  key_num=3; 				
					kbd_state = state_2;//跳转到2状态
			}
			else//按键被屏蔽,跳转0状态
				kbd_state = state_0;
			break;
			
		case state_2:   //判断是否弹起
			kbd_io=0x0f;//将按键强制有效 
			kbd_press =kbd_io;//再获取端口的数值
			if(kbd_press == 0x0f)	kbd_state = state_0;//是需要被屏蔽的状态,需要跳转到0状态
			break; 
		
		default:        //屏蔽不需要的IO
			break;
	}
}

main.c文件

#include "config.h"

void Timer0Init(void);

void main()
{
	SysInit(0);//关闭LED灯,数码管,蜂鸣器
	Timer0Init();//开启定时器
	while(1)
	{
		segbuff[0]=key_num/10;
		segbuff[1]=key_num%10;
		if(key_num%8 == 0) LED_Select(ledtab[1]);
		if(key_num%8 == 1) LED_Select(ledtab[2]);
		if(key_num%8 == 2) LED_Select(ledtab[3]);
		if(key_num%8 == 3) LED_Select(ledtab[4]);
		if(key_num%8 == 4) LED_Select(ledtab[5]);
		if(key_num%8 == 5) LED_Select(ledtab[6]);
		if(key_num%8 == 6) LED_Select(ledtab[7]);
		if(key_num%8 == 7) LED_Select(ledtab[8]);

	}
}
 
//中断1
void time0() interrupt 1
{
	scankbd();
	segs();
}

//定时器0
void Timer0Init(void)		//1毫秒@12.000MHz
{
	AUXR &= 0x7F;		//定时器时钟12T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0x18;		//设置定时初始值
	TH0 = 0xFC;		//设置定时初始值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	EA = 1;
	ET0 = 1;
}

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值