STM32F4实现单总线挂多个国产温度传感器(QT18B20M)

网上关于STM32F1相关DS18B20的例程,虽然F4与F1代码相差不大,但可供新手开发者借鉴;

一般例程都是检测一个传感器,代码一般都是跳过ROM检测,直接获取温度值。这种写法并不适用于单总线上挂载多个DS18B20的情况,本文针对这种情况完善的单总线挂多个DS18B20检测,实现获取每个DS18B20的序列号和温度。

  国产18B20在配置IO相关内容略有区别,除了基础的时序代码内容外,增加了读取位操作、检测总线传感器数目以及读取指定传感器温度。

  核心代码如下:

       QT18B20M.c文件代码:

/***********************************************************************
文件名称:QT18B20.C   功放温度
功    能:完成对对QT18B20的基本操作
编写时间:2024.3.12
编 写 人:
注    意:
***********************************************************************/
#include "QT18B20PA.h"
#include "delay.h"
#include "M_Global.h"

/* 定义GPIO端口     PD0 */
#define RCC_DQ		RCC_AHB1Periph_GPIOC
#define PORT_DQ		GPIOC
#define PIN_DQ		GPIO_Pin_12


//IO方向设置
#define QT18B20M_IO_IN()  {GPIOD->MODER&=~(3<<(12*2));GPIOD->MODER|=0<<12*2;}	//PG9输入模式
#define QT18B20M_IO_OUT() {GPIOD->MODER&=~(3<<(12*2));GPIOD->MODER|=1<<12*2;} 	//PG9输出模式
 
IO操作函数											   
#define	QT18B20M_DQ_OUT PCout(12) //数据端口	PG9
#define	QT18B20M_DQ_IN  PCin(12)  //数据端口	PG9 
  
//复位QT18B20M
void QT18B20M_Rst(void)	   
{                 
	QT18B20M_IO_OUT(); //SET PG11 OUTPUT
  QT18B20M_DQ_OUT=0; //拉低DQ
  DelayUs(750);    //拉低750us
  QT18B20M_DQ_OUT=1; //DQ=1 
	DelayUs(15);     //15US
}
//等待QT18B20M的回应
//返回1:未检测到QT18B20M的存在
//返回0:存在
u8 QT18B20M_Check(void) 	   
{   
	u8 retry=0;
	QT18B20M_IO_IN();//SET PG11 INPUT	 
    while (QT18B20M_DQ_IN&&retry<200)
	{
		retry++;
		DelayUs(1);
	};	 
	if(retry>=200)return 1;
	else retry=0;
    while (!QT18B20M_DQ_IN&&retry<240)
	{
		retry++;
		DelayUs(1);
	};
	if(retry>=240)return 1;	    
	return 0;
}
//从QT18B20M读取一个位
//返回值:1/0
u8 QT18B20M_Read_Bit(void) 			 // read one bit
{
  u8 data;
	QT18B20M_IO_OUT();//SET PG11 OUTPUT
  QT18B20M_DQ_OUT=0; 
	DelayUs(2);
  QT18B20M_DQ_OUT=1; 
	QT18B20M_IO_IN();//SET PG11 INPUT
	DelayUs(12);
	if(QT18B20M_DQ_IN)data=1;
  else data=0;	 
  DelayUs(50);           
  return data;
}

u8 QT18B20M_2Read_Bit(void)
{
	u8 data=0,i;
	for (i = 0;i<2;i++)
	{
		data <<= 1;
		if(QT18B20M_Read_Bit())
		{
			data |=1;
		}
		DelayUs(2);
	}
	//printf("data:0x%x\r\n",data);
	return data;
}
//从QT18B20M读取一个字节
//返回值:读到的数据
u8 QT18B20M_Read_Byte(void)    // read one byte
{        
    u8 i,j,dat;
    dat=0;
	for (i=1;i<=8;i++) 
	{
        j=QT18B20M_Read_Bit();
        dat=(j<<7)|(dat>>1);
    }						    
    return dat;
}


//写入一个位
//dat:要写入的字节
void QT18B20M_Write_Bit(u8 dat)
{
	QT18B20M_IO_OUT();	//SET PG11 OUTPUT;
	if(dat&0x01)
	{
		QT18B20M_DQ_OUT=0;	// Write 1
		DelayUs(2);                            
		QT18B20M_DQ_OUT=1;
		DelayUs(60);  
	}
	else
	{
		QT18B20M_DQ_OUT=0;	// Write 0
		DelayUs(60);             
		QT18B20M_DQ_OUT=1;
		DelayUs(2);
	}
}



//写一个字节到QT18B20M
//dat:要写入的字节
void QT18B20M_Write_Byte(u8 dat)     
 {             
    u8 j;
    u8 testb;
	  QT18B20M_IO_OUT();//SET PG11 OUTPUT;
    for (j=1;j<=8;j++) 
	{
        testb=dat&0x01;
        dat=dat>>1;
        if (testb) 
        {
            QT18B20M_DQ_OUT=0;// Write 1
            DelayUs(2);                            
            QT18B20M_DQ_OUT=1;
            DelayUs(60);             
        }
        else 
        {
            QT18B20M_DQ_OUT=0;// Write 0
            DelayUs(60);             
            QT18B20M_DQ_OUT=1;
            DelayUs(2);                          
        }
    }
}
//开始温度转换
void QT18B20M_Start(void)// ds1820 start convert
{   						               
    QT18B20M_Rst();	   
	  QT18B20M_Check();	 
    QT18B20M_Write_Byte(0xcc);// skip rom
    QT18B20M_Write_Byte(0x44);// convert
} 
//初始化QT18B20M的IO口 DQ 同时检测DS的存在
//返回1:不存在
//返回0:存在    	 
u8 QT18B20M_Init(void)
{
	GPIO_InitTypeDef  GPIO_InitStructure;

  RCC_AHB1PeriphClockCmd(RCC_DQ, ENABLE);//使能GPIOG时钟

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;		/* 设为输出口 */
	GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;		/* 设为开漏模式 */
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;	/* 上下拉电阻不使能 */
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	/* IO口最大速度 */

	GPIO_InitStructure.GPIO_Pin = PIN_DQ;
	GPIO_Init(PORT_DQ, &GPIO_InitStructure);
	
	
	
 	QT18B20M_Rst();
	return QT18B20M_Check();
}  
//从QT18B20M得到温度值
//精度:0.1C
//返回值:温度值 (-550~1250) 
float QT18B20M_Get_Temp(u8 arr[8])
{
	u8 temp;
	u8 TL,TH;
	short tem;
	float t;
	QT18B20M_Start ();  			// ds1820 start convert
	QT18B20M_Rst();
	QT18B20M_Check();	 

	QT18B20M_Write_Byte(0x55);        //匹配ROM指令
	for(temp = 0;temp < 8;temp ++)   		//发送8个字节的序列号   
	{  
		QT18B20M_Write_Byte(arr[temp]);  
	}  
	DelayUs(10);  
	QT18B20M_Write_Byte(0xbe);    //读取温度指令 
	TL = QT18B20M_Read_Byte();    //低8位数据
	TH = QT18B20M_Read_Byte();    //高8位数据
	if(TH>7)
	{
		TH=~TH;
		TL=~TL; 
		temp=0;//温度为负
	}else temp=1;//温度为正 	  
	tem=TH; //获取高8位
	tem<<=8;    
	tem|=TL;//获取低8位
	t=(float)tem*0.0625;//转换 
	if(temp)return t; //返回温度值
	else return -(t+1);    

}

/************************************************************************************************************************* 
*函数名:u8 QT18B20M_SearchROM(u8 (*pID)[8],u8 Num)   
*功能  :查询QT18B20M的ROM
*参数  :(1)、 pID:总线上QT18B20M的ID存储的缓冲区指针
				(2)、 Num:QT18B20M的个数,在MAXNUM中有定义
*返回  :搜索到总线上QT18B20M的个数
*************************************************************************************************************************/  

u8 QT18B20M_SearchROM(u8 (*pID)[8])
{
		u8 k,m,n,x=0; 
		u8 s=0,conflict=0;  
    u8 num = 0; 
		u8 Value[64]={0};		//每一位的值
		u8 Flag[MAXNUM]={0};//标志位		
    while(num<MAXNUM)  
    {  
        QT18B20M_Rst();								//复位QT18B20M总线  
				QT18B20M_Check();	 						//等待回应
        QT18B20M_Write_Byte(0xF0);	//搜索ROM  
				x=0;			
        for(m=0;m<8;m++)  
        {  
					for(n=0;n<8;n++)  
					{  
						k=QT18B20M_2Read_Bit();		// 读两位数据
						k&=0x03;  
						s= s>>1;  
						switch(k)
						{
							case 0:						//如果读取到的数据为00,则有冲突,需进行冲突位判断  
								conflict=1;			//置1说明至少2台设备
								Flag[x]=8*m+n;	//表明在8*m+n位有冲突
								if(Value[Flag[x]]==0)QT18B20M_Write_Bit(0);//写0,使总线上为0的器件响应   
								else
								{
									s=s|0x80;  
									QT18B20M_Write_Bit(1);//写1,使总线上为1的器件响应    
								}
								x++;
								break;
							case 1:								 //0000 0001 如果读到的数据为0
								QT18B20M_Write_Bit(0);//写0,使总线上为0的器件响应  
								break;
							case 2:								 //0000 0010 如果读到的数据为1
								s=s|0x80;  
								QT18B20M_Write_Bit(1);//写1,使总线上为1的器件响应  
								break;
							case 3:								 //0000 0011 ,说明没有设备存在
								return 0; 					 //搜索完成,返回搜索到的个数
							default:							 //其他结果,忽略
								break;
						}
						DelayUs(5);
					}  
					pID[num][m]=s;
					//printf("pID[%d][%d]=0x%02x\r\n",num,m,s);
					s=0;
        }
				if(conflict==0)return 1;//如果冲突标志位为0,说明只有一台设备
				for(n=0;n<x;n++)		//排除算法
				{
					if(n)
					{
						for(m=0;m<n;m++)Value[Flag[x-m-1]]=0;
					}
					if(Value[Flag[x-n-1]]==0)
					{
						Value[Flag[x-n-1]]=1;
						break;
					}
				}
				if(n==x)return ++num;
				num++;
    }  
    return num;     //返回搜索到的个数 
}



/*************************************************************************************************************************
*函数        	:	s16 QT18B20M_ReadDesignateTemper(u8 pID[8])
*功能        	:	读取指定ID的QT18B20M温度
*参数        	:	pID:QT18B20M ID,必须事先知道,如果不知道请启动ROM搜索
*返回        	:	温度值
*依赖			: 	底层宏定义
*说明        	:	温度值扩大了100倍,温度值是个有符号数.
*************************************************************************************************************************/
s16 QT18B20M_ReadDesignateTemper(u8 pID[8])
{
	u8 th, tl;
	s16 data;
	
//	if(QT18B20M_Rst() == FALSE)	
//	{
//		return 0xffff;				//返回错误
//	}

	QT18B20M_Write_Byte(0xcc);		//跳过读序列号
	QT18B20M_Write_Byte(0x44);		//启动温度转换
	QT18B20M_Rst();
	QT18B20M_Write_Byte(0x55);		//发送序列号匹配命令
	for(data = 0;data < 8;data ++)	//发送8byte的序列号	
	{
	   QT18B20M_Write_Byte(pID[data]);
	}
	DelayUs(10);
	QT18B20M_Write_Byte(0xbe);	//读取温度
	tl = QT18B20M_Read_Byte();	//读取低八位
	th = QT18B20M_Read_Byte(); 	//读取高八位
	data = th;
	data <<= 8;
	data |= tl;
	data *= 6.25;				//温度值扩大100倍,精确到2位小数
	
	return data;
} 

QT18B20M.h文件代码:

/***********************************************************************
文件名称:QT18B20.H
功    能:完成对对QT18B20的基本操作
编写时间:2024.3.12
编 写 人:
注    意:
***********************************************************************/
#ifndef QT18B20PA_H
#define QT18B20PA_H

#include "stm32f4xx.h"
#define MAXNUM 12

void QT18B20M_Write_Bit(u8 dat);//写入一个位

u8 QT18B20M_2Read_Bit(void);//读出两个位
u8 QT18B20M_SearchROM(u8 (*pID)[8]);//搜索ROM
s16 QT18B20M_ReadDesignateTemper(u8 pID[8]);	//读取指定ID的QT18B20M温度
 	
u8 QT18B20M_Init(void);			//初始化QT18B20M
float QT18B20M_Get_Temp(u8 arr[8]);//获取温度
void QT18B20M_Start(void);		//开始温度转换
void QT18B20M_Write_Byte(u8 dat);//写入一个字节
u8 QT18B20M_Read_Byte(void);		//读出一个字节
u8 QT18B20M_Read_Bit(void);		//读出一个位
u8 QT18B20M_Check(void);			//检测是否存在QT18B20M
void QT18B20M_Rst(void);			//复位QT18B20M   

#endif

main.c文件代码:

#include "stm32f4xx.h"
#include "ds18b20.h"
#include "sys.h"
#include "delay.h"
#include <stdio.h>

#define DS18B20_NUM		4
u8 ID_Buff[DS18B20_NUM][8];
int main(void)
{
	OS_CPU_SR  cpu_sr;
	s16 temp;
	u8 buff[16];
	u8 i,j,num;

	SYSTEM_ClockInit(9);			//初始化系统时钟72MHz
	JTAG_Set(SWD_ENABLE);			//只开启SWD调试模式
	DevInit();


	uart_printf("start system ...\r\n\r\n");

	num = DS18B20_SearchROM(ID_Buff,DS18B20_NUM);
	uart_printf("总线上实际挂载DS18B20数量: %d\r\n",DS18B20_NUM);
	uart_printf("搜索到的DS18B20数量: %d\r\n",num);

	
	for(i = 0;i < num;i ++)
	{
		uart_printf("\r\n DS18B20 No%d ID: ",i);
		for(j = 0;j < 8;j ++)
		{
			uart_printf("%02X ",ID_Buff[i][j]);
		}
	}

	i = 0;
	while(1)
	{

		LED1 = ~LED1;
		Delay_MS(1000);
		temp = DS18B20_ReadDesignateTemper(ID_Buff[i ++]);
		uart_printf("\r\n DS18B20 No%d Temp:%d ",i,temp);
		if(i == 4)
		{
		 	i = 0;
			uart_printf("\r\n");
		}

	}
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值