stm32f103c8t6ds18b20oled显示
时间: 2025-05-17 21:15:40 浏览: 20
### 实现 STM32F103C8T6 上 DS18B20 温度传感器与 OLED 显示屏的数据交互
#### 硬件准备
为了实现该功能,需要以下硬件组件:
- **STM32F103C8T6 开发板**
- **DS18B20 温度传感器**
- **OLED 显示屏 (通常为 0.96 英寸 IIC 接口)**
- 杜邦线若干
#### 软件环境
开发工具可以选择 Keil MDK 或者 STM32CubeIDE。此外还需要安装 HAL 库或者标准外设库。
---
#### 主要原理
DS18B20 是一种数字化温度传感器,支持单总线通信协议。它能够将采集到的温度数据转换成数字信号并通过一根数据线传输给 MCU[^1]。在此项目中,STM32 将通过 GPIO 口模拟单总线协议来读取 DS18B20 的温度值,并将其显示在 OLED 屏幕上。
OLED 显示屏则可以通过 I2C 协议连接至 STM32,用于实时显示当前温度值[^2]。
---
#### 示例代码
以下是完整的代码示例:
```c
#include "stm32f1xx_hal.h"
#include "ssd1306.h"
// 定义 DS18B20 引脚
#define DS18B20_PIN GPIO_Pin_0
#define DS18B20_PORT GPIOA
void delay_us(uint16_t us);
uint8_t OneWire_Reset(void);
void OneWire_WriteByte(uint8_t dat);
uint8_t OneWire_ReadByte(void);
float read_temperature();
int main(void)
{
HAL_Init();
SystemClock_Config(); // 配置系统时钟
__HAL_RCC_GPIOA_CLK_ENABLE(); // 启用 GPIOA 时钟
GPIO_InitTypeDef GPIO_InitStruct = {0};
// 初始化 PA0 作为 DS18B20 数据引脚
GPIO_InitStruct.Pin = DS18B20_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出模式
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(DS18B20_PORT, &GPIO_InitStruct);
SSD1306_Init(); // 初始化 OLED 显示屏
SSD1306_Clear(); // 清除屏幕内容
while (1)
{
float temperature = read_temperature(); // 获取温度值
char buffer[20];
sprintf(buffer, "Temp: %.2f C", temperature); // 格式化字符串
SSD1306_GotoXY(0, 0); // 设置光标位置
SSD1306_Puts(buffer, &Font_7x10, 1); // 打印温度信息
SSD1306_UpdateScreen(); // 更新屏幕
HAL_Delay(1000); // 每秒刷新一次
}
}
/**
* @brief 读取 DS18B20 温度值
*/
float read_temperature()
{
uint8_t data[9]; // 存储从 DS18B20 中读取的数据
float temp;
OneWire_Reset(); // 复位 DS18B20 总线
OneWire_WriteByte(0xCC); // 跳过 ROM 地址匹配命令
OneWire_WriteByte(0x44); // 发起温度转换命令
HAL_Delay(750); // 等待温度转换完成
OneWire_Reset(); // 再次复位总线
OneWire_WriteByte(0xCC); // 跳过 ROM 地址匹配命令
OneWire_WriteByte(0xBE); // 发送读寄存器命令
for(int i=0;i<9;i++) // 读取 9 字节数据
{
data[i]=OneWire_ReadByte();
}
int16_t raw_temp = (data[1] << 8) | data[0]; // 组合高低字节得到原始温度值
temp = (float)(raw_temp / 16.0); // 计算实际温度值
return temp;
}
/**
* @brief 延迟函数(微秒级)
*/
void delay_us(uint16_t us)
{
__HAL_TIM_SET_COUNTER(&htim2, 0); // 使用 TIM2 进行定时
while (__HAL_TIM_GET_COUNTER(&htim2) < us);
}
/**
* @brief DS18B20 总线复位操作
*/
uint8_t OneWire_Reset(void)
{
uint8_t presence_pulse = 0;
DS18B20_PORT->MODER |= (1 << (2*DS18B20_PIN)); // 设置为推挽输出模式
DS18B20_PORT->ODR &= ~(1 << DS18B20_PIN); // 输出低电平
delay_us(480); // 至少保持 480us
DS18B20_PORT->ODR |= (1 << DS18B20_PIN); // 放开总线
DS18B20_PORT->MODER &= ~(1 << (2*DS18B20_PIN)); // 切换回输入模式
delay_us(70); // 等待至少 60~75us
if (!(DS18B20_PORT->IDR & (1<<DS18B20_PIN))) // 如果检测到存在脉冲
{
presence_pulse = 1;
}
delay_us(410); // 等待剩余时间
return presence_pulse;
}
/**
* @brief 向 DS18B20 写入一个字节
*/
void OneWire_WriteByte(uint8_t dat)
{
for(uint8_t i=0;i<8;i++)
{
DS18B20_PORT->MODER |= (1 << (2*DS18B20_PIN)); // 设置为推挽输出模式
DS18B20_PORT->ODR &= ~(1 << DS18B20_PIN); // 下拉总线
delay_us(2); // 持续时间为 tLOW=6us min.
if(dat&0x01) // 当前位为 '1'
DS18B20_PORT->ODR |= (1 << DS18B20_PIN); // 提升总线电压
else // 当前位为 '0'
DS18B20_PORT->ODR &= ~(1 << DS18B20_PIN); // 保持下拉状态
delay_us(60); // 持续时间为 tHIGH=60us max.
DS18B20_PORT->MODER &= ~(1 << (2*DS18B20_PIN));// 切换回输入模式
dat >>= 1; // 移动到下一个比特
}
}
/**
* @brief 从 DS18B20 读取一个字节
*/
uint8_t OneWire_ReadByte(void)
{
uint8_t value = 0;
for(uint8_t i=0;i<8;i++)
{
DS18B20_PORT->MODER |= (1 << (2*DS18B20_PIN)); // 设置为推挽输出模式
DS18B20_PORT->ODR &= ~(1 << DS18B20_PIN); // 下拉总线
delay_us(2); // 持续时间为 tLOW=6us min.
DS18B20_PORT->MODER &= ~(1 << (2*DS18B20_PIN));// 切换回输入模式
delay_us(12); // 等待主机释放总线后的延迟
if(DS18B20_PORT->IDR & (1<<DS18B20_PIN)) // 读取当前位的状态
value |= (1<<(7-i));
delay_us(55); // 持续时间为 tSLOT=60us max.
}
return value;
}
```
上述代码实现了以下几个核心功能:
1. **初始化 DS18B20 和 OLED 显示屏**。
2. **通过单总线协议读取 DS18B20 的温度值**。
3. **将温度数据显示在 OLED 屏幕上**。
---
#### 注意事项
- 在调试过程中需要注意 DS18B20 的供电方式以及接线是否正确。
- 若使用多个 DS18B20 设备,则需要处理其唯一的 ROM 地址识别逻辑。
- OLED 显示屏的地址可能因型号不同而有所差异,请确认具体设备的 I2C 地址设置。
---
阅读全文
相关推荐



















