链接: 视频
基本框架
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];//相当于保存了