蓝桥杯十四届单片机国赛试题及代码

    今年十四届单片机国赛试题在程序题设计方面难度有所下降,但选择题没有了以往可以在手册中可以找到的单片机类选择题,选择题难度较高,因此想获得一个不错的成绩,需要在选择题方面有所加强

试题展示8320c8da8acb4ae780cd9aabd6d58a44.jpg696586bcf93c495a9694e4b41c47d5bb.jpg

e74256a9696b4bff800b566c8ec22458.jpg

a4611a7298574382aad1b56888fb4965.jpg

ed8a1581eab64487af699e59744eb62d.jpg

39536be7845d44d59de9dc29ccf3f8e5.jpg

8c9a706801a94367a0c15d58a3d9bfe9.jpg

设计说明 

此次国赛采用了温度传感器DS18B20模块,LED模块,按键模块,Pcf8591DAC模块,iic,超声波模块,外设模块不算多,没有13届的定时器分配问题,思路很容易理清。

个人觉得难点在于S8.9两个按键的处理,最好是判断两个同时按下做一个标记在超过两秒后进行初始化功能,因为在松手时不一定能准确控制在10ms内。

矩阵按键模块

#include "bsp_key.h"



unsigned char Key_Read(void)
{
	unsigned int Key_New;
	unsigned char Key_Value;
	
	P44 = 0;P42 = 1;P35 = 1;P34 = 1;
	Key_New = P3&0X0F;
	
	P44 = 1;P42 = 0;P35 = 1;P34 = 1;
	Key_New = (Key_New<<4)|(P3&0X0F);
	
	P44 = 1;P42 = 1;P35 = 0;P34 = 1;
	Key_New = (Key_New<<4)|(P3&0X0F);
	
	P44 = 1;P42 = 1;P35 = 1;P34 = 0;
	Key_New = (Key_New<<4)|(P3&0X0F);
	
	switch(~Key_New)
	{
		case 0x8000:Key_Value = 4;break;
		case 0x4000:Key_Value = 5;break;
		case 0x2000:Key_Value = 6;break;
		case 0x1000:Key_Value = 7;break;
		
		case 0x0800:Key_Value = 8;break;
		case 0x0400:Key_Value = 9;break;
		case 0x0200:Key_Value = 10;break;
		case 0x0100:Key_Value = 11;break;
		
		case 0x0080:Key_Value = 12;break;
		case 0x0040:Key_Value = 13;break;
		case 0x0020:Key_Value = 14;break;
		case 0x0010:Key_Value = 15;break;
		
		case 0x0008:Key_Value = 16;break;
		case 0x0004:Key_Value = 17;break;
		case 0x0002:Key_Value = 18;break;
		case 0x0001:Key_Value = 19;break;
		
		case 0x0c00:Key_Value = 89;break;
		default :Key_Value = 0;
	}
	return Key_Value; 
}

数码管显示模块

#include "bsp_seg.h"
void Seg_Tran(unsigned char *seg_string,unsigned char *seg_buf)
{
	unsigned char i = 0;
	unsigned char j = 0;
	unsigned char temp;
	for(i = 0;i<= 7;i++,j++)
	{
		switch(seg_string[j])
		{
			case '0':temp = 0xc0;break;
			case '1':temp = 0xf9;break;
			case '2':temp = 0xa4;break;
			case '3':temp = 0xb0;break;
			case '4':temp = 0x99;break;
			case '5':temp = 0x92;break;
			case '6':temp = 0x82;break;
			case '7':temp = 0xf8;break;
			case '8':temp = 0x80;break;
			case '9':temp = 0x90;break;
			
			case 'A':temp = 0x88;break;
			case 'B':temp = 0x83;break;
			case 'C':temp = 0xc6;break;
			case 'D':temp = 0xa1;break;
			case 'E':temp = 0x86;break;
			case 'F':temp = 0x8e;break;
			case ' ':temp = 0xff;break;
			case '-':temp = 0xbf;break;
			
			case 'H':temp = 0x89;break;			
			case 'L':temp = 0xc7;break;
			case 'N':temp = 0xc8;break;			
			case 'P':temp = 0x8c;break;
			case 'U':temp = 0xc1;break;
			
			default:temp = 0xff;break;
		}
		if(seg_string[j+1] == '.')
		{
			temp &= 0x7f;
			j++;
		}
		seg_buf[i] = temp;
	}
}

void Seg_Disp(unsigned char *seg_buf,unsigned char pos)
{
	P0 = 0XFF;
	P2 = P2 & 0X1F |0XE0;
	P2 &= 0X1F;
	
	P0 = 1<<pos;
	P2 = P2 & 0X1F |0Xc0;
	P2 &= 0X1F;
	
	P0 = seg_buf[pos];
	P2 = P2 & 0X1F |0XE0;
	P2 &= 0X1F;
}

DS18B20模块

unsigned int rd_temperature(void)
{
	unsigned char low,high;
	
	init_ds18b20();
	Write_DS18B20(0xcc);//跳过rom只有一个温度传感器
	Write_DS18B20(0x44);//转换温度
	
	init_ds18b20();
	Write_DS18B20(0xcc);
	Write_DS18B20(0xbe); //将温度依次返回
	
	low = Read_DS18B20();//先读低温度
	high = Read_DS18B20();//先读低温度
	
	return((high<<8)|low);
}

超声波模块

#include "bsp_ultrasonic.h"

sbit TX = P1^0;
sbit RX = P1^1;

void ultrasonic_Timer0init(void)
{
	AUXR &= 0x7F;		//定时器时钟12T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0xF4;		//设置定时初值
	TH0 = 0xFF;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 0;		//定时器0不开始计时
}


unsigned char ultrasonic_rec(void)
{
	unsigned char num = 10;//与定时器12mhz形成40hz的超声波
	unsigned char Distance;
	
	TX = 0;
	TL0 = 0xF4;		//设置定时初值
	TH0 = 0xFF;		//设置定时初值
	
	TR0 = 1;
	while(num--)
	{
		while(!TF0);
		TX ^= 1;
		TF0 = 0;
	}		
	
	TR0 = 0;
	TL0 = 0;		//此时装0时将定时称0.017换算距离
	TH0 = 0;		//设置定时初值
	TR0 = 1;
	
	while(RX && (~TF0));//RX平时为1变0是接收到40hz脉冲
	TR0 = 0;
	if(TF0 == 1)//距离溢出
	{
		Distance = 255;
		TF0 = 0;
	}
	else 
	{
		Distance = (((TH0<<8)|TL0)*0.017);
		TF0 = 0;
	}
	return Distance;
}

显示定时器模块

#include "Timer.h"

void Timer1Init(void)		//1毫秒@12.000MHz
{
	AUXR &= 0xBF;		//定时器时钟12T模式
	TMOD &= 0x0F;		//设置定时器模式
	TL1 = 0x18;		//设置定时初值
	TH1 = 0xFC;		//设置定时初值
	TF1 = 0;		//清除TF1标志
	TR1 = 1;		//定时器1开始计时
	
	ET1 = 1;
}

LED及继电器模块

#include "bsp_led.h"

void Led_Disp(unsigned char ucLed)
{
	P0 = (~ucLed);
	P2 = P2 & 0X1F |0X80;
	P2 &= 0X1F;
}



void Relay(unsigned char relay)
{
	P0 = relay;
	P2 = P2 & 0X1F |0Xa0;
	P2 &= 0X1F;
}

DAC模块

#include "bsp_iic.h"

#define DELAY_TIME 5
sbit SDA = P2^1;
sbit SCL = P2^0;

//
void IIC_Delay(unsigned char i)
{
    do{_nop_();}
    while(i--);        
}

//
void IIC_Start(void)
{
    SDA = 1;
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SDA = 0;
    IIC_Delay(DELAY_TIME);
    SCL = 0;	
}

//
void IIC_Stop(void)
{
    SDA = 0;
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SDA = 1;
    IIC_Delay(DELAY_TIME);
}

//
void IIC_SendAck(bit ackbit)
{
    SCL = 0;
    SDA = ackbit;  					
    IIC_Delay(DELAY_TIME);
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SCL = 0; 
    SDA = 1;
    IIC_Delay(DELAY_TIME);
}

//
bit IIC_WaitAck(void)
{
    bit ackbit;
	
    SCL  = 1;
    IIC_Delay(DELAY_TIME);
    ackbit = SDA;
    SCL = 0;
    IIC_Delay(DELAY_TIME);
    return ackbit;
}

//
void IIC_SendByte(unsigned char byt)
{
    unsigned char i;

    for(i=0; i<8; i++)
    {
        SCL  = 0;
        IIC_Delay(DELAY_TIME);
        if(byt & 0x80) SDA  = 1;
        else SDA  = 0;
        IIC_Delay(DELAY_TIME);
        SCL = 1;
        byt <<= 1;
        IIC_Delay(DELAY_TIME);
    }
    SCL  = 0;  
}

//
unsigned char IIC_RecByte(void)
{
    unsigned char i, da;
    for(i=0; i<8; i++)
    {   
    	SCL = 1;
		IIC_Delay(DELAY_TIME);
		da <<= 1;
		if(SDA) da |= 1;
		SCL = 0;
		IIC_Delay(DELAY_TIME);
    }
    return da;    
}



void Pcf8591_DAC(float Dac_data)
{
	IIC_Start();
	IIC_SendByte(0x90);//选择选择pcf8591写东西模式
	IIC_WaitAck();
	
	IIC_SendByte(0x41);//选择写0x41通道
	IIC_WaitAck();
	
	IIC_SendByte(Dac_data);//发送写的内容
	IIC_WaitAck();
	IIC_Stop();//停止对iic的控制
}

初始化

#include "bsp_init.h"



void Clc_Peripheral(void)
{
	P0 = 0XFF;
	P2 = P2 & 0X1F |0X80;
	P2 &= 0X1F;
	
	P0 = 0X00;
	P2 = P2 & 0X1F |0XA0;
	P2 &= 0X1F;
}

主函数

#include "STC15F2K60S2.H"
#include "bsp_init.h"
#include "Timer.h"
#include "bsp_led.h"
#include "bsp_key.h"
#include "bsp_seg.h"
#include "stdio.h"
#include "bsp_onewire.h"
#include "bsp_iic.h"
#include "bsp_ultrasonic.h"

//程序减速
unsigned int Seg_Slow_Down = 0;
unsigned int Key_Slow_Down = 0;
unsigned int Led_Slow_Down = 0;

///三大服务模块
void Key_Proc(void);
void Seg_Proc(void);
void Led_Proc(void);

void Delay500ms()		//@12.000MHz
{
	unsigned char i, j, k;

	_nop_();
	_nop_();
	i = 23;
	j = 205;
	k = 120;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}



//按键
unsigned char Key_Value,Key_Down,Key_Old,Key_Up;

//数码管
unsigned char seg_string[10];
unsigned char seg_buf[8] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
unsigned char pos;

//LED
unsigned char ucLed;																				

//其他变量
float Temperature;//测得的距离
float Distance;//测得的距离
float Distance_Disp;//调整后的距离
bit Distance_M__CM_flag = 0;//CM和M标志 0为初始CM

unsigned char Inter_Face = 0x11;//界面标号 0x11测距界面 0x21参数界面-距离参数 0x22参数界面-温度参数 0x31校准值界面 0x32介质传输速度界面 0x33DAC下限界面
unsigned long ms_Tick = 0;
unsigned long Key_ms_Tick = 0;
unsigned long xdata Data_record_ms_Tick = 0;
unsigned char Distance_DAC;
unsigned char Distance_Canshu = 40;//距离参数
unsigned char Temperature_Canshu = 30;//温度参数
int Distance_calibration = 0;//校准值
unsigned int xdata Ultrasonic_medium = 340;//介质传播速度
float DAC_Low_Vlaue = 1.0;//DAC下限
bit Key_89_2s_flag = 0;
bit Data_record = 0;
bit DAC_flag = 0;
float DAC_Data;
void main(void)
{
	Clc_Peripheral();
	Timer1Init();
	rd_temperature();
	Delay500ms();
	EA = 1;

	ultrasonic_Timer0init();
	
	while(1)
	{
		Key_Proc();
		Seg_Proc();
		Led_Proc();

	}
}
void tm1_isr() interrupt 3
{
	ms_Tick++;
	if(++Key_Slow_Down == 10)Key_Slow_Down = 0;
	if(++Seg_Slow_Down == 70)Seg_Slow_Down = 0;
	if(++Led_Slow_Down == 100)Led_Slow_Down = 0;
	
	else if(((Inter_Face >> 4) ==  0x03)&&(ms_Tick % 100) == 0)
	{
		ucLed &= 0x7f;
		ucLed ^= 0x01;
	}
	
	Led_Disp(ucLed);
	Seg_Disp(seg_buf,pos);
	if(++pos == 8)pos = 0;
}
void Key_Proc(void)
{
	if(Key_Slow_Down) return;
	Key_Slow_Down = 1;
	
	
	Key_Value = Key_Read();
	Key_Down = Key_Value & (Key_Old ^ Key_Value);//按键按下
	Key_Up = ~Key_Value & (Key_Old ^ Key_Value);//按键弹起
	Key_Old = Key_Value;
	
	if(Key_Down)
	{
		if(Key_Down == 89)Key_89_2s_flag = 1;
		Key_ms_Tick =  ms_Tick;
	}
	if(((ms_Tick - Key_ms_Tick) <= 2000)&&(Data_record == 0))//短按 按下2s内
	{
		switch(Key_Up)
		{
			case 4:
				if((Inter_Face >> 4) == 0x01) Inter_Face = 0x21;
				else if((Inter_Face >> 4) == 0x02) Inter_Face = 0x31;
				else if((Inter_Face >> 4) == 0x03) Inter_Face = 0x11;
				break;
			case 5:
				if(Inter_Face == 0x11)Distance_M__CM_flag ^= 1;
				else if(Inter_Face == 0x21)Inter_Face = 0x22;
				else if(Inter_Face == 0x22)Inter_Face = 0x21;
				else if(Inter_Face == 0x31)Inter_Face = 0x32;
				else if(Inter_Face == 0x32)Inter_Face = 0x33;
				else if(Inter_Face == 0x33)Inter_Face = 0x31;
				break;
			case 8://按键++判断 以及记录功能
				if(Inter_Face == 0x11)
				{
					Data_record = 1;
					Data_record_ms_Tick = ms_Tick;
				}
				else if(Inter_Face == 0x21)
				{
					Distance_Canshu += 10;
					if(Distance_Canshu == 100)Distance_Canshu = 90;
				}
				else if(Inter_Face == 0x22)
				{
					Temperature_Canshu += 1;
					if(Temperature_Canshu == 81)Temperature_Canshu = 80;
				}
				else if(Inter_Face == 0x31)
				{
					Distance_calibration += 5;
					if(Distance_calibration == 95)Distance_calibration = 90;
				}
				else if(Inter_Face == 0x32)
				{
					Ultrasonic_medium += 10;
					if(Ultrasonic_medium == 10000)Ultrasonic_medium = 9990;
				}
				else if(Inter_Face == 0x33)
				{
					DAC_Low_Vlaue += 0.1;
					if(DAC_Low_Vlaue >= 2.0)DAC_Low_Vlaue = 2.0;
				}
				break;
			case 9://按键--判断 以及DAC输出功能
				if(Inter_Face == 0x11)DAC_flag = 1;
				else if(Inter_Face == 0x21)
				{
					Distance_Canshu -= 10;
					if(Distance_Canshu == 0)Distance_Canshu = 10;
				}
				else if(Inter_Face == 0x22)
				{
					Temperature_Canshu -= 1;
					if(Temperature_Canshu == 255)Temperature_Canshu = 0;
				}
				else if(Inter_Face == 0x31)
				{
					Distance_calibration -= 5;
					if(Distance_calibration == -95)Distance_calibration = -90;
				}
				else if(Inter_Face == 0x32)
				{
					Ultrasonic_medium -= 10;
					if(Ultrasonic_medium == 0)Ultrasonic_medium = 10;
				}
				else if(Inter_Face == 0x33)
				{
					DAC_Low_Vlaue -= 0.1;
					if(DAC_Low_Vlaue <= 0.1)DAC_Low_Vlaue = 0.1;
				}
				break;
		}
	}
	else if(((ms_Tick - Key_ms_Tick) > 2000)&&(Key_89_2s_flag == 1))//长按判断标志是否为1
	{
		ucLed ^=0xff;
		Key_89_2s_flag = 0;
		Distance_M__CM_flag = 0;
		Distance_Canshu = 40;
		Temperature_Canshu = 30;
		Distance_calibration = 0;
		Ultrasonic_medium = 340;
		DAC_Low_Vlaue = 1.0;
	}
	if((Data_record == 1)&&((ms_Tick - Data_record_ms_Tick) < 6000))
	{
		if((ms_Tick%1000) == 0)Distance_DAC = ultrasonic_rec();
	}
	else if((Data_record == 1)&&((ms_Tick - Data_record_ms_Tick) > 6000))Data_record = 0;
	
}

void Seg_Proc(void)
{
	if(Seg_Slow_Down) return;
	Seg_Slow_Down = 1;
	
	Temperature = (rd_temperature()/16.0);
	Distance = ultrasonic_rec();
	Distance_Disp = ((Ultrasonic_medium/340.0)*Distance+Distance_calibration);//将标准环境下的速度进行调整和校准
	
	//*****DAC输出*****
	if(Distance_Disp >= 90)DAC_Data = 255;
	else if(Distance_Disp <= 10)DAC_Data = 51;
	else if((Distance_Disp > 10)&&(Distance_Disp < 90))DAC_Data = 51*(((5-DAC_Low_Vlaue)/80.0)*Distance_Disp+(DAC_Low_Vlaue - ((5-DAC_Low_Vlaue)/8.0)));
	
	if(DAC_flag == 1)Pcf8591_DAC(DAC_Data);
	//****************
	switch(Inter_Face)
	{
		case 0x11:
			if(Distance_M__CM_flag == 0)sprintf(seg_string,"%03.1f-%4d",Temperature,(unsigned int)Distance_Disp);	//cm
			else if(Distance_M__CM_flag == 1)sprintf(seg_string,"%03.1f-%4.2f",Temperature,(Distance_Disp/100.0));	//m
			break;
		case 0x21:
			sprintf(seg_string,"P1    %02d",(unsigned int)Distance_Canshu);//距离参数界面
			break;
		case 0x22:
			sprintf(seg_string,"P2    %02d",(unsigned int)Temperature_Canshu);//温度参数界面
			break;
		case 0x31:
			sprintf(seg_string,"F1   %3d",Distance_calibration);//距离校准界面
			break;
		case 0x32:
			sprintf(seg_string,"F2  %4d",Ultrasonic_medium);//介质速度界面
			break;
		case 0x33:
			sprintf(seg_string,"F2    %2.1f",DAC_Low_Vlaue);//dac下限界面
			break;
			
	}
	
	Seg_Tran(seg_string,seg_buf);
}

void Led_Proc(void)//Led 和继电器
{
	if(Led_Slow_Down) return;
	Led_Slow_Down = 1;
	if(Inter_Face == 0x11)
	{
		if(Distance_Disp > 255)ucLed = 0xff;
		else if(Distance_Disp < 255)
		{
			ucLed = Distance_Disp;
		}
	}
	else if((Inter_Face >> 4) ==  0x02)//L8
	{
		ucLed &= 0x0;
		ucLed |= 0x80;
	}
	//继电器
	if((Distance_Disp < (Distance_Canshu+5))&&(Distance_Disp > (Distance_Canshu -5))&&(Temperature <= Temperature_Canshu))Relay(0x10);//L10
	else Relay(0x0);

}


功能演示

 B站视频连接: https://b23.tv/ixYMJaB

免责声明:函数模块采用蚂蚁工程科技子函数模块,代码仅供学习未商用,如有侵权请联系。

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HHBB108

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值