蓝桥杯---第六届省赛单片机组真题

发布于:2025-08-14 ⋅ 阅读:(15) ⋅ 点赞:(0)

先出手写的代码,代码分析还需要一段时间,不难,大家认真写。

#include <STC15F2K60S2.H>
#include "Seg.h"
#include "LED.h"
#include "Key.h"
#include "DS1302.h"
#include "DS18B20.h"

idata unsigned char DS18B20_Flag = 0;  //DS18B20采集标志位,为1开始采集
idata unsigned char DS1302_Slow_Down;  //DS1302实时时钟读取延时
idata unsigned char Seg_Slow_Down;  //数码管延时变量
idata unsigned char Key_Slow_Down;  //按键延时变量
idata unsigned char Seg_Buf[8]={10,10,10,10,10,10,10,10};  //数码管显示内容
idata unsigned char Seg_Scan;   //数码管扫描
idata unsigned char LED_Buf[8]={0,0,0,0,0,0,0,0};    //LED亮灭数据
idata unsigned char Key_Val,Key_Down,Key_Up,Key_Old;  //按键参数
unsigned char Time[3]={23,59,50};  //存储时间
idata unsigned char Temper;   //温度

unsigned char Seg_Show_Mode;  //数码管显示模式
idata unsigned char Gather_Time[4] = {1,5,30,60};  //设置采集时间数组
idata unsigned char Gather_Time_Index;   //设置采集时间指针,用于变化采集时间
idata unsigned char Real_Gather_Time;   //采集时间,将设置值传给Real_Gather_Time

idata unsigned int Time_1000ms;    //计时1s,用于设计时钟界面1s闪烁
idata unsigned char Time_1000_Flag;   

idata unsigned char Temper_Gather[10];    //采集温度数据
idata unsigned char Temper_Gather_Index;   //温度数组指针
idata unsigned int Time_1000_Gather;      //用于采集界面计时
idata unsigned char Count;     //1s变化一次,相当与秒计时器

idata unsigned char LED_Disable_Flag;   //按下按键6可以开始展示温度,同时熄灭LED,LED_Disable_Flag == 1时表示熄灭
idata unsigned int Time_1000_LED;     //单独设计LED周期闪烁,防止4T判断时周期错误
idata unsigned char Time_1000_LED_Flag;

void System_Init()  //系统初始化
{
	unsigned char temp;
	
	//关闭所有LED
	P0 = 0xff;
	temp = P2 & 0x1f;
	temp = temp | 0x80;
	P2 = temp;
	temp = P2 & 0x1f;
	P2 = temp;
	
	//关闭外设
	P0 = 0x00;
	temp = P2 & 0x1f;
	temp = temp | 0xa0;
	P2 = temp;
	temp = P2 & 0x1f;
	P2 = temp;
	
}

//定时器一初始化,自己加上EA = 1;ET1 = 1;
void Timer1_Init(void)		//1毫秒@12.000MHz
{
	AUXR &= 0xBF;			//定时器时钟12T模式
	TMOD &= 0x0F;			//设置定时器模式
	TL1 = 0x18;				//设置定时初始值
	TH1 = 0xFC;				//设置定时初始值
	TF1 = 0;				//清除TF1标志
	TR1 = 1;				//定时器1开始计时
	EA = 1;                 //打开总中断
	ET1 = 1;                //打开定时器一中断允许位
}


void Key_Proc()   //按键处理函数
{
	if(Key_Slow_Down <20) return;  //按键减速
	   Key_Slow_Down = 0;
	
	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_Show_Mode == 0)
			{
				LED_Disable_Flag = 0;    //复位LED_Disable_Flag
			if(++Gather_Time_Index == 4)   //选择采集时间
				Gather_Time_Index = 0;
		    }
		break;
			
		case 5: //确定采集时间,开始采集
			if(Seg_Show_Mode == 0)
			{
				Real_Gather_Time = Gather_Time[Gather_Time_Index]; //确定采集时间
				Gather_Time_Index  = 0;
				Seg_Show_Mode = 1;   //开始采集
			}
		break;
			
		case 6:  //开始展示数据
			if(Seg_Show_Mode == 2)
			{
				LED_Disable_Flag = 1;
				if(++Temper_Gather_Index == 10)
					Temper_Gather_Index = 0;
			}
		break;
			
		case 7:  //重新确认采集时间,重新开始采集
			if(Seg_Show_Mode == 2)
			{
				Seg_Show_Mode = 0;
				Temper_Gather_Index = 0;
		        Time_1000_Gather = 0;
		        Count = 0;
			}
		break;
	}
}


void Seg_Proc()   //数码管处理函数
{
	if(Seg_Slow_Down <100) return;  //减速
	   Seg_Slow_Down = 0;
	
	switch(Seg_Show_Mode)
	{
		case 0:  //采集时间界面
			Seg_Buf[0] = Seg_Buf[1] = Seg_Buf[2] = Seg_Buf[3] = Seg_Buf[4] = 10;  //熄灭
			Seg_Buf[5] = 11;  //-
		    Seg_Buf[6] = Gather_Time[Gather_Time_Index]/10%10;
		    Seg_Buf[7] = Gather_Time[Gather_Time_Index]%10;
		break;
		
		case 1:  //时间显示界面(界面二)
	       Seg_Buf[0] = Time[0]/10%10;
	       Seg_Buf[1] = Time[0]%10;
		
		   Seg_Buf[2] = Time_1000_Flag ? 11:10;  //闪烁
		
	       Seg_Buf[3] = Time[1]/10%10;
	       Seg_Buf[4] = Time[1]%10;
		
	       Seg_Buf[5] = Time_1000_Flag ? 11:10;  //闪烁
		
	       Seg_Buf[6] = Time[2]/10%10;
	       Seg_Buf[7] = Time[2]%10;
		break;
		
		case 2:   //数据显示界面(界面三)
			
		   Seg_Buf[0] = 11;  //-
		
	       Seg_Buf[1] = Temper_Gather_Index/10%10;   //索引值
		   Seg_Buf[2] = Temper_Gather_Index%10;
		
	       Seg_Buf[3] = Seg_Buf[4] = 10;
	       Seg_Buf[5] = 11;  //-
		
	       Seg_Buf[6] = Temper_Gather[Temper_Gather_Index]/10%10;  //采集数据
	       Seg_Buf[7] = Temper_Gather[Temper_Gather_Index]%10;
		
		break;
		
	}
}

void LED_Proc()  //LED处理函数
{
	LED_Buf[0] = (Seg_Show_Mode == 2) & (LED_Disable_Flag == 0) & (Time_1000_LED_Flag) ;
	//当处于界面二时采集数据完成,自动跳转界面三(显示界面),此时按下S6(LED_Disable_Flag == 1直接熄灭)
	//Time_1000_LED_Flag闪烁控制
	//LED亮的条件,处于界面三,未按下S6,Time_1000_LED_Flag条件为真
}

void DS1302_Proc()  // DS1302处理函数
{
	if(DS1302_Slow_Down <160) return;  //减速
	   DS1302_Slow_Down = 0;
	
	DS1302_Read();  //获取时间
}

void DS18B20_Proc()
{
	if(DS18B20_Flag == 0) return;    //未到单次采集时间,不采集
	DS18B20_Flag = 0;   //DS18B20_Flag == 1开始采集一次,复位标志位
	
	Temper_Gather[Temper_Gather_Index] = (unsigned char)Temperature_Read(); //开始采集
	Temper_Gather_Index++;
	
	if(Temper_Gather_Index == 10)  //采集完成,自动跳转界面三显示
	{
		Seg_Show_Mode = 2;
		Temper_Gather_Index = 0;
		Time_1000_Gather = 0;
		Count = 0;
	}
}

void main()
{
	System_Init();
	Timer1_Init();
	DS1302_Write();
	while((unsigned char)Temperature_Read() == 85);
	while(1)
	{
		Key_Proc();
		Seg_Proc();
		LED_Proc();
		DS1302_Proc();
		DS18B20_Proc();
	}
}

//定时器一中断打开---中断标志位3
void Timer1_Routine() interrupt 3
{
	Seg_Slow_Down++;
	Key_Slow_Down++;
	DS1302_Slow_Down++;
	
	if(Seg_Show_Mode == 2 && (LED_Disable_Flag == 0))  //处于界面三且未按下S6,开始闪烁
	{
		if(++Time_1000_LED == 1000)
	{
		Time_1000_LED = 0;
		Time_1000_LED_Flag ^=1; 
	}
	}
	else  //不满足则清空计时
	{
		Time_1000_LED = 0;
	}
	
	if(++Time_1000ms == 1000)  //设计时间显示界面闪烁
	{
		Time_1000ms = 0;
		Time_1000_Flag ^=1; 
	}
	
	if(Seg_Show_Mode == 1)  //处于时间显示界面,开始采集数据
	{
		if(++Time_1000_Gather == 1000)   //计时
		{
			Count++;   //秒计时器
			Time_1000_Gather = 0;
			if(Count == Real_Gather_Time)   //当秒计时器达到采集时间间隔
			{
				Count = 0;
				DS18B20_Flag = 1;   //开始温度采集
			}
		}
	}
	
	if(++Seg_Scan == 8) Seg_Scan = 0;
	if(Seg_Buf[Seg_Scan] > 20)  //判断带小数点的数据
		Seg_Disp(Seg_Scan,Seg_Buf[Seg_Scan]-',',1);
	else
		Seg_Disp(Seg_Scan,Seg_Buf[Seg_Scan],0);
	
	LED_Disp(LED_Buf);         //LED扫描
}


网站公告

今日签到

点亮在社区的每一天
去签到