【蓝桥杯单片机-0.基于定时器的倒计时程序设计】

蓝桥杯单片机-0.基于定时器的倒计时程序设计


链接: 视频

基本框架

User - 用户层(main)
Driver - 底层(固定)

建立工程模板 - 编写底层函数Key,Seg
.c 编写底层函数
.h 声明底层函数

Key_Read(); Seg_Disp()

Key.c

#include <Key.h>

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;
}

Key.h

#include <REGX52.H>

unsigned char Key_Read();

Seg.c

#include "Seg.h"

unsigned char Seg_Dula[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00};
unsigned char Seg_Wela[] = {0xfe,0xfd,0xfb,0xf7,0xef,0xdf};

void Seg_Disp(unsigned char wela,dula)
{
	P0 = 0x00; 
	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;	
}

Seg.h

#include <REGX52.H>

void Seg_Disp(unsigned char wela,dula);

Main:
1.头文件
2.变量声明
3.Key_Proc()
4.Seg_Proc()
5.Led_Proc()
6.Timer0Init() 定时器0中断初始化函数,通过stc生成
7.Server 定时器0中断服务函数
8.Main

/* 头文件声明区 */
#include <REGX52.H>//单片机寄存器专用头文件
#include <Key.h>//按键底层驱动专用头文件
#include <Seg.h>//数码管底层驱动专用头文件

/* 变量声明区 */
unsigned char Key_Val,Key_Down,Key_Old;//按键专用变量
unsigned char Key_Slow_Down;//按键减速专用变量
unsigned char Seg_Buf[6] = {10,10,10,10,10,10};//数码管显示数据存放数组
unsigned char Seg_Pos;//数码管扫描专用变量
unsigned int Seg_Slow_Down;//数码管减速专用变量


/* 键盘处理函数 */
void Key_Proc()
{
	if(Key_Slow_Down) return;
	Key_Slow_Down = 1;//键盘减速程序

	Key_Val = Key_Read();//实时读取键码值
	Key_Down = Key_Val & (Key_Old ^ Key_Val);//捕捉按键下降沿
	Key_Old = Key_Val;//辅助扫描变量

}

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

}

/* 其他显示函数 */
void Led_Proc()
{

}

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

/* 定时器0中断服务函数 */
void Timer0Server() interrupt 1
{
 	TL0 = 0x18;		//设置定时初始值
	TH0 = 0xFC;		//设置定时初始值   
	if(++Key_Slow_Down == 10) Key_Slow_Down = 0;//键盘减速专用
	if(++Seg_Slow_Down == 500) Seg_Slow_Down = 0;//数码管减速专用
	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();
	}
}

在这里插入图片描述

减速代码

有时候比如温度传感器接收到信息再处理转化的周期是750ms,但是一般main函数执行一遍的速度是20ms。这样,上一次的数据还没处理好下一次的数据就又来了。

unsigned char Key_Slow_Down;//按键减速专用变量
unsigned char Seg_Pos;//数码管扫描专用变量
unsigned int Seg_Slow_Down;//数码管减速专用变量
/* 定时器0中断服务函数 */
void Timer0Server() interrupt 1
{
 	TL0 = 0x18;		//设置定时初始值
	TH0 = 0xFC;		//设置定时初始值   
	if(++Key_Slow_Down == 10) Key_Slow_Down = 0;//键盘减速专用
	if(++Seg_Slow_Down == 500) Seg_Slow_Down = 0;//数码管减速专用
	if(++Seg_Pos == 6) Seg_Pos = 0;//数码管显示专用
	Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos]);
}

蜂鸣器

在这里插入图片描述
在这里插入图片描述
P2_3为0,响
P2_3为1,灭
在这里插入图片描述
这个点变蓝就是响了

初赛模拟题

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

对应代码

Driver中的底层不用变,就在main.c中编写即可。
以下为完整代码。

//头文件声明区
#include <REGX52.H>
#include "Key.h"
#include "Seg.h"

//变量声明区
unsigned char Key_Slow_Down;//按键减速专用 10ms
unsigned int Seg_Slow_Down;//数码管减速专用  500ms
unsigned char Key_Val,Key_Down,Key_Old;//按键扫描专用
unsigned char Seg_Pos;//数码管扫描量
unsigned char Seg_Buf[6] = {10,10,10,10,10,10};//数码管显示数据存放数组
unsigned char Seg_Mode; //数码管显示界面 0-显示 1-设置
unsigned int Timer_1000ms;//1000毫秒标志位
unsigned char Time_Count = 30;//系统计时变量
bit System_Flag;//系统标志位 0-暂停 1-开始
unsigned char Set_Dat[3] = {15,30,60};//设置参数储存数组
unsigned char Set_Dat_Index = 1;
unsigned int Timer_500ms;//500毫秒标志位
bit Seg_Flag;//数码管标志位

//按键处理函数
void Key_Proc()
{
	if(Key_Slow_Down) return; //不是0时返回
	Key_Slow_Down = 1;//为0时才能进来,这里赋值为1是为了下一次循环
	
	Key_Val = Key_Read();
	Key_Down = Key_Val & (Key_Val ^ Key_Old);//捕捉下降沿
	Key_Old = Key_Val;//辅助扫描
	
	switch(Key_Down)
	{
		case 1://启动
			if(Seg_Mode==0)
				System_Flag = 1;
		break;
		
		case 3://切换
			if(Seg_Mode ==1)
				Time_Count = Set_Dat[Set_Dat_Index];//相当于保存了
			Seg_Mode ^= 1;//取反
		break;
		
		case 4://设置
			if(Seg_Mode == 1)
			{
				if(++Set_Dat_Index == 3)
					Set_Dat_Index = 0;
			}
		break;
			
		case 2:
			if(Seg_Mode == 0)
			{
				Time_Count = Set_Dat[Set_Dat_Index];
			}
		break;
			
				
	}
}

//信息处理函数
void Seg_Proc()
{
	if(Seg_Slow_Down) return;
	Seg_Slow_Down = 1;
	
	Seg_Buf[0] = Seg_Mode+1;
	if(Seg_Mode == 0)//显示
	{
		Seg_Buf[4] = Time_Count/10%10;
		Seg_Buf[5] = Time_Count%10;
	}
	else
	{
		if(Seg_Flag == 1)
		{
			Seg_Buf[4] = Set_Dat[Set_Dat_Index]/10%10;
			Seg_Buf[5] = Set_Dat[Set_Dat_Index]%10;
		}
		else
		{
			Seg_Buf[4] = 10;
			Seg_Buf[5] = 10;
		}
		
	}
}

//其他显示函数
void Led_Proc()
{
	if(Time_Count ==0 )
	{
		P1 = 0x00;
		P2_3 = 0;
	}
	else
	{
		P1 = 0xff;
		P2_3=1;
	}
}

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

//定时器0中断服务函数
void Time0Server() interrupt 1
{
	TL0 = 0x18;
	TH0 = 0xFC;
	
	if(++Key_Slow_Down == 10) Key_Slow_Down = 0;
	if(++Seg_Slow_Down == 500) Seg_Slow_Down = 0;
	if(++Seg_Pos == 6) Seg_Pos = 0;
	Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos]);//位选,段选
	if(System_Flag == 1)
	{
		if(++Timer_1000ms == 1000)
		{
			Timer_1000ms = 0;
			Time_Count--;
			if(Time_Count == 255)
			{
				Time_Count = 0;
			}
		}
	}
	
	if(++Timer_500ms == 500)
	{
		Timer_500ms = 0;
		Seg_Flag ^= 1;
	}
	
	
}


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

这里的显示-设置模式是通过Seg_Mode的0,1来改变

unsigned char Seg_Mode; //数码管显示界面 0-显示 1-设置

用数组来存储要切换的数据

unsigned char Set_Dat[3] = {15,30,60};//设置参数储存数组

这个打通了两种模式的数据

Time_Count = Set_Dat[Set_Dat_Index];//相当于保存了
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值