蓝桥杯 第七届省赛题 DS18B20问题

存在问题:在问题代码中改了一下DS18B20的时序就可以了,但是在测试代码,两种时序都能实现

img


一、问题代码:
1、DS18B29驱动代码(由于比赛中会提供驱动代码,所以驱动代码都是相同的)

#ifndef __ONEWIRE_H
#define __ONEWIRE_H

#include 
#define u8 unsigned char
#define u16 unsigned int
    
sbit DQ = P1^4;  

float Read_Scratchpad(); 
void Convert_T();
u16 TEMP_Proc();
void Delay_OneWire(unsigned int t) ;
#endif

#include "onewire.h"

//单总线内部延时函数
void Delay_OneWire(unsigned int t) 
{
    unsigned char i=8;
    while(t--){
//        for(i=0;i<8;i++);
        while(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;
}

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

2、主函数


#include 
#include 
#include 
#include "onewire.h"
#define u8 unsigned char
#define u16 unsigned int
code unsigned char Seg_Table[] = 
{
0xc0, //0
0xf9, //1
0xa4, //2
0xb0, //3
0x99, //4
0x92, //5
0x82, //6
0xf8, //7
0x80, //8
0x90, //9
0x88, //A
0x83, //b
0xc6, //C
0xa1, //d
0x86, //E
0x8e //F
};
//数码管
u8 COD[8],COT[9],PSI;
u8 seg_mode=1;
//定时器
u16 ms_count,seg_delay,s_count,temper_r_delay=991;
u8 key_delay,temper_c_delay=25;
//
u8 PWM_mode;
u16 show_time;
u8 set_time;
float show_temper;
void All_Close();
void Timer0_Init(void);
void SEG_Rroc();
void Key_Proc();
void Led_Lx(u8 Lx);
void Temper_Conert_Proc();
void Temper_Read_Proc();
void main()
{
    All_Close();
    Timer0_Init();
//    Convert_T();
    while(1)
    {
        SEG_Rroc();
        Key_Proc();
        Temper_Conert_Proc();
        Temper_Read_Proc();
    }
}
void Delay1000ms()        //@12MHz
{
    unsigned char i, j, k;

    _nop_();
    _nop_();
    i = 46;
    j = 153;
    k = 245;
    do
    {
        do
        {
            while (--k);
        } while (--j);
    } while (--i);
}
    
    
/*******************************/
/*
        关闭无关设备
*/
void All_Close()
{
    //关闭蜂鸣器和继电器
    P0 = 0x00;
    P2 = P2 & 0x1f | (0x50<<1);
    P2 &= 0x1f;
    //关闭LED
    P0 = 0xff;
    P2 = P2 & 0x1f | (0x40<<1);
    P2 &= 0x1f;
}

/*************LED**************/
/*
    根据传入的数据显示LED灯
*/
void Led_Show(u8 l_data)
{
    ET0 = 0;
    P0 = l_data;
    P2 = P2 & 0x1f | (0x40<<1);
    P2 &= 0x1f;
    ET0 = 1;
}
/*
    显示某个LED灯
*/
void Led_Lx(u8 Lx)
{
    ET0 = 0;
    P0 = ~(0x01<<(Lx-1));
    P2 = P2 & 0x1f | (0x40<<1);
    P2 &= 0x1f;
    ET0 = 1;
}
/************数码管***********/
void SEG_TSL(u8* input,u8* output)
{
    u8 i;
    for(i=0;i<8;i++)
    {
        switch(input[i])
        {
            case '0':output[i] = Seg_Table[0];break;
            case '1':output[i] = Seg_Table[1];break;
            case '2':output[i] = Seg_Table[2];break;
            case '3':output[i] = Seg_Table[3];break;
            case '4':output[i] = Seg_Table[4];break;
            case '5':output[i] = Seg_Table[5];break;
            case '6':output[i] = Seg_Table[6];break;
            case '7':output[i] = Seg_Table[7];break;
            case '8':output[i] = Seg_Table[8];break;
            case '9':output[i] = Seg_Table[9];break;
            case 'C':output[i] = Seg_Table[12];break;
            case '-':output[i] = ~0x40;break;
            default:output[i] = 0xff;
        }
    }
}
void SEG_Show(u8 COD,u8 PSI)
{
    //消隐
    P0 = 0xff;
    P2 = P2 & 0x1f | (0x70<<1);
    P2 &= 0x1f;
    //位选
    P0 = 0x01<0x1f | (0x60<<1);
    P2 &= 0x1f;    
    //段选
    P0 = COD;
    P2 = P2 & 0x1f | (0x70<<1);
    P2 &= 0x1f;        
}

/*************定时器***************/
void Timer0_Isr(void) interrupt 1
{
    ms_count++;
    if(ms_count == seg_delay)seg_delay = 0;
    if(ms_count % 10 == 0)key_delay = 0;
    if(ms_count == temper_c_delay)temper_c_delay = 0;
    if(ms_count == temper_r_delay)temper_r_delay = 0;
    if(ms_count == 1000)
    {
        ms_count = 0;
        if(show_time-- == 0)show_time = 0;
    }
    
    SEG_Show(COD[PSI],PSI);
    if(PSI++ == 7)PSI = 0;
}

void Timer0_Init(void)        //1毫秒@12MHz
{
    AUXR &= 0x7F;            //定时器时钟12T模式
    TMOD &= 0xF0;            //设置定时器模式
    TL0 = 0x18;                //设置定时初始值
    TH0 = 0xFC;                //设置定时初始值
    TF0 = 0;                //清除TF0标志
    TR0 = 1;                //定时器0开始计时
    ET0 = 1;                //使能定时器0中断
    EA  = 1;
}
/**************按键*******************/
/*
    按键检测
*/
u8 D_Key()
{
    u8 i;
    for(i=0;i<4;i++)
    {
        if((P3 & (0x08>>i)) == 0)
            return i+4;
    }
    return 0;
}
u8 Key_read()
{
    u8 i;
    for(i=0;i<4;i++)
    {
            if(!(P3 & (0x01<return 7-i;
            }
    }
    return 0;
}
/*************************************/

void SEG_Rroc()
{
    if(seg_delay)return;
    seg_delay = 999;
    if(seg_mode == 1)
        sprintf(COT,"-%1u- %04u",(u16)1,(u16)show_time);
    if(seg_mode == 2)
    {
        sprintf(COT,"-%1u-  %2.0fC",(u16)4,show_temper);
    }
    if(show_time == 0)
    {
        PWM_mode = 0;
    }
    SEG_TSL(COT,COD);
}

void Key_Proc()
{
    static key_old;
    u8 key_now,key_down;
    if(key_delay)return;    
    key_delay = 1;
    
    key_now = D_Key();
    key_down = key_now & (key_now ^ key_old);
    key_old = key_now;
    if(key_down == 4)
    {
        if(PWM_mode++ == 4)PWM_mode = 1;
        Led_Lx(PWM_mode);
    }
    if(key_down == 5)
    {
        
        if(++set_time == 3)set_time = 0;
        show_time = set_time*60;
        if(PWM_mode == 0)
        {
            PWM_mode = 1;
            Led_Lx(PWM_mode);
        }
    }
    if(key_down == 6)
    {
        show_time = 0;
        PWM_mode = 0;
        set_time = 0;
        Led_Show(0xff);
    }
    if(key_down == 7)
    {
        if(++seg_mode == 3)seg_mode = 1;
    }
}
void Temper_Conert_Proc()
{
    if(temper_c_delay)return;
    temper_c_delay = 25;
    

    Convert_T();

}
void Temper_Read_Proc()
{
    if(temper_r_delay)return;
    temper_r_delay = 991;
    

    show_temper = Read_Scratchpad(); 

}

二、测试代码:
1、

#ifndef _PUBLIC_H
#define _PUBLIC_H

#include "STC15F2K60S2.H" 

#define u8 unsigned char
#define u16 unsigned int

void Delay_1ms(u16 num);
void Close_All(void);
void Delay_10us(u16 num);
#endif

#include "Public.h"
// 延时函数(最小约1ms@12MHz)
void Delay_1ms(u16 num)
{
  unsigned int i=8;
  while(num--)
    {
//        while(i--);
          for(i=0; i<8; i++);
    }

}


/*
    输入变量:无
    输出变量:无
    功能:关闭蜂鸣器和继电器
*/
void Close_All(void)
{
    //关闭蜂鸣器和继电器
    P0 = 0x00;
    P2 = (P2 & 0x1f) | 0xA0;
    P2 &= 0x1f;
    //关闭LED灯
    P0 = 0xff;
    P2 = (P2 & 0x1F) | 0x80;
    P2 &= 0x1f;    
}

void Delay_10us(u16 num)
{
  u16 i;
  while(num--)
    for(i=0; i<5; i++);
}

2、主函数:

// 使用程序前,将J13调整为IO模式(2-3脚短接)
#include "Public.h"
#include "stdio.h"
#include "onewire.h"
u8 SEG_COT[9];
u8 SEG_Code[8];
u8 SEF_POS = 0;
u16 SEG_delay;
void SEG_TSL(u8 *input,u8 *output);
void SEG_Show(u8 num,u16 PIS);
void Timer_0_Init(u16 time);
void SEG_Proc();

// 主函数
void main(void)
{

    Close_All();    
    Timer_0_Init(1000);
  while(1)
  { 
        SEG_Proc();
  }
}
u16 TEMP_Proc();
void SEG_Proc()
{
    float temper;
    u16 t_temp;
    if(SEG_delay)return;
    SEG_delay = 1;
    t_temp = TEMP_Proc();
    if(!(t_temp & 0xf800))//符号位为0
    {
        temper = t_temp*0.0625;
        sprintf(SEG_COT, "    %2.2f", temper);
    }
    else if(t_temp | 0x07ff)//符号位为1
    {
        temper = ((~t_temp)+1)*0.0625;
        sprintf(SEG_COT, "-%04.2f", temper);
    }
    SEG_TSL(SEG_COT,SEG_Code);
}
u16 TEMP_Proc()
{
    u8 LSB,MSB;
    init_ds18b20();
    Write_DS18B20(0xcc);
    Write_DS18B20(0x44);
    
    init_ds18b20();
    Write_DS18B20(0xcc);
    Write_DS18B20(0xbe);
    LSB = Read_DS18B20();
    MSB = Read_DS18B20();
    init_ds18b20();    
    
    return LSB | (MSB<<8);
}
/***************************数码管*****************************/
/*
  输入变量:input,输入字符数组;output:输出16进制数数组
    输出变量:无
    功能:将字符串转化为对应数码管显示的16进制数
    注意:记得定义数组——u8 SEG_COT[9];u8 SEG_Code[8];
*/
void SEG_TSL(u8 *input,u8 *output)
{
    u8 i=0,temp=0,j=0;
    for(i=0;i<8;i++,j++)
    {
        switch(input[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 'B': temp = 0x83; break;
      case 'C': temp = 0xc6; break;
      case 'D': temp = 0xA1; break;
      case 'E': temp = 0x86; break;
      case 'F': temp = 0x8E; break;
      case 'H': temp = 0x89; break;
      case 'L': temp = 0xC7; break;
      case 'N': temp = 0xC8; break;
      case 'P': temp = 0x8c; break;
      case 'U': temp = 0xC1; break;
      case '-': temp = 0xbf; break;
      case ' ': temp = 0xff; break;
      default: temp = 0xff;
        }
        if(input[j+1] == '.')
        {
            temp &= 0x7f;
            j++;
        }
        output[i] = temp;
    }
}

/*
    输入变量:num,要显示数据;PIS,显示位置,从左到右分别为0-7
    输出变量:无
    功能:操作138译码器,4-7分别对应Y4-Y7,其余都会使译码器不起作用
    注意:需要把存放从1-f对应的16进制数数组也移植
*/
void SEG_Show(u8 num,u16 PIS)
{
        //消影
      P0 = 0xff;
        P2 = (P2 & 0x1f) | 0xE0;
    P2 &= 0x1f;
        //改变显示位置
      P0 = 0x01<0x1f) | 0xC0;
      P2 &= 0x1f;
        //改变数据
      P0 = num;
        P2 = (P2 & 0x1f) | 0xE0;
    P2 &= 0x1f;
}

/***************************定时器*****************************/
/*
    输入变量:定时时长___us
    输出变量:无
    功能:配置并开启定时器0
*/
void Timer_0_Init(u16 time)
{
    //12T模式
    AUXR &= 0x7f;
    //定时器0 模式0
    TMOD &= 0xf0;
    //设置初值
    TH0 = (65536-time)/256;
    TL0 = (65536-time)%256;
    //打开中断
    ET0 = 1;
    EA = 1;
    //开始计数
    TR0 = 1;
}

void Timer_0_IT(void) interrupt 1
{
    if(SEG_delay++ == 500)SEG_delay = 0;//0.5s
    
    SEG_Show(SEG_Code[SEF_POS],SEF_POS);
    if(++SEF_POS == 8 )SEF_POS = 0;
}

3、DS18B29驱动代码:


#ifndef __ONEWIRE_H
#define __ONEWIRE_H

#include "Public.h"

sbit DQ = P1^4;  
void Write_DS18B20(unsigned char dat);
unsigned char Read_DS18B20(void);
bit init_ds18b20(void);
#endif


#include "onewire.h"

//
void Delay_OneWire(unsigned int t) 
{
    unsigned char i=8;
    while(t--){
        for(i=0;i<8;i++);
//        while(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;
}
/*********************/
/*
        转换温度
*/
void Convert_T()
{
    //初始化
    EA = 0;
    init_ds18b20();
    EA = 1;
    EA = 0;
    //跳过ROM命令
    Write_DS18B20(0xcc);
    EA = 1;
    EA = 0;
  //功能命令,转换温度
    Write_DS18B20(0x44);
    EA = 1;
}

/*
    读取温度
*/
float Read_Scratchpad()
{
    u8 LSB,MSB;
    //初始化
    EA = 0;
    init_ds18b20();
    EA = 1;
    //跳过ROM命令
    EA = 0;
    Write_DS18B20(0xcc);
    EA = 1;
  //功能命令,读取温度
    EA = 0;
    Write_DS18B20(0xbe);
    EA = 1;
    EA = 0;
    LSB = Read_DS18B20();
    EA = 1;
    EA = 0;
    MSB = Read_DS18B20();
    EA = 1;
    return ((MSB<<8) | LSB)/16.0;
}

u16 TEMP_Proc()
{
    u8 LSB,MSB;
    init_ds18b20();
    Write_DS18B20(0xcc);
    Write_DS18B20(0x44);
    
    init_ds18b20();
    Write_DS18B20(0xcc);
    Write_DS18B20(0xbe);
    LSB = Read_DS18B20();
    MSB = Read_DS18B20();
    init_ds18b20();    
    
    return LSB | (MSB<<8);
}