2022年蓝桥杯单片机省赛(第十三届第一场)真题解析

2022年单片机省赛

  • 有关题目
  • 实现代码
  • main.c
  • onewire.h
  • onewire.c
  • ds1302.h
  • ds1302.c
  • 有关题目







    实现代码

    注意:
    数据处理方面:由于ds1302芯片存储的数据是BCD码,所以我们要进行BCD码与十进制之间的转换,例如0x16 的BCD码为16,十进制为1 * 16 + 6 = 32。
    源文件修改方面:官方给onewire.h,ds1302.h中使用的时C51的头件"reg52.h",我们需修改为对应的15系列头文件"STC15F2K60S2.h",这样才可以使用一些特殊位寄存器。

    底层代码:需修改驱动代码onewire.c中单总线延时函数,官方给我们是STC89C52RC系列,15系列的单片机速度比51快8~12倍,需要修改对应的延时函数。修改如下
    void Delay_OneWire(unsigned int t)
    {
    char i;
    while(t–)
    for (i = 0; i < 12; i++);
    }

    main.c

    #include "STC15F2K60S2.h"
    #include "onewire.h"
    #include "ds1302.h"
    
    #define uchar unsigned char
    #define uint unsigned int
    
    sbit L1 = P0^0;
    sbit L2 = P0^1;
    sbit L3 = P0^2;
    
    uchar jm = 0;//界面初始化温度界面
    code uchar tab[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff, 0xc1, 0xbf}; 
    //U -  11 12
    
    uchar init_time[3] = {0x40, 0x59, 0x23};//初始化时间秒 分 时
    uchar time[3] = { 0 };//秒 分 时
    
    bit mod_flag;//0为温度控制模式
    bit rel_flag;//继电器是否闭合标志,为0未闭合
    bit flag_5s;
    bit led10_flag;//初始化0为led10熄灭
    bit L1_flag;//初始化0为L1熄灭
    bit L3_flag;//初始化0为L3熄灭
    
    float curr_temp;
    uchar para_temp = 23;
    
    void sys_init();
    void key_handle();
    float rd_temperature();
    void rd_time();
    void rel_handle();
    void led();
    
    void dsp_smg_bit(uchar pos, val);
    void display();//显示功能,分四个大块
    void dsp_temp();
    void dsp_time();
    void dsp_para();
    void dsp_min_sec();//长按S17显示分秒
    
    void delay_k(uchar t);//延时t * 10us
    void Delay1ms();		//1ms@12.000MHz,延时1ms用于给足数码管足够显示时间
    
    void main()
    {
    	sys_init();
    	while(1)
    	{
    		curr_temp = rd_temperature();
    		rd_time();//实时读取时间
    		key_handle();
    		display();	
    		rel_handle();//继电器处理
    		led();
    	}
    }
    
    void led()
    {	
    	if (time[0] == 0x00 && time[1] == 0x00)
    	{
    		L1_flag = 1;
    	}					   
    	if (L1_flag)
    	{
    		P2 = (P2 & 0x1f) | 0x80;
    		L1 = 0;
    	}
    	else 
    	{
    		P2 = (P2 & 0x1f) | 0x80;
    		L1 = 1;
    	}
    	
    	if (!mod_flag)
    	{
    		P2 = (P2 & 0x1f) | 0x80;
    		L2 = 0;
    	}
    	else 
    	{
    	 	P2 = (P2 & 0x1f) | 0x80;
    		L2 = 1;
    	}
    	
    	if (led10_flag)
    	{
    		//继电器吸附,间隔0.1sL3闪烁
    		if (L3_flag)
    		{
    			P2 = (P2 & 0x1f) | 0x80;
    			L3 = 0;
    		}
    		else 
    			L3 = 1;
    	}
    
    	P0 |= 0xf8;//将L4~L8熄灭
    	P2 &= 0x1f;
    }
    
    void rel_handle()
    {
    	uint t = (uchar)(curr_temp * 10);
    	if (!mod_flag)
    	{
    		if (t > para_temp * 10)
    		{
    			led10_flag = 1;
    			P2 = (P2 & 0x1f) | 0xa0;
    			P0=0X10;
    		}
    		else 
    		{	
    			led10_flag = 0;
    			P2 = (P2 & 0x1f) | 0xa0;
    			P0 = 0xaf;
    		}	
    	}
    	else if (mod_flag)
    	{
    		if (time[0] == 0x00 && time[1] == 0x00)
    		{
    			rel_flag = 1;//整点,继电器吸附标志
    		}
    		if (rel_flag)
    		{
    			P2 = (P2 & 0x1f) | 0xa0;
    			P0 = 0x10;
    			led10_flag = 1;
    		}
    		else 
    		{
    			P2 = (P2 & 0x1f) | 0xa0;
    			P0 = 0xaf;
    			led10_flag = 0;
    		}
    	}
    	//P0 |= 0x00;
    	//P2 &= 0x1f;
    }
    
    
    void rd_time()
    {
    	uchar t;
    	
    	t = Read_Ds1302_Byte(0x81);//秒
    	time[0] = t / 16 * 10 + t % 16 ;
    	
    	t = Read_Ds1302_Byte(0x83);//分
    	time[1] = t / 16 * 10 + t % 16 ;
    	
    	t = Read_Ds1302_Byte(0x85);//时
    	time[2] = t / 16 * 10 + t % 16 ;
    }
    
    void display()
    {
    	if (0 == jm)
    		dsp_temp();
    	else if (1 == jm)
    		dsp_time();
    	else if (2 == jm)
    		dsp_para();
    }
    void dsp_min_sec()
    {
    	dsp_smg_bit(1, 11);//U
    	dsp_smg_bit(2, 2);//
    	
    	dsp_smg_bit(4, time[1] / 10);
    	dsp_smg_bit(5, time[1] % 10);
    	dsp_smg_bit(6, 12);//-
    	dsp_smg_bit(7, time[0] / 10);
    	dsp_smg_bit(8, time[0] % 10);
    
    }
    void dsp_para()
    {
    	dsp_smg_bit(1, 11);//U
    	dsp_smg_bit(2, 3);//
    	
    	dsp_smg_bit(7, para_temp / 10 % 10);
    	dsp_smg_bit(8, para_temp % 10);
    }
    
    void dsp_time()
    {
    	dsp_smg_bit(1, 11);//U
    	dsp_smg_bit(2, 2);//
    	
    	dsp_smg_bit(4, time[2] / 10);
    	dsp_smg_bit(5, time[2] % 10);
    	dsp_smg_bit(6, 12);//-
    	dsp_smg_bit(7, time[1] / 10);
    	dsp_smg_bit(8, time[1] % 10);
    }
    
    void dsp_temp()
    {
    	uint x = (uint)(curr_temp * 10);//当前温度扩大10倍
    	dsp_smg_bit(1, 11);//U
    	dsp_smg_bit(2, 1);//
    	dsp_smg_bit(6, x / 100 % 10);
    	
    	//第7位数码管显示小数点
    	P2 = (P2 & 0x1f) | 0xc0;
    	P0 = 1 << (7 - 1);
    	
    	P2 = (P2 & 0x1f) | 0xe0;
    	P0 = tab[x / 10 % 10] & 0x7f;
    	Delay1ms();
    	
    	P0 = 0xff;
    	P2 &= 0x1f;
    	
    	dsp_smg_bit(8, x % 10);
    }
    
    void dsp_smg_bit(uchar pos, val)
    {
    	P2 = (P2 & 0x1f) | 0xc0;
    	P0 = 1 << (pos - 1);
    	
    	P2 = (P2 & 0x1f) | 0xe0;
    	P0 = tab[val];
    	Delay1ms();
    	
    	P0 = 0xff;
    	P2 &= 0x1f;
    }
    
    void Delay1ms()		//@12.000MHz
    {
    	unsigned char i, j;
    
    	i = 12;
    	j = 169;
    	do
    	{
    		while (--j);
    	} while (--i);
    }
    
    void delay_k(uchar t)
    {
    	while(t--)
    		display();
    }
    
     void key_handle()
    {
    	P35 = P34 = P32 = 1;
    	P33 = 0;//第四行拉低
    	if(!P35)//s12
    	{
    		delay_k(10);
    		if(!P35)
    		{
    			
    			if (++jm >= 3)
    			jm = 0;
    			while(!P35)
    			{
    				display();
    			}
    		}
    	}
    	
    	if(!P34)//s16
    	{
    		delay_k(10);
    		if(!P34)
    		{
    			if (2 == jm)
    			{	
    				if (++para_temp > 99)
    					para_temp = 99;
    			}
    				while(!P34)
    			{
    				display();
    			}
    		}
    	}
    	
    	P35 = P34 = P33 = 1;
    	P32 = 0;//第三行拉低
    	if(!P35)//s13
    	{
    		delay_k(10);
    		if(!P35)
    		{	
    			mod_flag = !mod_flag;
    			while(!P35)
    			{
    				display();
    			}
    		}
    	}
    	
    	if(!P34)//s17
    	{
    		delay_k(10);
    		if(!P34)
    		{
    			if (2 == jm)
    			{
    				if (--para_temp < 10)//参数操作 + 参数检查
    					para_temp = 10;
    			}
    			if (1 == jm)
    			{
    				while(!P34)//s17的长按键操作
    				{
    					rd_time();
    					dsp_min_sec();
    				}
    			}
    			while(!P34)
    			{
    				display();
    			}		
    		}
    	}
    }
    
    float rd_temperature()
    {
    	uchar l, h;
    	uint t;
    	float temp;
    	init_ds18b20();
    	Write_DS18B20(0xcc);
    	Write_DS18B20(0x44);
    	
    	init_ds18b20();
    	Write_DS18B20(0xcc);
    	Write_DS18B20(0xbe);
    	
    	l = Read_DS18B20();
    	h = Read_DS18B20();
    	
    	t = (h & 0x0f);
    	t <<= 8;
    	t |= l;
    	temp = t * 0.0625;
    	
    	return temp;
    }
    
    void timer0() interrupt 1
    {
    	static uint i1, i2, i3;
    	if (rel_flag)//继电器闭合5秒断开标志
    	{
    		if (++i1 == 5000)
    		{
    			i1 = 0;
    			rel_flag = 0;
    		}
    	}
    	if (L1_flag)
    	{
    		if (++i2 == 5000)
    		{
    			i2 = 0;
    			L1_flag = 0;
    		}
    	}
    	if (++i3 == 100)//0.1s切换一次L3的状态,使其闪烁
    	{
    		L3_flag = !L3_flag;
    		i3 = 0;
    	}
    }
    
    
    void sys_init()
    {
    	//关蜂鸣器,继电器
    	P2 = (P2 & 0x1f) | 0xa0;
    	P0 = 0xaf;
    	
    	P2 = (P2 & 0x1f) | 0x80;
    	P0 = 0xff;
    	P2 &= 0x1f;
    
    	Write_Ds1302_Byte(0x8e,0x00);//关闭写保护
    	Write_Ds1302_Byte(0x80, init_time[0]);//秒
    	Write_Ds1302_Byte(0x82, init_time[1]);//分
    	Write_Ds1302_Byte(0x84, init_time[2]);//时
    	Write_Ds1302_Byte(0x8e,0x80);//开启写保护
    	
    	//1ms
    	AUXR &= 0x7F;		//定时器时钟12T模式
    	TMOD &= 0xF0;		//设置定时器模式
    	TL0 = 0x18;		//设置定时初值
    	TH0 = 0xFC;		//设置定时初值
    	TF0 = 0;		//清除TF0标志
    	TR0 = 1;		//定时器0开始计时
    	
    	ET0 = 1;
    	ET1 = 0;//禁止定时器中断1中断
    	EA = 1;
    }
    

    onewire.h

    #ifndef __ONEWIRE_H
    #define __ONEWIRE_H
    
    #include <STC15F2K60S2.H>
    
    bit init_ds18b20(void);
    unsigned char Read_DS18B20(void);
    void Write_DS18B20(unsigned char dat);
    void Delay_OneWire(unsigned int t);  
    
    #endif
    
    
    

    onewire.c

    /*
      程序说明: 单总线驱动程序
      软件环境: Keil uVision 4.10 
      硬件环境: CT107单片机综合实训平台(外部晶振12MHz) STC89C52RC单片机
      日    期: 2011-8-9
    */
    #include "onewire.h"
    
    sbit DQ = P1^4;  //单总线接口
    
    //单总线延时函数
    void Delay_OneWire(unsigned int t)  //STC89C52RC
    {
    	char i;
    	while(t--)
    		for (i = 0; i < 12; i++);
    }
    
    //通过单总线向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;
    }
    
    
    

    ds1302.h

    #ifndef __DS1302_H
    #define __DS1302_H
    
    #include "STC15F2K60S2.h"
    #include <intrins.h>
    
    sbit SCK = P1^7;		
    sbit SDA = P2^3;		
    sbit RST = P1^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
    
    

    ds1302.c

    #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;
    	}
    }   
    
    //向DS1302寄存器写入数据
    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; 
    }
    
    //从DS1302寄存器读出数据
    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);			
    }
    
    
    物联沃分享整理
    物联沃-IOTWORD物联网 » 2022年蓝桥杯单片机省赛(第十三届第一场)真题解析

    发表评论