zoukankan      html  css  js  c++  java
  • 完美实现STM32单总线挂多个DS18B20

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

      主要的DS18B20时序代码没变,增加了搜索ROM函数,获取温度时先匹配ID。

      核心代码如下:

      DS18B20.c文件代码:

    #include "DS18B20.h"
    #include "Delay.h"
    #include "stdio.h" // printf用
    
    #define DS18B20_GPIO_NUM				 GPIO_Pin_5
    #define DS18B20_GPIO_X					GPIOC
    #define RCC_APB2Periph_DS18B20_GPIO_X	RCC_APB2Periph_GPIOC
    
    #define DS18B20_DQ_OUT_Low			GPIO_ResetBits(DS18B20_GPIO_X,DS18B20_GPIO_NUM) 
    #define DS18B20_DQ_OUT_High			GPIO_SetBits(DS18B20_GPIO_X,DS18B20_GPIO_NUM) 
    #define DS18B20_DQ_IN				GPIO_ReadInputDataBit(DS18B20_GPIO_X,DS18B20_GPIO_NUM) 
    
    #define MaxSensorNum 8
    unsigned char DS18B20_ID[MaxSensorNum][8];	// 存检测到的传感器DS18B20_ID的数组,前面的维数代表单根线传感器数量上限
    unsigned char DS18B20_SensorNum;			// 检测到的传感器数量(从1开始,例如显示1代表1个,8代表8个)
    
    // 配置DS18B20用到的I/O口
    void DS18B20_GPIO_Config(void)
    {
    	GPIO_InitTypeDef GPIO_InitStructure;
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_DS18B20_GPIO_X, ENABLE);
    	GPIO_InitStructure.GPIO_Pin = DS18B20_GPIO_NUM;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(DS18B20_GPIO_X, &GPIO_InitStructure);
    	GPIO_SetBits(DS18B20_GPIO_X, DS18B20_GPIO_NUM);
    }
    
    // 引脚输入
    void DS18B20_Mode_IPU(void)
    {
    	GPIO_InitTypeDef GPIO_InitStructure;
    	GPIO_InitStructure.GPIO_Pin = DS18B20_GPIO_NUM;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    	GPIO_Init(DS18B20_GPIO_X, &GPIO_InitStructure);
    }
    
    // 引脚输出
    void DS18B20_Mode_Out(void)
    {
    	GPIO_InitTypeDef GPIO_InitStructure;
    	GPIO_InitStructure.GPIO_Pin = DS18B20_GPIO_NUM;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(DS18B20_GPIO_X, &GPIO_InitStructure);
    
    }
    
    // 复位,主机给从机发送复位脉冲
    void DS18B20_Rst(void)
    {
    	DS18B20_Mode_Out();
    	DS18B20_DQ_OUT_Low;		// 产生至少480us的低电平复位信号
    	Delay_us(480);
    	DS18B20_DQ_OUT_High;	// 在产生复位信号后,需将总线拉高
    	Delay_us(15);
    }
    
    // 检测从机给主机返回的应答脉冲。从机接收到主机的复位信号后,会在15~60us后给主机发一个应答脉冲
    u8 DS18B20_Answer_Check(void)
    {
    	u8 delay = 0;
    	DS18B20_Mode_IPU(); // 主机设置为上拉输入
    	// 等待应答脉冲(一个60~240us的低电平信号 )的到来
    	// 如果100us内,没有应答脉冲,退出函数,注意:从机接收到主机的复位信号后,会在15~60us后给主机发一个存在脉冲
    	while (DS18B20_DQ_IN&&delay < 100)
    	{
    		delay++;
    		Delay_us(1);
    	}
    	// 经过100us后,如果没有应答脉冲,退出函数
    	if (delay >= 100)//Hu200
    		return 1;
    	else
    		delay = 0;
    	// 有应答脉冲,且存在时间不超过240us
    	while (!DS18B20_DQ_IN&&delay < 240)
    	{
    		delay++;
    		Delay_us(1);
    	}
    	if (delay >= 240)
    		return 1;
    	return 0;
    }
    
    // 从DS18B20读取1个位
    u8 DS18B20_Read_Bit(void)
    {
    	u8 data;
    	DS18B20_Mode_Out();
    	DS18B20_DQ_OUT_Low; // 读时间的起始:必须由主机产生 >1us <15us 的低电平信号
    	Delay_us(2);
    	DS18B20_DQ_OUT_High;
    	Delay_us(12);
    	DS18B20_Mode_IPU();// 设置成输入,释放总线,由外部上拉电阻将总线拉高
    	if (DS18B20_DQ_IN)
    		data = 1;
    	else
    		data = 0;
    	Delay_us(50);
    	return data;
    }
    
    // 从DS18B20读取2个位
    u8 DS18B20_Read_2Bit(void)//读二位 子程序
    {
    	u8 i;
    	u8 dat = 0;
    	for (i = 2; i > 0; i--)
    	{
    		dat = dat << 1;
    		DS18B20_Mode_Out();
    		DS18B20_DQ_OUT_Low;
    		Delay_us(2);
    		DS18B20_DQ_OUT_High;
    		DS18B20_Mode_IPU();
    		Delay_us(12);
    		if (DS18B20_DQ_IN)	dat |= 0x01;
    		Delay_us(50);
    	}
    	return dat;
    }
    
    // 从DS18B20读取1个字节
    u8 DS18B20_Read_Byte(void)	// read one byte
    {
    	u8 i, j, dat;
    	dat = 0;
    	for (i = 0; i < 8; i++)
    	{
    		j = DS18B20_Read_Bit();
    		dat = (dat) | (j << i);
    	}
    	return dat;
    }
    
    // 写1位到DS18B20
    void DS18B20_Write_Bit(u8 dat)
    {
    	DS18B20_Mode_Out();
    	if (dat)
    	{
    		DS18B20_DQ_OUT_Low;// Write 1
    		Delay_us(2);
    		DS18B20_DQ_OUT_High;
    		Delay_us(60);
    	}
    	else
    	{
    		DS18B20_DQ_OUT_Low;// Write 0
    		Delay_us(60);
    		DS18B20_DQ_OUT_High;
    		Delay_us(2);
    	}
    }
    
    // 写1字节到DS18B20
    void DS18B20_Write_Byte(u8 dat)
    {
    	u8 j;
    	u8 testb;
    	DS18B20_Mode_Out();
    	for (j = 1; j <= 8; j++)
    	{
    		testb = dat & 0x01;
    		dat = dat >> 1;
    		if (testb)
    		{
    			DS18B20_DQ_OUT_Low;// 写1
    			Delay_us(10);
    			DS18B20_DQ_OUT_High;
    			Delay_us(50);
    		}
    		else
    		{
    			DS18B20_DQ_OUT_Low;// 写0
    			Delay_us(60);
    			DS18B20_DQ_OUT_High;// 释放总线
    			Delay_us(2);
    		}
    	}
    }
    
    //初始化DS18B20的IO口,同时检测DS的存在
    u8 DS18B20_Init(void)
    {
    	DS18B20_GPIO_Config();
    	DS18B20_Rst();
    	return DS18B20_Answer_Check();
    }
    
    // 从ds18b20得到温度值,精度:0.1C,返回温度值(-550~1250),Temperature1返回浮点实际温度
    float DS18B20_Get_Temp(u8 i)
    {
    	//u8 flag;
    	u8 j;//匹配的字节
    	u8 TL, TH;
    	short Temperature;
    	float Temperature1;
    	DS18B20_Rst();
    	DS18B20_Answer_Check();
    	DS18B20_Write_Byte(0xcc);// skip rom
    	DS18B20_Write_Byte(0x44);// convert
    	DS18B20_Rst();
    	DS18B20_Answer_Check();
    
    	// DS18B20_Write_Byte(0xcc);// skip rom
    	//匹配ID,i为形参
    	DS18B20_Write_Byte(0x55);
    	for (j = 0; j < 8; j++)
    	{
    		DS18B20_Write_Byte(DS18B20_ID[i][j]);
    	}
    
    	DS18B20_Write_Byte(0xbe);// convert
    	TL = DS18B20_Read_Byte(); // LSB   
    	TH = DS18B20_Read_Byte(); // MSB  
    	if (TH & 0xfc)
    	{
    		//flag=1;
    		Temperature = (TH << 8) | TL;
    		Temperature1 = (~Temperature) + 1;
    		Temperature1 *= 0.0625;
    	}
    	else
    	{
    		//flag=0;
    		Temperature1 = ((TH << 8) | TL)*0.0625;
    	}
    	return Temperature1;
    }
    
    // 自动搜索ROM
    void DS18B20_Search_Rom(void)
    {
    	u8 k, l, chongtuwei, m, n, num;
    	u8 zhan[5];
    	u8 ss[64];
    	u8 tempp;
    	l = 0;
    	num = 0;
    	do
    	{
    		DS18B20_Rst(); //注意:复位的延时不够
    		Delay_us(480); //480、720
    		DS18B20_Write_Byte(0xf0);
    		for (m = 0; m < 8; m++)
    		{
    			u8 s = 0;
    			for (n = 0; n < 8; n++)
    			{
    				k = DS18B20_Read_2Bit();//读两位数据
    
    				k = k & 0x03;
    				s >>= 1;
    				if (k == 0x01)//01读到的数据为0 写0 此位为0的器件响应
    				{
    					DS18B20_Write_Bit(0);
    					ss[(m * 8 + n)] = 0;
    				}
    				else if (k == 0x02)//读到的数据为1 写1 此位为1的器件响应
    				{
    					s = s | 0x80;
    					DS18B20_Write_Bit(1);
    					ss[(m * 8 + n)] = 1;
    				}
    				else if (k == 0x00)//读到的数据为00 有冲突位 判断冲突位
    				{
    					//如果冲突位大于栈顶写0 小于栈顶写以前数据 等于栈顶写1
    					chongtuwei = m * 8 + n + 1;
    					if (chongtuwei > zhan[l])
    					{
    						DS18B20_Write_Bit(0);
    						ss[(m * 8 + n)] = 0;
    						zhan[++l] = chongtuwei;
    					}
    					else if (chongtuwei < zhan[l])
    					{
    						s = s | ((ss[(m * 8 + n)] & 0x01) << 7);
    						DS18B20_Write_Bit(ss[(m * 8 + n)]);
    					}
    					else if (chongtuwei == zhan[l])
    					{
    						s = s | 0x80;
    						DS18B20_Write_Bit(1);
    						ss[(m * 8 + n)] = 1;
    						l = l - 1;
    					}
    				}
    				else
    				{
    					//没有搜索到
    				}
    			}
    			tempp = s;
    			DS18B20_ID[num][m] = tempp; // 保存搜索到的ID
    		}
    		num = num + 1;// 保存搜索到的个数
    	} while (zhan[l] != 0 && (num < MaxSensorNum));
    	DS18B20_SensorNum = num;
    	//printf("DS18B20_SensorNum=%d
    ",DS18B20_SensorNum);
    }

      DS18B20.h文件代码:

    #ifndef __DS18B20_H
    #define __DS18B20_H 
      
    #include "stm32f10x.h"
    
    u8 DS18B20_Init(void);
    u8 DS18B20_Read_Byte(void);
    u8 DS18B20_Read_Bit(void);
    u8 DS18B20_Answer_Check(void);
    void  DS18B20_GPIO_Config(void);
    void  DS18B20_Mode_IPU(void);
    void  DS18B20_Mode_Out(void);
    void  DS18B20_Rst(void);
    void  DS18B20_Search_Rom(void);
    void  DS18B20_Write_Byte(u8 dat);
    float DS18B20_Get_Temp(u8 i);
    
    #endif
      main.c文件代码:

    #include "stm32f10x.h"
    #include "stdio.h"
    #include "string.h"//strlen、memset用到
    #include "USART.h"
    #include "Delay.h"
    #include "DS18B20.h"
    
    extern unsigned char DS18B20_ID[8][8];//检测到的传感器ID存数组
    extern unsigned char DS18B20_SensorNum;
    
    int main(void)
    {
    	u8 num=0;
    	USART1_init(9600);
    	while(DS18B20_Init())//初始化DS18B20,兼检测18B20
    	{
    		printf("DS18B20 Check Failed!
    ");  
    	}
    	printf("DS18B20 Ready!
    ");
    	while(1)
    	{	  
    		DS18B20_Search_Rom();
    		printf("DS18B20_SensorNum:%d
    ",DS18B20_SensorNum);
    	  for(num=0;num<DS18B20_SensorNum;num++)
    		{
    			printf("ID:%02x%02x%02x%02x%02x%02x%02x%02x TM:%.2f
    ",DS18B20_ID[num][0],DS18B20_ID[num][1],DS18B20_ID[num][2],DS18B20_ID[num][3],DS18B20_ID[num][4],DS18B20_ID[num][5],DS18B20_ID[num][6],DS18B20_ID[num][7],DS18B20_Get_Temp(num));
    		}
    		printf("
    ");
    		Delay_s(2);
    	}	
    }

      运行结果如图:


      帮严博士出本科题的时候,出了一个DS18B20的分布式温度检测系统,要求肯定不仅仅是这篇文章的简略例子了。不仅单总线,一块单片机还要挂多总线,实现更多传感器数据采集,最好还配上上位机,反正把自己能想到的东西都加进来了,把一个简单的DS18B20包装得高大上。

  • 相关阅读:
    JAVA理解逻辑程序的书上全部重要的习题
    体检套餐管理系统的综合版
    一路奔跑,一路寻找
    员工考勤信息管理小程序
    枚举的独特强大之处
    C#中HashTable的用法
    项目经理评分
    若想成功,请记住!
    数组的经典例子
    S1的小成果:MyKTV系统
  • 原文地址:https://www.cnblogs.com/sandeepin/p/12236536.html
Copyright © 2011-2022 走看看