相信大家一直都在寻找12届蓝桥杯单片机国赛试题跟答案吧,下面小编就展示12届单片机的试题跟个人代码。

试题展示

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

设计说明

  此次的国赛,从模块上看,是五大基本模块:按键模块、数码管模块、LED模块、IIC模块、ds1302模块,另外,再加上一个小编不是特别熟悉的超声波模块,在这六个模块中,不管怎么说,我们还是能够写出一点东西的。话不多说了,详细地设计就请看下面的代码吧。

代码解析

main函数:

#include "config.h"

extern unsigned char segbuff[],second;
unsigned char key_num = 16;//按键的值
unsigned char flag_L6;//LED的L6点亮的分别标识
unsigned char distan = 0;//记录红外测得的距离
unsigned char flag_S8 = 0;//触发模式 定时模式 模式切换表示
extern unsigned char flag_S4 ,flag_S5;//S4 S5按键
unsigned char time_count = 2,distance_count = 20;//时间参数 距离参数
unsigned char max_distance = 0,min_distance = 0;//记录测得距离的最大值  最小值
unsigned int ave_distance = 0;//平均值
unsigned char flag_L5 = 0;//记录实时测得的距离符合条件的次数
unsigned char light = 120;//记录测得的光照强度
unsigned char s;//记录上次的时间 秒
unsigned int count = 0;//记录中断的次数 就相当于定时的时间
unsigned char VV = 0;//记录本次测得距离的电压值(0-255)

void main(){
	sysinit();//关闭外设
	Timer1Init();//开启定时器1
	Timer0Init();//开启定时器0
	ds1302_init(0x20,0x20,0x00);//设置初试时间
	while(1){
		key_num = scankbd();
		switch(key_num){
			case 0://S4
				if(++flag_S4 == 2) flag_S4 = 0;
				break;
			case 1://S5
				if(++flag_S5 == 3) flag_S5 = 0;
				break;
			case 4://S8
				if(++flag_S8 == 3) flag_S8 = 0;
				break;
			case 5://S9
				if(flag_S5%2==0 && flag_S4==1){//时间参数
					if(time_count == 2){
						time_count++;
					}else if(time_count == 9){
						time_count = 2;
					}else{
						time_count += 2;
					}
				}else if((flag_S5%2==1 && flag_S4==1)){//距离参数
					distance_count += 10;
					if(distance_count == 90) distance_count = 10;
				}
				break;
		}
		if(flag_S8%2 == 0){//定时模式 测距离
			if(s != second){
				distan = wave_recv();
				distance_compare();
				s = second;
			}
		}else{//触发模式 测距离
			if(count%50 ==0){
				light = adc_read(0x01);//读取光敏电阻
			}
			if(light<130){//暗状态
				if(count%5 ==0){
					distan = wave_recv();
					distance_compare();
				}
				flag_L6 = 1;//LED6熄灭
			}else{//亮状态
				flag_L6 = 0;//LED6点亮
			}
		}
		if(distan <=10){//DAC输出 图表第1段
			dac_out(51.0);
		}else if(distan>=80){//DAC输出 图表第3段
			dac_out(255.0);
		}else{//DAC输出 图表第2段
			VV = distan*4.0/70*51.0;
			dac_out(VV);
		}
		if(distan>distance_count-6 && distan<distance_count+6){//用于判断L5是否点亮
			flag_L5++;//本次测得距离符合条件,积累次数加1
		}else{
			flag_L5 = 0;//本次测得的距离不符合条件,积累次数直接变成0
		}
		S5_play();//数码管显示
	}
}

void time1() interrupt 3{
	count++;
	if(count%2 == 0) {
		segs();//数码管显示
		led();//LED点亮
	}
	if(count%2000 == 0){
		ds1302_read();//读取时间
	}
}

config.h文件:

#ifndef _CONFIG_H_
#define _CONFIG_H_

#include <STC15F2K60S2.h>
#include "iic.h"
#include "ds1302.h"
#include "ultrasonic.h"

void sysinit();//关闭外设函数
void segs();//数码管显示函数
void led();//LED函数
unsigned char scankbd();//按键函数
void Timer1Init(void);//定时器函数
void S5_play();
void distance();
void data_paly();
void led();
void distance_compare();

#endif

config.c文件:

#include "config.h"

#define kbd_io P3
#define kbd_maskrow 0x0f

sbit L1 = P0^0;
sbit L2 = P0^1;
sbit L3 = P0^2;
sbit L4 = P0^3;
sbit L5 = P0^4;
sbit L6 = P0^5;
sbit realy = P0^4;
sbit buzzer = P0^6;

extern unsigned char flag_L5,flag_L6;//LED的L5 L6点亮的分别标识
extern unsigned char max_distance,min_distance;//记录测得距离的最大值  最小值
extern unsigned int ave_distance;//平均值
extern unsigned char distan;//记录红外测得的距离
extern unsigned char flag_S8;//触发模式 定时模式 模式切换表示
unsigned char flag_S4 = 0;//按下S4模式切换控制标志
unsigned char flag_S5 = 0;//按下S5切换控制标志
extern unsigned char time_count,distance_count;//时间参数 距离参数
extern unsigned char hour,minute,second;//时间的时 分 秒
unsigned char segbuff[] = {10,10,10,10,10,10,10,10};
code unsigned char segtab[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0xff,
0xc0&0x7f,0xf9&0x7f,0xa4&0x7f,0xb0&0x7f,0x99&0x7f,0x92&0x7f,0x82&0x7f,0xf8&0x7f,0x80&0x7f,0x90&0x7f,0xbf,0xff,
0xc7,0xc6,0x8e,0x8c,0x89,0xfe,0xbf,0xf7};//L C F P H 最大值标志 平均值表示 最小值表示

void sysinit(){//关闭外设函数
	P2 = P2&0x1f|0x80;P0 = 0xff;P2 = P2&0x1f;//关闭LED灯
	P2 = P2&0x1f|0xa0;realy = 0;buzzer = 0;P2 = P2&0x1f;//关闭蜂鸣器与继电器
	P2 = P2&0x1f|0xe0;P2 = 0xff;P2 = P2&0x1f;//关闭数码管的段选;
	P2 = P2&0x1f|0xc0;P2 = 0x00;P2 = P2&0x1f;//关闭数码管的位选
}

void segs(){//数码管显示函数
	static unsigned char segaddr = 0;
	P2 = P2&0x1f|0xe0;P0 = 0xff;P2 = P2&0x1f;//段选消影
	P2 = P2&0x1f|0xc0;P0 = 1<<segaddr;P2 = P2&0x1f;//位选
	P2 = P2&0x1f|0xe0;P0 = segtab[segbuff[segaddr]];P2 = P2&0x1f;//段选
	if(++segaddr == 8) segaddr = 0;
}

unsigned char scankbd(){//按键函数
	unsigned char key_num = 16;
	static unsigned char kbd_state = 0;
	unsigned char kbd_press;
	switch(kbd_state){
		case 0:
			kbd_io = 0x0f;P42 =0;P44 = 0;kbd_press = kbd_io;
			if(kbd_press != kbd_maskrow){
				kbd_state = 1;
			}
			break;
		case 1:
			kbd_press = kbd_io;
			if(kbd_press != kbd_maskrow){
				if((kbd_io&0x08)==0) key_num = 0;
				if((kbd_io&0x04)==0) key_num = 1;
				if((kbd_io&0x02)==0) key_num = 2;
				if((kbd_io&0x01)==0) key_num = 3;
				
				kbd_io = 0xf0;P42 = 1;P44 = 1;
				
				if(P44 == 0) key_num += 0;
				if(P42 == 0) key_num += 4;
				if((kbd_io&0x20)==0) key_num += 8;
				if((kbd_io&0x10)==0) key_num += 12;
				kbd_state = 2;
			}else{
				kbd_state = 0;
			}
			break;
		case 2:
			kbd_io = 0x0f;P42 = 0;P44 = 0;kbd_press = kbd_io;
			if(kbd_press == kbd_maskrow){
				kbd_state = 0;
			}
			break;
		default: break;
	}
	return key_num;
}

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

void S5_play(){
	if(flag_S5%3==0 && flag_S4==0){//数据显示 时间显示
		segbuff[0] = hour/16;
		segbuff[1] = hour%16;
		segbuff[2] = 10;
		segbuff[3] = minute/16;
		segbuff[4] = minute%16;
		segbuff[5] = 10;
		segbuff[6] = second/16;
		segbuff[7] = second%16;
	}else if(flag_S5%3==1 && flag_S4==0){//数据显示 距离显示
		distance();
	}else if(flag_S5%3==2 && flag_S4==0){//数据显示 数据记录显示
		data_paly();	
	}
	
	if(flag_S5%2==0 && flag_S4==1){//参数显示 时间参数
		segbuff[0] = 27;
		segbuff[1] = 1;
		segbuff[2] = 11;
		segbuff[3] = 11;
		segbuff[4] = 11;
		segbuff[5] = 11;
		segbuff[6] = time_count/10;
		segbuff[7] = time_count%10;
	}else if(flag_S5%2==1 && flag_S4==1){//参数显示 距离参数
		segbuff[0] = 27;
		segbuff[1] = 2;
		segbuff[2] = 11;
		segbuff[3] = 11;
		segbuff[4] = 11;
		segbuff[5] = 11;
		segbuff[6] = distance_count/10;
		segbuff[7] = distance_count%10;
	}
}

//距离显示函数
void distance(){
	if(flag_S8%2 == 0){//定时器模式下
		segbuff[0] = 24;
		segbuff[1] = 26;//F
		segbuff[2] = 11;
		segbuff[3] = 11;
		segbuff[4] = 11;
		if(distan>=100){
			segbuff[5] = distan/100;
		}else{
			segbuff[5] = 11;
		}
		segbuff[6] = distan%100/10;
		segbuff[7] = distan%10;
	}else if(flag_S8%2 == 1){//触发模式下
		segbuff[0] = 24;
		segbuff[1] = 25;//C
		segbuff[2] = 11;
		segbuff[3] = 11;
		segbuff[4] = 11;
		if(distan>=100){
			segbuff[5] = distan/100;
		}else{
			segbuff[5] = 11;
		}
		segbuff[6] = distan%100/10;
		segbuff[7] = distan%10;
	}
}

//数据显示
void data_paly(){
	if(flag_S8%3 == 0){//显示最大值
		segbuff[0] = 28;//H
		segbuff[1] = 29;
		segbuff[2] = 11;
		segbuff[3] = 11;
		segbuff[4] = 11;
		if(max_distance>100){
			segbuff[5] = max_distance/100;
		}else{
			segbuff[5] = 11;
		}
		segbuff[6] = max_distance%100/10;
		segbuff[7] = max_distance%10;
	}else if(flag_S8%3 == 1){//显示平均值
		segbuff[0] = 28;//H
		segbuff[1] = 30;
		segbuff[2] = 11;
		segbuff[3] = 11;
		if(ave_distance>1000){
			segbuff[4] = ave_distance/1000;
		}else{
			segbuff[4] = 11;
		}
		if(ave_distance>100){
			segbuff[5] = ave_distance%1000/100;
		}else{
			segbuff[5] = 11;
		}
		segbuff[6] = ave_distance%1000%100/10+12;
		segbuff[7] = ave_distance%10;
	}else if(flag_S8%3 == 2){//显示最小值
		segbuff[0] = 28;//H
		segbuff[1] = 31;
		segbuff[2] = 11;
		segbuff[3] = 11;
		segbuff[4] = 11;
		if(min_distance>100){
			segbuff[5] = min_distance/100;
		}else{
			segbuff[5] = 11;
		}
		segbuff[6] = min_distance%100;
		segbuff[7] = min_distance%10;
	}
}


unsigned char distan_count;
void distance_compare(){
	static unsigned int sum = 0;
	distan_count++;
	max_distance = distan>max_distance?distan:max_distance;
	min_distance = distan<min_distance?distan:min_distance;
	sum += distan;
	ave_distance = ((double)(sum/distan_count))*10;
}

void led(){//LED函数
	P2 = P2&0x1f|0x80;P0 = 0xff;P2 = P2&0x1f;
	if(flag_S5%3==0 && flag_S4==0){//时间数据显示 L1点亮
		P2 = P2&0x1f|0x80;L1 = 0;P2 = P2&0x1f;
	}else{
		P2 = P2&0x1f|0x80;L1 = 1;P2 = P2&0x1f;
	}
	
	if(flag_S5%3==1 && flag_S4==0){//距离数据显示  L2点亮
		P2 = P2&0x1f|0x80;L2 = 0;P2 = P2&0x1f;
	}else{
		P2 = P2&0x1f|0x80;L2 = 1;P2 = P2&0x1f;
	}
	
	if(flag_S5%3==2 && flag_S4==0){//数据显示  L3点亮
		P2 = P2&0x1f|0x80;L3 = 0;P2 = P2&0x1f;
	}else{
		P2 = P2&0x1f|0x80;L3 = 1;P2 = P2&0x1f;
	}
	
	if(flag_S5%3==1 && flag_S4==0 && flag_S8%2==1){//触发模式下 L4点亮
		P2 = P2&0x1f|0x80;L4 = 0;P2 = P2&0x1f;
	}else{
		P2 = P2&0x1f|0x80;L4 = 1;P2 = P2&0x1f;
	}
	
	if(flag_L5 >= 3){//连续3次符合条件 L5点亮
		P2 = P2&0x1f|0x80;L5 = 0;P2 = P2&0x1f;
	}else{
		P2 = P2&0x1f|0x80;L5 = 1;P2 = P2&0x1f;
	}
	
	if(flag_L6 == 0){//光线条件为亮 L6点亮
		P2 = P2&0x1f|0x80;L6 = 0;P2 = P2&0x1f;
	}else{
		P2 = P2&0x1f|0x80;L6 = 1;P2 = P2&0x1f;
	}
}

iic.h文件:

#ifndef _IIC_H
#define _IIC_H
#include "STC15F2K60S2.H"

sbit SDA = P2^1;  
sbit SCL = P2^0;  

void IIC_Start(void);//总线启动 
void IIC_Stop(void);  //总线停止
bit IIC_WaitAck(void);  //等待应答
void IIC_SendAck(bit ackbit); //发送应答
void IIC_SendByte(unsigned char byt);//通过IIC总线发送数据 
unsigned char IIC_RecByte(void); //从IIC总线接收数据

void IIC_Delay(unsigned char i);

//dac与adc不能够同时使用,需要分开使用
unsigned char adc_read(unsigned char addr);//addr表示需要读取的位置,传回来读取到的数据
void dac_out(unsigned char date);


#endif

iic.c文件:

#include "iic.h"
#include "intrins.h"
#include "STC15F2K60S2.h"

#define DELAY_TIME 5

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;
}

//通过IIC总线发送数据
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;  
}

//从IIC总线接收数据
unsigned char IIC_RecByte(void)
{
    unsigned char i, date;
    for(i=0; i<8; i++)
    {   
    	SCL = 1;
			IIC_Delay(DELAY_TIME);
			date <<= 1;
			if(SDA) date |=0x01;
			SCL = 0;
			IIC_Delay(DELAY_TIME);
    }
    return date;    
}

//读取ADC数据
unsigned char adc_read(unsigned char add){
	unsigned char dat = 0;
	IIC_Start();
	IIC_SendByte(0x90);
	IIC_WaitAck();
	IIC_SendByte(add);
	IIC_WaitAck();
	//IIC_Stop();
	
	IIC_Start();
	IIC_SendByte(0x91);
	IIC_WaitAck();
	dat = IIC_RecByte();
	IIC_SendAck(1);
	IIC_Stop();
	
	return dat;
}

//DAC输出
void dac_out(unsigned char date){
	IIC_Start();
	IIC_SendByte(0x90);//通信并且发送写入请求
	IIC_WaitAck();
	IIC_SendByte(0x43);//给予写入的地址
	IIC_WaitAck();
	
	IIC_SendByte(date);//发送数据
	IIC_WaitAck();
	IIC_Stop();
}

** ultrasonic.h文件:**

#ifndef _ULTRASONIC_H
#define _ULTRASONIC_H

#include <STC15F2K60S2.h>

void Timer0Init();
unsigned char wave_recv();

#endif

ultrasonic.c文件:

#include "ultrasonic.h"

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

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

unsigned char wave_recv(){
	unsigned char ucdist,num = 10;
	TX = 0;
	TL0 = 0xf4;
	TH0 = 0xff;
	TR0 = 1;//定时器0开始计时
	while(num--){
		while(!TF0)
			;
		TX ^= 1;
		TF0 = 0;
	}
	TR0 = 0;
	TL0 = 0;
	TH0 = 0;
	TR0 = 1;
	while(RX&&!TF0)
		;
	TR0 = 0;
	if(TF0){
		TF0 = 0;
		ucdist = 255;
	}else{
		ucdist = ((TH0<<8)+TL0)*0.017;
	}
	return ucdist;
}

ds1302.h文件:

#ifndef __DS1302_H
#define __DS1302_H

#include <STC15F2K60S2.h>
#include <intrins.h>

void Write_Ds1302(unsigned char temp);//写入时钟数据函数
void Write_Ds1302_Byte( unsigned char address,unsigned char dat );//在时钟特定地址写入特定数值的函数
unsigned char Read_Ds1302_Byte( unsigned char address );//读取特定地址的时钟数据函数

void ds1302_init(unsigned char h,unsigned char m,unsigned char s);//给时钟设定初始值
void ds1302_read();//读取时钟的数据

#endif

ds1302.c文件:

#include "ds1302.h"

sbit SCK=P1^7;		
sbit SDA=P2^3;		
sbit RST = P1^3;   // DS1302复位

unsigned char hour = 0x20,minute = 0x20,second = 0x00;//时钟的时分秒												

void Write_Ds1302(unsigned  char temp) //写入时钟数据函数
{
	unsigned char i;
	for (i=0;i<8;i++)     	
	{ 
		SCK=0;
		SDA=temp&0x01;
		temp>>=1; 
		SCK=1;
	}
}   

void Write_Ds1302_Byte( unsigned char address,unsigned char dat )//在时钟特定地址写入特定数值的函数     
{
 	RST=0;	_nop_();
 	SCK=0;	_nop_();
 	RST=1; 	_nop_();  
 	Write_Ds1302(address);	
 	Write_Ds1302(dat);		
 	RST=0; 
}

unsigned char Read_Ds1302_Byte ( unsigned char address )//读取特定地址的时钟数据函数
{
 	unsigned char i,temp=0x00;
 	RST=0;	_nop_();
 	SCK=0;	_nop_();
 	RST=1;	_nop_();
 	Write_Ds1302(address);
 	for (i=0;i<8;i++) 	
 	{		
		SCK=0;
		temp>>=1;	
 		if(SDA)
 		temp|=0x80;	
 		SCK=1;
	} 
 	RST=0;	_nop_();
 	SCK=0;	_nop_();
	SCK=1;	_nop_();
	SDA=0;	_nop_();
	SDA=1;	_nop_();
	return (temp);			
}

unsigned char hour ,minute ,second ;

void ds1302_init(unsigned char h,unsigned char m,unsigned char s){
	Write_Ds1302_Byte(0x8e,0x00);
	Write_Ds1302_Byte(0x84,h);
	Write_Ds1302_Byte(0x82,m);
	Write_Ds1302_Byte(0x80,s);
	Write_Ds1302_Byte(0x8e,0x80);
}

void ds1302_read(){
	hour = Read_Ds1302_Byte(0x85);
	minute = Read_Ds1302_Byte(0x83);
	second = Read_Ds1302_Byte(0x81);
}

总结

    其实呢,单片机开发就像是搭建积木,只要有足够的耐心还是能够搭建成功的。至于本套试题呢,从模块上来讲与11届的试题相差不大,就是将DS18B20换成了超声波;从按键组合的功能上看呢,本届试题的功能更加丰富;但是总体上来说变化不大,但是难度稍稍加大了。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐