目录

One-Wire介绍与认识

一、单线通信

二、电源模式--One-Wire设备可以工作在两种电源模式下

三、唯一的设备地址

四、通信速度

 One-Wire通信的工作原理

一、初始化(Reset)

二、设备寻址--ROM操作指令

三、信号时序与数据读写

读取DS18B20数据

DS18B20驱动代码


One-Wire介绍与认识

一、单线通信

1、One-Wire,即单线总线,又叫单总线。是由Dallas Semiconductor(现属于Maxim Integrated)开发的数据通信协议。

2、它因仅需一根数据线(加上一条地线)即可实现数据通信而得名。

3、它是一种半双工的通信机制,意味着数据可以在两个方向上传输,但在同一时间内只能进行单向传输。

4、所有数据都在一条线上传输,因此单总线协议对时序要求非常严格以确保数据的完整性。

5、One-Wire协议虽然在硬件上较为简单,但在软件实现上可能较为复杂,需要精确控制数据线的时序。尽管如此,它仍然是一种非常经济且有效的通信解决方案,尤其适用于需要大量连接点的应用场景。

二、电源模式--One-Wire设备可以工作在两种电源模式下

该协议使用一根数据线同时传输数据和电源。设备通过电线上的数据脉冲获取电源,称为“寄生电源”(parasitic power),或者直接使用专门的电源线供电。
寄生电源模式(Parasitic Power):设备从数据线上获取能量,适用于能量需求较低的应用。

 工作在寄生电源下的典型接法


外部供电模式(Normal Power):设备通过外部电源供电,适用于需要更多能量的应用。 

外部供电下的典型接法

三、唯一的设备地址

1、每个One-Wire设备都拥有一个唯一的64位地址(通常称为ROM代码),包括一个8位的家族码、48位的序列号和一个8位的CRC校验码。

2、该地址在设备制造时烧录进去,并且是不可更改的。因此通信总线上的每个设备都可以被唯一标识。

3、这种特性允许多个设备共享同一条总线,主机可以通过地址识别并与单个从设备通信。
4、One-Wire协议采用主从结构,主机控制总线的通信流程。从设备只有在被主机选择之后才会响应数据请求。
 
 

四、通信速度

One-Wire协议采用主从结构,主机控制总线的通信流程。从设备只有在被主机选择之后才会响应数据请求。
One-Wire通信支持两种速度模式:

1. 标准模式:数据传输速率为15.3 kbps。
 2.加速模式:数据传输速率为125 kbps,但并非所有设备都支持加速模式。

 One-Wire通信的工作原理

一、初始化(Reset)


主机通过拉低数据线产生一个复位脉冲,然后释放总线,等待从机的应答脉冲。

从机在检测到复位脉冲后,会在一定时间后拉低数据线产生应答脉冲,表示它在线。

二、设备寻址--ROM操作指令

1、在检测到应答脉冲后,主机可以发出ROM(寻址)命令,主设备通过ROM读取操作读取每个设备的64位唯一地址,然后可以对特定设备发出命令,这些命令与从机设备的唯一ROM代码相关,允许主机指定操作某个从机设备。

2、忽略ROM指令(CCh):这条指令允许总线控制器不用提供64 位ROM 编码就使用功能指令。在单点总线情况下使用该命令,器件无需发回64 位ROM 编码,从而节省了时间。如果总线上有不止一只从机,若发出忽略ROM指令,由于多只从机同时传送信号,总线上就会发生数据冲突。

2、在发出ROM命令后,主机可以发出功能命令,例如读取或写入数据,启动温度转换等。

三、信号时序与数据读写

One-Wire协议比较简单,通常直接在硬件层次进行通信。主设备通过控制总线电压变化来进行数据读写,并通过时间间隔来确定数据的值。

1、单总线信号类型:复位脉冲、存在脉冲、写0、写1、读0、读1

2、定义了严格的信号时序,包括复位脉冲、写0和写1的时隙,以及读时隙。这些时隙定义了数据的采样和传输时间。

3、 通过总线的拉低或释放来表示二进制的0和1,并通过特定的时序判断数据位。

4、写操作:主设备通过控制总线的高低电平以及时隙来写入数据,低电平表示“0”,高电平表示“1”。


5、读操作:主设备将总线拉低后释放,从设备根据要传送的数据位是否为1决定是否拉低总线。

 详细时序图如下

读取DS18B20数据

 

DS18B20驱动代码

//DS18B20驱动代码
//IO方向设置
#define DS18B20_IO_IN()  {GPIOA->CRH&=0XFFFF0FFF;GPIOA->CRH|=8<<12;}
#define DS18B20_IO_OUT() {GPIOA->CRH&=0XFFFF0FFF;GPIOA->CRH|=3<<12;}

//IO操作函数											   
#define	DS18B20_DQ_OUT PAout(11) //数据端口	PA11
#define	DS18B20_DQ_IN  PAin(11)  //数据端口	PA11

//复位DS18B20
void DS18B20_Rst(void)	   	
{                 
	DS18B20_IO_OUT(); 	//SET PA11 OUTPUT
    DS18B20_DQ_OUT=0; 	//拉低DQ
    delay_us(750);    	//拉低750us
    DS18B20_DQ_OUT=1; 	//DQ=1 
	delay_us(15);     	//15US
}

//等待DS18B20的回应
//返回1:未检测到DS18B20的存在
//返回0:存在
u8 DS18B20_Check(void) 	   
{   
	u8 retry=0;
	DS18B20_IO_IN();	//SET PA11 INPUT	 
    while (DS18B20_DQ_IN&&retry<200)
	{
		retry++;
		delay_us(1);
	};	 
	if(retry>=200)return 1;
	else retry=0;
    while (!DS18B20_DQ_IN&&retry<240)
	{
		retry++;
		delay_us(1);
	};
	if(retry>=240)return 1;	    
	return 0;
}

//从DS18B20读取一个位
//返回值:1/0
u8 DS18B20_Read_Bit(void) 	 
{
    u8 data;
	DS18B20_IO_OUT();	//SET PA11 OUTPUT
    DS18B20_DQ_OUT=0; 
	delay_us(2);
    DS18B20_DQ_OUT=1; 
	DS18B20_IO_IN();	//SET PA11 INPUT
	delay_us(12);
	if(DS18B20_DQ_IN)data=1;
    else data=0;	 
    delay_us(50);           
    return data;
}

//从DS18B20读取一个字节
//返回值:读到的数据
u8 DS18B20_Read_Byte(void)     
{        
    u8 i,j,dat;
    dat=0;
	for (i=1;i<=8;i++) 
	{
        j=DS18B20_Read_Bit();
        dat=(j<<7)|(dat>>1);
    }						    
    return dat;
}

//写一个字节到DS18B20
//dat:要写入的字节
void DS18B20_Write_Byte(u8 dat)     
{             
    u8 j;
    u8 testb;
	DS18B20_IO_OUT();	//SET PA11 OUTPUT;
    for (j=1;j<=8;j++) 
	{
        testb=dat&0x01;
        dat=dat>>1;
        if (testb) 
        {
            DS18B20_DQ_OUT=0;	// Write 1
            delay_us(2);                            
            DS18B20_DQ_OUT=1;
            delay_us(60);             
        }
        else 
        {
            DS18B20_DQ_OUT=0;	// Write 0
            delay_us(60);             
            DS18B20_DQ_OUT=1;
            delay_us(2);                          
        }
    }
}

//开始温度转换
void DS18B20_Start(void) 
{   						               
    DS18B20_Rst();	   
	DS18B20_Check();	 
    DS18B20_Write_Byte(0xcc);	// skip rom
    DS18B20_Write_Byte(0x44);	// convert
} 

//初始化DS18B20的IO口 DQ 同时检测DS的存在
//返回1:不存在
//返回0:存在    	  
u8 DS18B20_Init(void)
{
 	GPIO_InitTypeDef  GPIO_InitStructure;
 	
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	 //使能PORTA口时钟 
	
 	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;				//PORTA.11 推挽输出
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		  
 	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 	GPIO_Init(GPIOA, &GPIO_InitStructure);

 	GPIO_SetBits(GPIOA,GPIO_Pin_11);    //输出1

	DS18B20_Rst();

	return DS18B20_Check();
}  

//从ds18b20得到温度值
//精度:0.1C
//返回值:温度值 (-550~1250) 
short DS18B20_Get_Temp(void)
{
    u8 temp;
    u8 TL,TH;
	short tem;
    DS18B20_Start ();  			// ds1820 start convert
    DS18B20_Rst();
    DS18B20_Check();	 
    DS18B20_Write_Byte(0xcc);	// skip rom
    DS18B20_Write_Byte(0xbe);	// convert	    
    TL=DS18B20_Read_Byte(); 	// LSB   
    TH=DS18B20_Read_Byte(); 	// MSB  
	    		  
    if(TH>7)
    {
        TH=~TH;
        TL=~TL; 
        temp=0;					//温度为负  
    }else temp=1;				//温度为正	  	  
    tem=TH; 					//获得高八位
    tem<<=8;    
    tem+=TL;					//获得底八位
    tem=(float)tem*0.625;		//转换     
	if(temp)return tem; 		//返回温度值
	else return -tem;    
}

 读取DS18B20的数据

//读取DS18B20的数据
 int main(void)
 {	 	    
	short temperature;    	   

	delay_init();	    	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	uart_init(115200);	 	//串口初始化为 115200
 	while(DS18B20_Init())	//DS18B20初始化	
	{
		delay_ms(200);
 
	}								   
	while(1)
	{	    	    
			temperature=DS18B20_Get_Temp();	
			printf("temperature=%d.%dC\r\n",temperature/10,temperature%10);
			delay_ms(100);
	}
}

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐