百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT技术 > 正文

STM32-ADC如何把采集的数据转换为小数

wptr33 2025-07-06 17:24 4 浏览

编辑

一、代码原理解析

这段代码围绕 “STM32 中 ADC 数据采集、整数与小数计算及串口输出” 展开,核心是数据类型的使用(unsigned int/signed int/float )、ADC 数值转换及串口打印,拆解如下:

1. 变量类型与用途

  • unsigned int AD;
    无符号整型变量,用于存储 ADC 原始采样值(ADC 通常输出 12 位、10 位等无符号数据,用 unsigned int 适配其范围 )。
  • signed int ADC_ConvertedValueLoca;
    有符号整型变量,用于存储整数形式的转换结果(如电压值按比例换算后的整数部分,或直接放大后的整数值 )。
  • float ADC_ConvertedValueLocal;
    单精度浮点型变量,用于存储带小数的精确转换结果(如实际电压值,包含小数部分 )。

2. ADC 数据采集与转换

AD = HAL_ADC_GetValue(&hadc3);
  • 功能:调用 STM32 HAL 库函数 HAL_ADC_GetValue ,从 hadc3 对应的 ADC 通道读取原始采样值,存入 AD 。假设 ADC 是 12 位分辨率,AD 的范围是 0~4095(对应电压范围 0~3.3V ,需结合硬件电路 )。
ADC_ConvertedValueLoca = AD * 3.3 / 4096;
  • 原理:将 ADC 原始值(AD )转换为整数形式的电压值(或比例值 )。公式 AD * 3.3 / 4096 的意义是: 3.3 是参考电压(假设 ADC 参考电压为 3.3V )。 4096 是 12 位 ADC 的满量程值(2^12 = 4096 )。 计算结果本应是带小数的电压值(如 1.234V ),但因存储到 signed int 变量中,小数部分会被截断,只保留整数部分(如 1 )。
ADC_ConvertedValueLocal = (double)ADC_value * 3.3 / 4096;
  • 原理:将 ADC 原始值(ADC_value ,需与 AD 逻辑一致 )转换为浮点型电压值。通过 (double) 强制类型转换,让计算过程在浮点环境下执行,保留小数部分,结果更精确(如 1.234567 )。

3. 串口输出(sprintf + HAL_UART_Transmit )

sprintf((char*)ch1, "AD:%5d", AD);
ch1[18] = '\r';
ch1[19] = '\n';
HAL_UART_Transmit(&huart1, ch1, sizeof(ch1), 0x10);
  • sprintf 功能:将 AD 的值按格式 AD:%5d 写入字符串数组 ch1 。%5d 表示以 5 个字符宽度输出整数,不足补空格。
  • 手动添加换行符:ch1[18] = '\r'; ch1[19] = '\n'; 是在字符串指定位置添加回车(\r )和换行(\n ),让串口输出的内容自动换行,符合串口调试习惯。
  • HAL_UART_Transmit:调用 STM32 HAL 库函数,将 ch1 中的数据通过 huart1 对应的串口发送出去,sizeof(ch1) 是发送数据长度,0x10 是超时时间(可根据需求调整 )。

4. 整数与浮点输出对比

  • 整数输出
  • sprintf((char*)ch1, "AD:%10d", ADC_ConvertedValueLoca);
  • 因 ADC_ConvertedValueLoca 是 signed int ,存储的是截断后的整数(如 1 ),串口输出为整数形式(如 AD: 1 )。
  • 浮点输出
  • printf("计算得出电压值 = %f V \r\n", ADC_ConvertedValueLocal);
  • ADC_ConvertedValueLocal 是 float 类型,%f 格式符会输出带小数的数值(如 计算得出电压值 = 1.234567 V ),保留小数精度。

二、应用方法与场景

这种 ADC 数据采集、类型转换及串口输出的代码,常见于嵌入式系统的模拟量采集与调试场景(如电压、温度、传感器信号采集 ),以下说明典型用法和扩展思路:

1. 典型应用场景(电压采集与调试 )

在 STM32 项目中,采集外部电压并通过串口实时打印,流程如下:

#include "stm32f4xx_hal.h"
#include <stdio.h>
#include <string.h>

ADC_HandleTypeDef hadc3;
UART_HandleTypeDef huart1;
char ch1[20]; // 假设串口发送缓冲区大小为 20

int main(void) {
    // 1. 初始化 ADC、UART(需调用 HAL_ADC_Init、HAL_UART_Init 等 )
    HAL_Init();
    MX_ADC3_Init();
    MX_USART1_UART_Init();

    unsigned int AD;
    signed int ADC_ConvertedValueLoca;
    float ADC_ConvertedValueLocal;

    while (1) {
        // 2. 采集 ADC 原始值
        AD = HAL_ADC_GetValue(&hadc3);

        // 3. 转换为整数形式(截断小数 )
        ADC_ConvertedValueLoca = AD * 3.3 / 4096;

        // 4. 串口输出原始值(整数 )
        memset(ch1, 0, sizeof(ch1)); // 清空缓冲区
        sprintf((char*)ch1, "AD:%5d", AD);
        ch1[18] = '\r';
        ch1[19] = '\n';
        HAL_UART_Transmit(&huart1, ch1, sizeof(ch1), 0x10);
        HAL_Delay(1000);

        // 5. 串口输出整数转换值
        memset(ch1, 0, sizeof(ch1));
        sprintf((char*)ch1, "AD:%10d", ADC_ConvertedValueLoca);
        ch1[18] = '\r';
        ch1[19] = '\n';
        HAL_UART_Transmit(&huart1, ch1, sizeof(ch1), 0x10);
        HAL_Delay(1000);

        // 6. 转换为浮点形式(保留小数 )
        ADC_ConvertedValueLocal = (double)AD * 3.3 / 4096;

        // 7. 串口输出浮点值(用 printf 更方便,需重定向 printf 到串口 )
        printf("AD转换原始值 = 0x%04X \r\n", AD);
        printf("计算得出电压值 = %f V \r\n", ADC_ConvertedValueLocal);
        HAL_Delay(1000);
    }
}
  • 关键步骤: 初始化 ADC 和 UART 外设,确保硬件能正常工作。 循环采集 ADC 数据,分别转换为整数和浮点类型,通过串口输出,方便调试观察。

2. 扩展与优化思路

  • 精度优化
    ADC 原始值是整数,转换为电压时若需更高精度,可改用 double 类型(如 ADC_ConvertedValueLocal = (double)AD * 3.3 / 4096; ),或调整公式中的比例系数。
  • 串口输出优化
    • 重定向 printf 到串口:通过实现 fputc 函数,让 printf 直接输出到串口,简化代码(替代 sprintf + HAL_UART_Transmit ):
    • int fputc(int ch, FILE *f) { HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, 0xFFFF); return ch; }
    • 使用环形缓冲区:若数据发送频繁,避免 HAL_UART_Transmit 的阻塞问题,可结合 DMA 或环形缓冲区实现非阻塞发送。
  • 数据滤波
    实际采集的 ADC 数据可能有噪声,可添加滑动平均滤波等算法,提升数据稳定性:
  • #define FILTER_LEN 10 unsigned int adc_buff[FILTER_LEN] = {0}; unsigned int adc_index = 0; unsigned int adc_sum = 0; // 采集并滤波 AD = HAL_ADC_GetValue(&hadc3); adc_sum -= adc_buff[adc_index]; adc_buff[adc_index] = AD; adc_sum += AD; adc_index = (adc_index + 1) % FILTER_LEN; AD = adc_sum / FILTER_LEN; // 取平均值作为滤波后的值

3. 注意事项

  • 类型截断问题
    ADC_ConvertedValueLoca = AD * 3.3 / 4096; 中,若 AD 是 unsigned int ,3.3 是 double ,计算时会自动转换为浮点,但赋值给 signed int 会截断小数,若需保留小数必须用 float/double 存储。
  • 串口缓冲区溢出
    ch1 数组大小为 20,若 sprintf 输出的内容超过数组长度,会导致缓冲区溢出,破坏其他内存数据。需确保格式化字符串长度不超过数组大小,或动态分配缓冲区。
  • ADC 校准与参考电压
    实际应用中,需先执行 ADC 校准(HAL_ADCEx_Calibration_Start ),且确保参考电压(3.3V )与硬件一致,否则转换结果会有偏差。

总结

这段代码的核心是利用不同数据类型(int/float )处理 ADC 原始值的整数与小数转换,结合串口输出实现数据调试。理解其原理后,可扩展到温度传感器(如 NTC )、电流采集等场景,通过优化滤波、串口输出方式,提升数据处理的精度和稳定性,是嵌入式模拟量采集与调试的基础实践。

相关推荐

F103C8T6移植FATFS文件系统 版本R0.15

STM32F103C8T6芯片在W25Q64上移植FATFS(版本R0.15)实现过程:1、首先完成USART初始化和调试,用于传输信息到串口调试软件。2、完成SPI相关参数配置及调试,用于单片机和存...

stm32使用MPU6050或ADXL345控制的车辆减速灯

本实验例程采用MPU6050六轴运动处理组件...

STM32F103串口输出prtinf覆盖(stm32printf函数的串口输出)

采用正点原子的板子,有如下坑,记录如下:(1)main中应用头文件#include"stdio.h"(2)采用hal进行fputc和fgetc覆盖,如下intfputc(intc...

STM32 学习8 USART串口通讯与printf重定向

一、串口通信介绍STM32F103ZET6包含多个UART、USART串口。...

教你如何使用SEGGER RTT优雅的实现日志系统

今天开始了BMS系统的软件代码部分的搭建,计划是分成三层:硬件驱动,AFE层和系统应用层。第一步肯定是先把底层的IIC通信调通,CG861xx的IIC通信和TI的BQ769X0...

终极调试利器,各种Link通吃(link4a调制方式)

今天继续更新一期KEIL调试方法。事实上,关于调试方法,鱼鹰写了一个系列,汇总文为《佛祖保佑,永无BUG,永不修改|KEIL调试系列总结篇》,对于KEIL方法感兴趣的可以看看。这个调试...

在 STM32 中使用 printf() 函数,别漏掉这几行代码!

问:在STM32上轻松使用printf函数除了点亮LED外,向串行控制台发送打印信息可能是调试嵌入式项目时最简单、最直接且最常用的技术。虽然大多数平台都拥有可以在UART总线上传输数据的API,但它们...

高性能异步io机制:io_uring(异步io select)

io_uring是linux内核5.10引入的异步io接口。相比起用户态的DPDK、SPDK,io_uring作为内核的一部分,通过mmap的方式实现用户和内核共享内存,并基于m...

精品博文ARM中打印函数print 的几种实现方法

1利用C库函数printf步骤:1)首先需要包含头文件stdio.h。2)然后定义文件句柄。实际上就是一个int型变量封装在结构体中。struct__FILE{inthandle;};3)定...

C语言char的详解(c语言(char))

在C语言中,char是一种基础数据类型,用于表示字符或小整数值。对char的理解和处理非常重要,尤其是在字符串操作、文件读写或其他需要直接控制内存的应用场景中。下面从基本定义、存储方式、常见用法...

C语言之文件操作(c语言文件操作实验总结)

文件操作是C语言中非常重要的功能,用于读取和写入文件中的数据。C语言提供了一组标准库函数(如fopen、fclose、fread、fwrite等)来实现文件操作。以下是针对C语言初学者的详细讲解。...

STM32-ADC如何把采集的数据转换为小数

编辑一、代码原理解析这段代码围绕“STM32中ADC数据采集、整数与小数计算及串口输出”展开,核心是数据类型的使用(unsignedint/signedint/float)、ADC数...

循环队列原理及在单片机串口通讯中的应用(二)

前言书接上回,前文主要介绍了环形队列的实现原理以及C语言实现及测试过程,本文将回归到嵌入式平台的应用中,话不多说,淦,上干货!...

STM32编程中printf函数重定向背后的原理

  在C语言中,printf是一个非常好用的函数,尤其是在程序调试阶段,我们可以通printf打印变量的值来帮助查错。在学习C语言的时候我们的开发环境和运行环境都是PC机,printf函数打印到PC机...

MySQL 避坑指南之隐式数据类型转换

...