2021年第十二届第一场蓝桥杯单片机设计与开发省赛
今年的蓝桥杯第一场单片机与设计,我个人认为要比去年的简单一些。其中有几个功能在今年的模拟赛中就有考察。话不多说上代码
首先主函数
#include "stdio.h"
#include "Timer.h"
#include "onewire.h"
#include "Init.h"//初始化
#include "Key.h"//key
#include "Seg.h"// seg
#include "Led.h"//led
#include "iic.h"
void Key_Proc(void);
void Seg_Proc(void);
void Led_Proc(void);
unsigned long ms_Tick = 0;//定时器与显示用
unsigned int Key_Slow_Down;//按键减速用
unsigned int Seg_Slow_Down;//数码管减速用
unsigned int Led_Slow_Down;//LED灯减速用
unsigned char Key_Value; //按键用
unsigned char Key_Old, Key_Down;
unsigned char seg_string[10];//数码管用
unsigned char seg_buf[8];
unsigned char pos;
unsigned char ucLed;//Led用
unsigned char ucled1,ucled2; //界面与模式的灯
unsigned int ucSec;//配合ms_Tick变量使用的计数变量
unsigned char Runing_Mode=0;//0是温度界面,1是参数界面,2是DAC界面
unsigned char Dac_Mode=0;//0是模式1,1是模式2
unsigned char Wendu_Canshu,Wendu_Canshu_S=25;
float Wendu,Dac_Value;
void main(void)
{
Init_System();//初始化系统关闭LED/继电器/蜂鸣器
Timer1Init();//定时器1初始化
EA = 1;//打开总中断
while(1)
{
Key_Proc();//调用按键函数
Seg_Proc();
Led_Proc();
}
}
初始化程序
void Init_System(void)
{
P0 = 0XFF;
P2 = P2 & 0X1F | 0x80;//关LED
P2 &= 0X1F;
P0 = 0X00;
P2 = P2 & 0X1F | 0xA0;//关闭蜂鸣器和继电器
P2 &= 0X1F;
}
Key_Proc函数
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_Old = Key_Value;//检测电平变化,
switch(Key_Down)//
{
case 4:
Runing_Mode++;
if(Runing_Mode==3)//使界面在温度显示,温度设置界面,DAC输出界面轮转
Runing_Mode=0;
if(Runing_Mode!=1)
Wendu_Canshu=Wendu_Canshu_S;//使设定的温度参数在退出设置界面时才有效
break;//界面切换
case 5:
Dac_Mode^=1; //DAC电压输出模式在模式1到2中切换
break;//模式切换
case 8:
if(Runing_Mode==1)
{
if(Wendu_Canshu_S>0)//温度参数最低为0(个人设置)
Wendu_Canshu_S--;
}
break;//温度参数减
case 9:
if(Runing_Mode==1)
{
if(Wendu_Canshu_S<99)//最高为99(避免多一位数多占个数码管)
Wendu_Canshu_S++;
}
break;//温度参数加
}
}
Seg_Proc函数
void Seg_Proc(void)
{
if(Seg_Slow_Down) return;
Seg_Slow_Down = 1;
Wendu=(rd_temperature()/16.0);
if(Runing_Mode==0)//温度界面
{
sprintf(seg_string,"C %5.2f",Wendu);//显示温度
}
else if(Runing_Mode==1)//温度参数界面
{
sprintf(seg_string,"P %2d",(unsigned int)Wendu_Canshu_S);
}
else if(Runing_Mode==2)//DAC界面
{
sprintf(seg_string,"A %4.2f",Dac_Value);
}
if(Dac_Mode==0)//DAc模式1
{
if(Wendu<Wendu_Canshu)//实际温度小于温度参数输出为0
{
Dac_Value=0;//两种不同DAc模式下的电压输出
}
else
Dac_Value=5;//大于则输出为5V
}
else if(Dac_Mode==1)//DAC 模式2
{
if(Wendu<20)//实际温度在20度下输出为1V
{
Dac_Value=1;
}
else if(Wendu>40)//实际温度大于40度输出为4V
{
Dac_Value=4;
}
else
Dac_Value=(Wendu-20)*0.15+1;
}//实际温度在20到40间一摄氏度等于0.15V,当然要加上小于20度时的1V
Pcf8591_Dac(Dac_Value*51); //按键盘选择的模式DAC输出电压
Seg_Tran(seg_string, seg_buf);
}
Seg程序
#include "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 'C': temp = 0xc6; break;
case 'P': temp = 0x8c; break;
case ' ': temp = 0xff; 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 = 1<<pos;
P2 = P2 & 0X1F | 0xc0;//位码选通
P2 &= 0X1F;
P0 = 0xff;
P2 = P2 & 0X1F | 0xe0;//段码选通,数码管消隐
P2 &= 0X1F;
P0 = seg_buf[pos];
P2 = P2 & 0X1F | 0xe0;//段码选通
P2 &= 0X1F;
}
Led程序
void Led_Disp(unsigned char ucLed)
{
P0 = (~ucLed);
P2 = P2 & 0X1F | 0x80;//打开锁存器
P2 &= 0X1F;
}
Led_Proc函数
void Led_Proc(void)
{
if(Led_Slow_Down) return;
Led_Slow_Down = 1;
if(Dac_Mode==0)//DAC模式1下L1亮(在2021年3月模拟有类似题)
{
ucled1=0x01;
}
else
ucled1=0x00;//在模式2下不亮
if(Runing_Mode==0)//在温度界面下L2亮
{
ucled2=0x02;
}
else if(Runing_Mode==1)//在温度设置参数下L3亮
{
ucled2=0x04;
}
else if(Runing_Mode==2)//在DAC电压显示界面L3亮
{
ucled2=0x08;
}
ucLed=ucled1|ucled2;//将数码管与DAC电压输出模式下的LED结合
}
IIC总线驱动程序
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);
}
//等待应答
bit IIC_WaitAck(void)
{
bit ackbit;
SCL = 1;
IIC_Delay(DELAY_TIME);
ackbit = SDA;
SCL = 0;
IIC_Delay(DELAY_TIME);
return ackbit;
}
//通过I2C总线发送数据
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;
}
void Pcf8591_Dac(unsigned char trans_dat)
{
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(0x41);
IIC_WaitAck();
IIC_SendByte(trans_dat);
IIC_WaitAck();
IIC_Stop();
}
温度转换函数
void Delay_OneWire(unsigned int t) //STC89C52RC
{
t *= 12;//与c52的区别是12倍延时
while(t--);
}
//通过单总线向DS18B20写一个字节
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);
}
//从DS18B20读取一个字节
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;
}
//DS18B20设备初始化
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;
}//以上代码是底层函数,比赛会给
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);//将高八位与低八位结合成为温度
}
定时器函数
void Timer1Init(void) //1毫秒@12.000MHz 定时器1
{
AUXR &= 0xBF; //定时器时钟12T模式
TMOD &= 0x0F; //设置定时器模式
TL1 = 0x18; //设置定时初值
TH1 = 0xFC; //设置定时初值
TF1 = 0; //清除TF1标志
TR1 = 1; //定时器1开始计时
ET1 = 1;
}
接下来附带几张开发板测试图
界面1温度显示界面
界面2温度参数设置界面
界面3DAC电压输出第一模式
界面3DAC电压输出第二模式
好了以上就是我本次参加蓝桥杯的个人代码了,由于本人没有学太深入有很多地方还是有点问题,这也是我第一次写文章,所以恳请路过的大佬多多指点下,先谢谢啦