【嵌入式开发学习】第8天:I2C 传感器驱动 + 完整项目整合(温湿度采集系统)

核心目标:掌握 I2C 通信原理,驱动真实 I2C 温湿度传感器(AHT10),整合前 7 天知识点(GPIO、定时器、串口、中断、函数封装),实现 “定时采集温湿度 + 串口上传数据 + 电脑指令控制采集频率” 的完整嵌入式系统 —— 这是从 “零散知识点” 到 “实际应用” 的关键跨越。

一、I2C 通信原理:嵌入式 “多设备互联” 的常用接口(30 分钟)

I2C(Inter-Integrated Circuit)是两线制同步通信接口,仅需 SCL(时钟线)和 SDA(数据线)就能实现多设备通信,核心优势是 “布线简单、支持多从机”,广泛用于传感器、EEPROM 等外设。

1. 核心概念(新手必懂)
  • 通信线:SCL(Serial Clock,时钟线,主机输出时钟)、SDA(Serial Data,数据线,双向传输数据);
  • 主从结构:STM32 作为 “主机”,传感器(AHT10)作为 “从机”,主机控制通信节奏;
  • 从机地址:每个 I2C 从机有唯一地址(AHT10 默认地址 0x38),主机通过地址识别要通信的设备;
  • STM32 引脚对应(F103C8T6):I2C1 的 SCL=PB6,SDA=PB7(需配置为 I2C 功能,开启上拉电阻)。
2. HAL 库 I2C 核心函数(重点记)
  • 主机发送数据:HAL_I2C_Master_Transmit(&hi2c1, 从机地址, 发送缓冲区, 数据长度, 超时时间);
  • 主机接收数据:HAL_I2C_Master_Receive(&hi2c1, 从机地址, 接收缓冲区, 数据长度, 超时时间);
  • 传感器初始化:通过 I2C 发送 “初始化指令”,让传感器进入工作模式(不同传感器指令不同,参考 datasheet)。
3. 嵌入式场景意义

I2C 是传感器通信的 “主流接口”(比 SPI 布线少,比单总线稳定),学会 I2C 驱动后,可快速适配大多数温湿度、光照、气压传感器,是嵌入式外设开发的核心技能。


二、硬件准备(实操基础)

  1. 核心硬件:STM32F103C8T6 开发板、AHT10 温湿度传感器模块、USB-TTL 模块、杜邦线;
  2. 接线方式(I2C1 通信):
    • AHT10 VCC → 开发板 3.3V(务必接 3.3V,接 5V 会烧毁传感器);
    • AHT10 GND → 开发板 GND;
    • AHT10 SCL → 开发板 PB6(I2C1_SCL);
    • AHT10 SDA → 开发板 PB7(I2C1_SDA);
  3. 串口接线(同第七天):开发板 PA9→TTL Tx,PA10→TTL Rx,GND→GND(用于数据上传和指令接收)。

三、实操:完整温湿度采集系统(70 分钟,核心整合)

目标:开发板通过 I2C 驱动 AHT10 采集温湿度,1 秒采集一次(定时器控制),串口上传数据到电脑;电脑发送指令 “F5”(500ms 采集一次)、“F10”(1 秒)、“F20”(2 秒),可修改采集频率。

步骤 1:CubeIDE 配置(I2C + 定时器 + 串口 + GPIO)
  1. 新建工程 “AHT10_TempHumi_System”,选择 STM32F103C8T6;
  2. 配置 I2C1:
    • 左侧 “Connectivity→I2C1”:Mode 选 “I2C”;
    • 参数默认:时钟频率 100kHz(标准模式),其他保持默认;
    • 配置引脚:PB6 设为 “I2C1_SCL”,PB7 设为 “I2C1_SDA”(CubeIDE 自动开启上拉电阻);
  3. 配置串口 USART1(同第七天):异步模式,波特率 9600,PA9=TX,PA10=RX;
  4. 配置定时器 TIM3(定时核心):
    • 预分频器 7199、自动重载值 9999(默认 1 秒中断一次,后续通过指令修改 ARR 实现频率切换);
    • 使能 TIM3 中断;
  5. 生成初始化代码。
步骤 2:编写 AHT10 传感器驱动(封装读取逻辑)

main.c的 “USER CODE BEGIN 0” 区域添加传感器驱动函数(基于 AHT10 datasheet 指令):

c

/* USER CODE BEGIN 0 */
#include <string.h>

// AHT10传感器地址(默认0x38,7位地址)
#define AHT10_ADDR 0x38<<1  // I2C通信时需左移1位(8位数据格式,最低位是读写位)

// AHT10初始化指令(参考datasheet)
#define AHT10_INIT_CMD 0xE1  // 初始化+正常模式
// AHT10采集指令
#define AHT10_MEASURE_CMD 0xAC  // 触发温湿度采集

// 全局变量:存储温湿度数据
float temperature = 0.0;  // 温度(℃)
float humidity = 0.0;     // 湿度(%RH)

// 函数1:AHT10初始化
uint8_t AHT10_Init(I2C_HandleTypeDef *hi2c) {
  uint8_t init_buf[3] = {AHT10_INIT_CMD, 0x00, 0x00};  // 初始化指令+参数
  // 发送初始化指令(主机→AHT10)
  if (HAL_I2C_Master_Transmit(hi2c, AHT10_ADDR, init_buf, 3, 100) != HAL_OK) {
    return 1;  // 初始化失败
  }
  HAL_Delay(10);  // 传感器初始化需要时间
  return 0;  // 初始化成功
}

// 函数2:读取AHT10温湿度数据
uint8_t AHT10_ReadData(I2C_HandleTypeDef *hi2c) {
  uint8_t measure_buf[3] = {AHT10_MEASURE_CMD, 0x33, 0x00};  // 采集指令+参数
  uint8_t recv_buf[6] = {0};  // 接收缓冲区(AHT10返回6字节数据)
  
  // 1. 发送采集指令
  if (HAL_I2C_Master_Transmit(hi2c, AHT10_ADDR, measure_buf, 3, 100) != HAL_OK) {
    return 1;  // 指令发送失败
  }
  HAL_Delay(80);  // 传感器采集需要时间( datasheet 要求≥75ms)
  
  // 2. 接收采集结果(6字节数据)
  if (HAL_I2C_Master_Receive(hi2c, AHT10_ADDR, recv_buf, 6, 100) != HAL_OK) {
    return 1;  // 数据接收失败
  }
  
  // 3. 解析数据(根据AHT10 datasheet的格式换算)
  // 湿度数据:recv_buf[1]<<12 | recv_buf[2]<<4 | (recv_buf[3]&0xF0)>>4
  uint32_t humi_raw = (recv_buf[1] << 12) | (recv_buf[2] << 4) | ((recv_buf[3] & 0xF0) >> 4);
  humidity = (humi_raw / 1048576.0) * 100.0;  // 换算为湿度(0-100%RH)
  
  // 温度数据:(recv_buf[3]&0x0F)<<16 | recv_buf[4]<<8 | recv_buf[5]
  uint32_t temp_raw = ((recv_buf[3] & 0x0F) << 16) | (recv_buf[4] << 8) | recv_buf[5];
  temperature = (temp_raw / 1048576.0) * 200.0 - 50.0;  // 换算为温度(-40~85℃)
  
  return 0;  // 读取成功
}
/* USER CODE END 0 */
步骤 3:编写系统核心逻辑(定时采集 + 串口上传 + 指令控制)
  1. 定义全局变量(main.c的 “USER CODE BEGIN 2” 区域):

c

/* USER CODE BEGIN 2 */
uint32_t timer_count = 0;  // 定时器计数
uint16_t arr_val = 9999;   // TIM3自动重载值(默认1秒:(7199+1)*(9999+1)/72e6=1s)
uint8_t recv_buf[10] = {0};  // 串口接收缓冲区(存储电脑指令)
uint8_t send_buf[60] = {0};  // 串口发送缓冲区
/* USER CODE END 2 */
  1. 主函数初始化(main函数中):

c

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_I2C1_Init();
  MX_USART1_UART_Init();
  MX_TIM3_Init();

  /* USER CODE BEGIN 2 */
  // 1. 初始化AHT10传感器
  if (AHT10_Init(&hi2c1) == 0) {
    sprintf((char*)send_buf, "AHT10传感器初始化成功!\r\n");
    HAL_UART_Transmit(&huart1, send_buf, strlen((char*)send_buf), 100);
  } else {
    sprintf((char*)send_buf, "AHT10传感器初始化失败!\r\n");
    HAL_UART_Transmit(&huart1, send_buf, strlen((char*)send_buf), 100);
  }

  // 2. 启动定时器中断和串口中断接收
  HAL_TIM_Base_Start_IT(&htim3);
  HAL_UART_Receive_IT(&huart1, recv_buf, 3);  // 接收3字节指令(如F5\r、F10\r)

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}
  1. 定时器中断回调(定时采集 + 串口上传):

c

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
  if (htim->Instance == TIM3) {
    // 1. 读取温湿度数据
    if (AHT10_ReadData(&hi2c1) == 0) {
      // 2. 格式化数据并串口上传
      sprintf((char*)send_buf, "温湿度数据:温度=%.1f℃,湿度=%.1f%%RH\r\n", temperature, humidity);
      HAL_UART_Transmit(&huart1, send_buf, strlen((char*)send_buf), 100);
    } else {
      sprintf((char*)send_buf, "温湿度读取失败!\r\n");
      HAL_UART_Transmit(&huart1, send_buf, strlen((char*)send_buf), 100);
    }
  }
}
  1. 串口中断回调(解析电脑指令,修改采集频率):

c

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
  if (huart->Instance == USART1) {
    // 解析指令:F5→500ms,F10→1s,F20→2s
    if (strcmp((char*)recv_buf, "F5\r") == 0) {
      arr_val = 4999;  // 500ms:(7199+1)*(4999+1)/72e6=0.5s
      sprintf((char*)send_buf, "采集频率已修改为500ms一次\r\n");
    } else if (strcmp((char*)recv_buf, "F10\r") == 0) {
      arr_val = 9999;  // 1s
      sprintf((char*)send_buf, "采集频率已修改为1s一次\r\n");
    } else if (strcmp((char*)recv_buf, "F20\r") == 0) {
      arr_val = 19999;  // 2s:(7199+1)*(19999+1)/72e6=2s
      sprintf((char*)send_buf, "采集频率已修改为2s一次\r\n");
    } else {
      sprintf((char*)send_buf, "指令错误!支持指令:F5(500ms)、F10(1s)、F20(2s)\r\n");
    }

    // 应用新的自动重载值(修改定时器定时时长)
    __HAL_TIM_SET_AUTORELOAD(&htim3, arr_val);
    // 发送反馈信息
    HAL_UART_Transmit(&huart1, send_buf, strlen((char*)send_buf), 100);
    // 清空接收缓冲区,重新开启中断接收
    memset(recv_buf, 0, sizeof(recv_buf));
    HAL_UART_Receive_IT(&huart1, recv_buf, 3);
  }
}
步骤 4:下载测试(完整系统验证)
  1. 电脑端打开串口助手,配置:波特率 9600、8N1、对应 COM 口;
  2. 下载程序后,串口助手收到初始化信息:AHT10传感器初始化成功!
  3. 默认 1 秒收到一条温湿度数据:温湿度数据:温度=25.3℃,湿度=45.2%RH
  4. 发送指令 “F5”(回车),收到反馈:采集频率已修改为500ms一次,数据上传频率加快;
  5. 发送指令 “F20”(回车),反馈:采集频率已修改为2s一次,数据上传频率变慢。

四、第八天必掌握的 3 个关键知识点(10 分钟自测)

  1. I2C 通信核心:两线制(SCL/SDA)、主从结构、从机地址,HAL 库核心函数HAL_I2C_Master_Transmit/HAL_I2C_Master_Receive
  2. 传感器驱动逻辑:“发送指令→等待采集→接收数据→解析换算”,必须参考 datasheet 的指令和数据格式;
  3. 系统整合思路:定时器控制采集周期、I2C 读取传感器、串口实现数据上传和指令交互,各模块通过全局变量和回调函数联动。

总结

今天完成了第一个 “完整嵌入式应用系统”!这个系统整合了前 8 天的所有核心知识点:GPIO(硬件接线)、I2C(传感器通信)、定时器(定时任务)、串口(双向交互)、中断(回调响应)、函数封装(传感器驱动)—— 这就是实际嵌入式项目的典型架构。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值