找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4076|回复: 0
打印 上一主题 下一主题
收起左侧

基于STM32自码 DS18B20驱动程序

[复制链接]
跳转到指定楼层
楼主
ID:267624 发表于 2017-12-27 12:23 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
为了加深对于底层驱动开发的认识和理解,楼主决定自撸常见模块,传感器的驱动程序。-------立贴为证。
DS18B20是一款单总线可编程分辨率的数字温度计,详细内容可见中英文datasheet,笔者不在赘述。
很早就接触到的温度传感器,也相信每一个曾学习过嵌入式开发的人都用过,笔者在STM32F4上自码DS18B20驱动,有些小小心得:
1.初始化时序要注意,笔者亲测,在MCU控制单总线为低电平240us即可(数据手册上要求至少480us)释放总线,等待60us后即可检测到到DS18B20返回的拉低单总线信号,此处,需注意至少应在此等待120us,否则可能会导致温度传感器无法正常工作。

2.初学者需注意时序,对于DS18B20的操作都必需经过三步:初始化,ROM命令(多为跳过指令0xCC),DS18B20功能命令。再次强调对其的每一个操作必须经过这三步,可阅读code加深理解。
3.在读取DS18B20时,注意顺序,DS18B20先发送低位,在字节读取时应当注意。
4.初学者应尝试实现对于DS18B20内部ROM的8位系列号(28H),和48位唯一序列号进行读取,以及修改温度传感器内部EEPROM的过温、低温报警值。(可参考笔者code)

废话不多说,上码:
  1. #include <ds18b20.h>  
  2. #include "delay.h"  
  3. #include "usart.h"   
  4.   
  5. //ds18b20初始化  
  6. void  init_ds18b20( void )  
  7. {  
  8.     init_onewire_out();  
  9.     GPIO_ResetBits(GPIOG,GPIO_Pin_9);  
  10.     delay_us(480);  
  11.     init_onewire_in();  
  12.     delay_us(60);  
  13.     if( !DQ_In)  
  14.     {  
  15.         delay_us(120);  
  16.                   
  17.     }  
  18. }  
  19. //ds18b20 检测  
  20. void  chack_ds18b20( void )  
  21. {  
  22.     init_onewire_out();  
  23.     GPIO_ResetBits(GPIOG,GPIO_Pin_9);  
  24.     delay_us(240);  
  25.     init_onewire_in();  
  26.     delay_us(60);  
  27.     if( !DQ_In)  
  28.     {  
  29.         delay_us(80);  
  30.         if( !DQ_In )  
  31.             printf("检测到DS18B20!\r\n");  
  32.                   
  33.     }  
  34.   
  35. }  
  36. //设置为主设备写总线,从设备读总线  
  37. void init_onewire_out( void )  
  38. {  
  39.     GPIO_InitTypeDef  GPIO_InitStructure;  
  40.   
  41.     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);//使能GPIOG时钟  
  42.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;  
  43.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式  
  44.     GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出  
  45.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz  
  46.     GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉  
  47.     GPIO_Init(GPIOG, &GPIO_InitStructure);//初始化  
  48. }  
  49. //设置为主设备读取总线,从设备写总线  
  50. void init_onewire_in( void )  
  51. {  
  52.       
  53.     GPIO_InitTypeDef  GPIO_InitStructure;  
  54.   
  55.     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);//使能GPIOG时钟  
  56.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;  
  57.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//普通输入模式  
  58. //  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出  
  59.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz  
  60.     GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉  
  61.     GPIO_Init(GPIOG, &GPIO_InitStructure);//初始化  
  62. }  
  63.   
  64. void ds18b20_write_byte( u8 data )  
  65. {  
  66.     u8 i;  
  67.     u8 j=0;  
  68.     init_onewire_out();  
  69.     for(i=0;i<8;i++)  
  70.         {  
  71.             j=data & 0x01;  
  72.             if(j)  
  73.             {  
  74.                 DQ_Out=0;       //写1  
  75.                 delay_us(15);  
  76.                 DQ_Out=1;  
  77.                 delay_us(60);  
  78.                   
  79.             }  
  80.             else  
  81.             {  
  82.                 DQ_Out=0;       //写0  
  83.                 delay_us(60);  
  84.                 DQ_Out=1;  
  85.                 delay_us(1);  
  86.             }  
  87.             data = data>>1;  
  88.         }     
  89. }  
  90. //读取DS18B20 的一位  
  91. u8 ds18b20_read_bit( void )  
  92. {     
  93.     u8 bit;  
  94.     init_onewire_out();  
  95.     DQ_Out=0;  
  96.     delay_us(2);  
  97.     DQ_Out=1;  
  98.     init_onewire_in();  
  99.     delay_us(12);  
  100.     if(DQ_In)  
  101.         bit=1;  
  102.     else  
  103.         bit=0;  
  104.     delay_us(50);  
  105.     return bit;  
  106. }  
  107. //读ds18b20的字节  
  108. u8 ds18b20_read_byte ( void )  
  109. {  
  110.     u8 data=0;  
  111.     u8 i;  
  112.     u8 j=0;  
  113.     for(i=0;i<8;i++)  
  114.     {  
  115.         j=ds18b20_read_bit();  
  116.         if(j)           //注意顺序即可,ds18b20先发送地位到总线上  
  117.             j=j<<i;  
  118.         data |=j;  
  119.   
  120.     }  
  121.     return data;  
  122. }  
  123. //获取ds18b20的系列码和48位唯一序列号  
  124. void ds18b20_read_rom_number()  
  125. {  
  126.     u32 number=0;  
  127.     u8 data,i,serial_num,ds18b20_crc;  
  128.     init_ds18b20();  
  129.     ds18b20_write_byte(0x33);  
  130.     serial_num = ds18b20_read_byte();  
  131.     for(i=0;i<6;i++)  
  132.     {  
  133.         data = ds18b20_read_byte();  
  134.         number |= data;  
  135.         number = number<<8;  
  136.     }  
  137.     ds18b20_crc = ds18b20_read_byte();  
  138.       
  139.     printf("系列号是:%d\r\n",serial_num);  
  140.     printf("序列号是:%d\r\n",number);  
  141.     printf("CRC校验为:%d\r\n",ds18b20_crc);  
  142.       
  143. }  
  144. //开启ds18b20温度转换  
  145. void tem_chage( void )  
  146. {  
  147.     init_ds18b20();  
  148.     ds18b20_write_byte(0xcc);       //忽略rom指令  
  149.     ds18b20_write_byte(0x44);   //开启转换  
  150. }  
  151.   
  152. short  get_temp( void )  
  153. {  
  154.     int temp=0;  
  155.     u8 i,TH,TL;  
  156.     short tem;  
  157.   
  158.     tem_chage();  
  159.     delay_us(10);  
  160.     init_ds18b20();  
  161.     ds18b20_write_byte(0xcc);       //忽略rom指令  
  162.     ds18b20_write_byte(0xbe);   //读取温度转换值  
  163.     TL=ds18b20_read_byte();  
  164.     TH=ds18b20_read_byte();  
  165.       
  166.     if(TH > 7)       //通过判读存储器的高五位的0,1来判断温度的正负,  
  167.     {  
  168.         temp = 0;   //为负  
  169.         TH =~TH;  
  170.         TL =~TL;   
  171.     }  
  172.     else   
  173.         temp = 1;   //为正  
  174.     tem = TH;  
  175.     tem =tem<<8;  
  176.     tem =tem+TL;  
  177.     tem = (double)tem * 0.625;  
  178.     if(temp)  
  179.         return tem;  
  180.     else  
  181.         return -tem;  
  182.       
  183. }  
  184. void ds18b20_return_TH_TL_CONF( void )  
  185. {  
  186.     char data,data_TH,data_TL,CONF;  
  187.     init_ds18b20();  
  188.     ds18b20_write_byte(0xcc);       //忽略rom指令  
  189.     ds18b20_write_byte(0xbe);   //读取温度转换值  
  190.     data = ds18b20_read_byte();  
  191.     data = ds18b20_read_byte();  
  192.     data_TH = ds18b20_read_byte();  
  193.     data_TL = ds18b20_read_byte();  
  194.     CONF =ds18b20_read_byte();  
  195.     printf("过温报警的温度为:%d℃\r\n",data_TH);  
  196.     printf("低温报警的温度为:%d℃\r\n",-(data_TL-128));  
  197.     CONF &=0x60 ;  
  198.     CONF =CONF>>5;  
  199.     switch (CONF) {  
  200.         case 0:  
  201.             printf("ds18b20的测量精度为9位,精度为0.5℃\r\n");  
  202.             break;  
  203.         case 1:  
  204.             printf("ds18b20的测量精度为10位,精度为0.25℃\r\n");  
  205.             break;  
  206.         case 2:  
  207.             printf("ds18b20的测量精度为11位,精度为0.125℃\r\n");  
  208.             break;  
  209.         case 3:  
  210.             printf("ds18b20的测量精度为12位,精度为0.0625℃\r\n");  
  211.             break;  
  212.         default:  
  213.             printf("error!!\r\n");  
  214.             break;  
  215.     }  
  216. }  
  217. //设置温度报警值和配置精度,TH过温报警值(TH>0),TL低温报警值(TL为负数 ),mode配置模式0,1,2,3  
  218. //mode=0 精度为9位  00011111 dat=31  
  219. //mode=1 精度为10位  00111111   dat=63  
  220. //mode=2 精度为11位 01011111    dat=95  
  221. //mode=3 精度为12位  01111111   dat =127  
  222. void ds18b20_write_TH_TL_CONF(u8 TH,u8 TL,u8 mode)  
  223. {  
  224.     u8 dat;  
  225.     switch (mode){  
  226.         case 0:  
  227.             dat=31;  
  228.             break;  
  229.         case 1:  
  230.             dat=63;  
  231.             break;  
  232.         case 2:  
  233.             dat=95;  
  234.             break;  
  235.         case 3:  
  236.             dat=127;  
  237.             break;  
  238.         default:  
  239.             printf("mode error!!\r\n");  
  240.             dat=127;  
  241.             break;  
  242.     }  
  243.     TL=TL+128;  
  244.     init_ds18b20();  
  245.     ds18b20_write_byte(0xcc);       //忽略rom指令  
  246.     ds18b20_write_byte(0x4e);   //写入暂存寄存器 ,过温和低温报警值  
  247.     ds18b20_write_byte(TH); //写入20°为过温报警值  
  248.     ds18b20_write_byte(TL); //写入-20°为低温报警值  
  249.     ds18b20_write_byte(dat);    //写入精度  
  250.     init_ds18b20();  
  251.     ds18b20_write_byte(0xcc);       //忽略rom指令  
  252.     ds18b20_write_byte(0x48);   //将写入的暂存寄存器拷入EEPROM  
  253. }  
  254. void ds18b20_chack_self( void )  
  255. {  
  256.     chack_ds18b20();  
  257.     ds18b20_read_rom_number();  
  258.     ds18b20_return_TH_TL_CONF();  
  259. }  
复制代码


笔者用串口助手得到结果如下:

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表