news 2026/5/10 13:55:51

从Arduino迁移到STM32:手把手教你用CubeMX HAL库重写ADS1115的I2C驱动

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从Arduino迁移到STM32:手把手教你用CubeMX HAL库重写ADS1115的I2C驱动

从Arduino迁移到STM32:用CubeMX HAL库重构ADS1115的I2C驱动全指南

当Arduino开发者初次接触STM32时,往往会被复杂的底层配置所困扰。本文将以ADS1115模数转换器为例,带你完成从Arduino Wire库到STM32 HAL库的平滑过渡。我们将使用STM32CubeMX工具链,基于STM32F103RCT6开发板,逐步构建完整的I2C驱动方案。

1. 开发环境与工具链准备

对于习惯Arduino简单生态的开发者,STM32的开发环境搭建可能是第一个挑战。我们需要准备以下工具:

  • STM32CubeMX:图形化配置工具(版本≥6.0)
  • HAL库:STM32硬件抽象层库
  • IDE选择:Keil MDK-ARM或STM32CubeIDE
  • 硬件准备
    • STM32F103RCT6开发板
    • ADS1115模块(16位ADC)
    • 杜邦线若干

提示:安装CubeMX时建议勾选"Install all embedded software packages"选项,确保HAL库完整安装

与Arduino的"开箱即用"不同,STM32需要手动配置时钟树。在CubeMX中,按照以下步骤初始化系统时钟:

// 时钟配置示例(72MHz主频) RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9; HAL_RCC_OscConfig(&RCC_OscInitStruct); RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);

2. I2C外设的CubeMX配置

在Arduino中,I2C通信只需简单的Wire.begin()即可初始化。而在STM32中,我们需要通过CubeMX进行详细配置:

  1. 打开CubeMX,选择STM32F103RCT6芯片
  2. 在"Pinout & Configuration"标签页中:
    • 激活I2C1外设
    • 配置PB6为I2C1_SCL,PB7为I2C1_SDA
  3. 在"I2C"配置界面设置参数:
参数项推荐值说明
I2C Speed ModeStandard100kHz标准模式
Clock Speed100000100kHz时钟频率
Duty Cycle2Tlow/Thigh=2
Analog FilterEnable启用模拟滤波器
Digital Filter0数字滤波器系数
  1. 生成代码时,确保勾选"Generate peripheral initialization as a pair of .c/.h files"

与Arduino不同,STM32的I2C需要显式处理错误状态。以下是HAL库中常见的错误处理模式:

HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(&hi2c1, devAddr, pData, Size, Timeout); if(status != HAL_OK) { Error_Handler(); // 自定义错误处理函数 // 可添加重试逻辑 HAL_I2C_Init(&hi2c1); // 重新初始化I2C }

3. ADS1115驱动移植实战

ADS1115作为16位精度的ADC,在Arduino中通常使用现成的库。现在我们用HAL库实现相同的功能。

3.1 寄存器配置对比

ADS1115的核心是配置寄存器,以下是Arduino与STM32的实现对比:

Arduino风格(Wire库)

void ads1115_config() { Wire.beginTransmission(ADS1115_ADDRESS); Wire.write(ADS1115_REG_CONFIG); Wire.write(config_high_byte); Wire.write(config_low_byte); Wire.endTransmission(); }

STM32 HAL库实现

#define ADS1115_ADDRESS 0x90 // ADDR接地时的地址 #define ADS1115_REG_CONFIG 0x01 void ADS1115_Config(I2C_HandleTypeDef *hi2c, uint8_t config_high, uint8_t config_low) { uint8_t config_data[3] = {ADS1115_REG_CONFIG, config_high, config_low}; HAL_I2C_Master_Transmit(hi2c, ADS1115_ADDRESS, config_data, 3, HAL_MAX_DELAY); // 添加错误处理和重试机制 uint32_t tickstart = HAL_GetTick(); while(HAL_I2C_GetState(hi2c) != HAL_I2C_STATE_READY) { if((HAL_GetTick() - tickstart) > 100) { break; // 超时处理 } } }

3.2 数据读取实现

ADS1115的数据读取需要先写入指针寄存器,再发起读取请求。以下是完整的读取流程:

  1. 设置转换寄存器指针
uint8_t pointer_reg = 0x00; // 指向转换寄存器 HAL_I2C_Master_Transmit(&hi2c1, ADS1115_ADDRESS, &pointer_reg, 1, 100);
  1. 读取转换结果
uint8_t rx_data[2]; HAL_I2C_Master_Receive(&hi2c1, ADS1115_ADDRESS | 0x01, rx_data, 2, 100); int16_t raw_value = (rx_data[0] << 8) | rx_data[1];
  1. 电压值转换
float convert_to_voltage(int16_t raw, uint8_t pga) { const float full_scale[8] = {6.144, 4.096, 2.048, 1.024, 0.512, 0.256, 0.256, 0.256}; return (raw * full_scale[pga]) / 32768.0; }

注意:ADS1115返回的是二进制补码格式,需处理负电压情况

3.3 多通道采样实现

ADS1115支持4路差分或单端输入,通过配置MUX位实现通道切换:

MUX配置输入模式代码宏定义
0x4000AIN0 vs AIN1ADS1115_MUX_DIFF_0
0x5000AIN0 vs AIN3ADS1115_MUX_DIFF_1
0x7000AIN3 vs GNDADS1115_MUX_SING_3

通道切换示例:

void ADS1115_SetChannel(I2C_HandleTypeDef *hi2c, uint8_t channel) { uint16_t config = ADS1115_OS_SINGLE | channel | ADS1115_PGA_6V | ADS1115_MODE_SINGLE; uint8_t config_data[3] = {ADS1115_REG_CONFIG, config>>8, config&0xFF}; HAL_I2C_Master_Transmit(hi2c, ADS1115_ADDRESS, config_data, 3, 100); }

4. 高级应用与性能优化

4.1 中断模式读取

相比Arduino的轮询方式,STM32可以利用中断提高效率:

  1. 在CubeMX中启用I2C中断
  2. 实现中断回调函数:
void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c) { if(hi2c->Instance == I2C1) { // 处理接收完成事件 process_adc_data(rx_buffer); } }
  1. 启动非阻塞读取:
HAL_I2C_Master_Receive_IT(&hi2c1, ADS1115_ADDRESS | 0x01, rx_data, 2);

4.2 DMA传输优化

对于高速采样场景,可以配置DMA减轻CPU负担:

  1. CubeMX中配置I2C DMA通道
  2. 初始化DMA:
hdma_i2c1_rx.Instance = DMA1_Channel7; hdma_i2c1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; hdma_i2c1_rx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_i2c1_rx.Init.MemInc = DMA_MINC_ENABLE; hdma_i2c1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma_i2c1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; HAL_DMA_Init(&hdma_i2c1_rx);
  1. 启动DMA传输:
HAL_I2C_Master_Receive_DMA(&hi2c1, ADS1115_ADDRESS | 0x01, adc_buffer, BUFFER_SIZE);

4.3 软件滤波实现

移植Arduino常见的中值平均滤波算法:

#define SAMPLE_SIZE 10 float median_avg_filter(uint8_t channel) { float samples[SAMPLE_SIZE]; for(int i=0; i<SAMPLE_SIZE; i++) { samples[i] = read_ads1115_channel(channel); HAL_Delay(1); } // 排序找出最大值和最小值 float min = samples[0], max = samples[0], sum = 0; for(int i=0; i<SAMPLE_SIZE; i++) { if(samples[i] < min) min = samples[i]; if(samples[i] > max) max = samples[i]; sum += samples[i]; } return (sum - min - max) / (SAMPLE_SIZE - 2); }

5. 调试技巧与常见问题

从Arduino迁移到STM32时,开发者常遇到以下问题:

  1. I2C通信失败

    • 检查上拉电阻(通常4.7kΩ)
    • 用逻辑分析仪验证时序
    • 确保地址正确(ADDR引脚状态)
  2. HAL库超时问题

    // 在stm32f1xx_hal_conf.h中调整超时时间 #define HAL_I2C_TIMEOUT 1000 // 默认是0xFFFF
  3. 电压读数不稳定

    • 添加0.1μF去耦电容
    • 启用ADS1115内部PGA
    • 适当降低数据速率

调试时可使用以下辅助函数:

void I2C_Scan(I2C_HandleTypeDef *hi2c) { printf("Scanning I2C bus...\n"); for(uint8_t addr = 1; addr < 127; addr++) { HAL_StatusTypeDef status = HAL_I2C_IsDeviceReady(hi2c, addr << 1, 3, 10); if(status == HAL_OK) { printf("Device found at 0x%02X\n", addr); } } }

移植过程中最耗时的往往是时序问题。STM32的HAL_I2C库虽然抽象了底层细节,但在时序控制上不如Arduino的Wire库灵活。当遇到通信问题时,可以尝试调整I2C时钟频率或添加适当的延时。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/10 13:53:45

WPS-Zotero:科研写作终极指南,5分钟实现跨平台文献管理自动化

WPS-Zotero&#xff1a;科研写作终极指南&#xff0c;5分钟实现跨平台文献管理自动化 【免费下载链接】WPS-Zotero An add-on for WPS Writer to integrate with Zotero. 项目地址: https://gitcode.com/gh_mirrors/wp/WPS-Zotero 还在为学术论文的格式调整而烦恼吗&…

作者头像 李华
网站建设 2026/5/10 13:46:10

如何在5分钟内实现Figma界面全中文汉化?

如何在5分钟内实现Figma界面全中文汉化&#xff1f; 【免费下载链接】figmaCN 中文 Figma 插件&#xff0c;设计师人工翻译校验 项目地址: https://gitcode.com/gh_mirrors/fi/figmaCN 还在为Figma复杂的英文界面而头疼吗&#xff1f;作为一名中文设计师&#xff0c;面对…

作者头像 李华
网站建设 2026/5/10 13:38:36

ETS2LA终极指南:为欧洲卡车模拟器2带来智能驾驶革命

ETS2LA终极指南&#xff1a;为欧洲卡车模拟器2带来智能驾驶革命 【免费下载链接】Euro-Truck-Simulator-2-Lane-Assist Plugin based interface program for ETS2/ATS. 项目地址: https://gitcode.com/gh_mirrors/eur/Euro-Truck-Simulator-2-Lane-Assist 你是否曾梦想在…

作者头像 李华