万图 发表于 2024-10-11 08:10

基于STM32F103的ADC应用与实现


STM32F103是一款非常流行的32位微控制器,基于Cortex-M3内核,具备较强的处理能力和丰富的外设资源,广泛应用于工业控制、消费电子等领域。在嵌入式系统中,ADC(模拟数字转换器)功能非常重要,它可以将模拟信号(如温度、电压)转换为数字信号,供MCU进行处理。本篇文章将介绍如何在STM32F103中使用ADC,并通过示例代码展示如何采集模拟信号。

1. STM32F103硬件概述STM32F103拥有多达16通道的12位ADC,可以同时采集多个模拟信号。其ADC模块具备以下特点:

[*]12位分辨率,高精度采集模拟信号
[*]多通道支持,可以采集多个信号源
[*]DMA支持,可以通过DMA方式自动采集数据,减少CPU负担
[*]转换速度快,适用于实时采集需求

2. 硬件准备
[*]STM32F103开发板
[*]一个可调电位器(作为输入模拟信号)
[*]若干杜邦线

3. 开发环境
[*]IDE: Keil MDK5
[*]库文件: STM32F1 HAL库

4. ADC配置步骤在STM32F103中使用ADC主要分为以下几个步骤:

[*]GPIO配置:将模拟输入信号引脚配置为模拟模式
[*]ADC初始化:设置ADC的分辨率、时钟、触发方式等参数
[*]采集数据:通过启动ADC并读取转换结果获取模拟信号的数字值
[*]处理数据:将采集到的数字信号进行处理或显示

5. 示例代码:使用STM32F103采集模拟信号下面的代码展示了如何使用STM32F103的ADC功能,读取一个电位器的电压值并通过串口发送到PC端。
#include "stm32f10x.h"
#include "stm32f10x_adc.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_usart.h"

// ADC初始化
void ADC_Configuration(void) {
    GPIO_InitTypeDef GPIO_InitStructure;
    ADC_InitTypeDef ADC_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);// 开启ADC1和GPIOA时钟

    // 配置PA0为模拟输入
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;// 设置为模拟输入模式
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // 配置ADC1
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;// 独立模式
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;// 单通道模式
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;// 连续转换模式
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;// 软件触发
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;// 右对齐
    ADC_InitStructure.ADC_NbrOfChannel = 1;// 采集通道数
    ADC_Init(ADC1, &ADC_InitStructure);

    // 配置ADC通道
    ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);// 采集通道0(PA0)

    // 启用ADC
    ADC_Cmd(ADC1, ENABLE);

    // 校准ADC
    ADC_ResetCalibration(ADC1);
    while (ADC_GetResetCalibrationStatus(ADC1));
    ADC_StartCalibration(ADC1);
    while (ADC_GetCalibrationStatus(ADC1));

    // 启动ADC转换
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}

// 串口初始化
void USART_Configuration(void) {
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);

    // 配置PA9为USART1_TX
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // 配置PA10为USART1_RX
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // 配置USART1
    USART_InitStructure.USART_BaudRate = 9600;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_Init(USART1, &USART_InitStructure);

    // 启用USART1
    USART_Cmd(USART1, ENABLE);
}

// 串口发送字符
void USART_SendChar(char c) {
    USART_SendData(USART1, c);
    while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
}

// 串口发送字符串
void USART_SendString(char* str) {
    while (*str) {
      USART_SendChar(*str++);
    }
}

int main(void) {
    uint16_t adc_value;

    ADC_Configuration();// 初始化ADC
    USART_Configuration();// 初始化串口

    while (1) {
      adc_value = ADC_GetConversionValue(ADC1);// 读取ADC值
      char buffer;
      sprintf(buffer, "%d\n", adc_value);// 将ADC值转为字符串
      USART_SendString(buffer);// 通过串口发送ADC值
      for (int i = 0; i < 1000000; i++);// 延时
    }
}

6. 代码解析
[*]ADC_Configuration函数:初始化ADC模块,包括使能时钟、配置引脚和设置ADC工作模式等。ADC1被配置为单通道模式,并通过软件触发方式进行采样。
[*]USART_Configuration函数:配置USART1用于串口通信。通过PA9和PA10作为串口的TX和RX引脚,串口波特率设置为9600。
[*]main函数:主循环中不断读取ADC的转换值,并通过串口将结果发送到PC。通过电位器调节输入电压,ADC值会随之变化。

7. 实际应用在实际应用中,ADC可以用于采集多种模拟信号,如电压、电流、温度等。STM32F103的ADC模块性能强大,采样速度快,适用于需要精确采集信号的场景。通过本文的代码示例,开发者可以快速掌握STM32F103 ADC的使用方法,并将其应用于各种传感器或电压采集场景。

8. 常见问题
[*]ADC采样精度不高:可能是因为参考电压不稳定或信号有干扰,可以考虑使用滤波器或稳定的外部参考电压。
[*]串口数据乱码:检查串口的波特率设置是否正确,确保PC端的波特率与STM32F103一致。
[*]ADC转换速度慢:可以适当调整ADC的采样时间,或通过DMA方式提升数据传输效率。

9. 结论STM32F103的ADC模块功能强大,能够方便地采集模拟信号并将其转换为数字信号,供MCU处理。通过本文的示例代码,大家可以快速上手使用STM32的ADC功能,应用于各种模拟信号的采集场景。

公羊子丹 发表于 2024-10-11 08:10

STM32F103确实好用,ADC加串口这套组合,实战性能很强。

周半梅 发表于 2024-10-11 08:11

我用的也是电位器做输入,代码完美跑起来了。

帛灿灿 发表于 2024-10-11 08:11

终于找到一篇详细的教程了,之前卡在ADC初始化好久。

童雨竹 发表于 2024-10-11 08:11

代码很清晰,按部就班就能实现ADC和串口通信。

Wordsworth 发表于 2024-10-11 08:12

有没有办法提高ADC的转换速度,感觉有点慢?

Bblythe 发表于 2024-10-11 08:12

我用了温度传感器,直接拿这个代码改了下,效果很好。

Pulitzer 发表于 2024-10-11 08:12

串口发送数据那里很简洁,搞定PC端通信太省心了。

Uriah 发表于 2024-10-11 08:12

太及时了,我正好在研究STM32的ADC,这篇文章讲得很清楚。

Uriah 发表于 2024-10-11 08:13

我是用的STM32F103C8,代码稍作调整就跑通了,效果不错。

iyoum 发表于 2024-10-11 19:46

可以使用HSE或HSI作为时钟源,并通过RCC配置适当的预分频器。

Stahan 发表于 2024-10-13 22:31

这个adc精度怎么样啊

macpherson 发表于 2024-10-14 09:36

温度变化可能影响ADC的转换精度和稳定性。
在设计时考虑温度补偿措施,以提高ADC在不同温度下的性能表现。

mmbs 发表于 2024-10-14 11:12

尽量缩短 ADC 输入信号线的长度,过长的信号线容易引入外界干扰,并且会增加信号的寄生电容和电感,影响信号的完整性。

jtracy3 发表于 2024-10-14 22:16

要将模拟地和数字地分开布线,避免数字信号对模拟信号的干扰。在合适的位置将模拟地和数字地单点连接,通常在电源的滤波电容附近。

uiint 发表于 2024-10-15 11:55

ADC 的转换结果与参考电压密切相关。确保提供给 ADC 的参考电压稳定,任何参考电压的波动都会直接影响转换精度。例如,如果使用外部参考电压源,要选择纹波小、噪声低的电源芯片。

sdlls 发表于 2024-10-16 19:41

如果使用多个ADC通道,合理安排转换顺序和时间,避免通道间的相互干扰。

timfordlare 发表于 2024-10-17 10:00

对于STM32F103,需要使能ADC1或ADC2的时钟,通常是通过RCC_APB2PeriphClockCmd函数来实现。

primojones 发表于 2024-10-18 18:01

考虑进行 ADC 数据校准。STM32F103 提供了一些校准功能,可以提高 ADC 的转换精度。在初始化或者定期执行校准操作,以补偿 ADC 内部的失调误差等。

gygp 发表于 2024-10-18 21:33

ADC 对电源噪声非常敏感。在硬件设计时,要对电源进行良好的滤波处理。在靠近 STM32F103 芯片的电源引脚处添加去耦电容,如 100nF 和 1μF 的电容组合,以滤除高频和低频噪声。
页: [1] 2 3
查看完整版本: 基于STM32F103的ADC应用与实现