三行按键消抖
四舍五入保留两位小数
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显示 } }