蓝桥杯第十届单片机国赛真题(CT107D——IAP15F2K61S2)

文章目录

  • 前言
  • 一、代码相关定义、声明
    • 1.头文件声明
    • 2.变量声明
    • 3.函数声明
  • 二、主要函数
    • 1.main函数
    • 2.按键扫描
    • 3.数码管显示
    • 4.数据采集
    • 5.串口处理
    • 6.LED指示功能
    • 7.定时器中断
    • 8.串口中断
    • 9.消除85°C显示
  • 三、省赛国赛经验


前言

相关说明:

开发板: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 "Usart.h"
#include "bsp_ultrasonic.h"

2.变量声明

//--定时器滴答变量
unsigned long ms_Tick = 0;

//--长短按判别计时
xdata unsigned long Long_Short_Touch_ms_Tick = 0;

//--定时器减速变量
unsigned int Key_Slow_Down;
unsigned int Seg_Slow_Down;
unsigned int Led_Slow_Down;
unsigned int Volatge_Output_Slow_Down;

//--按键专用变量
unsigned char Key_Value;
unsigned char Key_Old, Key_Down;

//--长按按键功能函数是否执行过标志
bit S8_Long_Touch_Func_Exc_Flag = 0;
bit S9_Long_Touch_Func_Exc_Flag = 0;

//--数码管专用变量
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;

bit Data_Compare_Interface_Flag = 0;//数据和参数界面标志位,0-数据界面,1-参数界面
unsigned char Data_Interface_Trans_Flag = 0;//数据界面三种显示标志,0-温度,1-距离,2-次数
bit Compare_Interface_Trans_Flag = 0;//参数界面两种显示标志,0-温度参数,1-距离参数

unsigned char Temp_Comp = 30;//温度参数比较值
unsigned char Dist_Comp = 35;//超声波距离参数比较值
unsigned char Temp_Comp_Old = 30;//温度参数进入时候的数值
unsigned char Dist_Comp_Old = 35;//超声波距离参数进入时候的数值


unsigned int Compare_Value_Change_Times = 1000;//参数变化次数
bit DA_Out_Ctrl_Flag = 0;//控制DA是否输出的标志0-启动DA输出,1-停止DA输出

xdata float Temp_Value;//温度传感器采集的数值
unsigned char Dist_Value;//超声波采集的距离值

//--EEPROM测试专用变量
unsigned char eeprom_string[2] = {0,0};//用于存储变化次数

//--串口专用变量
xdata unsigned int Usart_Slow_Down;
unsigned char Uart_Buf[15];//数据发送和接收的缓存区
unsigned char Uart_Buf_Index = 0;

unsigned char Uart_Send_Data_String[12];

3.函数声明

void Key_Proc(void);
void Seg_Proc(void);
void Led_Proc(void);
void Data_Collect_Proc(void);//数据采集函数
void Delay750ms();//用来消除85°C显示

二、主要函数

1.main函数

void main(void)
{

	Cls_Peripheral();//关闭LED/继电器/蜂鸣器
	Timer1Init();//定时器1初始化
	EA = 1;//打开总中断
	EEPROM_Read(eeprom_string, 0, 2);
	Compare_Value_Change_Times = (eeprom_string[0]<<8)|(eeprom_string[1]);
	UsartInit();
	Ultrasonic_Timer0Init();
	rd_temperature();
	Delay750ms();//用于消除上电显示85°C的影响
	while(1)
	{
		Key_Proc();
		Data_Collect_Proc();
		Seg_Proc();
		Led_Proc();
		Uart_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;//检测电平,一直按着一直等于一个数

	if(Key_Down != 0)//表示有按键按下去,也就是按键产生了下降沿,开始计时
	{
		Long_Short_Touch_ms_Tick = ms_Tick;
		S8_Long_Touch_Func_Exc_Flag = 0;//使能长按功能
		S9_Long_Touch_Func_Exc_Flag = 0;//使能长按功能
	}
	
	if((ms_Tick - Long_Short_Touch_ms_Tick) < 1000)//如果数值小于一秒,且产生了上升沿,认为是短按
	{
				
			switch(Key_Up)//这个结构很常见,判别是哪个按键按下去了,根据按键按下的情况,控制内部数据变量的变化
			{
				case 5://界面按键 ,0-数据界面,1-参数界面
						Data_Compare_Interface_Flag ^= 1;//完成数据界面和参数界面的切换
						Data_Interface_Trans_Flag = 0;//切换后,保证默认为第一个界面
						Compare_Interface_Trans_Flag = 0;//切换后,保证默认为第一个界面
			
						if(Data_Compare_Interface_Flag == 1)//如果刚刚跳转到参数界面,存储当前的参数值
						{
							Temp_Comp_Old = Temp_Comp;
							Dist_Comp_Old = Dist_Comp;
						}
						else //如果刚刚跳转到数据界面,判断数值是否发生变化,如果发生变化,变更次数+1
						{
							if((Temp_Comp_Old != Temp_Comp)||(Dist_Comp_Old != Dist_Comp))
							Compare_Value_Change_Times++;
							
							eeprom_string[0] = (Compare_Value_Change_Times>>8);//把高8位存储
							eeprom_string[1] = (Compare_Value_Change_Times & 0x00ff);//把低8位存储
							
						 //--EEPROM测试
							EEPROM_Write(eeprom_string, 0, 2);	

						}
						break;//这个break很重要
				
				case 4://切换按键
						if(Data_Compare_Interface_Flag == 0)//在数据界面
						{
							if(++Data_Interface_Trans_Flag == 3) Data_Interface_Trans_Flag =0;//完成0-2的变化,0-温度,1-距离,2-次数
						}
						else //表示在参数界面
						{
							Compare_Interface_Trans_Flag ^= 1;//完成0-1切换,0-温度参数,1-距离参数			
						}
						break;//这个break很重要				

				case 9://加功能
						if((Data_Compare_Interface_Flag == 1)&&(Compare_Interface_Trans_Flag == 0))//如果是温度参数界面
							Temp_Comp += 2;
						else if((Data_Compare_Interface_Flag == 1)&&(Compare_Interface_Trans_Flag == 1))//如果是距离参数界面
							Dist_Comp += 5;
						
						if(Temp_Comp >= 99) Temp_Comp = 99;//压制到99
						if(Dist_Comp >= 99) Dist_Comp = 99;						
						
						break;//这个break很重要				
				
				case 8://减功能
						if((Data_Compare_Interface_Flag == 1)&&(Compare_Interface_Trans_Flag == 0))//如果是温度参数界面
							Temp_Comp -= 2;
						else if((Data_Compare_Interface_Flag == 1)&&(Compare_Interface_Trans_Flag == 1))//如果是距离参数界面
							Dist_Comp -= 5;
						
						if(Temp_Comp >= 200) Temp_Comp = 0;//压制到0
						if(Dist_Comp >= 200) Dist_Comp = 0;							
						
						break;//这个break很重要				

			}
	}
	else //如果刚刚下降沿产生的时间,一旦超过1s,只要不更新Long_Short_Touch_ms_Tick数值,永远进入这个函数,认为是长按
	{
		if((Key_Old == 8)&&(S8_Long_Touch_Func_Exc_Flag == 0))//表示S8长按,且第一次执行
		{
			S8_Long_Touch_Func_Exc_Flag = 1;//立马变化,防止长按按钮没有释放的时候,再次执行
			Compare_Value_Change_Times = 0;//变化次数变为0
			eeprom_string[0] = 0;
			eeprom_string[1] = 0;
			EEPROM_Write(eeprom_string, 0, 2);				
		}
		
		else if((Key_Old == 9)&&(S9_Long_Touch_Func_Exc_Flag == 0))//表示S9长按,且第一次执行
		{
			S9_Long_Touch_Func_Exc_Flag = 1;//立马变化,防止长按按钮没有释放的时候,再次执行		
			DA_Out_Ctrl_Flag ^= 1;//DA输出标志位翻滚
		}
	}
}

3.数码管显示

void Seg_Proc(void)
{
	if(Seg_Slow_Down) return;
	Seg_Slow_Down = 1;
	
	if(Data_Compare_Interface_Flag == 0)//0-数据界面
	{
		switch(Data_Interface_Trans_Flag)//0-温度,1-距离,2-次数
		{
			case 0:
				sprintf(seg_string,"C   %5.2f",Temp_Value);	
				break;
			
			case 1:
				sprintf(seg_string,"L     %02d",(unsigned int)Dist_Value);					
				break;		
		
			case 2:
				sprintf(seg_string,"N  %5d",(unsigned int)Compare_Value_Change_Times);					
				break;		
		}
	}
	else//1-参数界面
	{
		if(Compare_Interface_Trans_Flag == 0) //0-温度参数,1-距离参数	
				sprintf(seg_string,"P  1  %02d",(unsigned int)Temp_Comp);			
		else
				sprintf(seg_string,"P  2  %02d",(unsigned int)Dist_Comp);			
	}
	
	Seg_Tran(seg_string, seg_buf);
}

4.数据采集

void Data_Collect_Proc(void)//每500ms采集一次数据
{
		if(Data_Collect_Slow_Down) return;
	Data_Collect_Slow_Down = 1;

	Temp_Value = (rd_temperature()/16.0);//温度传感器采集的数值
  Dist_Value = Wave_Recv();
	if(Dist_Value > 99)
		Dist_Value = 99;
	
	//借用一片地方,用于DA的输出
	if(DA_Out_Ctrl_Flag == 0)//0-启动 1-停止
	{
		if(Dist_Value <= Dist_Comp)
			Pcf8591_Dac(102);//输出2v
		else 
			Pcf8591_Dac(204);//输出4v
	}
	else
			Pcf8591_Dac(20);//输出0.4v
}

5.串口处理

void Uart_Proc(void)
{
	if(Usart_Slow_Down) return;
		Usart_Slow_Down = 1;
	
	if((Uart_Buf[Uart_Buf_Index-1] == 0x0a)&&(Uart_Buf[Uart_Buf_Index-2] == 0x0d))//拿到的数据帧的倒数后两位为帧尾,表示收到一个数据帧
	{
		if((Uart_Buf_Index == 4)&&(Uart_Buf[0]=='S')&&(Uart_Buf[1]=='T'))//收到第一种指令ST
		{
			sprintf(Uart_Send_Data_String,"$%02d,%5.2f\r\n",(unsigned int)Dist_Value,Temp_Value);
		}
		else if ((Uart_Buf_Index == 6)&&(Uart_Buf[0]=='P')&&(Uart_Buf[1]=='A')&&(Uart_Buf[2]=='R')&&(Uart_Buf[3]=='A'))//收到第二种指令PARA
		{
			sprintf(Uart_Send_Data_String,"#%02d,%02d\r\n",(unsigned int)Dist_Comp,(unsigned int)Temp_Comp);		
		}
		else//其他情况
		{
			sprintf(Uart_Send_Data_String,"ERROR\r\n");			
		}
		Usart_Send_String(Uart_Send_Data_String);//自动寻找最后一个位置为\0地方,控制发送结束
		Uart_Buf_Index = 0;
		
	}
	else if(Uart_Buf_Index > 6)//表示一直没有收到想要的数据帧
	{
		sprintf(Uart_Send_Data_String,"ERROR\r\n");		
		Usart_Send_String(Uart_Send_Data_String);//自动寻找最后一个位置为\0地方,控制发送结束
		Uart_Buf_Index = 0;		
	}
}

6.LED指示功能

void	Led_Proc(void)
{
	if(Led_Slow_Down) return;
	Led_Slow_Down = 1;
		
 	//温度值比较
	if(Temp_Value <= Temp_Comp)//熄灭L1
		ucLed &= (~0x01);
	else //点亮L1
		ucLed |= 0x01;		
 
	//距离比较
	if(Dist_Value < Dist_Comp)//点亮L2
		ucLed |= 0x02;	
	else //熄灭L2
		ucLed &= (~0x02);
	
	//DA输出
	if(DA_Out_Ctrl_Flag == 0)//启动状态,L3点亮
		ucLed |= 0x04;	
	else //停止状态,L3熄灭
		ucLed &= (~0x04);				
}

7.定时器中断

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(++Volatge_Output_Slow_Down == 500) Volatge_Output_Slow_Down = 0;
	if(++Usart_Slow_Down == 100) Usart_Slow_Down = 0;		
	
    Seg_Disp(seg_buf, pos);//用于数码管显示
	if(++pos == 8) pos = 0;
	
	Led_Disp(ucLed);//用于LED显示
}

8.串口中断

void Uart() interrupt 4
{
	if (RI)
	{
		RI = 0;                 //清除RI位

		Uart_Buf[Uart_Buf_Index] = SBUF;              //P0显示串口数据
		Uart_Buf_Index++;//第n个数据过来之后,变成了n
	}
}

9.消除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);
}

三、省赛国赛经验

  省赛和国赛的题目最起码要做过一遍。主要训练逻辑思路,可以先用自己写好的各个模块驱动代码。比赛前几天全部代码都要重新写,包括新建工程开始,到各个驱动模块代码。比赛的时候,我是先写好大模板和各个模块的代码,然后才开始做按要求去实现功能的,功能由简单到难。

你可能感兴趣的:(蓝桥杯真题,单片机,蓝桥杯,51单片机,c语言)