【蓝桥杯单片机第十三届国赛真题】
·
【蓝桥杯单片机第十三届国赛真题】
前言
有幸进入国赛,为自己大学最后一个比赛画上完满的句号^@^
下面为蓝桥杯单片机第十三届国赛程序部分,功能差不多都实现了,可能存在小bug,望大佬指正,有需完整工程的小伙伴可自行下载。
注意
这届国赛中使用到的资源比较多,频率,超声波都有同时使用到,一般来说都是用定时器0来进行超声波测距和频率的发生,很显然这次不行,在该工程中超声波测距使用的是PCA方式,频率还是使用定时器0,定时器2则用于数码管刷新以及其他数据周期刷新处理。定时器1也可用作超声波测距,但该题目中还有pwm输出,虽然定时器1我用作了pwm输出。具体定时器的分配可根据题目功能需求以及个人习惯来进行合理的分配使用即可。
1.PCA测距方式
/*==========================PCA方式进行超声波测距=========================*/
sbit TX = P1^0;
sbit RX = P1^1;
uint time_us = 0;
bit flag_over = 0;
void PCA_Init(void)
{
CCON = 0;
CMOD = 0x01;
CCAPM0 = 0x11;
}
void PAC_Server() interrupt 7
{
CR = 0;
if(CCF0)
{
CCF0 = 0;
time_us = (uint)(CCAP0H << 8)|CCAP0L;
flag_over = 0;
}
else if(CF)
{
CF = 0;
flag_over = 1;
}
}
void Delay12us() //@12.000MHz
{
unsigned char i;
_nop_();
_nop_();
i = 33;
while (--i);
}
void Send_Wave(void)
{
uchar i = 0;
for(i = 0;i<8;i++)
{
TX = 0;
Delay12us();
TX = 1;
Delay12us();
}
}
uint Get_Distance(void)
{
uint dis = 0;
Send_Wave();
CH = CL = 0;
CCF0 = CF = 0;
CR = 1;
if(flag_over)
{
dis = 999;
}
else
{
dis = time_us * 0.017 + 0.5;
}
return dis;
}
2.定时器1pwm输出
根据题目要求输出1khz 也及时1000us,这里定时中断设置为200us,整个周期分为5分,当所测频率大于频率参数时输出80%占空比,也就是4份,否则输出20%占空比也就是1份。
void Timer1Init(void) //200微秒@12.000MHz
{
AUXR |= 0x40; //定时器时钟1T模式
TMOD &= 0x0F; //设置定时器模式
TL1 = 0xA0; //设置定时初始值
TH1 = 0xF6; //设置定时初始值
TF1 = 0; //清除TF1标志
TR1 = 1; //定时器1开始计时
ET1 = 1;
EA = 1;
}
//定时器1中断用于产生PWM输出 200us中一次中断
void Timer1_Server() interrupt 3
{
static uchar pwm_count = 0;
pwm_count++;
if(pwm_count > 0 && pwm_count <= pwm_duty_value)
{
motor = 1;
}
else if(pwm_count > pwm_duty_value)
{
motor = 0;
}
else if(pwm_count == 5) //一个周期
{
pwm_count = 0;
}
}
工程链接
链接: https://pan.baidu.com/s/1bDhoTTWmTVtBvJlEvwI18g?pwd=87ih 提取码: 87ih 复制这段内容后打开百度网盘手机App,操作更方便哦
--来自百度网盘超级会员v5的分享
一、真题
二、源码
在main.c中主要分为5部分功能,smg_task数码管显示任务、data_task数据处理任务、logical_task逻辑处理任务、key_task按键任务以及中断任务。
/*=========================第十三届国赛===========================
@Author:小殷同学
@Date:2023.5.31
==================================================================*/
#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,0x89,0x88,0x8c};
//初始化,使所有数码管熄灭(必须是9个元素)
uchar relay = 0; //继电器
uchar motor = 0; //电机
uchar pwm_duty_value = 0; //电机PWM占空比
uchar L[9]; //LED
xdata uchar smg_bit[11] = {10,10,10,10,10,10,10,10,10}; //数码管位
xdata uint feq_value = 0; //频率值 hz
xdata uint feq_value_khz = 0; //频率值 khz
uchar relay_count = 0; //继电器开关次数
uint param_feq_value_khz = 9*10; //频率参数 khz
uchar param_humi_value = 40; //湿度参数
uchar param_dis_value = 6; //距离参数
xdata uint dis_value_cm = 0; //距离值 cm
xdata uint dis_value_m = 0; //距离值 m
uint humi_value = 0; //湿度值
uchar data_interface = 1; //数据界面
uchar param_interface = 1; //参数界面
uchar f_index = 1; //频率索引
uchar dis_index = 1; //距离索引
uint adc_value = 0; //adc值
bit l1_flash = 0,l2_flash = 0,l3_flash = 0; //L1 L2 L3闪烁标志位
uchar adc_feq = 0; //adc 采集刷新频率
uchar key_feq = 0; //按键刷新频率
uchar led_feq = 0; //LED刷新频率
uchar dis_feq = 0; //超声波刷新频率
/*===========================下面为函数相关声明=====================*/
void data_task(void);
void logical_task(void);
void smg_task(void);
void key_task(void);
void Init_System(void);
/*============================下面为函数实现=========================*/
void data_task(void)
{
if(T2H < 0xd9)
{
if(adc_feq > 120)
{
adc_feq = 1;
adc_value = Raed_ADC(0x43);
adc_value = adc_value * (5.0/255)*100;
}
if(led_feq > 50)
{
led_feq = 1;
Control_IO(0x80,~(L[1] << 0|L[2] << 1 |L[3] <<2|L[4] << 3|L[5] << 4|L[6] << 5 | L[7]<<6|L[8] << 7));
Control_IO(0xa0,relay << 4 | motor << 5);
}
//测距
if(dis_feq > 150)
{
dis_feq = 1;
dis_value_cm = Get_Distance_PCA();
dis_value_m = dis_value_cm;
}
}
}
void logical_task(void)
{
static old_flag = 0,flag = 0;
//下面为湿度值逻辑计算 y = 20x
if(adc_value < 500)
{
humi_value = (20 * adc_value)/100.0;
}
else
{
humi_value = 99;
}
//下面为DAC输出
if(humi_value >= 0 && humi_value < 16)
{
Write_DAC(51); //1V
}
else if(humi_value >=16 && humi_value <= 80)
{
//y = 1/16*x
Write_DAC(51 * (1/16.0 * humi_value));
}
else
{
Write_DAC(255); //5V
}
//下面为LED逻辑判断
L[1] = (l1_flash == 1 && data_interface == 1)?(1):(0);
L[2] = (l2_flash == 1 && data_interface == 2)?(1):(0);
L[3] = (l3_flash == 1 && data_interface == 3)?(1):(0);
L[4] = (feq_value > param_feq_value_khz*100 || feq_value_khz > param_feq_value_khz)?(10):(0);
L[5] = (humi_value > param_humi_value)?(1):(0);
L[6] = (dis_value_cm > param_dis_value * 10)?(1):(0);
L[7] = 0;
L[8] = 0;
//下面为继电器逻辑判断
if(dis_value_cm > param_dis_value * 10)
{
flag = 1;
old_flag = flag;
}
else
{
flag = 0;
}
relay = (flag == 1)?(1):(0);
if(old_flag == 1 && flag == 0) //开关一次
{
relay_count++;
old_flag = 0;
Write_AT24C02(0x00,relay_count);
Delay5ms();
}
//下面为脉冲输出功能
if(feq_value > param_feq_value_khz*100)
{
//输出 1khz 80% 1000us 200us一次中断
pwm_duty_value = 4;
}
else
{
//输出 1khz 20%
pwm_duty_value = 1;
}
}
void smg_task(void)
{
//频率界面
if(data_interface == 1)
{
//Hz
if(f_index == 1)
{
smg_bit[1] = 12; //F 0111 0001 0x8e
smg_bit[2] = 10;
smg_bit[3] = (feq_value > 99999)?(feq_value/100000):(10);
smg_bit[4] = (feq_value > 9999)?(feq_value/10000%10):(10);
smg_bit[5] = (feq_value > 999)?(feq_value/1000%10):(10);
smg_bit[6] = (feq_value > 99)?(feq_value/100%10):(10);
smg_bit[7] = (feq_value > 9)?(feq_value/10%10):(10);
smg_bit[8] = feq_value%10;
}
//khx
else if(f_index == 2)
{
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] = (feq_value_khz > 99)?(feq_value_khz/100):(10);
smg_bit[7] = (feq_value_khz > 9)?(feq_value_khz/10%10):(0);
smg_bit[8] = feq_value_khz%10;
}
}
//湿度界面
else if(data_interface == 2)
{
smg_bit[1] = 13; //H 1001 0001 0x89
smg_bit[2] = 10;
smg_bit[3] = 10;
smg_bit[4] = 10;
smg_bit[5] = 10;
smg_bit[6] = 10;
smg_bit[7] = humi_value/10;
smg_bit[8] = humi_value%10;
}
//测距界面
else if(data_interface == 3)
{
//cm 单位
if(dis_index == 1)
{
smg_bit[1] = 14; //R 0001 0001 0x88
smg_bit[2] = 10;
smg_bit[3] = relay_count/10;
smg_bit[4] = relay_count%10;
smg_bit[5] = 10;
smg_bit[6] = (dis_value_cm > 99)?(dis_value_cm/100):(10);
smg_bit[7] = (dis_value_cm > 9)?(dis_value_cm/10%10):(10);
smg_bit[8] = dis_value_cm%10;
}
//m 单位
else if(dis_index == 2)
{
smg_bit[1] = 14; //R 0001 0001 0x88
smg_bit[2] = 10;
smg_bit[3] = 10;
smg_bit[4] = 10;
smg_bit[5] = 10;
smg_bit[6] = (dis_value_m > 99)?(dis_value_m/100):(0);
smg_bit[7] = (dis_value_m > 9)?(dis_value_m/10%10):(10);
smg_bit[8] = dis_value_m%10;
}
}
//参数界面
else if(data_interface == 4)
{
//频率参数
if(param_interface == 1)
{
smg_bit[1] = 15; //P 0011 0001 0x8c
smg_bit[2] = param_interface;
smg_bit[3] = 10;
smg_bit[4] = 10;
smg_bit[5] = 10;
smg_bit[6] = (param_feq_value_khz > 99)?(param_feq_value_khz/100):(10);
smg_bit[7] = (param_feq_value_khz > 9)?(param_feq_value_khz/10%10):(0);
smg_bit[8] = param_feq_value_khz%10;
}
//湿度参数
else if(param_interface == 2)
{
smg_bit[1] = 15; //P 0011 0001 0x8c
smg_bit[2] = param_interface;
smg_bit[3] = 10;
smg_bit[4] = 10;
smg_bit[5] = 10;
smg_bit[6] = 10;
smg_bit[7] = param_humi_value/10;
smg_bit[8] = param_humi_value%10;
}
//距离参数
else if(param_interface == 3)
{
smg_bit[1] = 15; //P 0011 0001 0x8c
smg_bit[2] = param_interface;
smg_bit[3] = 10;
smg_bit[4] = 10;
smg_bit[5] = 10;
smg_bit[6] = (param_dis_value > 99)?(param_dis_value/100):(10);
smg_bit[7] = (param_dis_value > 9)?(param_dis_value/10%10):(0);
smg_bit[8] = param_dis_value%10;
}
}
}
void key_task(void)
{
uchar key_value = 0;
if(key_feq >20)
{
key_feq = 1;
key_value = Read_Key();
}
switch(key_value)
{
//界面切换 频率、湿度、测距、参数
case 4:
if(++data_interface > 4)
{
data_interface = 1;
}
break;
//参数切换 频率、湿度、距离
case 5:
if(data_interface == 4)
{
if(++param_interface > 3)
{
param_interface = 1;
}
}
break;
//参数加 特定界面下
case 6:
if(data_interface == 4)
{
switch(param_interface)
{
//频率加 0.5khz 范围 1-12khz 10-120
case 1:
if(param_feq_value_khz < 120) //扩大了10倍方便显示
{
param_feq_value_khz += 5;
}
else
{
param_feq_value_khz = 10;
}
break;
//湿度加 10 范围10-60
case 2:
if(param_humi_value < 60)
{
param_humi_value += 10;
}
else
{
param_humi_value = 10;
}
break;
//距离加 0.1m 范围0.1-1.2m 1-12
case 3:
if(param_dis_value < 12) //扩大10倍方便显示和计算
{
param_dis_value += 1;
}
else
{
param_dis_value = 1;
}
break;
}
}
//在距离界面下 进行cm 和m的切换
if(data_interface == 3)
{
if(++dis_index > 2)
{
dis_index = 1;
}
}
break;
//参数减 特定界面下
case 7:
if(data_interface == 4)
{
switch(param_interface)
{
//频率加 0.5khz 范围 1-12khz
case 1:
if(param_feq_value_khz > 1) //扩大了10倍方便显示
{
param_feq_value_khz -= 5;
}
else
{
param_feq_value_khz = 120;
}
break;
//湿度加 10 范围10-60
case 2:
if(param_humi_value > 10)
{
param_humi_value -= 10;
}
else
{
param_humi_value = 60;
}
break;
//距离加 0.1m 范围0.1-1.2m
case 3:
if(param_dis_value > 1) //扩大10倍方便显示和计算
{
param_dis_value -= 1;
}
else
{
param_dis_value = 12;
}
break;
}
}
//在频率界面下 进行hz 和khz显示切换
if(data_interface == 1)
{
if(++f_index > 2)
{
f_index = 1;
}
}
break;
default:break;
}
}
void Init_System(void)
{
Control_IO(0x80,0xff);
Control_IO(0xa0,0x00);
Control_IO(0xc0,0x00);
Timer0Init();
PCA_Init();
Timer1Init();
Timer2Init();
relay_count = Read_AT24C02(0x00);
Delay5ms();
}
void main(void)
{
Init_System();
while(1)
{
data_task();
logical_task();
smg_task();
key_task();
}
}
/*=============================下面为中断处理=========================*/
void Timer2_Server() interrupt 12
{
static uchar dsp_smg = 1;
static uint feq_count = 0;
static uint l1_t = 0,l2_t = 0,l3_t = 0;
if(++feq_count == 500)
{
feq_count = 0;
TR0 = 0;
feq_value =(((uint)TH0 << 8)|TL0) * 2;
feq_value_khz = feq_value/1000.0*10; //保留一位小数
TH0 = TL0 = 0;
TR0 = 1;
}
Control_IO(0xc0,0x00);
if((data_interface == 1 && f_index == 2 && dsp_smg == 7)
|| (data_interface == 3 && dis_index == 2 && dsp_smg == 6)
|| (data_interface == 4 && param_interface == 1 && dsp_smg == 7)
|| (data_interface == 4 && param_interface == 3 && dsp_smg == 7))
{
Control_IO(0xe0,smg_data[smg_bit[dsp_smg]] & 0x7f);
}
else
{
Control_IO(0xe0,smg_data[smg_bit[dsp_smg]]);
}
Control_IO(0xc0,1 << (dsp_smg - 1));
if(++dsp_smg > 8)
{
dsp_smg = 1;
}
//频率界面
if(data_interface == 1)
{
if(l1_t++ == 100) //0.1
{
l1_t = 0;
l1_flash = ~l1_flash;
}
}
//湿度界面
if(data_interface == 2)
{
if(l2_t++ == 100) //0.1
{
l2_t = 0;
l2_flash = ~l2_flash;
}
}
//距离界面
if(data_interface == 3)
{
if(l3_t++ == 100) //0.1
{
l3_t = 0;
l3_flash = ~l3_flash;
}
}
//下面为数据刷新频率
key_feq++;
adc_feq++;
led_feq++;
dis_feq++;
}
//定时器1中断用于产生PWM输出 200us中一次中断
void Timer1_Server() interrupt 3
{
static uchar pwm_count = 0;
pwm_count++;
if(pwm_count > 0 && pwm_count <= pwm_duty_value)
{
motor = 1;
}
else if(pwm_count > pwm_duty_value)
{
motor = 0;
}
else if(pwm_count == 5) //一个周期
{
pwm_count = 0;
}
}
更多推荐
已为社区贡献11条内容
所有评论(0)