2021年第十二届第一场蓝桥杯单片机设计与开发省赛


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温度显示模式
界面1温度显示界面

在这里插入图片描述
界面2温度参数设置界面

在这里插入图片描述
界面3DAC电压输出第一模式
在这里插入图片描述
界面3DAC电压输出第二模式

好了以上就是我本次参加蓝桥杯的个人代码了,由于本人没有学太深入有很多地方还是有点问题,这也是我第一次写文章,所以恳请路过的大佬多多指点下,先谢谢啦

在这里插入图片描述

  • 1
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值