【第十四届蓝桥杯单片机组模拟题1优化版】
第十四届蓝桥杯只剩下8天啦,兄弟们加油鸭
剩下的差不多一周的时间中可以在把之前做过的省赛题在复习一篇,以及客观题可以在看看往届的,说不定会考到两个原题哦,下面为第十四届蓝桥杯单片机组模拟题1的优化版,之前也发过一篇不过在效果上并不是很丝滑,也有部分小伙伴反应串口不能正常工作,但我自己这里是可以正常打印滴,当然应该还是代码逻辑处理上存在问题。
所以就在写一篇优化版吧,此篇文字结合了蓝桥之路作者Jack 独创按键算法以及定时器刷新显示数码管,和小蜜蜂老师相关的模板,和自己的一点点总结,此次题目串口的引脚和按键重复了,可以在代码上对按键的判断时避开串口相关的引脚,大家可以借鉴一下以下按键的写法哦,到时候可以直接默认就好啦。我在串口测试时最开始没有使用串口中断进行标志位的判断,现象是按键按了一次后数码管就卡死了,不知道为什么感觉逻辑上并没有什么问题,所以就采用了串口中断进行发送中断标志位的判断,目前我的开发板上的效果是十分丝滑滴,大家可以试试效果。
欢迎大家分享更好的写法,祝大家都可以在比赛中取得好成绩
下面为完整工程文件有需要的自提哈
链接:https://pan.baidu.com/s/117UPcE5RQIXVbJp5kE3qGw?pwd=22oj
提取码:22oj
–来自百度网盘超级会员V5的分享
Note:相关代码分享仅为个人学习记录 喜欢就给小殷一个小小的关注和赞吧!
/*======================第十四届蓝桥杯单片机模拟题=================================
@Author:小殷
@Date:2023.3.30
@Note:下面部分模板来自蓝桥之路作者Jack以及小蜜蜂老师
@分享仅为学习
=================================================================================*/
#include <stc15.h>
#include <intrins.h>
#include "stdio.h"
//==================================下面为变量和宏定义============================
//宏定义引脚操作
#define Control_Port(x, y) P0=y; P2=x; P2=0
sbit TX = P1^0; // T -> Transmit 发射
sbit RX = P1^1; // R -> Receive 接收
typedef unsigned char uchar;
typedef unsigned int uint;
//数码管段码(0~9、shut-off、"U")
uchar smg_data[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0xc1};
//初始化,使所有数码管熄灭(必须是9个元素)
uchar smg_bit[9] = {10,10,10,10,10,10,10,10,10};
uchar L[9]; //控制LED的自定义变量(必须是9个元素,通用写法)
uchar Interface = 1; //界面
uchar csb_count; //超声波测距刷新周期的计数变量
uchar key_feq; //矩阵按键刷新周期的计数变量
uchar Count_Blink; //LED闪烁刷新周期的计数变量
uint Distance; //超声波测的距离
uint Distan_Para = 30; //距离参数
bit Flag_Send; //串口发送标志位
bit uart_flag; //中断标志位
//===============================下面为函数相关声明===========================
void Delay5ms(); //@12.000MHz
void UartInit(void); //9600bps@12.000MHz
void SendByte(unsigned char dat); //发送一个字节
void SendString(unsigned char *str);//发送字符串
void Delay12us(); //@12.000MHz
void Measure_Distance(); //超声波测距
void Send_Wave(); //产生8个40KHx超声波信号
void Timer2_Init(void); //1毫秒@12.000MHz
uchar Read_Key_Value(void); //读取按键键值
void Init_System(void); //系统初始化
void Data_Tackle_Task(void); //数据处理任务
void Logic_Tackle_Task(void); //逻辑处理任务
void SMG_Display_Task(void); //数码管显示任务
void Key_Tackle_Task(void); //按键处理任务
//===============================下面为功能函数的实现==========================
void Delay5ms() //@12.000MHz
{
unsigned char i, j;
i = 10;
j = 183;
do
{
while (--j);
} while (--i);
}
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)
{
while(uart_flag);
uart_flag = 1;
SBUF = dat;
}
//发送一个字符串
void SendString(unsigned char *str)
{
//字符串以'\0'为结束标志
while(*str != '\0')
{
SendByte(*str++);
}
}
//超声波相关
void Delay12us() //@12.000MHz
{
unsigned char i;
_nop_();
_nop_();
i = 33;
while (--i);
}
void Send_Wave() //产生8个40KHx超声波信号
{
unsigned char i;
for(i = 0; i < 8; i++)
{
TX = 1;
Delay12us();
TX = 0;
Delay12us();
}
}
void Measure_Distance() //超声波测距
{
unsigned int time = 0;
TMOD &= 0xf0; //定时器0模式0,13位,最大8192个计数脉冲
TL0 = 0x00;
TH0 = 0x00;
Send_Wave(); //发送超声波信号
TR0 = 1; //启动定时器
while((RX == 1) && (TF0 == 0)); //等待超声波信号返回或者等到测量超出范围
TR0 = 0; //停止定时器
if(TF0 == 0) //正常测量范围
{
time = TH0;
time = (time << 8) | TL0;
Distance = ((time / 10) * 17) / 100 + 3;
//dis = time * 0.017;
}
else //超出测量范围
{
TF0 = 0;
Distance = 999;
}
}
void Timer2_Init(void) //1毫秒@12.000MHz
{
AUXR |= 0x04; //定时器时钟1T模式
T2L = 0x20; //设置定时初始值
T2H = 0xD1; //设置定时初始值
AUXR |= 0x10; //定时器2开始计时
IE2 |= 0x04; //(Interrupt Enable 2)打开定时器2中断
EA = 1; //(Enable All)打开总中断
}
uchar Read_Key_Value(void)
{
static uchar cnt = 0, //continue value
last_trg = 0; //last trigger value
uchar trg = 0, //trigger value
cur = 0, //current value
value = 3, //必须初始化为3
key_x = 0, //按键在x轴的坐标值
key_y = 0; //按键在y轴的坐标值
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^0;
trg = cur^cnt & cur;
cnt = cur;
//判断20ms内是否连续2次检测到有按键按下(用于消抖)
if((last_trg^trg & last_trg) && cur)
{
//计算矩阵按键的键值
value = key_x + key_y * 4;
}
last_trg = trg;
return value; //返回矩阵按键的键值
}
void Data_Tackle_Task(void)
{
uchar str[24];
if(T2H < 0xd9)
{
if(csb_count > 150)
{
csb_count = 1;
Measure_Distance();
}
}
if(Flag_Send)
{
Flag_Send = 0;
//Note: sprintf need include stdio.h
sprintf(str,"Distance:%dcm\r\n",Distance);
SendString(str);
}
}
void Logic_Tackle_Task(void)
{
L[1] = (Interface == 1) ? (1) : (0);
L[2] = (Interface == 2) ? (1) : (0);
if(Distance > Distan_Para)
{
if(Count_Blink > 200)
{
Count_Blink = 1;
L[3] = !L[3];
}
}
else
{
L[3] = 0;
Count_Blink = 201; //请思考:此语句的作用是什么?
}
}
void SMG_Display_Task(void)
{
//若处于距离显示界面
if(Interface == 1)
{
smg_bit[1] = 11; //显示字符“U”
smg_bit[2] = 1;
smg_bit[6] = (Distance > 99) ? (Distance / 100) : (10);
smg_bit[7] = (Distance > 9) ? (Distance / 10 % 10) : (10);
smg_bit[8] = Distance % 10;
}
//若处于参数显示界面
else if(Interface == 2)
{
smg_bit[1] = 11; //显示字符“U”
smg_bit[2] = 2;
smg_bit[6] = (Distan_Para > 99) ? (Distan_Para / 100) : (10);
smg_bit[7] = (Distan_Para > 9) ? (Distan_Para / 10 % 10) : (10);
smg_bit[8] = Distan_Para % 10;
}
}
void Key_Tackle_Task(void)
{
uchar key_value = 0; //独立按键的键值与开发板上的键值所对应
if(key_feq > 10) //10ms刷新一次按键,相当于消抖10ms
{
key_feq = 1;
key_value = Read_Key_Value();
}
if(key_value == 4) //短按S4
{
Interface = (Interface == 1) ? (2):(1);
}
else if(key_value == 8)
{
if(Interface == 1)
{
Distan_Para = Distance;
}
}
else if(key_value == 12)
{
if(Interface == 2)
{
if(Distan_Para < 990)
{
Distan_Para += 10;
}
}
}
else if(key_value == 16) //短按S16
{
if(Interface == 2)
{
if(Distan_Para >= 10)
{
Distan_Para -= 10;
}
}
}
else if(key_value == 9) //短按S9
{
Flag_Send = 1;
}
}
void Init_System(void)
{
//close Led
Control_Port(0x80, 0xff);
//Close buzzer & relay
Control_Port(0xa0, 0x00);
//Uart Init
UartInit();
//Wait for Uart Init Finish
Delay5ms();
//Timer2 Init
Timer2_Init();
}
int main(void)
{
//系统初始化
Init_System();
while(1)
{
//数据处理任务
Data_Tackle_Task();
//逻辑处理任务
Logic_Tackle_Task();
//数码管显示任务
SMG_Display_Task();
//矩阵按键处理任务
Key_Tackle_Task();
}
}
//===============================下面为中断相关============================
void Uart() interrupt 4
{
/*
if(RI)
{
RI = 0;
dat = SBUF;
}
*/
if(TI)
{
TI = 0;
uart_flag = 0;
}
}
void Timer2_Service() interrupt 12
{
static uchar dsp_com = 1;
/***********************数码管刷新显示*********************/
Control_Port(0x80, ~(L[3]<<2 | L[2]<<1 | L[1]<<0));
Control_Port(0xc0, 0);
Control_Port(0xe0, smg_data[smg_bit[dsp_com]]);
Control_Port(0xc0, 1 << (dsp_com-1));
if(++dsp_com > 8)
{
dsp_com=1;
}
/*********************** 刷新周期计数 ***********************/
++csb_count;
++Count_Blink;
++key_feq;
}