相信大家一直都在寻找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
#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
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
#include
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换成了超声波;从按键组合的功能上看呢,本届试题的功能更加丰富;但是总体上来说变化不大,但是难度稍稍加大了。