返回列表 发新帖我要提问本帖赏金: 60.00元(功能说明)

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

[复制链接]
 楼主| suncat0504 发表于 2024-12-10 21:37 | 显示全部楼层 |阅读模式
DS18B20是一款单总线驱动的温度传感器,占用口线少,驱动简单,只要按照协议发出符合时序要求的信号,就可以得到温度数据。
bf0721befd1fcaed5a54398d1bcf1220
典型应用电路:
6c9fa8b88135facca39c66ba4c05bc6e
我这里使用的第一种应用电路,使用PB4连接DQ端。为了方便驳接,我选择的是现成的模块:
c5e9c3bf0375cfd4ef818d7606e850f4
是用杜邦线连接到开发板上。
简单的读取温度值的步骤如下:
    1、跳过ROM操作。      
    2、发送温度转换命令。
    3、跳过ROM操作。
    4、发送读取温度命令。
    5、读取温度值。

      DS18B20温度传感器的初始化      

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

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

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

7e23743bf7233440364fa14f218dec96

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

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

  9.     /* DATA引脚:PB5 */
  10.     gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  11.     gpio_initstructure.gpio_out_type  = GPIO_OUTPUT_PUSH_PULL;
  12.     gpio_initstructure.gpio_mode = GPIO_MODE_OUTPUT;
  13.     gpio_initstructure.gpio_pins = DS18B20_DATA_PIN;
  14.     gpio_initstructure.gpio_pull = GPIO_PULL_UP;
  15.     gpio_init(GPIOB, &gpio_initstructure);
  16. }

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

  22.     /* DATA引脚:PB5 */
  23.     gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  24.     gpio_initstructure.gpio_out_type  = GPIO_OUTPUT_PUSH_PULL;
  25.     gpio_initstructure.gpio_mode = GPIO_MODE_INPUT;
  26.     gpio_initstructure.gpio_pins = DS18B20_DATA_PIN;
  27.     gpio_initstructure.gpio_pull = GPIO_PULL_UP;
  28.     gpio_init(GPIOB, &gpio_initstructure);
  29. }

  30. void Ds18b20Rst(void) {  
  31.     gpio_config_DS18B20_Out();
  32.         
  33.     gpio_bits_reset(DS18B20_PORT, DS18B20_DATA_PIN);
  34.     delay_us(750);              //主机发送复位脉冲480us-960us  
  35.     gpio_bits_set(DS18B20_PORT, DS18B20_DATA_PIN);
  36.    
  37.     delay_us(25);//18b20等待15-60us   
  38. }  
  39.    
  40. /*等待18b20响应
  41. * 返回1:未检测到18b20
  42. * 返回0:存在
  43. */  
  44. uint8_t Ds18b20Check(void) {   
  45.     uint8_t retry=0;  
  46.   
  47.     // 输入模式
  48.     gpio_config_DS18B20_In();

  49.     while(gpio_input_data_bit_read(DS18B20_PORT, DS18B20_DATA_PIN) && retry < 200) {   
  50.         retry++;  
  51.         delay_us(1);  
  52.     }
  53.    
  54.     if(retry>=200)return 1;  
  55.     else retry=0;  
  56.    
  57.     while(!gpio_input_data_bit_read(DS18B20_PORT, DS18B20_DATA_PIN) && retry < 240) {  
  58.         retry++;  
  59.         delay_us(1);  
  60.     }   
  61.     if(retry>240)return 1;  
  62.     return 0;   
  63. }  
  64. /*从18b20读取一个位
  65. * 返回值1/0
  66. */  
  67. uint8_t Ds18b20ReadBit(void) {  
  68.     uint8_t data;  

  69.     gpio_config_DS18B20_Out();

  70.     gpio_bits_reset(DS18B20_PORT, DS18B20_DATA_PIN);
  71.    
  72.     delay_us(2);
  73.    
  74.     gpio_bits_set(DS18B20_PORT, DS18B20_DATA_PIN);
  75.    
  76.     // 输入模式
  77.     gpio_config_DS18B20_In();

  78.     delay_us(12);  
  79.    
  80.     if(gpio_input_data_bit_read(DS18B20_PORT, DS18B20_DATA_PIN)) data=1;  
  81.     else data=0;
  82.    
  83.     delay_us(50);  

  84.     return data;  
  85. }  
  86. /*从18b20读取一个字节
  87. * 返回值:读到的数据
  88. */  
  89. uint8_t Ds18b20ReadByte(void) {  
  90.     uint8_t i,j,dat;  
  91.     dat=0;

  92.     for(i=1;i<=8;i++) {  
  93.         j=Ds18b20ReadBit();  
  94.         dat=(j<<7)|(dat>>1);//低位在前  
  95.     }  
  96.     return dat;  
  97. }

  98. /*写一个字节到Ds18b20
  99. * dat:要写入的字节
  100. */  
  101. void Ds18b20WriteByte(uint8_t dat) {   
  102.     uint8_t i;  
  103.     uint8_t temp;  

  104.     gpio_config_DS18B20_Out();

  105.     for(i=1;i<=8;i++) {  
  106.     temp=dat&0x01;  
  107.     dat=dat>>1;  
  108.     if (temp) {  
  109.         // 输出1  
  110.         gpio_bits_reset(DS18B20_PORT, DS18B20_DATA_PIN);
  111.         delay_us(2);  
  112.         gpio_bits_set(DS18B20_PORT, DS18B20_DATA_PIN);
  113.         delay_us(60);  
  114.     } else {  
  115.         // 输出0  
  116.         gpio_bits_reset(DS18B20_PORT, DS18B20_DATA_PIN);
  117.         delay_us(60);  
  118.         gpio_bits_set(DS18B20_PORT, DS18B20_DATA_PIN);
  119.         delay_us(2);  
  120.     }  
  121.     }  
  122. }  
  123.    
  124. /*从Ds18b20得到温度值
  125. * 返回值:温度值
  126. */  
  127. float Ds18b20GetTemp() {  
  128.     uint8_t temp;  
  129.     uint8_t TH=0,TL=0;  
  130.     short tem;  
  131.     float t;  

  132.     Ds18b20Rst();  
  133.     Ds18b20Check();  
  134.     // 跳过ROM操作  
  135.     Ds18b20WriteByte(0XCC);  
  136.     // 发出转换指令  
  137.     Ds18b20WriteByte(0X44);  
  138.     Ds18b20Rst();  
  139.     Ds18b20Check();  
  140.     // 跳过ROM操作  
  141.     Ds18b20WriteByte(0XCC);  
  142.     // 读数据,低位在前  
  143.     Ds18b20WriteByte(0XBE);  
  144.     TL=Ds18b20ReadByte();//LSB  
  145.     TH=Ds18b20ReadByte();//MSB  
  146.    
  147.     if(TH>7) {  
  148.         // 如果数据是负的  
  149.         TH=~TH;  
  150.         TL=~TL;  
  151.         // 负温度标志  
  152.         temp=0;  
  153.     } else {  
  154.         // 正温度  
  155.         temp=1;  
  156.     }  
  157.     tem=TH;//高八位  
  158.     tem<<=8;  
  159.     tem+=TL;//低八位  
  160.     // 计算温度值  
  161.     t=((float)tem*0.0625);  
  162.     if(temp) return t;  
  163.     else     return -t;  
  164. }  


在主程序中每间隔300ms读一次温度,得到的结果输出到SPI显示屏上。
c7a71cf3e6e4c88f6a630a126fba7adf
只要时序没问题,很容易调通的。如果通讯失败,建议用逻辑分析仪截取通讯过程信号分析,通常是脉冲的时间不匹配造成的。

打赏榜单

ArteryMCU 打赏了 50.00 元 2025-01-09
理由:[L021开发板评测活动]内容优质

ArterySW 打赏了 10.00 元 2025-01-07
理由:作品优秀

呐咯密密 发表于 2024-12-12 10:02 | 显示全部楼层
这就是1-Writer通信吧
 楼主| suncat0504 发表于 2024-12-12 13:13 | 显示全部楼层
呐咯密密 发表于 2024-12-12 10:02
这就是1-Writer通信吧

是的,感觉比I2C方便多了,不用考虑中间状态值。
[鑫森淼焱垚] 发表于 2025-2-11 16:29 | 显示全部楼层
好贴,点赞
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

158

主题

4504

帖子

6

粉丝
快速回复 在线客服 返回列表 返回顶部