【蓝桥杯单片机第八届国赛真题】

【蓝桥杯单片机第八届国赛真题】


前言

在这里插入图片描述

有幸进入国赛,为自己大学最后一个比赛画上完满的句号^@^

下面为蓝桥杯单片机第八届国赛程序部分,功能差不多都实现了,可能存在小bug,望大佬指正,总体来说这届难度并不是很大,有需完整工程的小伙伴可自行下载。

在这里插入图片描述

工程链接

链接: https://pan.baidu.com/s/15ertnZFP9RKCB_-hdL5VQA?pwd=fkw2 提取码: fkw2 复制这段内容后打开百度网盘手机App,操作更方便哦 
--来自百度网盘超级会员v5的分享

注意点

这届难度并不是很大,值得注意的是在进行EEPROM存储10次测距时,可以用更好的方式,下面为我使用的存储形式。


void Save_AT24C02_Data(void)
{
	static uchar i = 0;
	if(Read_AT24C02(0x00) == 0xee)  //上电不是第一次
	{
		set_dis = Read_AT24C02(0x88);
		Delay10ms();
		//读取10次存储的数据
		for(i = 0;i<10;i++)
		{
			dis_info[i] = (Read_AT24C02(i) << 8) |Read_AT24C02(i+10);
			Delay10ms();

		}
	}
	else
	{
		Write_AT24C02(0x00,0xee);
		for(i = 0;i <10;i++)             //第一次上电时都是0
		{
			Write_AT24C02(i,0);
			Delay10ms();
			Write_AT24C02(i+10,0);
			Delay10ms();
		}
	}
}

Save_AT24C02_Data这个函数的功能是进行初始化时,进行存储EEPROM中数据的读取,Read_AT24C02(0x00) == 0xee这句判断是为了非第一次上电进行之前内容的读取,else 里面的内容相当于进行第一次上电的初始化,因为数组是存储测距的数据所以在第一次上电时全部设置了0。
Write_AT24C02(i,0);
Delay10ms();
Write_AT24C02(i+10,0);
Delay10ms();
这里进行加10是为了进行存储地址区分,因为EEPROM这里只能读取一个字节,如果所测的距离在一个字节范围内当然可以直接进行该地址内容的读取和写入,防止所测距离大于一个字节的范围这里每次所测 的数据都放在了两个地址中,见data_task函数中进行EEPROM数据的写入,其中number为数组下标索引。
Write_AT24C02(number,dis_info[number] >> 8); //写高位
Delay10ms();
Write_AT24C02(number+10,dis_info[number] & 0xff); //写低位
Delay10ms();

一、真题

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

二、源码

在main.c中主要分为5部分功能,smg_task数码管显示任务、data_task数据处理任务、logical_task逻辑处理任务、key_task按键任务以及中断任务。
/*=======================================第八届国赛==================================
@Author:小殷同学
@Date:2023.6.2
===================================================================================*/
#include <STC15F2K60S2.H>
#include "public.h"
#include "iic.h"
/*====================================下面为变量相关定义============================*/
//数码管段码(0~9、shut-off、"-")
code uchar smg_data[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0xbf,0x8e};
//初始化,使所有数码管熄灭(必须是9个元素)
xdata uchar smg_bit[11] = {10,10,10,10,10,10,10,10,10};
uchar L[9];
xdata uchar  dis_info[10] = {0},info_index = 0;        //数组存储10组数据 下标索引
uchar number = 0;                                      //索引号
bit start_dis = 0;                                     //开始测距
bit dis_mode = 0;                                      //模式
bit finish_flag = 0,l1_flash = 0;                      //完成标志 和l1闪烁
uchar adc = 0;                                         //dac
uchar interface = 1;                          		   //界面
bit s5_flag = 0;                              		   //s5标志
uint dis = 0,sum_dis = 0,old_dis = 0,temp_dis =0,set_dis = 0;          //超声波距离 上次和本次和  上一次值
uchar dis_feq = 0;                             //超声波测距频率
uchar key_feq = 0;                             //按键扫描频率
/*===================================下面为函数相关声明================================*/
void smg_task(void);                            //数码管显示任务
void data_task(void);                           //数据处理任务
void logical_task(void);                        //逻辑处理任务
void key_task(void);                            //按键任务
void Save_AT24C02_Data(void);                   //存储读取数据AT24C02
/*==================================下面为函数相关实现==================================*/
void smg_task(void)
{
	//测距界面
	if(interface == 1)
	{
		smg_bit[1] = dis_mode;
		smg_bit[2] = 10;
		smg_bit[3] = 10;
		if(dis_mode == 0)
		{
			smg_bit[4] = old_dis/10;
			smg_bit[5] = old_dis%10;
		}
		else 
		{
			smg_bit[4] = sum_dis/10;
			smg_bit[5] = sum_dis%10;
		}
		smg_bit[6] = dis/100;
		smg_bit[7] = dis/10%10;
		smg_bit[8] = dis%10;
	}
	//回显界面
	else if(interface == 2)
	{
		smg_bit[1] = (number+1)/10; //加1 为了让显示索引从1-10 数组下标为0-9
		smg_bit[2] = (number+1)%10;
		smg_bit[3] = 10;
		smg_bit[4] = 10;
		smg_bit[5] = 10;
		smg_bit[6] = dis_info[number]/100;
		smg_bit[7] = dis_info[number]/10%10;
		smg_bit[8] = dis_info[number]%10;
	}
	//参数界面
	else if(interface == 3)
	{
		smg_bit[1] = 12;   //F 0111 0001 0x8e
		smg_bit[2] = 10;     
		smg_bit[3] = 10;
		smg_bit[4] = 10;
		smg_bit[5] = 10;
		smg_bit[6] = 10;
		smg_bit[7] = set_dis/10;
		smg_bit[8] = set_dis%10;
	}
}
void data_task(void)
{
	if(T2H < 0xd9)
	{
		if(start_dis)
		{
			if(dis_feq >120)
			{
				dis_feq = 1;
				temp_dis = dis;              //保存一次 在测距之前先保存之前的数据
				dis = get_distance();
				number++;                    //编号加加
				dis_info[number] = dis;      //数据存储
				start_dis = 0;
				finish_flag = 1;              //测距完成
				Write_AT24C02(number,dis_info[number] >> 8);  //写高位
				Delay10ms();
				Write_AT24C02(number+10,dis_info[number] & 0xff); //写低位
				Delay10ms();
			}
		}
	}
}

void logical_task(void)
{
	uchar i = 0;
	if(dis_mode == 0)
	{
		if(dis != temp_dis)         //判断距离是否发送改变
		{ 
			old_dis = temp_dis;
		}
	}
	else if(dis_mode == 1)
	{
		sum_dis = (dis + old_dis);
	}
	if(number > 10){
		number = 0;          //只测量10次
	}
	
	//DAC处理
	if(dis <= set_dis)
	{
		adc = 0;
		write_dac(0);  //0v
	}
	else
	{
		adc = (dis - set_dis)*0.02; 
		write_dac(adc * 51);
	}
	if(adc > 5)
	{
		write_dac(255);  //5v
	}
	
	//led控制
	if(finish_flag)
	{
		L[1] = (l1_flash == 1)?(1):(0);
	}
	
	L[7] = (interface == 3)?(1):(0);
	L[8] = (interface == 2)?(1):(0);

}


void key_task(void)
{
	uchar key_value = 0;
	static bit s5_flag = 0,s6_flag = 0;
	if(key_feq > 20)
	{
		key_feq = 1;
		key_value = Read_key();
	}
	switch(key_value)
	{
		case 4:
			start_dis = 1;
			interface = 1;
			break;
		case 5:
			if(s5_flag == 0)
			{
				s5_flag = 1;
				interface = 2;
			}
			else if(s5_flag == 1)
			{
				s5_flag = 0;
				interface = 1;
			}
			break;
		case 6:
			if(s6_flag == 0)
			{
				s6_flag = 1;
				interface = 3;
			}
			else if(s6_flag == 1)
			{
				s6_flag = 0;
				interface = 1;
			}
			break;
		case 7:
			if(interface == 1)
			{
				if(dis_mode == 0)
				{
					dis_mode = 1;
				}
				else if(dis_mode == 1)
				{
					dis_mode = 0;
				}
			}
			else if(interface == 2)
			{
				if(++number > 9)
				{
					number = 0;            //翻页索引
				}
			}
			
			//参数设置
			if(interface == 3)
			{
				//0-90
				if(set_dis < 90)
				{
					set_dis += 10;
				}
				else
				{
					set_dis = 0;
				}
				Write_AT24C02(0x88,set_dis);
				Delay10ms();
			}
			break;
		default:break;
	}
}

void Save_AT24C02_Data(void)
{
	static uchar i = 0;
	if(Read_AT24C02(0x00) == 0xee)  //上电不是第一次
	{
		set_dis = Read_AT24C02(0x88);
		Delay10ms();
		//读取10次存储的数据
		for(i = 0;i<10;i++)
		{
			dis_info[i] = (Read_AT24C02(i) << 8) |Read_AT24C02(i+10);
			Delay10ms();

		}
	}
	else
	{
		Write_AT24C02(0x00,0xee);
		for(i = 0;i <10;i++)             //第一次上电时都是0
		{
			Write_AT24C02(i,0);
			Delay10ms();
			Write_AT24C02(i+10,0);
			Delay10ms();
		}
	}
	
}

void Init_System(void)
{
	Control_IO(0x80,0xff);         //关闭LED
	Control_IO(0xa0,0x00);         //关闭继电器和蜂鸣器
	Control_IO(0xc0,0x00);         //关闭数码管
	Timer2Init();                  //定时器2初始化
	Save_AT24C02_Data();           //EEPROM数据读取
}

void main(void)
{
	Init_System();                 //系统初始化
	while(1)
	{
		smg_task();
		data_task();
		logical_task();
		key_task();
	}
}

/*=============================下面为中断相关处理=========================*/
void Timer2_Server() interrupt 12
{
	static uchar dsp_smg = 1,count = 0;
	static uint t = 0;
	//LED控制
	Control_IO(0x80,~(L[1] << 0 | L[2] << 1|L[7] << 6| L[8] << 7));
	//数码管控制
	Control_IO(0xc0,0x00);
	Control_IO(0xe0,smg_data[smg_bit[dsp_smg]]);
	Control_IO(0xc0,1 << (dsp_smg -1));
	if(++dsp_smg > 8)
	{
		dsp_smg = 1;
	}
	
	if(finish_flag)
	{
		if(t++ == 200)
		{
			t = 0;
			l1_flash = ~l1_flash;
			count++;
			if(count == 20)
			{
				count = 0;
				finish_flag = 0;
				L[1] = 0;       //防止第10次的时候L[1] 还处于亮灯状态
			}
		}
	}
	
	dis_feq++;
	key_feq++;
}

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小殷学长

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值