打印
[STM32F1]

基于STM32F103的ADC应用与实现

[复制链接]
29|10
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
万图|  楼主 | 2024-10-11 08:10 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

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[10];
        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初始化好久。

使用特权

评论回复
5
童雨竹| | 2024-10-11 08:11 | 只看该作者
代码很清晰,按部就班就能实现ADC和串口通信。

使用特权

评论回复
6
Wordsworth| | 2024-10-11 08:12 | 只看该作者
有没有办法提高ADC的转换速度,感觉有点慢?

使用特权

评论回复
7
Bblythe| | 2024-10-11 08:12 | 只看该作者
我用了温度传感器,直接拿这个代码改了下,效果很好。

使用特权

评论回复
8
Pulitzer| | 2024-10-11 08:12 | 只看该作者
串口发送数据那里很简洁,搞定PC端通信太省心了。

使用特权

评论回复
9
Uriah| | 2024-10-11 08:12 | 只看该作者
太及时了,我正好在研究STM32的ADC,这篇文章讲得很清楚。

使用特权

评论回复
10
Uriah| | 2024-10-11 08:13 | 只看该作者
我是用的STM32F103C8,代码稍作调整就跑通了,效果不错。

使用特权

评论回复
11
Clyde011| | 2024-10-11 08:13 | 只看该作者
我是用的STM32F103C8,代码稍作调整就跑通了,效果不错。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

35

主题

3687

帖子

0

粉丝