stm32的ds18b20的驱动移植-皇冠最新app版本

×
单片机 > 单片机程序设计 > 详情

stm32的ds18b20的驱动移植

发布时间:2025-01-20 发布时间:
|

折腾了一晚上,才把ds18b20的驱动移植到stm32上来。以前在51上使用过单个和多个连接的ds18b20,有现成的程序了,以为很快就能弄好,结果还是被卡住了,下面说下几个关键点吧:

   首先是延时的问题,stm32上若用软件延时的话不太好算时间,所以要么用定时器要么用systick这个定时器来完成延时的计算。相比之下用systick来的简单方便点。

   接着是stm32 io脚的配置问题,因为51是双向的io,所以作为输入输出都比较方便。stm32的io是准双向的io,网上查了下资料,说将stm32的io配置成开漏输出,然后外接上拉即可实现双向io。于是我也按规定做了,但调了老半天都不成功,是因为ds18b20没有响应的信号。在烦躁之际只有试下将接dq的io分别拉低和拉高看能不能读入正确的信号。结果果然是读入数据不对,原来我将io配成开漏输出后相当然的以为读数据是用gpio_readoutputdatabit(),这正是问题所在,后来将读入的函数改为gpio_readinputdatabit()就ok了。现在温度是现实出来了,但跟我家里那台德胜收音机上显示的温度相差2度,都不知道是哪个准了,改天再找个温度计验证下。

   下面引用一段ds18b20的时序描述,写的很详细:

ds18b20的控制流程

   根据ds18b20的通信协议,ds18b20只能作为从机,而单片机系统作为主机,单片机控制ds18b20完成一次温度转换必须经过3个步骤:复位、发送rom指令、发送ram指令。每次对ds18b20的操作都要进行以上三个步骤。

    复位过程为:单片机将数据线拉低至少480us,然后释放数据线,等待15-60us让ds18b20接收信号,ds18b20接收到信号后,会把数据线拉低60-240us,主机检测到数据线被拉低后标识复位成功;
    发送rom指令:rom指令表示主机对系统上所接的全部ds18b20进行寻址,以确定对那一个ds18b20进行操作,或者是读取某个ds18b20的rom序列号。
    发送ram指令:ram指令用于单片机对ds18b20内部ram进行操作,如读取寄存器的值,或者设置寄存器的值。
    具体的ram和ram指令请查阅ds18b20的数据手册。下面简单介绍:
      1、rom操作命令:ds18b20采用一线通信接口。因为一线通信接口,必须在先完成rom设定,否则记忆和控制功能将无法使用。一旦总线检测到从属器件的存在,它便可以发出器件rom操作指令,所有rom操作指令均为8位长度,主要提供以下功能命令:

1 )读rom(指令码0x33h):当总线上只有一个节点(器件)时,读此节点的64位序列号。如果总线上存在多于一个的节点,则此指令不能使用。

 2 )rom匹配(指令码0x55h):此命令后跟64位的rom序列号,总线上只有与此序列号相同的ds18b20才会做出反应;该指令用于选中某个ds18b20,然后对该ds18b20进行读写操作。

3 )搜索rom(指令码0xf0h):用于确定接在总线上ds18b20的个数和识别所有的64位rom序列号。当系统开始工作,总线主机可能不知道总线上的器件个数或者不知道其64位rom序列号,搜索命令用于识别所有连接于总线上的64位rom序列号。

4 )跳过rom(指令码0xcch):此指令只适合于总线上只有一个节点;该命令通过允许总线主机不提供64位rom序列号而直接访问ram,以节省操作时间。

5 )报警检查(指令码0xech):此指令与搜索rom指令基本相同,差别在于只有温度超过设定的上限或者下限值的ds18b20才会作出响应。只要ds18b20一上电,告警条件就保持在设置状态,直到另一次温度测量显示出非告警值,或者改变th或tl的设置使得测量值再一次位于允许的范围之内。储存在eeprom内的触发器用于告警。

   

2、ram指令

    ds18b20有六条ram命令:

  1)温度转换(指令码0x44h):启动ds18b20进行温度转换,结果存入内部ram。

  2)读暂存器(指令码0xbeh):读暂存器9个字节内容,此指令从ram的第1个字节(字节0)开始读取,直到九个字节(字节8,crc值)被读出为止。如果不需要读出所有字节的内容,那么主机可以在任何时候发出复位信号以中止读操作。

  3)写暂存器(指令码0x4eh):将上下限温度报警值和配置数据写入到ram的2、3、4字节,此命令后跟需要些入到这三个字节的数据。

  4)复制暂存器(指令码0x48h):把暂存器的2、3、4字节复制到eeprom中,用以掉电保存。

  5)重新调e2ram(指令码0xb8h):把eerom中的温度上下限及配置字节恢复到ram的2、3、4字节,用以上电后恢复以前保存的报警值及配置字节。

6)读电源供电方式(指令码0xb4h):启动ds18b20发送电源供电方式的信号给主cpu。对于在此命令送至ds18b20后所发出的第一次读出数据的时间片,器件都会给出其电源方式的信号。“0”表示寄生电源供电。“1”表示外部电源供电。

 

 

     下面是结合实际测试总结出来的ds18b20的操作流程:

1、ds18b20的初始化

  (1) 先将数据线置高电平“1”。

  (2) 延时(该时间要求的不是很严格,但是尽可能的短一点)。

  (3) 数据线拉到低电平“0”。

  (4) 延时490微秒(该时间的时间范围可以从480到960微秒)。

  (5) 数据线拉到高电平“1”。

  (6)延时等待(如果初始化成功则在15到60毫秒时间之内产生一个由ds18b20所返回的低电平“0”。据该状态可以来确定它的存在,但是应注意不能无限的进行等待,不然会使程序进入死循环,所以要进行超时控制)。

  (7)若cpu读到了数据线上的低电平“0”后,还要做延时,其延时的时间从发出的高电平算起(第(5)步的时间算起)最少要480微秒。

  (8) 将数据线再次拉高到高电平“1”后结束。  

  2、ds18b20的写操作

  (1) 数据线先置低电平“0”。

  (2) 延时确定的时间为2(小于15)微秒。

  (3) 按从低位到高位的顺序发送字节(一次只发送一位)。

  (4) 延时时间为62(大于60)微秒。

  (5) 将数据线拉到高电平,延时2(小于15)微秒。

  (6) 重复上(1)到(6)的操作直到所有的字节全部发送完为止。

  (7) 最后将数据线拉高。  

  3、 ds18b20的读操作

  (1)将数据线拉高“1”。

  (2)延时2微秒。

  (3)将数据线拉低“0”。

  (4)延时2(小于15)微秒。

  (5)将数据线拉高“1”,同时端口应为输入状态。

  (6)延时4(小于15)微秒。

  (7)读数据线的状态得到1个状态位,并进行数据处理。

  (8)延时62(大于60)微秒。

 

 

顺便把程序也贴上来吧,给大家参考下。

使用的方法:

只要调用一次 ds18b20_start() 来初始化ds18b20,然后每次读温度时直接调用 ds18b20_read()就可以了。如

ds18b20_start();
 while(1)
 {
   for(i=1000000;i>0;i--);
   val = ds18b20_read();
 }


view plaincopy to clipboardprint?
//========================================================  
 
//       ds18b20.c   by ligh  
 
//========================================================  
 
#include "stm32lib\stm32f10x.h"  
#include "ds18b20.h"  
 
   
 
#define enableint()    
#define disableint()   
 
#define ds_port  gpioa  
#define ds_dqio  gpio_pin_1  
#define ds_rcc_port rcc_apb2periph_gpioa  
#define ds_precision 0x7f  //精度配置寄存器 1f=9位; 3f=10位; 5f=11位; 7f=12位;  
#define ds_alarmth 0x64  
#define ds_alarmtl 0x8a  
#define ds_convert_tick 1000  
 
#define resetdq() gpio_resetbits(ds_port,ds_dqio)  
#define setdq() gpio_setbits(ds_port,ds_dqio)  
#define getdq() gpio_readinputdatabit(ds_port,ds_dqio)  
   
   
static unsigned char tempx_tab[16]={0x00,0x01,0x01,0x02,0x03,0x03,0x04,0x04,0x05,0x06,0x06,0x07,0x08,0x08,0x09,0x09};  
 
 
void delay_us(u32 nus)   
{    
 systick->load=nus*9;         //时间加载         
 systick->ctrl|=0x01;            //开始倒数       
 while(!(systick->ctrl&(1<<16))); //等待时间到达    
 systick->ctrl=0x00000000;       //关闭计数器   
 systick->val=0x00000000;        //清空计数器        
}    
 
   
 
unsigned char resetds18b20(void)  
{  
 unsigned char resport;  
 setdq();  
 delay_us(50);  
   
 resetdq();  
 delay_us(500); //500us (该时间的时间范围可以从480到960微秒)  
 setdq();  
 delay_us(40); //40us  
 //resport = getdq();  
 while(getdq());  
 delay_us(500); //500us  
 setdq();  
 return resport;  
}  
 
void ds18b20writebyte(unsigned char dat)  
{  
 unsigned char i;  
 for(i=8;i>0;i--)  
 {  
  resetdq();    //在15u内送数到数据线上,ds18b20在15-60u读数  
 delay_us(5);   //5us  
 if(dat & 0x01)  
  setdq();  
 else 
  resetdq();  
 delay_us(65);   //65us  
 setdq();  
 delay_us(2);   //连续两位间应大于1us  
 dat >>= 1;   
 }   
}  
 
 
unsigned char ds18b20readbyte(void)  
{  
 unsigned char i,dat;  
 setdq();  
 delay_us(5);  
 for(i=8;i>0;i--)  
 {  
  dat >>= 1;  
   resetdq();    //从读时序开始到采样信号线必须在15u内,且采样尽量安排在15u的最后  
 delay_us(5);  //5us  
 setdq();  
 delay_us(5);  //5us  
 if(getdq())  
   dat|=0x80;  
 else 
  dat&=0x7f;    
 delay_us(65);  //65us  
 setdq();  
 }  
 return dat;  
}  
 
 
void readrom(unsigned char *read_addr)  
{  
 unsigned char i;  
 
 ds18b20writebyte(readrom);  
    
 for(i=8;i>0;i--)  
 {  
 *read_addr=ds18b20readbyte();  
 read_addr ;  
 }  
}  
 
 
void ds18b20init(unsigned char precision,unsigned char alarmth,unsigned char alarmtl)  
{  
 disableint();  
 resetds18b20();  
 ds18b20writebyte(skiprom);   
 ds18b20writebyte(writescratchpad);  
 ds18b20writebyte(alarmtl);  
 ds18b20writebyte(alarmth);  
 ds18b20writebyte(precision);  
 
 resetds18b20();  
 ds18b20writebyte(skiprom);   
 ds18b20writebyte(copyscratchpad);  
 enableint();  
 
 while(!getdq()); //等待复制完成 ///////////  
}  
 
 
void ds18b20startconvert(void)  
{  
 disableint();  
 resetds18b20();  
 ds18b20writebyte(skiprom);   
 ds18b20writebyte(startconvert);   
 enableint();  
}  
 
void ds18b20_configuration(void)  
{  
 gpio_inittypedef gpio_initstructure;  
   
 rcc_apb2periphclockcmd(ds_rcc_port, enable);  
 
 gpio_initstructure.gpio_pin = ds_dqio;  
 gpio_initstructure.gpio_mode = gpio_mode_out_od; //开漏输出  
 gpio_initstructure.gpio_speed = gpio_speed_50mhz; //2m时钟速度  
 gpio_init(ds_port, &gpio_initstructure);  
}  
 
 
void ds18b20_start(void)  
{  
 ds18b20_configuration();  
 ds18b20init(ds_precision, ds_alarmth, ds_alarmtl);  
 ds18b20startconvert();  
}  
 
 
unsigned short ds18b20_read(void)  
{  
 unsigned char temperaturel,temperatureh;  
 unsigned int temperature;  
 
 disableint();  
 resetds18b20();  
 ds18b20writebyte(skiprom);   
 ds18b20writebyte(readscratchpad);  
 temperaturel=ds18b20readbyte();  
 temperatureh=ds18b20readbyte();   
 resetds18b20();  
 enableint();  
 
 if(temperatureh & 0x80)  
 {  
 temperatureh=(~temperatureh) | 0x08;  
 temperaturel=~temperaturel 1;  
 if(temperaturel==0)  
  temperatureh =1;  
 }  
 
 temperatureh=(temperatureh<<4) ((temperaturel&0xf0)>>4);  
 temperaturel=tempx_tab[temperaturel&0x0f];  
 
 //bit0-bit7为小数位,bit8-bit14为整数位,bit15为正负位  
 temperature=temperatureh;  
 temperature=(temperature<<8) | temperaturel;   
 
 ds18b20startconvert();  
 
 return temperature;  
}  
 
   
 
   
 
//============================================  
 
//     ds18b20.h  
 
//============================================  
 
#ifndef __ds18b20_h  
#define __ds18b20_h  
 
#define skiprom   0xcc    //跳过rom  
#define searchrom 0xf0 //搜索rom  
#define readrom   0x33 //读rom  
#define matchrom  0x55 //匹配rom  
#define alarmrom  0xec //告警rom  
 
#define startconvert   0x44 //开始温度转换,在温度转换期间总线上输出0,转换结束后输出1  
#define readscratchpad 0xbe //读暂存器的9个字节  
#define writescratchpad 0x4e //写暂存器的温度告警th和tl  
#define copyscratchpad 0x48 //将暂存器的温度告警复制到eeprom,在复制期间总线上输出0,复制完后输出1  
#define recalleeprom   0xb8   //将eeprom的温度告警复制到暂存器中,复制期间输出0,复制完成后输出1  
#define readpower      0xb4   //读电源的供电方式:0为寄生电源供电;1为外部电源供电  
 
 
void ds18b20_start(void);  
unsigned short ds18b20_read(void);  
 
 
#endif 


关键字:stm32  ds18b20  驱动移植

『本文转载自网络,皇冠最新app版本的版权归原作者所有,如有侵权请联系删除』

网站地图