【第十四届蓝桥杯单片机模拟题2优化版】
下面分享的是第十四届蓝桥杯单片机组模拟题2的优化版,相对于之前发布的文章,这次在写法上有了很大不同,主要解决了代码简洁高效的问题,代码中部分模板来自蓝桥之路作者Jack和小蜜蜂老师,当然也有自己的一些编程思路在里面,若有错还望各位大佬指出。
完整工程链接,需要自取
链接:https://pan.baidu.com/s/1_fbVY4zSYFRKMb1_-cvNAg?pwd=97ps
提取码:97ps
–来自百度网盘超级会员V5的分享
若有帮助,点个赞加关注吧,也可以分享给需要的小伙伴哦
===================================祝大家在比赛中都能取得好成绩=============================
#include <STC15F2K60S2.H>
#include "iic.h"
#include "stdio.h"
#include "string.h"
/*============================第十四届模拟题2=========================
@Author:小殷
@Date:2023.4.1
@Note:该程序中按键相关算法及部分模板来自蓝桥之路作者Jack
======================================================================*/
typedef unsigned char uchar;
typedef unsigned int uint;
#define Control_Port(x,y) P0 = y;P2 = x;P2 = 0;
//0-9 0xff - U F
code uchar smg_data[] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xff, 0xc1};
uchar smg_bit[9] ={10,10,10,10,10,10,10,10,10}; //默认关闭数码管
uchar Send_Buf[12] = {0},buf[12] = {0},count = 0; //串口接收发送标志相关
uchar usart_flag = 0; //接收完成标志位
uchar L[9] ,L8_Flag = 0; //led
bit L8_Status; //LED8 状态
uint adc_volt; //电压实时值
uint db_value = 0; //数码管显示值
uint db_param = 65; //db参数设置
uchar interface = 1; //界面
uchar key_feq = 0; //按键刷新频率
uchar adc_feq = 0; //adc采集频率
//============================下面为函数相关声明===========================
void Timer2Init(void); //1毫秒@12.000MHz
void smg_display_task(void); //数码管显示任务
uchar Read_ADC_Volt(void); //ADC采集
void data_tackle_task(void); //数据处理任务
uchar Read_Key_Value(void); //按键值获取
void Key_Tackle_Task(void); //按键处理任务
void SendByte(unsigned char dat); //发送一个字节
void SendString(unsigned char *str); //发送字符串
void UartInit(void); //串口初始化
void Init_System(void); //系统初始化
//============================下面为函数功能实现部分=======================
void Delay5ms() //@12.000MHz
{
unsigned char i, j;
i = 59;
j = 90;
do
{
while (--j);
} while (--i);
}
void Timer2Init(void) //1毫秒@12.000MHz
{
AUXR |= 0x04; //定时器时钟1T模式
T2L = 0x20; //设置定时初始值
T2H = 0xD1; //设置定时初始值
AUXR |= 0x10; //定时器2开始计时
IE2 |= 0x04;
EA = 1;
}
void UartInit(void) //9600bps@12.000MHz
{
SCON = 0x50; //8位数据,可变波特率
AUXR |= 0x40; //定时器时钟1T模式
AUXR &= 0xFE; //串口1选择定时器1为波特率发生器
TMOD &= 0x0F; //设置定时器模式
TL1 = 0xC7; //设置定时初始值
TH1 = 0xFE; //设置定时初始值
ET1 = 0; //禁止定时器%d中断
TR1 = 1; //定时器1开始计时
ES = 1;
EA = 1;
}
//发送一个字节
void SendByte(unsigned char dat)
{
SBUF = dat;
while(TI == 0); //等待发送完成
TI = 0; //清除标志位
}
//发送一个字符串
void SendString(unsigned char *str)
{
//字符串以'\0'为结束标志
while(*str != '\0')
{
SendByte(*str++);
}
}
void smg_display_task(void)
{
if(interface == 1)
{
smg_bit[1] = 11; //U 1000 0011 0xc1
smg_bit[2] = interface;
smg_bit[3] = 10;
smg_bit[4] = 10;
smg_bit[5] = 10;
smg_bit[6] = db_value/100;
smg_bit[7] = db_value/10%10;
smg_bit[8] = db_value%10;
}
else if(interface == 2)
{
smg_bit[1] = 11; //U 1000 0011 0xc1
smg_bit[2] = interface;
smg_bit[3] = 10;
smg_bit[4] = 10;
smg_bit[5] = 10;
smg_bit[6] = 10;
smg_bit[7] = (db_param > 9) ?(db_param/10%10):(10);
smg_bit[8] = db_param%10;
}
}
uchar Read_ADC_Volt(void)
{
uchar adc = 0;
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(0x03);
IIC_WaitAck();
IIC_Stop();
IIC_Start();
IIC_SendByte(0x91);
IIC_WaitAck();
adc = IIC_RecByte();
IIC_SendAck(1);
IIC_Stop();
// volt = adc * (5.0/255) * 100;
return adc;
}
//下面为数据处理任务
void data_tackle_task(void)
{
if(adc_feq > 20)
{
adc_feq = 1;
adc_volt = (Read_ADC_Volt() * (5.0/255)) * 100;
if(adc_volt > 0 && adc_volt <= 500)
{
//一次函数变化 y = 18x
db_value = 18 * adc_volt/10; //保留一位小数
}
else if(adc_volt > 500)
{
db_value = 900;
}
}
//下面为LED逻辑处理
L[1] = (interface == 1)?(1):(0);
L[2] = (interface == 2)?(1):(0);
if(db_value > db_param * 10)
{
L8_Flag = 1;
}
else
{
L8_Flag = 0;
}
if(usart_flag == 1)
{
usart_flag = 0;
//if(buf[0] == 'R' && buf[1] == 'e' && buf[2] == 't' && buf[3] == 'u' && buf[4] == 'r' && buf[5] == 'n')
if(strcmp(buf,"Return") == 0)
{
SendString("Noises: ");
if(db_value > 99)
{
SendByte(db_value/100 + '0');
SendByte(db_value/10%10 + '0');
SendByte('.');
SendByte(db_value%10 + '0');
}
else if(db_value > 9)
{
SendByte(db_value/10 + '0');
SendByte('.');
SendByte(db_value%10 + '0');
}
else
{
SendByte(db_value%10 + '0');
}
SendString("db\r\n");
}
}
}
uchar Read_Key_Value(void)
{
static uchar last_trg = 0,cnt = 0;
uchar trg = 0,cur = 0,value = 3,key_x = 0,key_y = 0;
//P3 = 0x0f; P3^0 P3^1 不使用 避免影响串口
P37 = 0;
P36 = 0;
P35 = 0;
P34 = 0;
P33 = 1;
P32 = 1;
//P31 = 1;
//P30 = 1;
P4 = 0x00;
//if(!P30) key_x = 3;
//else if(!P31) key_x = 2;
if(!P32) key_x = 1;
else if(!P33) key_x = 0;
P37 = 1;
P36 = 1;
P35 = 1;
P34 = 1;
P33 = 0;
P32 = 0;
//P31 = 0;
//P30 = 0;
P4 = 0xff;
if(!P34) key_y = 4;
else if(!P35) key_y = 3;
else if(!P42) key_y = 2;
else if(!P44) key_y = 1;
cur = key_y^0x00;
trg = cur ^ cnt & cur;
cnt = cur;
if((last_trg^trg&last_trg) && cur)
{
value = key_x + key_y * 4;
}
last_trg = trg;
return value;
}
void Key_Tackle_Task(void)
{
uchar key_value = 0;
if(key_feq > 10)
{
key_feq = 1;
key_value = Read_Key_Value();
}
switch(key_value)
{
case 12:
interface = (interface == 1)?(2):(1);
break;
case 16:
if(interface == 2)
{
if(db_param < 90)
{
db_param += 5;
}
else
{
db_param = 90;
}
}
break;
case 17:
if(interface == 2)
{
if(db_param > 5)
{
db_param -= 5;
}
else
{
db_param = 0;
}
}
break;
default:break;
}
}
void Init_System(void)
{
Control_Port(0x80,0xff); //关闭LED
Control_Port(0xa0,0x00); //关闭蜂鸣器 继电器
UartInit(); //串口初始化
Delay5ms(); //延时等待串口初始化完成
Timer2Init(); //定时器2初始化
}
void main(void)
{
Init_System(); //系统初始化
while(1)
{
data_tackle_task(); //数据处理任务
smg_display_task(); //数码管显示任务
Key_Tackle_Task(); //按键任务
}
}
//串口中断接收
void Usart_Server() interrupt 4
{
unsigned char temp =0;
if(RI)
{
RI = 0;
temp = SBUF;
if(temp == 0 || temp == '\r' || temp == '\n') //结束符判断
{
usart_flag = 1; //接收完成标志
buf[count] = '\0';
count = 0; //计数清零等待下一帧数据
}
else
{
buf[count++] = temp; //接数据的值存入到buf数组中
}
}
}
void Timer2_Server() interrupt 12
{
static uchar dsp_smg = 1;
static uchar L8_Count = 0;
Control_Port(0x80,~(L[1] << 0|L[2] << 1 | L[8] << 7));
Control_Port(0xc0,0);
//带小数显示
if(interface == 1 && dsp_smg == 7)
{
Control_Port(0xe0,smg_data[smg_bit[dsp_smg]] & 0x7f);
}
//不带小数显示
else
{
Control_Port(0xe0,smg_data[smg_bit[dsp_smg]]);
}
//数码管位选操作
Control_Port(0xc0,1 << (dsp_smg -1));
if(++dsp_smg > 8)
{
dsp_smg = 1;
}
key_feq++; //按键刷新频率
adc_feq++; //adc采集频率
if(L8_Flag)
{
if(++L8_Count == 100)
{
L8_Count = 1;
L8_Status = !L8_Status;
L[8] = L8_Status;
}
}
}
补充:
部分小伙伴反应串口点击发送后没有反应,因为在代码串口中断接收部分进行了接收符相关的判断的,所以在串口助手发送时需要勾选上发送结束符,好像题目并没有规定要接受到发送结束符之后再返回PC端数据,应该不进行判断也行,下面为不进行结束符判断补充
在接收完成的逻辑处理部分进行数组的清除和count清零