三行按键消抖

四舍五入保留两位小数

74CH573锁存器

传统51单片机(无锁存器设计)
直接驱动外设:10口直接连接LED、数码管等外设,无锁存器参与。
·缺点 :
信号稳定性差:动态扫描时寸(如数码管)易出现信号冲突或闪烁
IO资源浪费:每个外设需独占IO引脚,无法复用。
蓝桥杯单片机(基于74HC573锁存器)
锁存器功能:
信号保持:锁存器(如74HC573)可锁存10口状态,避免动态扫描时信号丢失,
资源复用:通过锁存器+74HC138译码器,实现多外设共享同一组10口(如PO和 P2)。
硬件设计:
锁存器使能控制:通过P2口高了位(P2.5-P2.7)控制74HC138译码器选择不同外设的锁存器使能信号(如Y4-Y7)。
典型应用:数码管段选、位选、LED、继电器等外设均通过锁存器管理。
12届省赛题练习
#include <STC15F2K60S2.H>//15单片机寄存器专属头文件
#include <Init.h>//初始化底层驱动专用头文件
#include <Key.h>//按键底层专属头文件
#include <Led.h>//Led底层驱动专用头文件
#include <Seg.h>//数码管底层专属头文件
#include <onewire.h>//温度读取底层专属头文件
#include "iic.h"
unsigned char Key_Slow_Down;//按键减速专用变量
unsigned char Key_Val,Key_Down,Key_Old,Key_Up;//按键专用变量
unsigned char Seg_Buf[8]={10,10,10,10,10,10,10,10};//数码管显示数据存放数组
unsigned char Seg_Point[8]={0,0,0,0,0,0,0,0};//数码管小数点数据存放数组
unsigned char Seg_Pos;//数码管扫描专用变量
unsigned int Seg_Slow_Down;//数码管减速专用变量
unsigned char ucLed[8]={0,0,0,0,0,0,0,0};//Led显示数据存放数组
unsigned char Seg_Disp_Mode;//数码管显示界面 0-温度显示界面 1-参数设置界面 2-DAC输出界面
float t;
unsigned char P_Data=25;
unsigned char P_Data_Ctrol=25;
float DAC_Disp;
bit OutPut_Mode;
/*键盘处理函数*/
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_Up = ~Key_Val&(Key_Old^Key_Val);//捕捉按键上升沿
Key_Old = Key_Val;//辅助按键扫描
switch(Key_Down)
{
case 4://界面切换按键
if(++Seg_Disp_Mode==3)
Seg_Disp_Mode=0;//当前处于温度参数设置界面
if(Seg_Disp_Mode==1)
P_Data=P_Data_Ctrol;//将实际控制数据赋值给设置变量
if(Seg_Disp_Mode==2)//当界面从参数设置切换出去后
P_Data_Ctrol=P_Data;//将设置数据保存到控制变量
break;
case 8://参数自减按键
if(Seg_Disp_Mode==1)//当前处于温度参数设置界面
{
if(--P_Data==255)//限制温度下限为0
P_Data=0;
}
break;
case 9://参数自加按键
if(Seg_Disp_Mode==1)
{
if(++P_Data==100)
P_Data=99;
}
break;
case 5://模式切换按键
OutPut_Mode^=1;//切换输出模式
break;
}
}
void Seg_Proc()
{
if(Seg_Slow_Down) return;
Seg_Slow_Down=1;//数码管减速程序
/*信息获取区域*/
t=rd_temperature();
/*数据显示区域*/
switch(Seg_Disp_Mode)
{
case 0://温度显示界面
Seg_Buf[0]=11;//标识符C
Seg_Buf[4]=(unsigned char)(t/10)%10;
Seg_Buf[5]=(unsigned char)t%10;
Seg_Point[5]=1;
Seg_Buf[6]=(unsigned int)(t*10)%10;
Seg_Buf[7]=(unsigned int)(t*100)%10;
break;
case 1://参数设置界面
Seg_Buf[0]=12;//标识符P
Seg_Buf[4]=Seg_Buf[5]=10;//熄灭第五、第六个数码管
Seg_Point[5] = 0;//关闭小数点
Seg_Buf[6]=P_Data/10%10;
Seg_Buf[7]=P_Data%10;
break;
case 2://DAC输出界面
Seg_Buf[0]=13;
Seg_Buf[5]=(unsigned char)DAC_Disp;
Seg_Buf[6]=(unsigned int)(DAC_Disp*10)%10;
Seg_Buf[7]=(unsigned int)(DAC_Disp*100)%10;
Seg_Point[5]=1;
break;
}
}
void Led_Proc()
{
unsigned char i;//用于for循环
if(OutPut_Mode==0)//DAC输出电压与温度相关
{
if(t<P_Data_Ctrol)
DAC_Disp=0;//DAC输出0V
else
DAC_Disp=5;//DAC输出5V
}
else
{
if(t<20)//当实时温度小于20度时
DAC_Disp=1;
else if(t>40)//当实时温度小于40度时
DAC_Disp=4;
else//当实时温度在20-40之间时
DAC_Disp=0.15*(t-20)+1;//DAC输出与实时温度为一次函数关系
}
Da_Write(DAC_Disp*51);//实时输出DAC
/*Led相关*/
ucLed[0] = !OutPut_Mode;//当前处于模式 1 状态,指示灯 L1 点亮,否则熄灭
for(i=0;i<3;i++)
{
ucLed[i+1]=(i==Seg_Disp_Mode);
}
}
void Timer0Init(void) //1毫秒@12.000MHz
{
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0=1; //定时器中断0打开
EA=1; //总中断打开
}
/*定时器0中断服务函数*/
void Timer0Server() interrupt 1
{
if(++Key_Slow_Down==10)Key_Slow_Down=0;//按键减速专用
if(++Seg_Slow_Down==500)Seg_Slow_Down=0;//数码管减速专用
if(++Seg_Pos==8)Seg_Pos=0;//数码管显示专用
Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos],Seg_Point[Seg_Pos]);
Led_Disp(Seg_Pos,ucLed[Seg_Pos]);
}
void Delay750ms() //@12.000MHz
{
unsigned char i, j, k;
i = 35;
j = 51;
k = 182;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void main()
{
rd_temperature();
Delay750ms();
System_Init();
Timer0Init();
while(1)
{
Key_Proc(); // 处理按键
Seg_Proc(); // 更新数码管显示
Led_Proc(); // 更新LED显示
}
}
我要赚赏金
