训练题——DS18B20部分
Author:Cherry_Ywj
0. 前言
本文档以 DS18B20 为例,主要介绍如何针对一种传感器编写相应的驱动库,驱动是单片机开发中难度较大的一环。从看别人代码并对照 datasheet 开始,学会调用别人编写的库,然后尝试着自己写。
1. 基础内容
1.1 开漏输出
STM32 的输出模式有推挽输出和开漏输出,推挽输出已经使用的很熟练了,也很简单,而开漏输出有一些新的特性。
在开漏模式时,上管 P-MOS 始终关断,呈现高阻态,输出控制只控制下管 N-MOS。所以,开漏模式没法主动输出高电平。因此,一般在设置开漏模式时,需要设置上拉模式。当设置输出为高电平时,实际上高电平是上拉电阻提供的,而输出低电平时,导通 N-MOS 即可。
强上拉和弱上拉
弱上拉指的是上拉电阻比较大,想想电阻的串并联,上拉电阻比较大时,如果外接一个比较小的电阻至地,则输出的电压就会比较小。
因此,上拉电阻越小,上拉就越强。开漏输出的上拉电阻是比较弱的上拉(上拉电阻约为40kΩ),所以在 DS18B20 的数据线上需要加一个 4.7kΩ 左右的上拉电阻,这个在后面会提到。
上面是开漏输出的一个特性,第二个特性是它还可以读取当前的引脚状态,即当成输入模式使用。这在双向传输数据都在一根数据线上的通信过程中非常有用。
1.2 datasheet
在之后进行代码驱动编写时,需要认真阅读 DS18B20 的数据手册,这里放个中文版手册:
https://zhuanlan.zhihu.com/p/453052826
之后涉及到的手册里面的内容不再过多解释。现在解释几个重要的部分
- 总线释放
当 STM32 主动控制数据线(DQ)时,称 STM32 控制着总线;而 STM32 释放总线时,则将总线的控制权交给了从机(DS18B20)
如何释放总线?
前面提到了开漏输出的特性,将开漏输出设置为高电平即为释放总线,因为高电平是由上拉电阻给的,并不是 STM32 本身,控制权已经不在 STM32 处。
- LSB & MSB
DS18B20 的数据传输都是从低位传到高位。
2. 代码编写
2.1 微秒函数
在与 DS18B20 的通信过程中涉及到许多微秒级别的延时,这里嫖了一份代码,直接用就行
#define CPU_FREQUENCY_MHZ 72 // STM32时钟主频
void delay_us(__IO uint32_t delay)
{
int last, curr, val;
int temp;
while (delay != 0)
{
temp = delay > 900 ? 900 : delay;
last = SysTick->VAL;
curr = last - CPU_FREQUENCY_MHZ * temp;
if (curr >= 0)
{
do
{
val = SysTick->VAL;
}
while ((val < last) && (val >= curr));
}
else
{
curr += CPU_FREQUENCY_MHZ * 1000;
do
{
val = SysTick->VAL;
}
while ((val <= last) || (val > curr));
}
delay -= temp;
}
}
2.2 宏定义
#define GPIO_PORT GPIOC
#define GPIO_PIN GPIO_PIN_0
#define DQ_OUT(x) HAL_GPIO_WritePin(GPIO_PORT,GPIO_PIN,x)
#define DQ_IN() HAL_GPIO_ReadPin(GPIO_PORT,GPIO_PIN)
前面已经介绍到,开漏输出也可以当作输出,也可以当作输入使用。
2.3 基本时序配置
在与 DS18B20 通信的过程中,主要涉及几个方面
- 复位(又称初始化)
- DS18B20 响应
- 向 DS18B20 写入数据
- 从 DS18B20 读取数据
这些过程在 datasheet 都以提及,阅读下面代码时请对照 datasheet
2.3.1 复位
void DS18B20_Rst(void)
{
DQ_OUT(0);
delay_us(750);
DQ_OUT(1); //释放总线
delay_us(15);
}
2.3.2 DS18B20响应
//返回0:响应成功
uint8_t DS18B20_Check(void)
{
uint8_t temp=0;
while(DQ_IN()&&temp<200) //等待18B20拉低电平
{
temp++;
delay_us(1);
}
if(temp>=200) //如果超过200us电平还没被拉低,说明没检测到
return 1;
temp=0;
while(!DQ_IN()&&temp<240) //等待18B20拉低电平结束,电平重新为高
{
temp++;
delay_us(1);
}
if(temp>=240)
return 1;
return 0;
}
2.3.3 向 DS18B20 写入数据
void DS18B20_Write_Byte(uint8_t data)
{
uint8_t i=0;
uint8_t bit=0;
for(i=0;i<8;++i)
{
bit=data&0x01;
data=data>>1;
if(bit) //写1
{
DQ_OUT(0);
delay_us(2);
DQ_OUT(1);
delay_us(60);
}
else //写0
{
DQ_OUT(0);
delay_us(60);
DQ_OUT(1);
delay_us(2);
}
}
}
这里要说明一下为什么写 0 时最后需要拉高总线 2us,这是为了防止如果写入的数据一直是 0 时,超过 480 us 就会被当成复位信号从而把 DS18B20 复位了!
2.3.4 读取数据
读取数据比较复杂,需要先写好读取单个 bit 的函数,再读取一个 byte
//从18B20读取一个bit
uint8_t DS18B20_Read_Bit(void)
{
uint8_t bit;
DQ_OUT(0);
delay_us(2);
DQ_OUT(1);
delay_us(12);
bit=DQ_IN();
delay_us(50);
return bit;
}
//从18B20读取一个byte
uint8_t DS18B20_Read_Byte(void)
{
uint8_t i=0,bit=0,data=0;
for(i=0;i<8;++i)
{
bit=DS18B20_Read_Bit();
data=(bit<<7)|(data>>1);
}
return data;
}
2.4 温度读取
前面的基础工作都已经做好,现在来实现温度的读取吧
配置 DS18B20 完成指定任务需要三个阶段
- 初始化(复位)
- ROM命令
- DS18B20功能命令
三个步骤需要循环进行才能正常工作,每次只能执行一个 ROM 命令和功能指令
float DS18B20_Get_Temp(void)
{
uint8_t temp;
uint8_t TL,TH;
short tem;
DS18B20_Rst();
DS18B20_Check();
DS18B20_Write_Byte(0xcc); // skip rom
DS18B20_Write_Byte(0x44); // 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; //获得底八位
float res=(float)tem*0.0625; //转换
if(temp)return res; //返回温度值
else return -res;
}
训练题——DS18B20部分的更多相关文章
- X-NUCA 2017 web专题赛训练题 阳光总在风雨后和default wp
0X0.前言 X-NUCA 2017来了,想起2016 web专题赛,题目都打不开,希望这次主办方能够搞好点吧!还没开赛,依照惯例会有赛前指导,放一些训练题让CTFer们好感受一下题目. 题目有一大 ...
- PAT乙级真题及训练题 1025. 反转链表 (25)
PAT乙级真题及训练题 1025. 反转链表 (25) 感觉几个世纪没打代码了,真是坏习惯,调了两小时把反转链表调出来了,心情舒畅. 这道题的步骤 数据输入,数组纪录下一结点及储存值 创建链表并储存上 ...
- 日常 java+雅思+训练题1
今天主要学了一些类似c中的一些语句,java也是一样类似的,只有一些点需要稍微注意一下,一些语句是新增的需要知道. 完完全全新学的知识就是class和instance的区别.如何创建实例.数据的封装. ...
- java基础集合经典训练题
第一题:要求产生10个随机的字符串,每一个字符串互相不重复,每一个字符串中组成的字符(a-zA-Z0-9)也不相同,每个字符串长度为10; 分析:*1.看到这个题目,或许你脑海中会想到很多方法,比如判 ...
- 2016huas暑假集训训练题 G-Who's in the Middle
题目链接:http://acm.hust.edu.cn/vjudge/contest/121192#problem/G 此题大意是给定一个数n 然后有n个数 要求求出其中位数 刚开始以为是按数学中的 ...
- 2016HUAS暑假集训训练题 G - Oil Deposits
Description The GeoSurvComp geologic survey company is responsible for detecting underground oil dep ...
- c语言训练题:关于张三李四王五说谎的问题(此处用javascript实现)
(第一篇博文) 今天在一个交流群里见他们无聊,然后找到之前收藏的一些c语言题目放出去想让他们做,结果反倒是自己不会做,于是花了很多时间去想. 原题:张三说李四在说谎,李四说王五在说谎,王五说张三和李四 ...
- 中南大学2018年ACM暑期集训前期训练题集(入门题) X: 又一道简单题
简直智障,上一题V题,样例输出里面的“Case:”不要输出,到了这题又是要输出的了 #include<iostream> using namespace std; int num[1000 ...
- 中南大学2018年ACM暑期集训前期训练题集(入门题) J : A Simple Problem
毒瘤哇!为什么要用long long 啊!!!这个题没有加法操作啊,为什么会爆int啊!!!! 思路: http://www.cnblogs.com/buerdepepeqi/p/9048130.ht ...
- 树状数组训练题1:弱弱的战壕(vijos1066)
题目链接:弱弱的战壕 这道题似乎是vijos上能找到的最简单的树状数组题了. 原来,我有一个错误的思想,我的设计是维护两个树状数组,一个是横坐标,一个是纵坐标,然后读入每个点的坐标,扔进对应的树状数组 ...
随机推荐
- CCF 201909-1 小明种苹果
#include <iostream> #include <bits/stdc++.h> #include <string> using namespace std ...
- (原创)odoo动态设置树形视图中的字段,每个用户可定制自己要显示的字段
模块详情
- 最新go语言学习教程
go语言学习教程 集合了连接go routine.go连接redis.go连接kafka等示例,所有代码均经过实践,可以直接使用 https://github.com/fastbpmn/go-stud ...
- Linux中 cat查询文件指定内容-并输入到指定文件内
常用: ① cat xxx.log | grep -C 20 "查询关键字" ② grep -E '1805|1905' CloudPayment.log > out.log ...
- 【服务器数据恢复】VMware虚拟机数据恢复案例
服务器数据恢复环境:一台某品牌PowerEdge系列服务器和一台PowerVault系列存储,上层是ESXI虚拟机文件,虚拟机中运行SQL Server数据库. 服务器故障:机房非正常断电导致虚拟机无 ...
- window JAVA 环境变量配置
java win环境变量配置1.安装的时候拷贝出,安装目录C:\Program Files\Java\jdk1.8.0_40\2.在系统变量中,点击"新建",弹出窗口后在变量名输入 ...
- JAVA学习笔记-06
多态:可以理解为事物存在的多种体现形态 1.多态的基本体现 父类的引用指向了自己的子类对象 父类的引用也可以接收自己的子类对象 2.多态的前提 必须是类与类之间有关系,要么继承,要么实现 通常还有一个 ...
- 动手学强化学习 第二章 多臂tiger机问题 阅读笔记
第二章 多臂tiger机问题 第一节 简介 强化学习是一种试错型学习范式. 第二节 问题介绍 多臂tiger机(multi-armed bandit,MAB)不存在状态信息,只有动作和奖励.有一个拥有 ...
- Excel下载乱码
1.前端:一定不可以以ajax的请求方式,不然会弹出乱码. 要使用<a href="../Ajax/AjaxPrint.ashx?action=PrintClick&Tid=& ...
- 手机安装python环境
一.安装Termux环境 1.下载Termux Qpython 安装以后玩爬虫各种报错,也就不纠结了,直接弄Termux 虚拟环境 下载链接:https://wiki.termux.com/wiki/ ...