【嵌入式】微芯旺KungFu32A156MQT读取DS18B20温度计

相关资料

(74条消息) DS18B20使用说明_ds18b20复位_Joyin_Lee的博客-CSDN博客

解决DS18B20读取异常的问题 - 知乎 (zhihu.com)

 

出现问题

为了方便,我从51单片机的例程里面移植,使用串口检查读取数据,但是DS18B20读取数据全部都是1

问题1使用check函数发现DS18B20不存在

在51单片机上连接串口发现读数也全都是1,原因是串口中断占用的时间扰乱了DS18B20的时序

解决办法关闭串口,使用DEBUG模式来编程,或者是读取完毕后再开启串口

 

问题2解决问题1后发现读出的数据全都是1

使用逻辑分析仪观察51单片机和KF32的时序图,发现51单片机时序清晰,KF32写入DS18B20数据的函数中时序图时和51单片机不一致,

检查各代码运行的时间,发现是在进行GPIO的输入输出转换的时间超过了15us,导致更不上DS18B20的时序,原因是我在变换GPIO模式的时候重启了GPIO。

 

 可见如果超过了DS18B20下拉的时间,那么本来该是低电平0的数据将会读到高电平1。

解决办法:将GPIO设置为输出模式,速度为高速,设置为开漏输出,上拉GPIO口。此时虽然是输出模式但依然可以直接读取到输入的电平,就不用进行输入输出转换了。终于DS18B20可以正常读数

 

问题3:check函数等待时间修改后,读数又为全是1

原因是单总线对于时序比较严格,等待时间修改后,程序将更快开始下一个指令输出,但是DS18B20的相应未结束,所以导致时序混乱,主从不同步。

 

代码

 GPIO

//GPIOx设置为输出
//输入:    GPIOx    : 指向GPIO内存结构的指针,取值为GPIOA_SFR~GPIOH_SFR。
//        GpioPin    : 端口引脚掩码,取值为GPIO_PIN_MASK_0~GPIO_PIN_MASK_15中的一个或多个组合。
void Lp_Gpio_Output_Config(GPIO_SFRmap* GPIOx,uint16_t GpioPin)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_Struct_Init(&GPIO_InitStructure);
    GPIO_InitStructure.m_Pin = GpioPin;
    GPIO_InitStructure.m_Speed = GPIO_HIGH_SPEED;    //初始化 GPIO输出速度
    GPIO_InitStructure.m_Mode = GPIO_MODE_OUT;        //初始化 GPIO方向为输出
    GPIO_InitStructure.m_PullUp = GPIO_PULLUP;        //初始化 GPIO上拉
    GPIO_InitStructure.m_PullDown = GPIO_NOPULL;    //初始化 GPIO不下拉
    GPIO_InitStructure.m_OpenDrain =GPIO_POD_OD;    //初始化 GPIO为开漏
    GPIO_Configuration(GPIOx,&GPIO_InitStructure);
}

DS18B20

/*
 * DS18B20.h
 *
 *  Created on: 2023-2-24
 *      Author: l22200182
 */

#ifndef DS18B20_H_
#define DS18B20_H_

#include "Lp_Gpio.h"

//设置GPIO
#define    DQ_GPIO_SFR        GPIOH_SFR
#define    DQ_PIN_MASK        GPIO_PIN_MASK_8

uint8_t DS18B20_Init(void);                //初始化DS18B20的IO口DQ,同时检测DS18B20的存在
uint8_t DS18B20_Check(void);            //检查DS18B20是否存在
float DS18B20_Read_Temperture(void);    //从DS18B20得到温度值

#endif /* DS18B20_H_ */
/*
 * DS18B20.c
 *
 *  Created on: 2023-2-24
 *      Author: l22200182
 */
#include "DS18B20.h"

//初始化DS18B20的GPIO
void DS18B20_Gpio_Init(){
    Lp_Gpio_Output_Config(GPIOH_SFR,GPIO_PIN_MASK_8);
}

//设置DQ电平
void DS18B20_Set_DQ(BitAction BitsValue){
    GPIO_Set_Output_Data_Bits(GPIOH_SFR,GPIO_PIN_MASK_8,BitsValue);
}

//读取DQ电平
BitAction DS18B20_Read_DQ(void){
    return GPIO_Read_Input_Data_Bit(GPIOH_SFR,GPIO_PIN_MASK_8);//不修改输出模式直接进行读取
}

//复位DS18B20
void DS18B20_Reset(void)
{
    DS18B20_Gpio_Init();    //重新初始化IO
    DS18B20_Set_DQ(RESET);    //拉低DQ
    systick_delay_us(750);    //拉低750us
    DS18B20_Set_DQ(SET);    //拉高DQ
    systick_delay_us(20);    //拉高20us
}


//检查DS18B20是否存在
//输出:    1:未检测到
//        0:存在
uint8_t DS18B20_Check(void)
{
    uint8_t time_temp=0;
    while(DS18B20_Read_DQ()&&time_temp<200)//等待DQ为低电平等200us
    {
        time_temp++;
        systick_delay_us(1);
    }
    if(time_temp>=200)return 1;
    else time_temp=0;
    while((!DS18B20_Read_DQ())&&time_temp<200)//等待DQ为高电平等200us
    {
        time_temp++;
        systick_delay_us(1);
    }
    if(time_temp>=200)return 1;//如果超时强制返回1
    return 0;
}

//从DS18B20读取一个位
//输出:    0/1
uint8_t DS18B20_Read_Bit(void){
    uint8_t de;
    uint8_t dat=0;
    DS18B20_Gpio_Init();
    DS18B20_Set_DQ(RESET);
    systick_delay_us(1);
    DS18B20_Set_DQ(SET);
    systick_delay_us(1);//这段时间不能过长,必须15us内读取数据
    if(DS18B20_Read_DQ())dat=1;//如果总线上高电平则数据为1
    else dat=0;//低电平则数据为0
    systick_delay_us(50);
    return dat;
}

//从DS18B20读取一个字节
//输出:    一个字节的数据
uint8_t DS18B20_Read_Byte(void)
{
    uint8_t i=0;
    uint8_t dat=0;
    uint8_t temp=0;
    //循环8次,每次读取1位,且先读低位后读高位
    for(i=0;i<8;i++){
        temp=DS18B20_Read_Bit();
        dat=(temp<<7)|(dat>>1);
    }
    return dat;
}

//写一个字节给DS18B20
//输入:    dat:要写入的字节
void DS18B20_Write_Byte(uint8_t dat){
    uint8_t de;
    uint8_t i=0;
    uint8_t temp=0;
    DS18B20_Gpio_Init();
    //循环8次,每次写1位,且先写低位后写高位
    for(i=0;i<8;i++){
        temp=dat&0x01;//选择低位准备写入
        dat>>=1;//将次高位移入低位
        if(temp){
            DS18B20_Set_DQ(RESET);
            systick_delay_us(1);
            DS18B20_Set_DQ(SET);
            systick_delay_us(60);
        }else{
            DS18B20_Set_DQ(RESET);
            systick_delay_us(60);
            DS18B20_Set_DQ(SET);
            systick_delay_us(1);
        }
    }
}

//开始温度转换
void DS18B20_Start(void){
    DS18B20_Reset();            //复位
    DS18B20_Check();            //检查DS18B20
    DS18B20_Write_Byte(0xcc);    //SKIP ROM    1100 1100
    DS18B20_Write_Byte(0x44);    //转换命令    0100 0100
}

//初始化DS18B20的IO口DQ,同时检测DS18B20的存在
//输出:    1:不存在
//        0:存在
uint8_t DS18B20_Init(void){
    DS18B20_Gpio_Init();
    DS18B20_Reset();
    return DS18B20_Check();
}

//从DS18B20得到温度值
//输出:    温度数据
float DS18B20_Read_Temperture(void){
    float temp;
    uint8_t dath=0;
    uint8_t datl=0;
    uint16_t value=0;

    DS18B20_Start();        //开始转换
    systick_delay_ms(250);    //转换时间
    systick_delay_ms(250);
    DS18B20_Reset();        //复位
    DS18B20_Check();
    DS18B20_Write_Byte(0xcc);//SKIP ROM
    DS18B20_Write_Byte(0xbe);//读存储器

    datl=DS18B20_Read_Byte();//低字节
    dath=DS18B20_Read_Byte();//高字节
    value=(dath<<8)+datl;    //合并为16位数据

    if((value&0xf800)==0xf800){//判断符号位,如果为负温度
        value=(~value)+1;        //负数的补码需要取反加1
        temp=value*(-0.0625);    //转换为摄氏度
    }else{
        temp=value*0.0625;        //正数
    }
    return temp;
}

main

#include "main.h"

int main(){
    SystemInit(120);
    systick_delay_init(120);

    DS18B20_Init();                                //初始化
    float temp_value=DS18B20_Read_Temperture();    //读取温度

    while(1){

    }
}

 

posted @ 2023-02-24 18:28  海底淤泥  阅读(187)  评论(0编辑  收藏  举报