今年十四届单片机国赛试题在程序题设计方面难度有所下降,但选择题没有了以往可以在手册中可以找到的单片机类选择题,选择题难度较高,因此想获得一个不错的成绩,需要在选择题方面有所加强
试题展示
设计说明
此次国赛采用了温度传感器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
免责声明:函数模块采用蚂蚁工程科技子函数模块,代码仅供学习未商用,如有侵权请联系。