STC8H开发(十一): GPIO单线驱动多个DS18B20数字温度计
目录
- STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解)
- STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解)
- STC8H开发(三): 基于FwLib_STC8的模数转换ADC介绍和演示用例说明
- STC8H开发(四): FwLib_STC8 封装库的介绍和使用注意事项
- STC8H开发(五): SPI驱动nRF24L01无线模块
- STC8H开发(六): SPI驱动ADXL345三轴加速度检测模块
- STC8H开发(七): I2C驱动MPU6050三轴加速度+三轴角速度检测模块
- STC8H开发(八): NRF24L01无线传输音频(对讲机原型)
- STC8H开发(九): STC8H8K64U模拟USB HID外设
- STC8H开发(十): SPI驱动Nokia5110 LCD(PCD8544)
- STC8H开发(十一): GPIO单线驱动多个DS18B20数字温度计
- STC8H开发(十二): I2C驱动AT24C08,AT24C32系列EEPROM存储
DS18B20
关于DS18B20的详细介绍说明已经转移到这组文章下
- DS18B20数字温度计 (一) 电气特性, 寄生供电模式和远距离接线
- DS18B20数字温度计 (二) 测温, ROM和CRC算法
- DS18B20数字温度计 (三) 1-WIRE总线 ROM搜索算法和实际测试
使用STC8H驱动DS18B20
接线
普通模式
GND -> GND
P35 -> DQ
3.3V -> VDD
寄生供电模式
这个模式下
- VDD和GND都要接地
- DQ 需要用5K电阻上拉. STC8H可以通过寄存器进行设置.
- 建议使用5V电压供电, 使用3.3V供电时, 可能会出现测温读数不更新的情况
GND -> GND -> VDD
P35 -> DQ
5V
寄生模式下, 发起温度转换后不能查询完成情况, 如果查询, 会导致测温不成功, 读数不变, 需要等待一个合理的时间, 例如1000毫秒, 然后直接读出温度值.
代码
代码可以从GitHub或者Gitee下载
定义 IO
只需要一个Pin, 在STC8H中, 注意要将其设置为上拉, 否则读出来的全是0
#define DS18B20_DQ P35
#define DS18B20_DQ_PULLUP() GPIO_SetPullUp(GPIO_Port_3, GPIO_Pin_5, HAL_State_ON)
#define DS18B20_DQ_INPUT() GPIO_P3_SetMode(GPIO_Pin_5, GPIO_Mode_Input_HIP)
#define DS18B20_DQ_OUTPUT() GPIO_P3_SetMode(GPIO_Pin_5, GPIO_Mode_InOut_OD)
#define DS18B20_DQ_LOW() DS18B20_DQ=RESET
#define DS18B20_DQ_HIGH() DS18B20_DQ=SET
IO 读写
读一个bit和一个byte
__BIT DS18B20_ReadBit(void)
{
__BIT b = RESET;
/* Line low */
DS18B20_DQ = RESET;
DS18B20_DQ_OUTPUT();
SYS_DelayUs(2);
/* Release line */
DS18B20_DQ_INPUT();
SYS_DelayUs(10);
/* Read line value */
if (DS18B20_DQ) {
/* Bit is HIGH */
b = SET;
}
/* Wait 50us to complete 60us period */
SYS_DelayUs(50);
/* Return bit value */
return b;
}
uint8_t DS18B20_ReadByte(void)
{
uint8_t i = 8, byte = 0;
while (i--)
{
byte >>= 1;
byte |= (DS18B20_ReadBit() << 7);
}
return byte;
}
写一个bit和一个byte
void DS18B20_WriteBit(__BIT b)
{
if (b)
{
/* Set line low */
DS18B20_DQ = RESET;
DS18B20_DQ_OUTPUT();
SYS_DelayUs(10);
/* Bit high */
DS18B20_DQ_INPUT();
/* Wait for 55 us and release the line */
SYS_DelayUs(55);
DS18B20_DQ_INPUT();
}
else
{
/* Set line low */
DS18B20_DQ = RESET;
DS18B20_DQ_OUTPUT();
SYS_DelayUs(65);
/* Bit high */
DS18B20_DQ_INPUT();
/* Wait for 5 us and release the line */
SYS_DelayUs(5);
DS18B20_DQ_INPUT();
}
}
void DS18B20_WriteByte(uint8_t byte)
{
uint8_t i = 8;
/* Write 8 bits */
while (i--)
{
/* LSB bit is first */
DS18B20_WriteBit(byte & 0x01);
byte >>= 1;
}
}
单个 DS18B20 的场景
初始化, 注意设置上拉, 以及输入和输出模式的切换
void DS18B20_Init(void)
{
DS18B20_DQ_PULLUP();
DS18B20_DQ_OUTPUT();
DS18B20_DQ = SET;
SYS_DelayUs(1000);
DS18B20_DQ = RESET;
SYS_DelayUs(1000);
DS18B20_DQ = SET;
SYS_DelayUs(2000);
}
读取温度, 这样读出的值并非温度值, 需要根据上面的温度转换, 乘以对应的温度单元值(默认为0.0625摄氏度)
// 发起转换
DS18B20_StartAll();
// 读取总线, 当转换完成时会变为高电平
while (!DS18B20_AllDone())
{
UART1_TxChar('.');
SYS_Delay(1);
}
// 重置总线
DS18B20_Reset();
// 跳过ROM选择
DS18B20_WriteByte(ONEWIRE_CMD_SKIPROM);
// 写入读取暂存器指令
DS18B20_WriteByte(ONEWIRE_CMD_RSCRATCHPAD);
// 读出9个字节的数据
for (i = 0; i < 9; i++)
{
/* Read byte by byte */
data[i] = DS18B20_ReadByte();
}
// 温度值位于第1和第2个字节
temperature = data[1];
temperature = temperature << 8 | data[0];
读取ROM
// 重置总线
DS18B20_Reset();
// 写入读取ROM指令, 注意这个命令不能用于连接多个设备的总线, 否则结果读数是无意义的
DS18B20_WriteByte(ONEWIRE_CMD_READROM);
// 读出数据
for (i = 0; i < 8; i++)
{
*buf++ = DS18B20_ReadByte();
}
多个 DS18B20 的场景
指定设备地址, 读取温度
// 重置总线
DS18B20_Reset();
// 根据地址选择设备
DS18B20_Select(addr);
// 对选中的设备, 发起转换
DS18B20_WriteByte(DS18B20_CMD_CONVERTTEMP);
// 等待转换结束
// 重置总线
DS18B20_Reset();
// 根据地址选择设备
DS18B20_Select(addr);
// 写入读取暂存器指令
DS18B20_WriteByte(ONEWIRE_CMD_RSCRATCHPAD);
// 读取数据
for (i = 0; i < 9; i++)
{
*buf++ = DS18B20_ReadByte();
}
参考
- 单线总线搜索算法 1-WIRE SEARCH ALGORITHM https://www.maximintegrated.com/en/design/technical-documents/app-notes/1/187.html
- 寄生供电模式 https://learn.openenergymonitor.org/electricity-monitoring/temperature/DS18B20-temperature-sensing
- 寄生供电模式 https://e-radionica.com/en/blog/hum-how-to-use-the-ds18b20-with-parasitic-power-supply/