单总线介绍
单总线,就像是电子世界里的“超级水管工”,它以一根线的简洁,完成了数据传输、设备供电乃至设备识别的多重任务,展现了极简主义的智慧与效率。想象一下,你住在一个高科技社区,所有的家电——冰箱、洗衣机、电视,甚至灯光,都通过家中的同一根“魔法管道”沟通交流,而这根管道就是单总线。
单总线的通俗理解
一绳千结,各有所指(寻址机制):如果把单总线比作一条长绳,那么绳上系着无数不同颜色和形状的结,每个结代表一个设备。这些结的排列组合就是设备的地址,确保信息准确无误地送到特定的电器。比如,当你想要调节客厅的灯光,单总线就通过识别那个特定的“结”,只对客厅的灯光发出指令。
一线多能,既传又供(供电与数据传输):单总线不仅仅传递信息,它还像一根“营养管”,为那些低功耗的小型设备提供必要的能源。这就好比那根“魔法管道”不仅传递控制信号,还能为管道上的小灯泡提供点亮所需的电力,实现了资源的最大化利用。
时序舞蹈,精准同步(时序控制):单总线上的信息传递,就像一场精心编排的舞蹈,每个动作都要严格按照节拍进行。主机和设备之间通过一系列精确的高低电平变化(如握手、读写时序)进行对话,确保数据不混淆、不遗漏,犹如舞者之间默契的配合。
实际应用场景
智能家居:在智能家居系统中,单总线可以连接众多传感器,如温度、湿度、光照传感器,以及执行器如智能插座、窗帘电机等,仅需一根线就能构建起整个家庭的智能网络,大幅减少布线成本和复杂度。
环境监测:在农田、森林等大型环境监测项目中,单总线连接的土壤湿度、空气温湿度传感器能广泛分布,实时收集数据,为科研和农业生产提供精准指导。
工业自动化:在工厂自动化领域,单总线可用于监控机器状态,如温度、压力等关键参数,实现低成本、高效率的设备维护管理。
STM32平台下的C语言示例
考虑到STM32平台的广泛应用,以下是一个简化的示例,演示如何在STM32微控制器上使用单总线协议与DS18B20温度传感器进行通信。这里假设使用HAL库进行GPIO操作。
#include "stm32f1xx_hal.h"
#define DHT11_GPIO_Port GPIOA
#define DHT11_Pin GPIO_PIN_0
#define DELAY_US_50 50
#define DELAY_MS_20 20
// DHT11读取函数
uint8_t read_dht11_data(uint8_t *data, uint8_t len) {
HAL_GPIO_WritePin(DHT11_GPIO_Port, DHT11_Pin, GPIO_PIN_RESET); // 发送开始信号
HAL_Delay(DELAY_MS_20); // 稳定时间
HAL_GPIO_WritePin(DHT11_GPIO_Port, DHT11_Pin, GPIO_PIN_SET); // 结束开始信号
HAL_Delay(DELAY_US_40); // 等待响应
if (HAL_GPIO_ReadPin(DHT11_GPIO_Port, DHT11_Pin) == GPIO_PIN_SET) // 检查DHT11响应
return 1; // 无响应
uint8_t idx = 0, cnt = 0;
while (idx < len) {
uint8_t bit = 0;
for (cnt = 0; cnt < 8; cnt++) { // 读取每一位
while (HAL_GPIO_ReadPin(DHT11_GPIO_Port, DHT11_Pin) == GPIO_PIN_SET); // 等待低电平结束
delayMicroseconds(50); // 确保低电平稳定读取
if (HAL_GPIO_ReadPin(DHT11_GPIO_Port, DHT11_Pin) == GPIO_PIN_RESET) // 读取高电平时间判断数据位
bit |= (1 << (7 - cnt));
while (HAL_GPIO_ReadPin(DHT11_GPIO_Port, DHT11_Pin) == GPIO_PIN_RESET); // 等待高电平结束
}
data[idx++] = bit;
}
// 校验数据
uint8_t sum = 0;
for (uint8_t i = 0; i < (len - 1); i++)
sum += data[i];
if (sum != data[len - 1])
return 1; // 校验失败
return 0; // 成功
}
int main(void) {
HAL_Init(); // 初始化HAL库
SystemClock_Config(); // 配置系统时钟
__HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOA时钟
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = DHT11_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(DHT11_GPIO_Port, &GPIO_InitStruct);
uint8_t data[5] = {0}; // 存储读取的40位数据(5字节)
while (1) {
if (read_dht11_data(data, 5) == 0) { // 读取成功
uint8_t humidity_int = data[0]; // 直接读取整数部分
uint8_t humidity_dec = data[1]; // 小数部分
uint8_t temp_int = data[2]; // 温度整数部分
uint8_t temp_dec = data[3]; // 温度小数部分
float humidity = humidity_int + humidity_dec / 10.0f;
float temp = ((temp_int & 0x7F) + temp_dec / 10.0f) * (temp_int & 0x80 ? -1 : 1); // 考虑负温度
printf("Temperature: %.1f°C, Humidity: %.1f%%\r\n", temp, humidity);
} else {
printf("Failed to read from DHT11.\r\n");
}
HAL_Delay(2000); // 每2秒读取一次
}
}