打印
[AT32L021]

【AT-START-L021测评】+驱动DS18B20获取温度

[复制链接]
411|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
DS18B20是一款单总线驱动的温度传感器,占用口线少,驱动简单,只要按照协议发出符合时序要求的信号,就可以得到温度数据。

典型应用电路:

我这里使用的第一种应用电路,使用PB4连接DQ端。为了方便驳接,我选择的是现成的模块:

是用杜邦线连接到开发板上。
简单的读取温度值的步骤如下:
    1、跳过ROM操作。      
    2、发送温度转换命令。
    3、跳过ROM操作。
    4、发送读取温度命令。
    5、读取温度值。

      DS18B20温度传感器的初始化      

主器件首先发出一个480-960微秒的低电平脉冲,然后释放总线变为高电平,并在随后的480微秒时间内对总线进行检测,如果有低电平出现说明总线上有DS18B20温度传感器已做出应答。若无低电平出现一直都是高电平说明总线上无DS18B20温度传感器应答。

  做为从器件的DS18B20温度传感器在一上电后就一直在检测总线上是否有480-960微秒的低电平出现,如果有,在总线转为高电平后等待15-60微秒后将总线电平拉低60-240微秒做出响应存在脉冲,告诉主机本器件已做好准备。若没有检测到就一直在检测等待。

DS18B20温度传感器的写操作     

写周期最少为60微秒,最长不超过120微秒。写周期一开始主器件先把总线拉低1微秒表示写周期开始。随后若主器件想写0,则将总线置为低电平,若主器件想写1,则将总线置为高电平,持续时间最少60微秒直至写周期结束,然后释放总线为高电平至少1微秒给总线恢复 。而DS18B20温度传感器则在检测到总线被拉底后等待15微秒然后从15us到45us开始对总线采样,在采样期内总线为高电平则为1,若采样期内总线为低电平则为0。



工程使用80MHZ的主频,DS18B20的驱动程序如下:
#include "ds18b20.h"

// 初始化18B20用到的GPIO口:PB4,输出模式
static void gpio_config_DS18B20_Out(void) {
    gpio_init_type gpio_initstructure;
   
    crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
   
    gpio_default_para_init(&gpio_initstructure);

    /* DATA引脚:PB5 */
    gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
    gpio_initstructure.gpio_out_type  = GPIO_OUTPUT_PUSH_PULL;
    gpio_initstructure.gpio_mode = GPIO_MODE_OUTPUT;
    gpio_initstructure.gpio_pins = DS18B20_DATA_PIN;
    gpio_initstructure.gpio_pull = GPIO_PULL_UP;
    gpio_init(GPIOB, &gpio_initstructure);
}

// 初始化18B20用到的GPIO口:PB4,输入模式
static void gpio_config_DS18B20_In(void) {
    gpio_init_type gpio_initstructure;
   
    gpio_default_para_init(&gpio_initstructure);

    /* DATA引脚:PB5 */
    gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
    gpio_initstructure.gpio_out_type  = GPIO_OUTPUT_PUSH_PULL;
    gpio_initstructure.gpio_mode = GPIO_MODE_INPUT;
    gpio_initstructure.gpio_pins = DS18B20_DATA_PIN;
    gpio_initstructure.gpio_pull = GPIO_PULL_UP;
    gpio_init(GPIOB, &gpio_initstructure);
}

void Ds18b20Rst(void) {  
    gpio_config_DS18B20_Out();
        
    gpio_bits_reset(DS18B20_PORT, DS18B20_DATA_PIN);
    delay_us(750);              //主机发送复位脉冲480us-960us  
    gpio_bits_set(DS18B20_PORT, DS18B20_DATA_PIN);
   
    delay_us(25);//18b20等待15-60us   
}  
   
/*等待18b20响应
* 返回1:未检测到18b20
* 返回0:存在
*/  
uint8_t Ds18b20Check(void) {   
    uint8_t retry=0;  
  
    // 输入模式
    gpio_config_DS18B20_In();

    while(gpio_input_data_bit_read(DS18B20_PORT, DS18B20_DATA_PIN) && retry < 200) {   
        retry++;  
        delay_us(1);  
    }
   
    if(retry>=200)return 1;  
    else retry=0;  
   
    while(!gpio_input_data_bit_read(DS18B20_PORT, DS18B20_DATA_PIN) && retry < 240) {  
        retry++;  
        delay_us(1);  
    }   
    if(retry>240)return 1;  
    return 0;   
}  
/*从18b20读取一个位
* 返回值1/0
*/  
uint8_t Ds18b20ReadBit(void) {  
    uint8_t data;  

    gpio_config_DS18B20_Out();

    gpio_bits_reset(DS18B20_PORT, DS18B20_DATA_PIN);
   
    delay_us(2);
   
    gpio_bits_set(DS18B20_PORT, DS18B20_DATA_PIN);
   
    // 输入模式
    gpio_config_DS18B20_In();

    delay_us(12);  
   
    if(gpio_input_data_bit_read(DS18B20_PORT, DS18B20_DATA_PIN)) data=1;  
    else data=0;
   
    delay_us(50);  

    return data;  
}  
/*从18b20读取一个字节
* 返回值:读到的数据
*/  
uint8_t Ds18b20ReadByte(void) {  
    uint8_t i,j,dat;  
    dat=0;

    for(i=1;i<=8;i++) {  
        j=Ds18b20ReadBit();  
        dat=(j<<7)|(dat>>1);//低位在前  
    }  
    return dat;  
}

/*写一个字节到Ds18b20
* dat:要写入的字节
*/  
void Ds18b20WriteByte(uint8_t dat) {   
    uint8_t i;  
    uint8_t temp;  

    gpio_config_DS18B20_Out();

    for(i=1;i<=8;i++) {  
    temp=dat&0x01;  
    dat=dat>>1;  
    if (temp) {  
        // 输出1  
        gpio_bits_reset(DS18B20_PORT, DS18B20_DATA_PIN);
        delay_us(2);  
        gpio_bits_set(DS18B20_PORT, DS18B20_DATA_PIN);
        delay_us(60);  
    } else {  
        // 输出0  
        gpio_bits_reset(DS18B20_PORT, DS18B20_DATA_PIN);
        delay_us(60);  
        gpio_bits_set(DS18B20_PORT, DS18B20_DATA_PIN);
        delay_us(2);  
    }  
    }  
}  
   
/*从Ds18b20得到温度值
* 返回值:温度值
*/  
float Ds18b20GetTemp() {  
    uint8_t temp;  
    uint8_t TH=0,TL=0;  
    short tem;  
    float t;  

    Ds18b20Rst();  
    Ds18b20Check();  
    // 跳过ROM操作  
    Ds18b20WriteByte(0XCC);  
    // 发出转换指令  
    Ds18b20WriteByte(0X44);  
    Ds18b20Rst();  
    Ds18b20Check();  
    // 跳过ROM操作  
    Ds18b20WriteByte(0XCC);  
    // 读数据,低位在前  
    Ds18b20WriteByte(0XBE);  
    TL=Ds18b20ReadByte();//LSB  
    TH=Ds18b20ReadByte();//MSB  
   
    if(TH>7) {  
        // 如果数据是负的  
        TH=~TH;  
        TL=~TL;  
        // 负温度标志  
        temp=0;  
    } else {  
        // 正温度  
        temp=1;  
    }  
    tem=TH;//高八位  
    tem<<=8;  
    tem+=TL;//低八位  
    // 计算温度值  
    t=((float)tem*0.0625);  
    if(temp) return t;  
    else     return -t;  
}  


在主程序中每间隔300ms读一次温度,得到的结果输出到SPI显示屏上。

只要时序没问题,很容易调通的。如果通讯失败,建议用逻辑分析仪截取通讯过程信号分析,通常是脉冲的时间不匹配造成的。

使用特权

评论回复
沙发
呐咯密密| | 2024-12-12 10:02 | 只看该作者
这就是1-Writer通信吧

使用特权

评论回复
板凳
suncat0504|  楼主 | 2024-12-12 13:13 | 只看该作者
呐咯密密 发表于 2024-12-12 10:02
这就是1-Writer通信吧

是的,感觉比I2C方便多了,不用考虑中间状态值。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:大连伊飞特信息技术有限公司软件工程师
简介:本人于1993年毕业于大连理工大学。毕业后从事单片机开发工作5年,之后转入软件开发工作至今。

130

主题

3870

帖子

5

粉丝