蓝桥杯单片机模拟题(深夜学习——单片机)

一、题目:

二、存在BUG的代码:

  1. DS18B20代码:

#ifndef __ONEWIRE_H
#define __ONEWIRE_H

#include "reg52.h"
#define u8 unsigned char
#define u16 unsigned int
    
sbit DQ = P3^7;  

u16 rd_temperature();  
void Convert_T();
#endif
#include "onewire.h"

//
void Delay_OneWire(unsigned int t)  
{
    while(t--);
}

//
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;
}

1void Convert_T()
{
    init_ds18b20();
    Write_DS18B20(0xcc);
    Write_DS18B20(0x44);
}

u16 rd_temperature()
{
    u8 LSB,LMB;
    init_ds18b20();
    Write_DS18B20(0xcc);
    Write_DS18B20(0xbe);
    
    LSB = Read_DS18B20();
    LMB = Read_DS18B20();
    
    return LSB | (LMB<<8);
}
  1. DS1302代码

#ifndef __DS1302_H
#define __DS1302_H

#include <reg52.h>
#include <intrins.h>

sbit SCK = P2^5;        
sbit SDA = P2^6;        
sbit RST = P2^7; 

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
#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);            
}
  1. 主函数:

#include "reg52.h"
#include "stdio.h"
#include "onewire.h"
#include "ds1302.h"      
#define u8 unsigned char
#define u16 unsigned int

#define set_mode 1 //参数设置模式
#define timer_mode 2 //时钟显示模式
#define temper_mode 3 //温度显示模式

sbit L1 = P2^0;
code unsigned char shownum[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00,0x40};
//数码管
u8 COD[8],PSI,COT[10];
u16 seg_delay;
u8 display_re;
//按键
u16 key_delay;
u8 key_now,key_old;
//DS1302
u16 count_500ms = 0;
u8 ds1302_time[3];
//DS18B20
u8 GAT_time=1;
u8 t_num=0,temper[10];
u8 count_1s;
//其他
u8 mode = set_mode;
//LED
u8 l_sign;
void Timer0_Init(void);
void SEG_Proc();    
void SEG_Set();
void Key_Proc();
void DS1302_Init(u8 hour,u8 minute,u8 second);
void main()
{
    Timer0_Init();
    SEG_Set();    
    while(1)
    {
        Key_Proc();
        SEG_Proc();
    }
}

/*********数码管*************/
/*
    将字符串转化成数码管代码
*/
void SEG_TSL(u8 *input,u8 *output)
{
    u8 i=0,j=0;
    for(i=0;i<8;i++,j++)
    {
        switch(input[j])
        {
            case '0': output[i] = shownum[0]; break;
      case '1': output[i] = shownum[1]; break;
      case '2': output[i] = shownum[2]; break;
      case '3': output[i] = shownum[3]; break;
      case '4': output[i] = shownum[4]; break;
      case '5': output[i] = shownum[5]; break;
      case '6': output[i] = shownum[6]; break;
      case '7': output[i] = shownum[7]; break;
      case '8': output[i] = shownum[8]; break;
      case '9': output[i] = shownum[9]; break;
      case '-': output[i] = 0x40; break;
      case ' ': output[i] = 0x00; break;
      default: output[i] = 0x00;
        }
        if(input[j+1] == '.')
        {
            output[i] |= 0x80;
            j++;
        }
    }
}

/*
    数码管显示函数
    P22,P23,P24协助译码器控制位选,其中P22为最低位
*/
void SEG_Show(u8 COD,u8 PSI)
{
    //消影
    P0 = 0x00;
//    //位选
    P2 =     P2 & 0xe3 | (PSI<<2);
    //段选
    P0 = COD;
    
}

/*
    参数设置界面
*/
void SEG_Set()
{
    sprintf(COT,"     -%02u",(u16)GAT_time);
    SEG_TSL(COT,COD);
}
/*
    时钟显示界面
*/
void SEG_Timer1()
{
    u8 TSL_time[3]={0},i=0;
    for(i=0;i<3;i++)
        TSL_time[i] = (ds1302_time[i]>>4)*10+(ds1302_time[i]&0x0f);
    sprintf(COT,"%02u-%02u-%02u",(u16)TSL_time[2],(u16)TSL_time[1],(u16)TSL_time[0]);
    SEG_TSL(COT,COD);
}
void SEG_Timer2()
{
    u8 TSL_time[3]={0},i=0;
    for(i=0;i<3;i++)
        TSL_time[i] = (ds1302_time[i]>>4)*10+(ds1302_time[i]&0x0f);
    sprintf(COT,"%02u %02u %02u",(u16)TSL_time[2],(u16)TSL_time[1],(u16)TSL_time[0]);
    SEG_TSL(COT,COD);
}
/*
    温度显示界面
*/
void SEG_Temper()
{
    sprintf(COT,"-%02u  -%02u",(u16)t_num,(u16)temper[t_num]);
    SEG_TSL(COT,COD);
}

/***************定时器***************************/
void Timer0_Init(void)        //1毫秒@12MHz
{
    TMOD &= 0xF0;            //设置定时器模式
    TMOD |= 0x01;            //设置定时器模式
    TL0 = 0x18;                //设置定时初始值
    TH0 = 0xFC;                //设置定时初始值
    TF0 = 0;                //清除TF0标志
    TR0 = 1;                //定时器0开始计时
    //开启中断
    EA = 1;
    ET0 = 1;
}

void Timer0_IT() interrupt 1
{
    TL0 = 0x18;                //设置定时初始值
    TH0 = 0xFC;                //设置定时初始值
    
    if(seg_delay++ == 500) seg_delay = 0;
    if(key_delay++ == 17)  key_delay = 0;
    
    SEG_Show(COD[PSI],PSI);
    if(PSI++ == 7)PSI = 0;
}

/**********************独立按键******************/
/*
    独立按键按键检测
  K4-K7
*/
u8 D_key()
{
    u8 i=0;
    for(i=0;i<4;i++)
    {
        if((P3 & (0x01<<i)) == 0)
            return i+4;
    }
    return 0;
}

/*********************DS1302**********************/
/*
    初始化DS1302的时间
*/
void DS1302_Init(u8 hour,u8 minute,u8 second)
{
    Write_Ds1302_Byte(0x80,((second/10)<<4) | second%10);
    Write_Ds1302_Byte(0x82,((minute/10)<<4) | minute%10);
    Write_Ds1302_Byte(0x84,((hour/10)<<4) | hour%10);
}

/*
    读取DS1302的时间
*/
void DS1302_Read(u8 *ds_time)
{
    u8 i=0;
    for(i=0;i<3;i++)
    {
        ds_time[i] = Read_Ds1302_Byte(0x81+i*2);
    }
}
/*******************DS18B20******************************/

/*
    读取DS18B20的温度
*/
void Temper_Read()
{
    Convert_T();
    temper[t_num] = rd_temperature()*0.0625;
    t_num++;
}
/************************************************/
/*
    数码管功能
*/
void SEG_Proc()
{
    if(seg_delay)return;
    seg_delay = 1;
    
    if((mode == set_mode) && display_re)
    {
            SEG_Set();
          display_re = 0;
    }
    if(mode == timer_mode )
    { 
        if(count_500ms == 2)
        {
            DS1302_Read(ds1302_time);
      SEG_Timer2();
            Temper_Read();
        }
        if(count_500ms == 4)
        {
            DS1302_Read(ds1302_time);
      SEG_Timer1();
            Temper_Read();
            count_500ms = 0;
        }
        if(t_num == 10)
        {
            mode = temper_mode;
            display_re = 1;
            t_num = 0;
            l_sign = 1;
        }    
        count_500ms++;
    }
    if(mode == temper_mode)
    {
        if(display_re)
        {
            display_re = 0;
            SEG_Temper();
        }
        if(l_sign)
        {
            L1 = !L1;
        }            
    }
}
/*
    按键功能
*/
void Key_Proc()
{
    u8 key_down=0;
    static u8 s_sign=2;
    if(key_delay)return;
    key_delay = 1;
    
    key_now = D_key();
    key_down = key_now & (key_now ^ key_old);
    key_old = key_now;
    if(mode == set_mode)
    {
        if(key_down == 4)
        {
            switch(s_sign)
            {
                case 1:GAT_time = 1;break;
                case 2:GAT_time = 5;break;
                case 3:GAT_time = 30;break;
                case 4:GAT_time = 60;break;
            }
            if(s_sign++ == 4)s_sign = 1;
            display_re = 1;//刷新数码管
        }    
        if(key_down == 5)
        {
            mode = timer_mode;
            DS1302_Init(23,59,50);
            DS1302_Read(ds1302_time);
      SEG_Timer1();
        }
    }
    if(mode == temper_mode)
    {
        if(key_down == 6)
        {
            t_num++;
            display_re = 1;
            if(t_num == 10)t_num = 0;
            l_sign = 0;
        }
        if(key_down == 7)
        {
            mode = set_mode;
            display_re = 1;
        }
    }
}

三、存在的问题:

1.第一个温度显示异常

(1)尝试在一开始做一次读操作,验证是否是第一次读操作的问题——仍然是85,证明不是读操作的问题,应该是读出的数据没有存到数组中

解决问题:DS18B20温度转换需要时间,所以我们要把转化温度和读取温度的操作分开,每一秒都转化温度,选择性读取其中的温度。

四、修改后的主函数:

#include "reg52.h"
#include "stdio.h"
#include "onewire.h"
#include "ds1302.h"      
#define u8 unsigned char
#define u16 unsigned int

#define set_mode 1 //参数设置模式
#define timer_mode 2 //时钟显示模式
#define temper_mode 3 //温度显示模式

sbit L1 = P2^0;
code unsigned char shownum[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00,0x40};
//数码管
u8 COD[8],PSI,COT[10];
u16 seg_delay;
u8 display_re;
//按键
u16 key_delay;
u8 key_now,key_old;
//DS1302
u16 count_500ms = 0;
u8 ds1302_time[3];
//DS18B20
u8 GAT_time=1;
u8 t_num=0,temper[10];
u8 count_1s;
//其他
u8 mode = set_mode;
//LED
u8 l_sign;
void Timer0_Init(void);
void SEG_Proc();    
void SEG_Set();
void Key_Proc();
void DS1302_Init(u8 hour,u8 minute,u8 second);
void main()
{
    Timer0_Init();
    SEG_Set();    
    while(1)
    {
        Key_Proc();
        SEG_Proc();
    }
}

/*********数码管*************/
/*
    将字符串转化成数码管代码
*/
void SEG_TSL(u8 *input,u8 *output)
{
    u8 i=0,j=0;
    for(i=0;i<8;i++,j++)
    {
        switch(input[j])
        {
            case '0': output[i] = shownum[0]; break;
      case '1': output[i] = shownum[1]; break;
      case '2': output[i] = shownum[2]; break;
      case '3': output[i] = shownum[3]; break;
      case '4': output[i] = shownum[4]; break;
      case '5': output[i] = shownum[5]; break;
      case '6': output[i] = shownum[6]; break;
      case '7': output[i] = shownum[7]; break;
      case '8': output[i] = shownum[8]; break;
      case '9': output[i] = shownum[9]; break;
      case '-': output[i] = 0x40; break;
      case ' ': output[i] = 0x00; break;
      default: output[i] = 0x00;
        }
        if(input[j+1] == '.')
        {
            output[i] |= 0x80;
            j++;
        }
    }
}

/*
    数码管显示函数
    P22,P23,P24协助译码器控制位选,其中P22为最低位
*/
void SEG_Show(u8 COD,u8 PSI)
{
    //消影
    P0 = 0x00;
//    //位选
    P2 =     P2 & 0xe3 | (PSI<<2);
    //段选
    P0 = COD;
    
}

/*
    参数设置界面
*/
void SEG_Set()
{
    sprintf(COT,"     -%02u",(u16)GAT_time);
    SEG_TSL(COT,COD);
}
/*
    时钟显示界面
*/
void SEG_Timer1()
{
    u8 TSL_time[3]={0},i=0;
    for(i=0;i<3;i++)
        TSL_time[i] = (ds1302_time[i]>>4)*10+(ds1302_time[i]&0x0f);
    sprintf(COT,"%02u-%02u-%02u",(u16)TSL_time[2],(u16)TSL_time[1],(u16)TSL_time[0]);
    SEG_TSL(COT,COD);
}
void SEG_Timer2()
{
    u8 TSL_time[3]={0},i=0;
    for(i=0;i<3;i++)
        TSL_time[i] = (ds1302_time[i]>>4)*10+(ds1302_time[i]&0x0f);
    sprintf(COT,"%02u %02u %02u",(u16)TSL_time[2],(u16)TSL_time[1],(u16)TSL_time[0]);
    SEG_TSL(COT,COD);
}
/*
    温度显示界面
*/
void SEG_Temper()
{
    sprintf(COT,"-%02u  -%02u",(u16)t_num,(u16)temper[t_num]);
    SEG_TSL(COT,COD);
}

/***************定时器***************************/
void Timer0_Init(void)        //1毫秒@12MHz
{
    TMOD &= 0xF0;            //设置定时器模式
    TMOD |= 0x01;            //设置定时器模式
    TL0 = 0x18;                //设置定时初始值
    TH0 = 0xFC;                //设置定时初始值
    TF0 = 0;                //清除TF0标志
    TR0 = 1;                //定时器0开始计时
    //开启中断
    EA = 1;
    ET0 = 1;
}

void Timer0_IT() interrupt 1
{
    TL0 = 0x18;                //设置定时初始值
    TH0 = 0xFC;                //设置定时初始值
    
    if(seg_delay++ == 500) seg_delay = 0;
    if(key_delay++ == 17)  key_delay = 0;
    
    SEG_Show(COD[PSI],PSI);
    if(PSI++ == 7)PSI = 0;
}

/**********************独立按键******************/
/*
    独立按键按键检测
  K4-K7
*/
u8 D_key()
{
    u8 i=0;
    for(i=0;i<4;i++)
    {
        if((P3 & (0x01<<i)) == 0)
            return i+4;
    }
    return 0;
}

/*********************DS1302**********************/
/*
    初始化DS1302的时间
*/
void DS1302_Init(u8 hour,u8 minute,u8 second)
{
    Write_Ds1302_Byte(0x80,((second/10)<<4) | second%10);
    Write_Ds1302_Byte(0x82,((minute/10)<<4) | minute%10);
    Write_Ds1302_Byte(0x84,((hour/10)<<4) | hour%10);
}

/*
    读取DS1302的时间
*/
void DS1302_Read(u8 *ds_time)
{
    u8 i=0;
    for(i=0;i<3;i++)
    {
        ds_time[i] = Read_Ds1302_Byte(0x81+i*2);
    }
}
/*******************DS18B20******************************/
/*
    读取DS18B20的温度
*/
void Temper_Read()
{
    temper[t_num] = rd_temperature()*0.0625;
    t_num++;
}
/************************************************/
/*
    数码管功能
*/
void SEG_Proc()
{
    if(seg_delay)return;
    seg_delay = 1;
    
    if((mode == set_mode) && display_re)
    {
            SEG_Set();
          display_re = 0;
    }
    if(mode == timer_mode )
    { 
        if(count_500ms == 2)
        {
            DS1302_Read(ds1302_time);
      SEG_Timer2();
            count_1s++;
            Convert_T();
        }
        if(count_500ms == 4)
        {
            DS1302_Read(ds1302_time);
      SEG_Timer1();
            count_1s++;
            count_500ms = 0;
            Convert_T();
        }
        if(count_1s == GAT_time)
        {
            count_1s = 0;
            Temper_Read();
        }
        if(t_num == 10)
        {
            mode = temper_mode;
            display_re = 1;
            t_num = 0;
            l_sign = 1;
        }    
        count_500ms++;
    }
    if(mode == temper_mode)
    {
        if(display_re)
        {
            display_re = 0;
            SEG_Temper();
        }
        if(l_sign)
        {
            L1 = !L1;
        }            
    }
}
/*
    按键功能
*/
void Key_Proc()
{
    u8 key_down=0;
    static u8 s_sign=2;
    if(key_delay)return;
    key_delay = 1;
    
    key_now = D_key();
    key_down = key_now & (key_now ^ key_old);
    key_old = key_now;
    if(mode == set_mode)
    {
        if(key_down == 4)
        {
            switch(s_sign)
            {
                case 1:GAT_time = 1;break;
                case 2:GAT_time = 5;break;
                case 3:GAT_time = 30;break;
                case 4:GAT_time = 60;break;
            }
            if(s_sign++ == 4)s_sign = 1;
            display_re = 1;//刷新数码管
        }    
        if(key_down == 5)
        {
            mode = timer_mode;
            DS1302_Init(23,59,50);
            DS1302_Read(ds1302_time);
      SEG_Timer1();
            Convert_T();
        }
    }
    if(mode == temper_mode)
    {
        if(key_down == 6)
        {
            t_num++;
            display_re = 1;
            if(t_num == 10)t_num = 0;
            l_sign = 0;
        }
        if(key_down == 7)
        {
            mode = set_mode;
            display_re = 1;
        }
    }
}

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第十三届蓝桥杯单片机模拟是一个使用单片机来实现一定功能的目。具体要求如下: 目要求使用单片机控制一个LED灯,根据输入的数字进行闪烁的频率控制。在开始时,需要通过按键输入一个0-9之间的数字,该数字代表了闪烁的频率,数字越大表示闪烁的频率越快。然后,用一个LED灯来表示这个输入的数字。 解决这个目的思路如下: 首先,我们需要配置单片机的IO口,将一个IO口连接到LED灯上,用于控制LED的亮灭。 然后,我们需要添加中断功能,使得按键输入可以被响应。当按键被按下时,会触发一个外部中断,进入中断服务函数。 在中断服务函数中,我们可以通过读取按键的状态得到输入的数字,并将该数字储存起来。 接下来,我们使用定时器来控制LED灯的闪烁频率。我们设置一个定时器,周期性地执行一个中断服务函数。在这个中断服务函数中,我们可以控制LED灯的亮灭状态。利用先前输入的数字,可以确定LED灯的闪烁频率。 最后,我们需要在主函数中进行一些初始化操作,如配置IO口、中断和定时器,并进入一个无限循环中。在循环中,程序将一直等待按键输入,并根据输入的数字进行相关操作。 总结起来,第十三届蓝桥杯单片机模拟通过按键输入一个数字来控制LED灯的闪烁频率。通过配置IO口、中断和定时器,我们可以实现这个功能。这道目考察了对单片机的基本操作和中断定时器的使用,是一个综合性较强的目。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值