一、源码
ds18b20.c
#include "./SYSTEM/delay/delay.h"
#include "./BSP/DS18B20/ds18b20.h"
/**
* @brief 复位DS18B20
* @param data: 要写入的数据
* @retval 无
*/
static void ds18b20_reset(void)
{
DS18B20_DQ_OUT(0); /* 拉低DQ,复位 */
delay_us(750); /* 拉低750us */
DS18B20_DQ_OUT(1); /* DQ=1, 释放复位 */
delay_us(15); /* 延迟15US */
}
/**
* @brief 等待DS18B20的回应
* @param 无
* @retval 0, DS18B20正常
* 1, DS18B20异常/不存在
*/
uint8_t ds18b20_check(void)
{
uint8_t retry = 0;
uint8_t rval = 0;
while (DS18B20_DQ_IN && retry < 200) /* 等待DQ变低, 等待200us */
{
retry++;
delay_us(1);
}
if (retry >= 200)
{
rval = 1;
}
else
{
retry = 0;
while (!DS18B20_DQ_IN && retry < 240) /* 等待DQ变高, 等待240us */
{
retry++;
delay_us(1);
}
if (retry >= 240) rval = 1;
}
return rval;
}
/**
* @brief 从DS18B20读取一个位
* @param 无
* @retval 读取到的位值: 0 / 1
*/
static uint8_t ds18b20_read_bit(void)
{
uint8_t data = 0;
DS18B20_DQ_OUT(0);
delay_us(2);
DS18B20_DQ_OUT(1);
delay_us(12);
if (DS18B20_DQ_IN)
{
data = 1;
}
delay_us(50);
return data;
}
/**
* @brief 从DS18B20读取一个字节
* @param 无
* @retval 读到的数据
*/
static uint8_t ds18b20_read_byte(void)
{
uint8_t i, b, data = 0;
for (i = 0; i < 8; i++)
{
b = ds18b20_read_bit(); /* DS18B20先输出低位数据 ,高位数据后输出 */
data |= b << i; /* 填充data的每一位 */
}
return data;
}
/**
* @brief 写一个字节到DS18B20
* @param data: 要写入的字节
* @retval 无
*/
static void ds18b20_write_byte(uint8_t data)
{
uint8_t j;
for (j = 1; j <= 8; j++)
{
if (data & 0x01)
{
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);
}
data >>= 1; /* 右移,获取高一位数据 */
}
}
/**
* @brief 开始温度转换
* @param 无
* @retval 无
*/
static void ds18b20_start(void)
{
ds18b20_reset();
ds18b20_check();
ds18b20_write_byte(0xcc); /* skip rom */
ds18b20_write_byte(0x44); /* convert */
}
/**
* @brief 初始化DS18B20的IO口 DQ 同时检测DS18B20的存在
* @param 无
* @retval 0, 正常
* 1, 不存在/不正常
*/
uint8_t ds18b20_init(void)
{
GPIO_InitTypeDef gpio_init_struct;
DS18B20_DQ_GPIO_CLK_ENABLE(); /* 开启DQ引脚时钟 */
gpio_init_struct.Pin = DS18B20_DQ_GPIO_PIN;
gpio_init_struct.Mode = GPIO_MODE_OUTPUT_OD; /* 开漏输出 */
gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */
gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */
HAL_GPIO_Init(DS18B20_DQ_GPIO_PORT, &gpio_init_struct); /* 初始化DS18B20_DQ引脚 */
/* DS18B20_DQ引脚模式设置,开漏输出,上拉, 这样就不用再设置IO方向了, 开漏输出的时候(=1), 也可以读取外部信号的高低电平 */
ds18b20_reset();
return ds18b20_check();
}
/**
* @brief 从ds18b20得到温度值(精度:0.1C)
* @param 无
* @retval 温度值 (-550~1250)
* @note 返回的温度值放大了10倍.
* 实际使用的时候,要除以10才是实际温度.
*/
short ds18b20_get_temperature(void)
{
uint8_t flag = 1; /* 默认温度为正数 */
uint8_t TL, TH;
short temp;
ds18b20_start(); /* ds1820 start convert */
ds18b20_reset();
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)
{/* 温度为负,查看DS18B20的温度表示法与计算机存储正负数据的原理一致:
正数补码为寄存器存储的数据自身,负数补码为寄存器存储值按位取反后+1
所以我们直接取它实际的负数部分,但负数的补码为取反后加一,但考虑到低位可能+1后有进位和代码冗余,
我们这里先暂时没有作+1的处理,这里需要留意 */
TH = ~TH;
TL = ~TL;
flag = 0; /* 温度为负 */
}
temp = TH; /* 获得高八位 */
temp <<= 8;
temp += TL; /* 获得底八位 */
/* 转换成实际温度 */
if (flag == 0)
{ /* 将温度转换成负温度,这里的+1参考前面的说明 */
temp = (double)(temp+1) * 0.625;
temp = -temp;
}
else
{
temp = (double)temp * 0.625;
}
return temp;
}
ds18b20.h
#ifndef __DS18B20_H
#define __DS18B20_H
#include "./SYSTEM/sys/sys.h"
/******************************************************************************************/
/* DS18B20引脚 定义 */
#define DS18B20_DQ_GPIO_PORT GPIOA
#define DS18B20_DQ_GPIO_PIN GPIO_PIN_8
#define DS18B20_DQ_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0) /* PG口时钟使能 */
/******************************************************************************************/
/* IO操作函数 */
#define DS18B20_DQ_OUT(x) do{ x ? \
HAL_GPIO_WritePin(DS18B20_DQ_GPIO_PORT, DS18B20_DQ_GPIO_PIN, GPIO_PIN_SET) : \
HAL_GPIO_WritePin(DS18B20_DQ_GPIO_PORT, DS18B20_DQ_GPIO_PIN, GPIO_PIN_RESET); \
}while(0) /* 数据端口输出 */
#define DS18B20_DQ_IN HAL_GPIO_ReadPin(DS18B20_DQ_GPIO_PORT, DS18B20_DQ_GPIO_PIN) /* 数据端口输入 */
uint8_t ds18b20_init(void); /* 初始化DS18B20 */
uint8_t ds18b20_check(void); /* 检测是否存在DS18B20 */
short ds18b20_get_temperature(void);/* 获取温度 */
#endif
digital.c
#include "./BSP/DIGITAL/digital.h"
// 0 1 2 3 4 5 6 7 8 9 A b C d E F - //数码管字表
unsigned char DIGITAL[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x8C,0xBF,0xC6,0xA1,0x86,0xFF,0xbf};
/**
* @brief 初始化数码管相关IO口, 并使能时钟
* @param 无
* @retval 无
*/
void Digital_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
__HAL_RCC_GPIOA_CLK_ENABLE(); //打开时钟
//推挽输出
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7, GPIO_PIN_SET);
//打开时钟
__HAL_RCC_GPIOB_CLK_ENABLE();
//推挽输出
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pin = GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15, GPIO_PIN_RESET);
}
/**
* @brief 显示一位数字
* @param num:需要显示的数字
* @retval 无
*/
void Show_One(uint8_t num)
{
HAL_GPIO_WritePin(GPIOA, DIGITAL[num]&0x00ff, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, ~DIGITAL[num]&0x00ff, GPIO_PIN_RESET);
}
/**
* @brief 显示
* @param bit_loc:需要显示的位置
num: 需要显示的数字,为四位数
* @retval 无
*/
void Digital_Display(uint8_t bit_loc,uint16_t num)
{
char temp_thou = num/1000; // 千
char temp_hund = (num/100)%10; // 百
char temp_tens = (num%100)/10; // 十
char temp_ones = num%10; // 个
switch(bit_loc)
{
case 0:
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_15, GPIO_PIN_RESET);
Show_One(temp_ones);
break;
case 1:
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, GPIO_PIN_RESET);
Show_One(temp_tens);
break;
case 2:
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_RESET);
Show_One(temp_hund);
break;
case 3:
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET);
Show_One(temp_thou);
break;
}
}
digital.h
#ifndef __DIGITAL_H
#define __DIGITAL_H
#include "./SYSTEM/sys/sys.h"
void Digital_Init(void);
void Show_One(uint8_t num);
void Digital_Display(uint8_t bit_loc,uint16_t num);
#endif
中断
/**
* @brief 定时器更新中断服务程序中需要做的事情
在HAL库中所有的外部中断服务函数都会调用此函数
* @param htim:相关的定时器句柄
* @retval 无
*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1) // 如果句柄是定时器1
{
static uint8_t loc = 0;
Digital_Display(loc, temperature);
loc++;
if(loc > 3)
loc = 0;
}
}
main.c
int16_t temperature = 0;
int main(void)
{
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
delay_init(72); /* 延时初始化 */
btim_timx_int_init(5000 - 1, 72 - 1); /* 定时时间5ms */
ds18b20_init(); /* ds18b20初始化 */
Digital_Init(); /* 数码管初始化 */
while(1)
{
temperature = (int16_t)ds18b20_get_temperature();
}
}
二、原理图
三、演示图
四、参考资料
ds18b20的源码是直接复制原子的,很好用!