第十四届蓝桥杯单片机组底层驱动测试赛事回顾
【第十四届蓝桥杯单片机组底层驱动测试】
下面分享的是第十四届蓝桥杯单片机组底层驱动代码的测试和相关说明,今年官方提供的资料包中底层驱动代码和以往有了变化,主要代码还是提供给了我们,只是此次没有了相关头文件iic.h ds1302 onewire.h,这三个文件需要我们自行添加,其次就是整个驱动的改动,下面将具体介绍。
完整工程和底层驱动文件有需要的自取哈
链接:https://pan.baidu.com/s/1yAfgSQ0ohivGgZngeYeqsw?pwd=3ub8
提取码:3ub8
--来自百度网盘超级会员V5的分享
有帮助就给博主一个关注和点赞吧,祝大家都可以取得好成绩哦
iic.c
在IIC.C文件我们除了要加上iic.h头文件,还需修改I2C_Delay函数,在该函数中只需保留一个_nop_()函数就行,多余的_nop_()函数删除掉,还要注意_nop_()函数头文件intrins.h的包含,另外IIC相关的SCL和SDA的引脚定义需要我们自己记住,在提供的资料包中并没有改引脚的定义,当然到时候也可以查看原理图,最好可以记住吧具体见iic.h。
/* # I2C代码片段说明
1. 本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
2. 参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
中对单片机时钟频率的要求,进行代码调试和修改。
*/
#include "iic.h"
#define DELAY_TIME 5
//
void I2C_Delay(unsigned char n)
{
do
{
_nop_();
}
while(n--);
}
//
void I2CStart(void)
{
sda = 1;
scl = 1;
I2C_Delay(DELAY_TIME);
sda = 0;
I2C_Delay(DELAY_TIME);
scl = 0;
}
//
void I2CStop(void)
{
sda = 0;
scl = 1;
I2C_Delay(DELAY_TIME);
sda = 1;
I2C_Delay(DELAY_TIME);
}
//
void I2CSendByte(unsigned char byt)
{
unsigned char i;
for(i=0; i<8; i++){
scl = 0;
I2C_Delay(DELAY_TIME);
if(byt & 0x80){
sda = 1;
}
else{
sda = 0;
}
I2C_Delay(DELAY_TIME);
scl = 1;
byt <<= 1;
I2C_Delay(DELAY_TIME);
}
scl = 0;
}
//
unsigned char I2CReceiveByte(void)
{
unsigned char da;
unsigned char i;
for(i=0;i<8;i++){
scl = 1;
I2C_Delay(DELAY_TIME);
da <<= 1;
if(sda)
da |= 0x01;
scl = 0;
I2C_Delay(DELAY_TIME);
}
return da;
}
//
unsigned char I2CWaitAck(void)
{
unsigned char ackbit;
scl = 1;
I2C_Delay(DELAY_TIME);
ackbit = sda;
scl = 0;
I2C_Delay(DELAY_TIME);
return ackbit;
}
//
void I2CSendAck(unsigned char ackbit)
{
scl = 0;
sda = ackbit;
I2C_Delay(DELAY_TIME);
scl = 1;
I2C_Delay(DELAY_TIME);
scl = 0;
sda = 1;
I2C_Delay(DELAY_TIME);
}
iic.h
在iic.h头文件 注意将各个函数的声明添加到这里哦,以及相关的头文件和引脚定义
#ifndef _IIC_H_
#define _IIC_H_
#include <STC15F2K60S2.H>
#include "intrins.h"
sbit sda = P2^1;
sbit scl = P2^0;
void I2C_Delay(unsigned char n);
void I2CStart(void);
void I2CSendByte(unsigned char byt);
void I2CStop(void);
unsigned char I2CWaitAck(void);
unsigned char I2CReceiveByte(void);
void I2CSendAck(unsigned char ackbit);
#endif
ds1302.c
在ds1302.c头文件中只需添加ds1302.h就好,其他函数中没有需要更改中,其余相关声明和引脚定义在ds1302.h中包含就好了
/* # DS1302代码片段说明
1. 本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
2. 参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
中对单片机时钟频率的要求,进行代码调试和修改。
*/
#include "ds1302.h"
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);
}
ds1302.h
在ds1302中同样没有提供引脚定义也需要我们自己记住哦
#ifndef _DS1302_H_
#define _DS1302_H_
#include <STC15F2K60S2.H>
#include "intrins.h"
sbit RST = P1^3;
sbit SCK = P1^7;
sbit SDA = P2^3;
void Write_Ds1302(unsigned char temp);
void Write_Ds1302_Byte( unsigned char address,unsigned char dat );
unsigned char Read_Ds1302_Byte ( unsigned char address );
#endif
onewire.c
onewire.c中相对以往的Delay_OneWire函数 这里进行了12倍的处理,就不需要我们自己改动了,只需添加onewire.h头文件就好,其他相关在onewire.h中包含
/* # 单总线代码片段说明
1. 本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
2. 参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
中对单片机时钟频率的要求,进行代码调试和修改。
*/
#include "onewire.h"
//
void Delay_OneWire(unsigned int t)
{
unsigned char i;
while(t--){
for(i=0;i<12;i++);
}
}
//
void Write_DS18B20(unsigned char dat)
{
unsigned char i;
for(i=0;i<8;i++)
{
DQ = 0;
DQ = dat&0x01;
Delay_OneWire(5);
DQ = 1;
dat >>= 1;
}
Delay_OneWire(5);
}
//
unsigned char Read_DS18B20(void)
{
unsigned char i;
unsigned char dat;
for(i=0;i<8;i++)
{
DQ = 0;
dat >>= 1;
DQ = 1;
if(DQ)
{
dat |= 0x80;
}
Delay_OneWire(5);
}
return dat;
}
//
bit init_ds18b20(void)
{
bit initflag = 0;
DQ = 1;
Delay_OneWire(12);
DQ = 0;
Delay_OneWire(80);
DQ = 1;
Delay_OneWire(10);
initflag = DQ;
Delay_OneWire(5);
return initflag;
}
onewire.h
注意温度的引脚P1^4 IO口哦,将相关函数声明添加到onewire.h头文件中,delay_onewire函数的static可去可不去都行
#ifndef _ONEWIRE_H_
#define _ONEWIRE_H_
#include <STC15F2K60S2.H>
sbit DQ = P1^4;
void Delay_OneWire(unsigned int t) ;
void Write_DS18B20(unsigned char dat);
unsigned char Read_DS18B20(void);
bit init_ds18b20(void);
#endif
以上就行三个驱动文件的讲解啦,下面以按键4 分别进行三个功能的切换显示,并且每个界面的切换伴随LED亮灭的切换
#include <STC15F2K60S2.H>
#include "iic.h"
#include "onewire.h"
#include "ds1302.h"
/*=========================================十四届蓝桥杯单片机底层驱动测试================================
@Author:小殷
@Date:2023.4.2
======================================================================================================*/
typedef unsigned char uchar;
typedef unsigned int uint;
#define Control_Port(x,y) P0 = y;P2 = x;P2 = 0
uchar smg_bit[9] = {10,10,10,10,10,10,10,10,10}; //设置为10对应着0xff 关闭数码管初始化
//数码管段码 0-9 shut-off -
uchar smg_data[] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xff, 0xbf,0xc1,0x86};
uchar key_feq = 0,t_feq = 0,adc_feq = 0; //按键 温度 adc采集刷新频率
uchar interface = 1; //界面
uchar hour = 0,min = 0,sec = 0; //时分秒
uint adc_volt = 0,Temperature = 0; //adc电压 温度
uchar L[4]; //LED控制
//==========================================下面为函数声明=================================================
void Timer2Init(void); //定时器2初始化
void Set_Timer(uchar hour,uchar min,uchar sec); //DS1302时间设置
uchar Read_ADC_Value(uchar addr); //ADC获取
uchar Read_Temperature_Value(void); //读取温度
uchar Read_Key_Value(void); //读取按键值
void Data_Tackle_Task(void); //数据处理
void SMG_Display_Task(void); //数码管显示
void Key_Tackle_Task(void); //按键处理
void Init_System(void); //系统初始化
//==========================================下面为函实现===================================================
void Timer2Init(void) //1毫秒@12.000MHz
{
AUXR |= 0x04; //定时器时钟1T模式
T2L = 0x20; //设置定时初始值
T2H = 0xD1; //设置定时初始值
AUXR |= 0x10; //定时器2开始计时
IE2 |= 0x04;
EA = 1;
}
void Set_Timer(uchar hour,uchar min,uchar sec)
{
Write_Ds1302_Byte(0x8e,0x00); //关闭写保护
Write_Ds1302_Byte(0x80,sec/10*16 + sec%10); //BCD码
Write_Ds1302_Byte(0x82,min/10*16 + min%10); //BCD码
Write_Ds1302_Byte(0x84,hour/10*16 +hour%10);//BCD码
Write_Ds1302_Byte(0x8e,0x80); //打开写保护
}
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;
}
uchar Read_Temperature_Value(void)
{
uchar LSB = 0,MSB = 0;
uint temp = 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);
temp = temp * 0.0625 * 10; //扩大十倍方便显示
return temp;
}
uchar Read_Key_Value(void)
{
static uchar last_trg = 0,cnt = 0;
uchar trg = 0,cur = 0,value = 3;
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;
return value;
}
void Data_Tackle_Task(void)
{
uchar time[3];
if(T2H < 0xd9)
{
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(adc_feq > 150)
{
adc_feq = 1;
adc_volt = Read_ADC_Value(0x03) * (5.0/255) * 100;
}
if(t_feq > 120)
{
t_feq = 1;
Temperature = Read_Temperature_Value();
}
//LED逻辑控制
L[1] = (interface == 1)?(1):(0);
L[2] = (interface == 2)?(1):(0);
L[3] = (interface == 3)?(1):(0);
}
void SMG_Display_Task(void)
{
if(interface == 1)
{
smg_bit[1] = 12; //U
smg_bit[2] = 10;
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 == 2)
{
smg_bit[1] = 13; //E 0110 0001 0x86
smg_bit[2] = 10;
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 == 3)
{
smg_bit[1] = hour/10;
smg_bit[2] = hour%10;
smg_bit[3] = 11;
smg_bit[4] = min/10;
smg_bit[5] = min%10;
smg_bit[6] = 11;
smg_bit[7] = sec/10;
smg_bit[8] = sec%10;
}
}
void Key_Tackle_Task(void)
{
uchar key_value = 0;
if(key_feq > 10)
{
key_feq = 1;
key_value = Read_Key_Value();
}
switch(key_value)
{
case 4:
if(interface == 1)
{
interface = 2;
}
else if(interface == 2)
{
interface = 3;
}
else if(interface == 3)
{
interface = 1;
}
break;
case 5:break;
case 6:break;
case 7:break;
default:break;
}
}
void Init_System(void)
{
Control_Port(0x80,0xff);
Control_Port(0xa0,0x00);
Control_Port(0xc0,0x00);
Timer2Init();
Set_Timer(23,59,50);
}
void main(void)
{
Init_System();
while(1)
{
Data_Tackle_Task();
SMG_Display_Task();
Key_Tackle_Task();
}
}
void Timer2_Server() interrupt 12
{
static uchar dsp_smg = 1;
Control_Port(0x80,~(L[1] << 0 | L[2] << 1| L[3] << 2));
Control_Port(0xc0,0x00);
if(interface == 1 && dsp_smg == 6 || interface == 2 &&dsp_smg == 7)
{
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;
}
key_feq++;
t_feq++;
adc_feq++;
}