【第十四届蓝桥杯单片机组模拟题1优化版】

【第十四届蓝桥杯单片机组模拟题1优化版】

第十四届蓝桥杯只剩下8天啦,兄弟们加油鸭
剩下的差不多一周的时间中可以在把之前做过的省赛题在复习一篇,以及客观题可以在看看往届的,说不定会考到两个原题哦,下面为第十四届蓝桥杯单片机组模拟题1的优化版,之前也发过一篇不过在效果上并不是很丝滑,也有部分小伙伴反应串口不能正常工作,但我自己这里是可以正常打印滴,当然应该还是代码逻辑处理上存在问题。
所以就在写一篇优化版吧,此篇文字结合了蓝桥之路作者Jack 独创按键算法以及定时器刷新显示数码管,和小蜜蜂老师相关的模板,和自己的一点点总结,此次题目串口的引脚和按键重复了,可以在代码上对按键的判断时避开串口相关的引脚,大家可以借鉴一下以下按键的写法哦,到时候可以直接默认就好啦。我在串口测试时最开始没有使用串口中断进行标志位的判断,现象是按键按了一次后数码管就卡死了,不知道为什么感觉逻辑上并没有什么问题,所以就采用了串口中断进行发送中断标志位的判断,目前我的开发板上的效果是十分丝滑滴,大家可以试试效果。
欢迎大家分享更好的写法,祝大家都可以在比赛中取得好成绩

【第十四届蓝桥杯单片机组模拟题1优化版】_第1张图片

下面为完整工程文件有需要的自提哈
链接:https://pan.baidu.com/s/117UPcE5RQIXVbJp5kE3qGw?pwd=22oj
提取码:22oj
–来自百度网盘超级会员V5的分享

在这里插入图片描述

Note:相关代码分享仅为个人学习记录 喜欢就给小殷一个小小的关注和赞吧!

/*======================第十四届蓝桥杯单片机模拟题=================================
@Author:小殷
@Date:2023.3.30
@Note:下面部分模板来自蓝桥之路作者Jack以及小蜜蜂老师
@分享仅为学习
=================================================================================*/
#include 
#include 
#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);		        //[email protected]
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)		//[email protected]
{
	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;
}

你可能感兴趣的:(蓝桥杯学习,单片机,蓝桥杯,嵌入式硬件)