【第十四届蓝桥杯单片机冲刺版】
明天就是正式比赛啦,今天可以在把各个模块练习一遍,常考的外设相关代码一定要熟练哦。
比赛时拿到资料包了,检查驱动文件,使用到的驱动文件,自己做相应的修改,确保是能够正常使用(驱动修改相关可看之前的文章)。
下面是自己将常考的外设结合一起的练习,需要完整工程的自取哈
链接:https://pan.baidu.com/s/1yc-GG_hqpqU5qzTsA8UOtA?pwd=l99q
提取码:l99q
--来自百度网盘超级会员V5的分享
祝大家都可以取得好成绩,有帮助就给个赞和关注吧
功能说明
下面练习中结合了温度采集、adc采集、时钟显示、超声波、频率测试、独立按键,矩阵按键、串口接收串口发送、长按等相关操作。
按键操作:
S4作为界面和模式切换(温度、电压、时间、距离)
S5 作为长按(第一次长按关闭LED显示第二次长按打开)
S6 作为长按(第一次长按关闭数码管显示第二次打开)
S7 作为向串口发送按键,会将当前界面的数据发送到串口
串口操作:
通过串口中断接收 字符A B C D 分别进行温度、电压、时间、距离界面和模式的切换并将当前界面数据发送到PC
定时器分配:
定时器1:一般用来做串口
定时器2:数码管以及一些频率变量刷新操作
定时器0:超声波或者频率
#include
#include "iic.h"
#include "onewire.h"
#include "ds1302.h"
/*========================十四届蓝桥杯单片机考前一天冲刺=========================
@Author:小殷
@Date:2023.4.7
================================================================================*/
sbit TX = P1^0;
sbit RX = P1^1;
typedef unsigned char uchar;
typedef unsigned int uint;
#define Control_Port(x,y) P0 = y;P2 = x;P2 = 0
//=======================下面为变量定义==========================
uchar smg_data[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0xc1,0xbf};
uchar smg_bit[9] = {10,10,10,10,10,10,10,10,10}; //数码管初始化全熄灭
uchar L[5]; //LED操作
uchar interface = 1; //界面
static uchar hour = 0,min= 0,sec = 0; //时分秒
static uint Temperature = 0; //温度
static uint adc_volt = 0; //电压
static uchar key_feq = 0; //按键刷新频率
static uchar adc_feq = 0; //adc采集频率
static uchar t_feq = 0; //温度刷新频率
static uchar dis_feq = 0; //距离刷新频率
static uchar smg_flag =1; //数码管打开关闭标志
static uchar led_flag =1; //led打开关闭标志
static uchar send_data_flag = 0; //按键发送
static uint distance = 0; //距离
uchar usart_cmd = 0; //串口接收指令缓存
//=======================下面为函数声明===========================
void Timer2Init(void); //1毫秒@12.0定时器2初始化
void Delay5ms(); //@12.000MHz 5ms延时
void UartInit(void); //[email protected]串口初始化
void Send_Byte(uchar dat); //发送一个字节
void Send_String(uchar *str); //发送字符串
void Delay12us(); //@12.000MHz 12us
void Send_Wave(void); //发波8个40khz
uint Get_Distance(void); //获取距离
void Set_DS1302_Timer(uchar hour,uchar min,uchar sec); //设置ds1302时间
float Read_Temperature(void); //温度获取
uchar Read_Key_Value(void); //键值获取
uchar Read_ADC_Value(uchar addr); //ADC获取
void Data_Tackle_Task(void); //数据处理任务
void Key_Tackle_Task(void); //按键处理任务
void SMG_Display_Task(void); //数码管处理任务
void Init_System(void); //系统初始化
void Send_Data(uchar interface); //发送数据 串口相关
void Send_Volt(void); //发送电压
void Send_Temperature(void); //发送温度
void Send_Timer(void); //发送时间
void Send_Distance(void); //发送距离
//========================下面为函数实现==========================
void Timer2Init(void) //1毫秒@12.000MHz
{
AUXR |= 0x04; //定时器时钟1T模式
T2L = 0x20; //设置定时初值
T2H = 0xD1; //设置定时初值
AUXR |= 0x10; //定时器2开始计时
IE2 |= 0x04;
EA = 1;
}
void Delay5ms() //@12.000MHz
{
unsigned char i, j;
i = 59;
j = 90;
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 Send_Byte(uchar dat)
{
SBUF = dat;
while(TI == 0);
TI = 0;
}
void Send_String(uchar *str)
{
while(*str != '\0')
{
Send_Byte(*str++);
}
}
void Delay12us() //@12.000MHz
{
unsigned char i;
_nop_();
_nop_();
i = 33;
while (--i);
}
void Send_Wave(void)
{
uchar i = 0;
for(i = 0;i<8;i++)
{
TX = 1;
Delay12us();
TX = 0;
Delay12us();
}
}
uint Get_Distance(void)
{
uint dis = 0;
TMOD &= 0xf0;
TH0 = 0;
TL0 = 0;
Send_Wave();
TR0 = 1;
while((RX == 1) && (TF0 == 0));
TR0 = 0;
if(TF0 == 0)
{
dis = (TH0 << 8)|TL0;
dis *= 0.017;
}
else
{
TF0 = 0;
dis = 999;
}
return dis;
}
uchar Read_Key_Value(void)
{
static uchar last_trg = 0,cnt = 0;
uchar cur = 0,trg = 0,value = 3;
static uint long_count = 0;
static bit long_flag = 0;
cur = (P3 | 0x10)^0xff;
trg = cur^cnt & cur;
cnt = cur;
if((last_trg ^ trg & last_trg) && cur)
{
if(cur & 0x08) value = 4;
else if(cur & 0x04) value = 5;
else if(cur & 0x02) value = 6;
else if(cur & 0x01) value = 7;
}
last_trg = trg;
if(cur)
{
if((!long_flag) && (++long_count == 100)) //1s
{
long_flag = 1;
if(cur & 0x04) value = 5 + 100;
else if(cur & 0x02) value = 6 + 100;
}
}
else
{
long_count = 0;
long_flag = 0;
}
return value;
}
uchar Read_ADC_Value(uchar addr)
{
uchar adc = 0;
I2CStart();
I2CSendByte(0x90);
I2CWaitAck();
I2CSendByte(addr);
I2CWaitAck();
I2CStop();
I2CStart();
I2CSendByte(0x91);
I2CWaitAck();
adc = I2CReceiveByte();
I2CSendAck(1);
I2CStop();
return adc;
}
void Set_DS1302_Timer(uchar hour,uchar min,uchar sec)
{
Write_Ds1302_Byte(0x8e,0x00);
Write_Ds1302_Byte(0x80,sec/10*16 + sec%10);
Write_Ds1302_Byte(0x82,min/10*16 + min%10);
Write_Ds1302_Byte(0x84,hour/10*16 + hour%10);
Write_Ds1302_Byte(0x8e,0x80);
}
float Read_Temperature(void)
{
uchar LSB = 0,MSB = 0;
float temp = 0.0;
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0x44);
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0xbe);
LSB = Read_DS18B20();
MSB = Read_DS18B20();
init_ds18b20();
temp = ((MSB << 8)|LSB) * 0.0625;
return temp;
}
void Key_Tackle_Task(void)
{
uchar key_value = 0;
if(key_feq > 10)
{
key_feq = 1;
key_value = Read_Key_Value();
}
if(key_value == 4)
{
if(++interface > 4)
{
interface = 1;
}
}
//长按S5 关闭LED 长按S6 关闭SMG
else if(key_value == 105)
{
led_flag = !led_flag;
}
else if(key_value == 106)
{
smg_flag = !smg_flag;
}
//S7 将电压发送到串口
if(key_value == 7)
{
send_data_flag = 1;
}
}
//对应界面的数据发送
void Send_Data(uchar interface)
{
switch(interface)
{
case 1:Send_Temperature();break;
case 2:Send_Volt();break;
case 3:Send_Timer();break;
case 4:Send_Distance();break;
}
}
void Send_Volt(void)
{
Send_String("Volt:");
Send_Byte(adc_volt/100+'0');
Send_Byte('.');
Send_Byte(adc_volt/10%10+'0');
Send_Byte(adc_volt%10+'0');
Send_String("v\r\n");
}
void Send_Temperature(void)
{
Send_String("Temperature:");
Send_Byte(Temperature/100+'0');
Send_Byte(Temperature/10%10+'0');
Send_Byte('.');
Send_Byte(Temperature%10+'0');
Send_String("℃\r\n");
}
void Send_Timer(void)
{
Send_String("Time:");
Send_Byte(hour/10+'0');
Send_Byte(hour%10+'0');
Send_Byte(':');
Send_Byte(min/10+'0');
Send_Byte(min%10+'0');
Send_Byte(':');
Send_Byte(sec/10+'0');
Send_Byte(sec%10+'0');
Send_String("\r\n");
}
void Send_Distance(void)
{
Send_String("Dis:");
if(distance > 99)
{
Send_Byte(distance/100+'0');
Send_Byte(distance/10%10+'0');
Send_Byte(distance%10+'0');
}
else if(distance > 9)
{
Send_Byte(distance/10%10+'0');
Send_Byte(distance%10+'0');
}
else
{
Send_Byte(distance%10+'0');
}
Send_String("cm\r\n");
}
void Data_Tackle_Task(void)
{
uchar time[3];
if(T2H < 0xd9)
{
if(adc_feq > 150)
{
adc_feq = 1;
adc_volt = Read_ADC_Value(0x03) * (5.0/255) * 100;
}
if(interface == 3)
{
time[0] = Read_Ds1302_Byte(0x81);
time[1] = Read_Ds1302_Byte(0x83);
time[2] = Read_Ds1302_Byte(0x85);
hour = (time[2]/16*10 + time[2]%16);
min = (time[1]/16*10 + time[1]%16);
sec = (time[0]/16*10 + time[0]%16);
}
if(t_feq > 150)
{
t_feq = 1;
Temperature = Read_Temperature() * 10;
}
if(dis_feq > 150)
{
dis_feq = 1;
distance = Get_Distance();
}
}
//LED控制
L[1] = (interface == 1)?(1):(0);
L[2] = (interface == 2)?(1):(0);
L[3] = (interface == 3)?(1):(0);
L[4] = (interface == 4)?(1):(0);
//串口发送
if(send_data_flag)
{
send_data_flag = 0;
Send_Data(interface);
}
//串口控制界面切换
switch(usart_cmd)
{
case 'A':interface = 1;Send_Data(interface);break; //温度
case 'B':interface = 2;Send_Data(interface);break; //电压
case 'C':interface = 3;Send_Data(interface);break; //时间
case 'D':interface = 4;Send_Data(interface);break; //距离
default:break;
}
usart_cmd = 0;
}
void SMG_Display_Task(void)
{
if(interface == 1)
{
smg_bit[1] = 11;
smg_bit[2] = interface;
smg_bit[3] = 10;
smg_bit[4] = 10;
smg_bit[5] = 10;
smg_bit[6] = Temperature/100;
smg_bit[7] = Temperature/10%10;
smg_bit[8] = Temperature%10;
}
else if(interface == 2)
{
smg_bit[1] = 11;
smg_bit[2] = interface;
smg_bit[3] = 10;
smg_bit[4] = 10;
smg_bit[5] = 10;
smg_bit[6] = adc_volt/100;
smg_bit[7] = adc_volt/10%10;
smg_bit[8] = adc_volt%10;
}
else if(interface == 3)
{
smg_bit[1] = hour/10;
smg_bit[2] = hour%10;
smg_bit[3] = 12;
smg_bit[4] = min/10;
smg_bit[5] = min%10;
smg_bit[6] = 12;
smg_bit[7] = sec/10;
smg_bit[8] = sec%10;
}
else if(interface == 4)
{
smg_bit[1] = 11;
smg_bit[2] = interface;
smg_bit[3] = 10;
smg_bit[4] = 10;
smg_bit[5] = 10;
smg_bit[6] = (distance>99)?(distance/100):(10);
smg_bit[7] = (distance>9)?(distance/10%10):(10);
smg_bit[8] = distance%10;
}
}
void Init_System(void)
{
Control_Port(0x080,0xff);
Control_Port(0xa0,0x00);
Control_Port(0xc0,0x00);
while(t_feq++ < 150)
{
Temperature = Read_Temperature() * 10;
}
UartInit();
Delay5ms();
Timer2Init();
Set_DS1302_Timer(11,59,50);
Send_String("Usart Test\r\n");
}
void main(void)
{
Init_System();
while(1)
{
Data_Tackle_Task();
Key_Tackle_Task();
SMG_Display_Task();
}
}
void Timer2_Server() interrupt 12
{
static uchar dsp_smg = 1;
if(led_flag)
{
Control_Port(0x80,~(L[1] << 0 | L[2] << 1 | L[3] <<2 | L[4] << 3));
}
else
{
Control_Port(0x80,0xff);
}
Control_Port(0xc0,0x00);
if(smg_flag)
{
if((interface == 1 && dsp_smg == 7) || (interface == 2 && dsp_smg == 6))
{
Control_Port(0xe0,smg_data[smg_bit[dsp_smg]] & 0x7f);
}
else
{
Control_Port(0xe0,smg_data[smg_bit[dsp_smg]]);
}
Control_Port(0xc0,1 << (dsp_smg - 1));
if(++dsp_smg > 8)
{
dsp_smg = 1;
}
}
else
{
Control_Port(0xc0,0x00);
}
key_feq++;
t_feq++;
adc_feq++;
dis_feq++;
}
void Usart_Server() interrupt 4
{
if(RI)
{
RI = 0;
usart_cmd = SBUF;
}
}
由于超声波和频率都是用定时器0,上面工程中使用的是超声波,频率部分请看下面哈
//频率测量在定时器2中断中进行 (定时器0)
void Init_Timer0(void)
{
AUXR = 0x80;
TMOD = 0x04;
TH0 = 0;
TL0 = 0;
TR0 = 1;
}
void Timer2_Server() interrupt 12
{
static uchar dsp_smg = 1;
static uint feq_count;
if(++feq_count == 500)
{
feq_count = 0;
TR0 = 0
Feq = ((uint)(TH0 << 8) | TL0) * 2;
TH0 = TL0 = 0;
TR0 = 1;
}
Control_Port(0xc0,0x00);
Control_Port(0xe0,smg_data[smg_bit[dsp_smg]]);
Control_Port(0xc0,1 << (dsp_smg -1));
if(++dsp_smg > 8)
{
dsp_smg = 1;
}
}