完美实现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\r\n",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!\r\n");
}
printf("DS18B20 Ready!\r\n");
while(1)
{
DS18B20_Search_Rom();
printf("DS18B20_SensorNum:%d\r\n",DS18B20_SensorNum);
for(num=0;num<DS18B20_SensorNum;num++)
{
printf("ID:%02x%02x%02x%02x%02x%02x%02x%02x TM:%.2f\r\n",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("\r\n");
Delay_s(2);
}
}
运行结果如图:
帮严博士出本科题的时候,出了一个DS18B20的分布式温度检测系统,要求肯定不仅仅是这篇文章的简略例子了。不仅单总线,一块单片机还要挂多总线,实现更多传感器数据采集,最好还配上上位机,反正把自己能想到的东西都加进来了,把一个简单的DS18B20包装得高大上。
完美实现STM32单总线挂多个DS18B20的更多相关文章
- DS18B20 for STM32 源代码 【worldsing笔记】
DS18B20是DALLAS公司生产的一线式数字温度传感器,具有3引脚TO-92小体积封装形式:温度测量范围为-55℃-+125℃,可编程为9位-12位A/D转换精度,测温分辨率可达0.0625℃.主 ...
- 「雕爷学编程」Arduino动手做(39)——DS18B20温度传感器
37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的.鉴于本人手头积累了一些传感器和模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里 ...
- STM32驱动DS18B20
DS18B20 是由 DALLAS 半导体公司推出的一种的“一线总线”接口的温度传感器.与传 统的热敏电阻等测温元件相比,它是一种新型的体积小.适用电压宽.与微处理器接口简单的 数字化温度传感器.一线 ...
- 1-wire单总线DS18B20
要想实现单总线通信,每一个挂在总线上的从机必须拥有开路或3态输出.单总线DS18B20的DQ引脚用内部电路实现了开漏输出,其等效电路如下图: 当单片机IO引脚配置为 mcu IO引脚 电流流向 DS1 ...
- 【蓝桥杯单片机11】单总线温度传感器DS18B20的基本操作
[蓝桥杯单片机11]单总线温度传感器DS18B20的基本操作 广东职业技术学院 欧浩源 单总线数字温度传感器DS18B20几乎成了各类单片机甚至ARM实验板的标配模块来,在蓝桥杯的往届省赛和国赛中,这 ...
- 玩转X-CTR100 l STM32F4 l DS18B20单总线温度传感器
我造轮子,你造车,创客一起造起来!塔克创新资讯[塔克社区 www.xtark.cn ][塔克博客 www.cnblogs.com/xtark/ ] 本文介绍X-CTR100控制器 扩展DS1 ...
- stm32 ds18b20 温度传感器
相关文章:http://blog.csdn.net/zhangxuechao_/article/details/74991985 举例 void DS18B20_in() { GPIO_InitTyp ...
- TCP/IP协议学习(三) STM32中ETH驱动配置注意事项
1.MII/RMII/SMI接口连接和配置 SMI又称站点管理接口,用于cpu与外置PHY芯片通讯,配置相关参数,包含MDC和MDIO两个管脚(CPU上有对应引脚,当然用普通GPIO口模拟SMI管理也 ...
- 基于ARM-LINUX的温度传感器驱动-DS18B20
转载:http://blog.csdn.net/ayangke/article/details/6883244 作者:冯建,华清远见嵌入式学院讲师. DS18B20数字温度传感器接线方便,封装成后可应 ...
随机推荐
- Visio图像应用
图像插入: 直接搜索然后插入 CAD是工程绘图. CAD属性设置框 下面是图像编辑: 通过格式中的旋转进行调整 但是CAD格式的图没有格式 图片可以设置题注 图片层次的使用 CAD图片颜色的修改在 图 ...
- FPGA之IO信号类型深入理解
在FPGA设计开发中,很多场合会遇到同一根信号既可以是输入信号,又可以是输出信号,即IO类型(Verilog定义成inout). 对于inout型的信号,我们既可以使用FPGA原语来实现,也可以使用V ...
- ubuntu conda install ERROR missing write permission错误
报错: ondaIOError: Missing write permissions in: /usr/local/anaconda3 # # You don't appear to have the ...
- 【题解】CTS2019珍珠(二项式反演+卷积)
[题解]CTS2019珍珠 题目就是要满足这样一个条件\(c_i\)代表出现次数 \[ \sum {[\dfrac {c_i } 2]} \ge 2m \] 显然\(\sum c_i=n\)所以,而且 ...
- Codeforces Round #524 (Div. 2)(前三题题解)
这场比赛手速场+数学场,像我这样读题都读不大懂的蒟蒻表示呵呵呵. 第四题搞了半天,大概想出来了,但来不及(中途家里网炸了)查错,于是我交了两次丢了100分.幸亏这次没有掉rating. 比赛传送门:h ...
- 基于Arduino的按键控制LED实验
I/O 口的意思即为INPUT 接口和OUTPUT 接口,到目前为止我们设计的小灯实验都还只是应用到Arduino 的I/O 口的输出功能,这个实验我们来尝试一下使用Arduino的I/O 口的输入功 ...
- Docker入门之快速安装和卸载使用Centos7
一.检查内核版本 注意:Docker要求操作系统必须是64位,如果使用的Centos内核版本为3.10以上 执行命令:uname -r 二.安装依赖软件包 执行命令:yum install -y y ...
- 【转】HTML5+WebGL:构建 3D 网页新世界
今年下半年, HTML5 和 WebGL 变成极热门词语,3D 网页来势汹汹.主流的浏览器 Google Chrome 以及 Mozilla Firefox 均致力于 HTML5+WebGL 的 3D ...
- 优化webpack构建时间的小技巧
在之前工作的地方,我们一直使用webpck去构建.但是,经过长达四年的更新迭代,每个人都在同一个项目中做了不同的操作和更新,这导致我们生产构建时间达到了惊人的一分半,watch模式的rebuild也达 ...
- rest实践2
通过url读取图片资源 其他的上传图片和对应的添加信息到数据库等的相关操作则引入crud来操作,编写相关代码的话==>要引入相关的crud包.