前言
相关说明:
开发板:CT107D (IAP15F2K61S2)
开发环境:Keil5
涉及题目:第九届蓝桥杯单片机国赛真题
主要函数代码及说明:
一、代码相关定义、声明
1.头文件声明
#include "stdio.h"
#include "Timer.h"
#include "bsp_init.h"
#include "bsp_key.h"
#include "bsp_seg.h"
#include "bsp_led.h"
#include "bsp_onewire.h"
#include "bsp_iic.h"
#include "bsp_555_PWM_Freq.h"
2.变量声明
//--定时器滴答变量
unsigned long ms_Tick = 0;
//--定时器滴答变量
xdata unsigned long ms_Tick = 0;
xdata unsigned long ms_Tick_LED_Liang = 0;
xdata unsigned long ms_Tick_LED_An = 0;
//--定时器减速变量
unsigned int Key_Slow_Down;
unsigned int Seg_Slow_Down;
unsigned int Led_Slow_Down;
//--按键专用变量
unsigned char Key_Value;
unsigned char Key_Old, Key_Down;
//--数码管专用变量
unsigned char seg_string[10];
unsigned char seg_buf[8] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
unsigned char pos;
//--LED专用变量
unsigned char ucLed = 0x00;
unsigned char Voltage_Shit;//电压的待处理原始数值
unsigned int Temp_Shit;//温度的待处理原始数值
unsigned int freq_Storage;
unsigned char Voltage_Shit_Storage;//电压的待处理原始数值
unsigned int Temp_Shit_Storage;//温度的待处理原始数值
unsigned char eeprom_string[5] = {0};
unsigned int freq;
bit state_flag = 0;//测试模板好坏需要用的一个变量
unsigned char Interface_Flag = 0;//界面标志,0-数据显示,1-数据回显,2-阈值界面
unsigned char UFC_Trans_Interface_Flag = 0;//界面标志,0-电压显示,1-频率回显,2-温度界面
unsigned char Compare_Value = 30;//阈值内容,数据实际是在0.1-5.0之间,我们存储为*10之后的数据,1-50之间。
3.函数声明
void Key_Proc(void);
void Seg_Proc(void);
void Led_Proc(void);
void Delay750ms(); //@12.000MHz
二、主要函数
1.main函数
void main(void)
{
Cls_Peripheral();//关闭LED/继电器/蜂鸣器
Timer1Init();//定时器1初始化
EA = 1;//打开总中断
EEPROM_Read(&Compare_Value, 5, 1);//更新阈值
PWM_555_Freq_Timer0Init(); //配置成了计数器模式,不自动重装
Pcf8591_Adc(Adj_Res_Channel);//直接读取的AD数值
rd_temperature();
Delay750ms();//用于消除上电显示85°C的影响
while(1)
{
Key_Proc();
Seg_Proc();
Led_Proc();
}
}
2.按键扫描
void Key_Proc(void)
{
if(Key_Slow_Down) return;
Key_Slow_Down = 1;
//三行代码
Key_Value = Key_Read();
Key_Down = Key_Value & (Key_Old ^ Key_Value);//下降沿,按得哪个按键,这个值就是几
Key_Old = Key_Value;//检测电平,一直按着一直等于一个数
switch(Key_Down)//这个结构很常见,判别是哪个按键按下去了,根据按键按下的情况,控制内部数据变量的变化
{
case 4://切换按键
if((Interface_Flag == 0)||((Interface_Flag == 1)))//如果是数据显示界面/数据回显界面
{
if(++UFC_Trans_Interface_Flag == 3) UFC_Trans_Interface_Flag = 0;//完成0-2的转换
}
break;//这个break很重要
case 5://存储按键
eeprom_string[0] = Voltage_Shit;//用于存储0-255的电压数值
eeprom_string[1] = freq>>8;//用于存储频率原始数值,高8位
eeprom_string[2] = freq&0x00ff;//用于存储频率原始数值,低8位
eeprom_string[3] = Temp_Shit>>8;//用于存温度原始数值,高8位
eeprom_string[4] = Temp_Shit&0x00ff;//用于存储温度原始数值,低8位
EEPROM_Write(eeprom_string, 0, 5);
break;//这个break很重要
case 7://设置按键
if(Interface_Flag != 2)//如果之前不是阈值界面
Interface_Flag = 2;//强制进入阈值界面
else//如果从阈值界面跳出
{
Interface_Flag = 0;//强制进入数据显示界面
EEPROM_Write(&Compare_Value, 5, 1);
}
break;//这个break很重要
}
if(Key_Down == 6)//表示6号按键已经按下去了
{
S6_Key_ms_Tick = ms_Tick;//记录当前的滴答值
}
if((ms_Tick - S6_Key_ms_Tick)< 800)//小于800ms,等待上升沿产生
{
if(Key_Up == 6)//如果产生上升沿,表示短按释放
{
if(Interface_Flag == 0)//如果当前是数据界面,强制进入回显界面
{
Interface_Flag = 1;
EEPROM_Read(eeprom_string, 0, 5);
Voltage_Shit_Storage = eeprom_string[0];
freq_Storage = (eeprom_string[1]<<8)|eeprom_string[2];
Temp_Shit_Storage = (eeprom_string[3]<<8)|eeprom_string[4];
}
else if(Interface_Flag == 2)//如果当前是阈值界面
{
Compare_Value++;
if(Compare_Value == 51)
Compare_Value = 1;
}
}
}
else//如果时长大于800ms,并没有产生上升沿,表示长按了
{
if(Key_Old == 6)//表示还在按压着
{
Compare_Value++;
if(Compare_Value == 51)
Compare_Value = 1;
}
}
}
3.数码管显示
void Seg_Proc(void)
{
if(Seg_Slow_Down) return;
Seg_Slow_Down = 1;
Voltage_Shit = Pcf8591_Adc(Adj_Res_Channel);//直接读取的AD数值
Temp_Shit = rd_temperature();//温度数据的原始数值
switch(Interface_Flag)
{
case 0://0-数据显示
switch(UFC_Trans_Interface_Flag)
{
case 0://0-电压显示
sprintf(seg_string,"U %3.1f",(Voltage_Shit/51.0));
break;
case 1://1-频率显示
sprintf(seg_string,"F %6d",freq);
break;
case 2://2-温度显示
sprintf(seg_string,"C %5.2f",(Temp_Shit/16.0));
break;
}
break;
case 1://1-数据回显
switch(UFC_Trans_Interface_Flag)
{
case 0://0-电压显示
sprintf(seg_string,"HU %3.1f",(Voltage_Shit_Storage/51.0));
break;
case 1://1-频率回显
sprintf(seg_string,"HF%6d",freq_Storage);
break;
case 2://2-温度界面
sprintf(seg_string,"HC %5.2f",(Temp_Shit_Storage/16.0));
break;
}
break;
case 2://2-阈值界面
sprintf(seg_string,"P %3.1f",(Compare_Value*0.1));
break;
}
Seg_Tran(seg_string, seg_buf);
}
4.LED指示功能
void Led_Proc(void)
{
if(Led_Slow_Down) return;
Led_Slow_Down = 1;
if(Interface_Flag == 0)//只有数据显示界面的时候
{
switch(UFC_Trans_Interface_Flag)
{
case 0://L3点亮
ucLed &= (~0x07);
ucLed |= (0x04);
break;
case 1://L2点亮
ucLed &= (~0x07);
ucLed |= (0x02);
break;
case 2://L1点亮
ucLed &= (~0x07);
ucLed |= (0x01);
break;
}
}
else//如果不是数据显示界面,低3位熄灭
{
ucLed &= (~0x07);
}
if((Voltage_Shit/51.0) > (Compare_Value*0.1))//让L8闪烁
{
if((ms_Tick - L8_ms_Tick)>=200)
{
L8_ms_Tick = ms_Tick;
ucLed ^= 0x80;
}
}
else//如果采集的电压值,比阈值要小,熄灭
ucLed &= (~0x80);
}
5.定时器中断
void tm1_isr() interrupt 3
{
ms_Tick++;//滴答定时器,能记录的数据长达29天
if(++Key_Slow_Down == 10) Key_Slow_Down = 0;//减速变量区,控制子函数的刷新频率
if(++Seg_Slow_Down == 500) Seg_Slow_Down = 0;
if(++Led_Slow_Down == 100) Led_Slow_Down = 0;
if((ms_Tick%1000) == 0)
{
freq = ((TH0<<8)|TL0);
TH0 = 0;
TL0 = 0;
}
Seg_Disp(seg_buf, pos);//用于数码管显示
if(++pos == 8) pos = 0;
Led_Disp(ucLed);//用于LED显示
}
6.消除85°C显示
void Delay750ms() //@12.000MHz 用来消除85°C显示
{
unsigned char i, j, k;
_nop_();
_nop_();
i = 35;
j = 51;
k = 182;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}