蓝桥杯模块学习13——DS18B20(深夜学习——单片机)

一、硬件电路:

  1. DS18B20内部电路:

(客观题可能会考,但是编程时由于我们直接输入命令让模块自己工作,所以我们并不需要了解该电路)

我们需要了解的是三部分:64位ROM、暂存器、EEPROM存储器

(1)64位ROM:存放地址码,其中包括了8位CRC校验码(由CRC发生器产生)+48位序列号(每个产品不同)+8位系列码(DS18B20都为0x28)

(2)暂存器:

(3)EEPROM存储器:包括TH、TL寄存器和配置寄存器CR

TH,TL:规定最高温度和最低温度

CR:规定了分辨率与最大转换时间

  1. 蓝桥杯板子上的电路

该电路可以分为两部分,一部分为1,3脚的供电部分;一部分为2接上拉电阻以满足漏极开路门输入输出

二、命令:

  1. ROM命令:

(由于板子上只有一个DS18B20,所以只需要记住0xCC跳过ROM操作就行)

2.功能命令:(重要)

三、具体操作步骤:(每发一个命令都要按照这个步骤,而不能连续发功能命令)

复位——》ROM命令——》功能命令

  1. 复位:

(1)首先将总线拉低480us,产生复位脉冲,然后释放总线(拉高电平)。

(2)这时DS8B20检测到请求之后,会将总线拉低60~240us,来表示应答,最后释放总线。

(3)单片机可以选择在第一次释放总线后60~240us去读取总线的电平,如果是低电平,那么表示初始化成功(基本不用这个操作)

  1. 写操作:(低位先行)

(1)写“0”操作:将总线拉低60到120us,再释放总线

(2)写“1”操作:将总线拉低小于15us,再释放总线

(3)一个写操作总时间必须大于60us,每两个写操作之间必须间隔1us

  1. 读操作:(低位先行)

(1)首先将总线拉低然后释放,让DS18B20知道我们要开始读数据了,然后DS18B20就会开始传数据

(2)然后我们就要在15us内将总线传输的数据读走

(3)一个读操作总时间大于60us,每两个读操作之间间隔1us

四、DS18B20实验:

  1. 我根据上面手册中的时序写了一份代码,但是实际的时序可能并不相同,我还是建议可以自己写一下收获会更多,但是比赛的时候建议直接用官方给的代码(写的不好仅供参考)

(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;
  while(num--)
    for(i=0; i<628; 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"

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();

sbit DQ = P1^4;  
void DS18B20_Init();
void DS18B20_Write(u8 w_dat);
u8 DS18B20_Read();
// 主函数
void main(void)
{
  Close_All();    
  Timer_0_Init(1000);
  while(1)
  { 
     SEG_Proc();
  }
}

void SEG_Proc()
{
    u8 LSB,MSB;
        u16 t_temp;
    if(SEG_delay)return;
    SEG_delay = 1;
    
        DS18B20_Init();
        DS18B20_Write(0xCC);
        //转换温度
        DS18B20_Write(0x44);
        
        DS18B20_Init();
        DS18B20_Write(0xCC);
        //读取暂存器
        DS18B20_Write(0xBE);
        //温度数据低八位
        LSB = DS18B20_Read();
        //温度数据高八位
        MSB = DS18B20_Read();
    
        t_temp = LSB | (MSB<<8);
    if((t_temp & 0xf800) == 0)//符号位为0
        sprintf(SEG_COT, "    %2.2f", t_temp*0.0625);
    else if((t_temp | 0x07ff) == 1)//符号位为1
        sprintf(SEG_COT, "-%04.2f", ((~t_temp)+1)*0.0625);//负数的补码要进行取反加一操作
    SEG_TSL(SEG_COT,SEG_Code);
}

void DS18B20_Init()
{
    u8 b_temp=1,time_out=10;
    while(b_temp && ((time_out--) != 0))
    {
        DQ = 0;
        Delay_us(48);
        DQ = 1;
        Delay_us(5);
        b_temp = DQ;
    }
    Delay_us(20);
}

void DS18B20_Write(u8 w_dat)
{
    u8 i=0;
    for(i=0;i<8;i++)
    {
            DQ = 0;
            Delay_us(1);
            DQ = w_dat&0x01;
            Delay_us(5);
            DQ = 1;
            w_dat >>= 1;
    }
}
u8 DS18B20_Read()
{
    u8 r_dat=0;
    u8 i=0;
    for(i=0;i<8;i++)
    {
            DQ = 0;
            r_dat >>= 1;
            DQ = 1;
            Delay_us(1);
            if(DQ)
            {
                    r_dat |= 0x80;
            }       
            Delay_us(5);
    }
    return r_dat;
}

/***************************数码管*****************************/
/*
  输入变量: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<<PIS;
       P2 = (P2 & 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;
}
  1. 根据官方写的时序:

(1)官方给的库函数

#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;
    while(t--){
        for(i=0;i<8;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)根据官方给的库函数写的主函数

// 使用程序前,将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<<PIS;
        P2 = (P2 & 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;
}

  • 6
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值