【蓝桥杯单片机第八届国赛真题】
文章目录
- 【蓝桥杯单片机第八届国赛真题】
- 前言
- 一、真题
- 二、源码
前言
有幸进入国赛,为自己大学最后一个比赛画上完满的句号^@^
下面为蓝桥杯单片机第八届国赛程序部分,功能差不多都实现了,可能存在小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++;
}