首页 > 其他分享 >51单片机基础之数码管、模块化及模板

51单片机基础之数码管、模块化及模板

时间:2024-12-10 23:56:56浏览次数:5  
标签:P3 char Temp 数码管 51 unsigned Seg 单片机 Key

数码管根据连接方式分为共阴极和共阳极数码管,数码管的统一逻辑就是先位选再段选

1、静态数码管

/*头文件区域*/
#include <REGX52.H>
#include <intrins.h>

/*延时函数*/
void Delay(unsigned int xms)		//@12.000MHz
{
	while(xms--)
	{
			unsigned char i, j;

		i = 2;
		j = 239;
		do
		{
			while (--j);
		} while (--i);
	}
}


/*变量声明区域*/
unsigned char Key_Val,Key_Down,Key_Up,Key_Old;
unsigned char Wela[] = {0xfe,0xfd,0xfb,0xf7,0xef,0xdf};
unsigned char Dula[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00};

/*按键检测函数*/
unsigned char Key_Read()
{
	unsigned char Temp = 0;
	if(P3_4 == 0) Temp = 1 ;
	if(P3_5 == 0) Temp = 2 ;
	if(P3_6 == 0) Temp = 3 ;
	if(P3_7 == 0) Temp = 4 ;
	return Temp;
}

/*数码管显示函数*/
void Seg_Disp(unsigned char wela,dula)
{
	P0 = 0;//消影-段码位码清零
	P2_6 = 1;
	P2_6 = 0;
	
	P0 = Wela[wela];//位码赋值
	P2_7 = 1;
	P2_7 = 0;
	
	P0 = Dula[dula];//段码赋值
	P2_6 = 1;
	P2_6 = 0;
}

/*Main*/
void main()
{
	while(1)
	{
		Key_Val = Key_Read();//获取键码值
		Key_Down = Key_Val & (Key_Val ^ Key_Old);//检测下降沿
		Key_Up = ~Key_Val & (Key_Val ^ Key_Old);//检测上升沿
		Key_Old = Key_Val;//扫描获取的键码值

		Seg_Disp(0,1);
	}
}

上图是静态数码管的代码

上图是现象,不同的单片机代码可能稍微不同,但是总的逻辑来讲静态数码管显就是

(一)、消影

(二)、位选赋值

(三)、段选赋值

代码是记不完的,逻辑却是相通的,要举一反三

2、动态数码管

本次不采用江科大Delay延时函数进行处理,采用定时器跳转中断进行扫描

/*头文件区域*/
#include <REGX52.H>
#include <intrins.h>

/*延时函数*/
void Delay(unsigned int xms)		//@12.000MHz
{
	while(xms--)
	{
			unsigned char i, j;

		i = 2;
		j = 239;
		do
		{
			while (--j);
		} while (--i);
	}
}


/*变量声明区域*/
unsigned char Key_Val,Key_Down,Key_Up,Key_Old;
unsigned char Seg_Wela[] = {0xfe,0xfd,0xfb,0xf7,0xef,0xdf};//数码管位码储存数据
unsigned char Seg_Dula[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00};//数码管断码储存数据
unsigned char Seg_Pos;//中间变量,用于嵌套循环
unsigned char Seg_Buf[] = {1,2,3,4,5,6};//选择要显示的数字

/*按键检测函数*/
unsigned char Key_Read()
{
	unsigned char Temp = 0;
	if(P3_4 == 0) Temp = 1 ;
	if(P3_5 == 0) Temp = 2 ;
	if(P3_6 == 0) Temp = 3 ;
	if(P3_7 == 0) Temp = 4 ;
	return Temp;
}

/*数码管显示函数*/
void Seg_Disp(unsigned char wela,dula)
{
	P0 = 0;//消影-段码位码清零
	P2_6 = 1;
	P2_6 = 0;
	
	P0 = Seg_Wela[wela];//位码赋值
	P2_7 = 1;
	P2_7 = 0;
	
	P0 = Seg_Dula[dula];//段码赋值
	P2_6 = 1;
	P2_6 = 0;
}

/*定时器初始化函数*/
void Timer0Init(void)		//1毫秒@12.000MHz
{
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	ET0 = 1;
	EA = 1;
}

/*定时器0中断服务函数*/
void Timer0_Serviver() interrupt 1
{	
	TL0 = 0x18;
	TH0 = 0xFC;		//给定时器重赋值保证能持续的进入中断函数
	if(++Seg_Pos == 6) Seg_Pos = 0;//中间变量在0~5之间反复循环,i++是判断后再自增,++i是先自增再判断
	Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos]);//嵌套,每次循环对应一个值
}

/*Main*/
void main()
{
	Timer0Init();
	while(1)
	{
		Key_Val = Key_Read();//获取键码值
		Key_Down = Key_Val & (Key_Val ^ Key_Old);//检测下降沿
		Key_Up = ~Key_Val & (Key_Val ^ Key_Old);//检测上升沿
		Key_Old = Key_Val;//扫描获取的键码值

		
	}
}

代码如图,定时器寄存器的配置详见江科大

现象结果如上

3、动态数码管拓展

上电数码管显示三位数500,按键1按下一次加100,按键2按下一次加200;

/*头文件区域*/
#include <REGX52.H>
#include <intrins.h>

/*延时函数*/
void Delay(unsigned int xms)		//@12.000MHz
{
	while(xms--)
	{
			unsigned char i, j;

		i = 2;
		j = 239;
		do
		{
			while (--j);
		} while (--i);
	}
}


/*变量声明区域*/
unsigned char Key_Val,Key_Down,Key_Up,Key_Old;
unsigned char Seg_Wela[] = {0xfe,0xfd,0xfb,0xf7,0xef,0xdf};//数码管位码储存数据
unsigned char Seg_Dula[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00};//数码管断码储存数据
unsigned char Seg_Pos;//中间变量,用于嵌套循环
unsigned char Seg_Buf[] = {10,10,10,10,10,10};//选择不显示数字,不直接在这里更改是为了后续的模块化
unsigned int Time = 500;
bit System_Flag;

/*按键检测函数*/
unsigned char Key_Read()
{
	unsigned char Temp = 0;
	if(P3_4 == 0) Temp = 1 ;
	if(P3_5 == 0) Temp = 2 ;
	if(P3_6 == 0) Temp = 3 ;
	if(P3_7 == 0) Temp = 4 ;
	return Temp;
}

/*数码管显示函数*/
void Seg_Disp(unsigned char wela,dula)
{
	P0 = 0;//消影-段码位码清零
	P2_6 = 1;
	P2_6 = 0;
	
	P0 = Seg_Wela[wela];//位码赋值
	P2_7 = 1;
	P2_7 = 0;
	
	P0 = Seg_Dula[dula];//段码赋值
	P2_6 = 1;
	P2_6 = 0;
}

/*定时器初始化函数*/
void Timer0Init(void)		//1毫秒@12.000MHz
{
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	ET0 = 1;
	EA = 1;
}

/*定时器0中断服务函数*/
void Timer0_Serviver() interrupt 1
{	
	TL0 = 0x18;
	TH0 = 0xFC;		//给定时器重赋值保证能持续的进入中断函数
	if(++Seg_Pos == 6) Seg_Pos = 0;//中间变量在0~5之间反复循环,i++是判断后再自增,++i是先自增再判断
	Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos]);//嵌套,每次循环对应一个值
}

/*Main*/
void main()
{
	Timer0Init();
	while(1)
	{
		Key_Val = Key_Read();//获取键码值
		Key_Down = Key_Val & (Key_Val ^ Key_Old);//检测下降沿
		Key_Up = ~Key_Val & (Key_Val ^ Key_Old);//检测上升沿
		Key_Old = Key_Val;//扫描获取的键码值
		switch(Key_Down)
		{
			case 1:
				Time +=100;//自增100
			break;
			case 2:
				Time -=100;//自减100
			break;
		}
		Seg_Buf[0] = Time/100%10;//百位
		Seg_Buf[1] = Time/10%10;//十位
		Seg_Buf[2] = Time/1%10;//个位
	}
}

根据上一篇博客,代码如上,计算3位数的数字模板 ,无法理解就记住即可

4、函数封装

目前需要封装按键、数码管

1、按键函数

接下来就是写按键的函数了

本次封装的是矩阵键盘,按键对应的IO口默认高电平

参考这是普中的51单片机原理图,P1口默认高电平,矩阵键盘分为4行4列,可以采用逐行扫描或者逐列扫描,和数码高管的扫描本质一样,单片机无法同时处理,只能在极短的时间反复扫描。

代码如图,这是之前的按键函数

#include "Key.h"

unsigned char Key_Read()
{
	unsigned char Temp = 0;//临时变量返回键码值
	P3_0 = 0;P3_1 = 1;P3_2 = 1;P3_3 = 1;//第一行
	if(P3_4 == 0) Temp = 1;
	if(P3_5 == 0) Temp = 2;
	if(P3_6 == 0) Temp = 3;
	if(P3_7 == 0) Temp = 4;
	
	P3_0 = 1;P3_1 = 0;P3_2 = 1;P3_3 = 1;//第二行
	if(P3_4 == 0) Temp = 5;
	if(P3_5 == 0) Temp = 6;
	if(P3_6 == 0) Temp = 7;
	if(P3_7 == 0) Temp = 8;
	
	P3_0 = 1;P3_1 = 1;P3_2 = 0;P3_3 = 1;//第三行
	if(P3_4 == 0) Temp = 9;
	if(P3_5 == 0) Temp = 10;
	if(P3_6 == 0) Temp = 11;
	if(P3_7 == 0) Temp = 12;
	
	P3_0 = 1;P3_1 = 1;P3_2 = 1;P3_3 = 0;//第四行
	if(P3_4 == 0) Temp = 13;
	if(P3_5 == 0) Temp = 14;
	if(P3_6 == 0) Temp = 15;
	if(P3_7 == 0) Temp = 16;
	return Temp;
}

同理,创建key.h

在.h文件中声明

2、数码管函数

数码管函数在上一篇博客中已提,再以相同办法进行封装

封装完成后,还需要把文件加入keil的Drvier中

右键Drvier选择添加已存在的文件

返回上一级找到Driver

并选择显示所有文件,并添加按键和数码管,可以只选.c文件,我选择都添加

这样就添加成功了

5、模板

(一)头文件声明

(二)变量声明

(三)按键处理函数

(四)信息处理函数

(五)其他信息处理函数

(六)定时器初始化

(七)定时器终端服务函数

(八)Main函数

按照这个顺序写,遇到哪个就补充,不死记

/*头文件区域*/
#include <REGX52.H>
#include "key.h"
#include "seg.h"

/*变量声明区域*/
unsigned char Key_Val,Key_Down,Key_Up,Key_Old;//按键检测变量
unsigned char Key_Slow_Down;//按键减速变量
unsigned char Seg_Slow_Down;//数码管减速变量
unsigned char Seg_Pos;//数码管遍历变量
unsigned char Seg_Buf[6] = {0,4,0,1,1,0};//数码管显示数据储存数组

/*按键处理函数*/
void Key_Proc()
{
	if(Key_Slow_Down) return;
	Key_Slow_Down = 1;//按键减速程序
	
	Key_Val = Key_Read();//获取键码值
	Key_Down = Key_Val & (Key_Val ^ Key_Old);//检测上升沿
	Key_Up =  ~Key_Val & (Key_Val ^ Key_Old);///检测下降沿
	Key_Old = Key_Val;//辅助扫描
	/*常用三行消抖,上升沿不常用,这里写出来是加深记忆*/
}

/*信息处理函数*/
void Seg_Proc()
{
	if(Seg_Slow_Down) return;
	Seg_Slow_Down = 1;//数码管减速程序
	
}

/*其他信息处理函数*/
void Led_Proc()
{

}

/*定时器初始化函数*/
void Timer0Init(void)		//1毫秒@12.000MHz
{
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	ET0 = 1;
	EA = 1;
}

/*定时器0中断服务函数*/
void Timer0Servier() interrupt 1
{
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	if(++Key_Slow_Down == 10) Key_Slow_Down = 0;//设置按键减速10ms
	if(++Seg_Slow_Down == 500) Seg_Slow_Down = 0;//设置数码管减速500ms
	if(++Seg_Pos == 6) Seg_Pos = 0;//遍历
	Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos]);	
}

/*Main*/
void main()
{
	Timer0Init();
	while(1)
	{
		Key_Proc();
		Seg_Proc();
		Led_Proc();
	}
}

这里的减速程序弥补了之前三行消抖发现不灵敏的情况,因为单片机处理一行代码的时间很短,while里循环一遍也很短,不同设备接收的时间不同也比单片机更长,当第一个循环的信息还没处理完,第二个循环就来了,导致错乱。如按键一般接收10ms,想要收发一致就需要一个减速程序给单片机减速,在1~9s不执行,在第0s时为if语句为假,执行下面的程序,但是单片机处理一条语句是很快的,如果我们不手动给减速变量置1,那在0~1秒内会执行很多次按键检测程序。随着能力的提升,后面会使用调度器处理。

在代码中我们给了数码管一个数组用于检测模板是否正确

本次总结就到这里了,希望大家多多点赞

标签:P3,char,Temp,数码管,51,unsigned,Seg,单片机,Key
From: https://blog.csdn.net/2401_86416551/article/details/144309783

相关文章

  • 51单片机基础之LED彩灯控制系统
    (一)显示界面数码管需要A和B,则需要在数码管段选数据储存数组添加0x77与0x7f(二)按键功能按键需要启动,暂停,则需要创建一个bit类型标志位,进行判断,实现四个模式的切换,需要定义模式的变量,用switch列举出来(三)彩灯模式34模式需要一个从外到内的LED数据数组,并建立一个用于遍历数组......
  • 2024-12-10单片机-8*8点阵闪烁
    我们设计横排点阵显示名字和竖排显示名字,通过四个按钮实现名字上下左右平移;例如我的名字,SYM开头。其实算法很简单,写一个简单的滑动窗口就好,实现数组的平移。实现代码:#include"reg51.h"typedefunsignedintu16;typedefunsignedcharu8;voiddelay_10us(u16ten_us){......
  • 基于STM32单片机的智能点滴输液报警器液位检测电机无线WiFi手机APP设计DR-01非接触液
    25-040-点滴检测+药水液位+电机控制+上下限+按键+声光提醒+TFT彩屏+WiFi产品功能描述:本系统由STM32F103C8T6单片机核心板、TFT液晶显示电路、无线无线WIFI/、点滴检测模块、步进电机控制电路、DR-01非接触液位传感器检测电路、蜂鸣器声光报警、按键电路、电源电路组成。【1......
  • STM32单片机芯片与内部13 TIM-通用定时器TIM2345 高级定时器TIM18-定时计数功能、库函
    目录一、通用定时器库函数工程模板1、TIM_TimeBaseInitTypeDef2、时钟3、初始化4、中断服务函数二、通用定时器库函数API1、初始化封装2、中断服务函数封装三、高级定时器库函数工程模板1、TIM_TimeBaseInitTypeDef2、时钟3、初始化4、中断服务函数四、高级定时......
  • STM32单片机芯片与内部12 TIM-基本定时器TIM67 -定时计数功能、库函数配置、HAL库配置
    目录一、功能二、库函数工程模板1、NVIC_InitTypeDef与TIM_TimeBaseInitTypeDef2、时钟使能3、初始化4、清除中断5、开启/关闭中断6、使能/失能计数器三、库函数API1、初始化的封装2、中断服务函数四、HAL库工程模板1、TIM_HandleTypeDef2、TIM_MasterConfigType......
  • Contest7519 - 虚树计算
    ContestA消耗战(弱化版)题意:只有一组询问的消耗战(B题)。这个题跟虚树没有半点关系。只是为B题做准备。令\(f_u\)为切断\(u\)与其子树内所有关键点的最小代价(不需要考虑\(u\)是关键点的情况)。答案为\(f_1\)。令\(mi_u\)为\(1\rightsquigarrowu\)的最小边权(特别......
  • 蓝桥杯单片机第十二届省赛第二场——基于西风模版
    一、题目框图二、代码实现1.Led.c#include"Led.h"codeunsignedcharSeg_Table[]={0xc0,//00xf9,//10xa4,//20xb0,//30x99,//40x92,//50x82,//60xf8,//70x80,//80x90,//90x88,//A0x83,//b0xc6,//C0xa1,//d0x86,//E0x8e,//F0xff, /......
  • 【064】基于51单片机无线亲子分离报警器【Keil程序+报告+原理图】
    ☆、设计硬件组成:51单片机最小系统+NRF24L01无线模块+震动器+按键电路+蜂鸣器+LED灯。1、本设计采用STC89C51/52、AT89C51/52、AT89C51/52单片机作为主控芯片;2、系统采用NRF24L01无线将主控板和子控板进行通讯;3、当主控板和子控板超出范围时两个板子都会发出声光报警提......
  • 基于51单片机的家用红外防盗及短信报警系统的设计与实现
    一、研究目的和意义由于近年来超大尺寸的集成电路、先进的通讯技术以及先进的单片机,以及公众对于安防的重视程度越来越高,使得使用单片机以及相关的外部元件来进行自动报警变得越来越容易,并且这种新型的系统具备了更少的元件、更加简易的操作、更加完善的功能,从而使得该系统的......
  • 基于单片机的自适应光源控制系统设计
    1研究背景与意义现如今中国的能源需求越来越多,但能源数量却很少,供不应求,特别是中国人口基数比较大,在此情况下节约能源是国家应该关注的内容,因此解决全国自适应光源的节能问题变得很重要。在此之前采用的城市照明大多数是低效且高耗的,这极大造成了资源的浪费,为解决资源短缺及......