【蓝桥杯单片机第六届国赛真题】
前言
有幸进入国赛,为自己大学最后一个比赛画上完满的句号^@^
下面为蓝桥杯单片机第六届国赛程序部分,功能差不多都实现了,可能存在小bug,望大佬指正,总体来说这届难度并不是很大,有需完整工程的小伙伴可自行下载。
链接: https://pan.baidu.com/s/1Hig3ys3Upz3BfHpNFcnj5Q?pwd=4dbj 提取码: 4dbj 复制这段内容后打开百度网盘手机App,操作更方便哦
--来自百度网盘超级会员v5的分享
一、真题
二、源码
在main.c中主要分为5部分功能,smg_task数码管显示任务、data_task数据处理任务、logical_task逻辑处理任务、key_task按键任务以及中断任务。
/*====================================第六届蓝桥杯单片机组国赛==================================
@Author:小殷童鞋
@Date:2023.6.1
*************************************************************************************************/
#include "public.h"
#include "iic.h"
/*=========================================下面为宏和变量定义====================================*/
//LED控制
uchar L[5];
uchar relay = 0;
uchar buzzer = 0;
//设置为10对应着0xff 关闭数码管初始化
uchar smg_bit[9] = {10,10,10,10,10,10,10,10,10};
//数码管段码 0-9 shut-off -
uchar smg_data[] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xff,0xbf};
uchar interface = 1; //界面变量
uchar adc = 0; //rb2 adc
uint volt = 0; //rb2电压
uint distance = 0; //超声波距离
uchar number = 0; //货物类别编号
uchar work_mode = 0; //1 为空载 2为非空载 3 为过载
bit l3_flag = 0; //L3闪烁标志位
uchar set_t1 = 2,set_t2 = 4; //第一类和第二类默认传送时间
bit start = 0; //开始传送
bit emergy_stop = 0; //停止传送
bit l4_flag = 0; //L4 闪烁标志
uchar set_bit = 0; //调整时间位
bit s6_flag = 0; //S6按下标志
bit set_bit_flash = 0;
//下面为数据刷新频率
uchar adc_feq = 0; //rb2采集频率
uchar key_feq = 0; //按键刷新频率
uchar dis_feq = 0; //超声波刷新频率
/*==========================================下面为函数相关声明=====================================*/
void Init_System(void); //系统初始化
void smg_task(void); //数码管显示任务
void data_task(void); //数据处理任务
void key_task(void); //按键处理任务
void logical_task(void); //逻辑处理任务
/*===========================================下面为函数实现=========================================*/
void smg_task(void)
{
if(interface == 1)
{
smg_bit[1] = interface;
smg_bit[2] = 10;
smg_bit[3] = 10;
smg_bit[4] = distance/10%10;
smg_bit[5] = distance%10;
smg_bit[6] = 10;
smg_bit[7] = 10;
smg_bit[8] = number;
}
else if(interface == 2)
{
//第一类时间
smg_bit[1] = interface;
smg_bit[2] = 10;
smg_bit[3] = 10;
smg_bit[4] = 10;
smg_bit[5] = 10;
smg_bit[6] = 10;
if(number == 1)
{
smg_bit[7] = set_t1/10;
smg_bit[8] = set_t1%10;
}
else
{
smg_bit[7] = set_t2/10;
} smg_bit[8] = set_t2%10;
}
else if(interface == 3)
{
smg_bit[1] = interface;
smg_bit[2] = 10;
smg_bit[3] = 10;
if(set_bit == 1)
{
if(set_bit_flash)
{
smg_bit[4] = set_t1/10;
smg_bit[5] = set_t1%10;
}
else
{
smg_bit[4] = 10;
smg_bit[5] = 10;
}
smg_bit[7] = set_t2/10;
smg_bit[8] = set_t2%10;
}
else if(set_bit == 2)
{
if(set_bit_flash)
{
smg_bit[7] = set_t2/10;
smg_bit[8] = set_t2%10;
}
else
{
smg_bit[7] = 10;
smg_bit[8] = 10;
}
}
smg_bit[6] = 10;
}
}
void data_task(void)
{
if(T2H < 0xd9)
{
if(dis_feq > 120)
{
dis_feq = 1;
distance = get_distance();
}
if(adc_feq > 150)
{
adc_feq = 1;
adc = read_rb2();
volt = adc * (5.0/255) * 100; //扩大100倍方便处理
//通过电压判断空载 非空载 过载
if(volt > 0 && volt < 100)
{
//空载
work_mode = 1;
}
else if(volt >= 100 && volt < 400)
{
//非空载
work_mode = 2;
}
else if(volt >= 400)
{
//过载
work_mode = 3;
}
}
}
}
void logical_task(void)
{
//通过距离判断货物类:大于30为2类 小于等于为1类
number = (distance > 30)?(2):(1);
//空载
L[1] = (work_mode == 1)?(1):(0);
//非空载
L[2] = (work_mode == 2)?(1):(0);
//过载 0.5s 闪烁
if(work_mode == 3)
{
L[3] = (l3_flag == 1)?(1):(0);
buzzer = 1;
}
else
{
L[3] = 0;
buzzer = 0;
}
//继电器控制
relay = (start == 1)?(1):(0);
//下面为紧急按键控制逻辑
L[4] = (l4_flag == 1)?(1):(0);
}
void key_task(void)
{
uchar key_value = 0;
if(key_feq > 20)
{
key_feq = 1;
key_value = read_key();
}
if(key_value == 4)
{
if(work_mode == 1 || work_mode == 3 || start == 1)
{
//无效
}
else
{
start = 1;
interface = 2;
}
}
else if(key_value == 5)
{
//在传送过程中才有效
if(start == 1)
{
//紧急停止 继电器断开 L4 0.5s闪烁 计时停止 再次按下传送恢复L4熄灭 恢复计时
if(emergy_stop == 0)
{
emergy_stop = 1;
l4_flag = 1;
}
else if(emergy_stop == 1)
{
emergy_stop = 0;
l4_flag = 0;
}
}
}
//下面按键仅在空载有效
else if(key_value == 6)
{
//时间设置按键
//第一次按下设置第一类时间 第二次设置第二类时间 第三次保存调整后的数据到EEPROM并关闭数码管显示
if(work_mode == 1)
{
s6_flag = 1;
interface = 3;
if(set_bit == 0)
{
set_bit = 1; //第一类
}
else if(set_bit == 1)
{
set_bit = 2; //第二类
}
else if(set_bit == 2)
{
set_bit = 3; //存储到eeprom
s6_flag = 0;
write_eeprom(0x01,set_t1);
Delay10ms();
write_eeprom(0x03,set_t2);
Delay10ms();
}
else if(set_bit == 3)
{
set_bit = 1;
}
}
}
else if(key_value == 7)
{
//时间调整
if(work_mode == 1 && interface == 3)
{
if(set_bit == 1)
{
//调整第一类时间
if(set_t1 >= 10)
{
set_t1 = 1;
}
else
{
set_t1++;
}
}
else if(set_bit == 2)
{
//调整第二类时间
if(set_t2 >= 10)
{
set_t2 = 1;
}
else
{
set_t2++;
}
}
}
}
}
void Init_System(void)
{
Control_IO(0x80,0xff); //关闭LED
Control_IO(0xa0,0x00); //关闭蜂鸣器和继电器
Control_IO(0xc0,0x00); //关闭数码管
Timer2Init(); //定时器2初始化
if(read_eeprom(0x00) == 0xff) //不是第一次上电
{
set_t1 = read_eeprom(0x01);
Delay10ms();
set_t2 = read_eeprom(0x03);
Delay10ms();
}
else
{
write_eeprom(0x00,0xff);
Delay10ms();
write_eeprom(0x01,set_t1);
Delay10ms();
write_eeprom(0x03,set_t2);
Delay10ms();
}
}
void main(void)
{
Init_System();
while(1)
{
logical_task(); //逻辑处理任务
smg_task(); //数码管显示任务
data_task(); //数据处理任务
key_task(); //按键处理任务
}
}
/*===============================================下面为中断处理========================================*/
void Timer2_Server() interrupt 12
{
static uchar dsp_smg = 1;
static uint l3_t = 0,time = 0,l4_t = 0,flash_t = 0;
//LED控制
Control_IO(0x80,~(L[1] << 0 | L[2] << 1| L[3] <<2 | L[4] <<3));
//继电器和蜂鸣器控制
Control_IO(0xa0,relay << 4 | buzzer << 6);
//数码管控制 空载下所有数码管熄灭
if(work_mode == 1 && s6_flag == 0)
{
Control_IO(0xc0,0x00);
}
else
{
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;
}
}
//L3闪烁控制
if(work_mode == 3)
{
if(l3_t++ == 500)
{
l3_t = 0;
l3_flag = ~l3_flag;
}
}
//L4 闪烁控制
if(emergy_stop == 1)
{
if(l4_t++ == 500)
{
l4_t = 0;
l4_flag = ~l4_flag;
}
}
//数码管闪烁时间设置
if(set_bit == 1 ||set_bit == 2)
{
if(flash_t ++ == 500)
{
flash_t = 0;
set_bit_flash = ~set_bit_flash;
}
}
if(start == 1 && emergy_stop == 0)
{
time++;
if(time == 1000) //1s
{
time = 0;
if(number == 1)
{
if(set_t1 > 0)
{
set_t1--;
}
else
{
set_t1 = 0; //时间到
start = 0;
}
}
else if(number == 2)
{
if(set_t2 > 0)
{
set_t2--;
}
else
{
set_t2 = 0;
start = 0;
}
}
}
}
//下面为数据刷新频率变量
adc_feq++;
key_feq++;
dis_feq++;
}