首页 > 其他分享 >STM32单片机快速入门——ADC篇

STM32单片机快速入门——ADC篇

时间:2025-01-22 21:27:24浏览次数:3  
标签:DMA 转换 STM32 单片机 InitStructure ADC ADC1 GPIO

目录

一.ADC简介

二.ADC组成

2.1 逐次逼近型ADC结构

2.2 ADC模块总体结构

三.ADC配置

3.1 时钟源的配置

3.2 ADC触发源选择

3.2.1 软件触发

3.2.2 定时器定时触发

3.3.3 外部中断触发

3.3 ADC转化模式

3.4 ADC对齐模式

3.5 ADC校准

3.6  ADC配置流程

四.ADC代码示例

4.1 ADC单通道+单次转换

4.2 多通道连续转换(带DMA)

五.附STM32F103C8T6引脚定义表


一.ADC简介

ADC(Analog-to-Digital Converter,模数转换器)是嵌入式开发中常用的功能之一,用于将模拟信号(如传感器的电压)转换为数字信号供MCU处理。STM32F1系列的ADC模块支持12位精度,具有多通道和多模式的特点,广泛应用于信号采集、控制等领域。

STM32的ADC是12位逐次逼近型ADC,转换时间为1us,输入电压的范围是0~3.3V,转换结果的数值范围是0~4095(即2^12),有12个输入通道,可测量10个外部(GPIO),和2个内部信号源(内部温度传感器 和 内部参考电压1.2V,不随供电电压的变化而变化,可以测量CPU的温度),有规则组和注入组两个转换单元,以及模拟看门狗自动监测输入电压范围,超出范围可直接通往NVIC申请中断。

二.ADC组成

2.1 逐次逼近型ADC结构

这里以8位ADC为例,STM32的ADC通常是12位的,但两者原理是一样的。

可以通过配置左下角的ADDA,ADDB,ADDC,然后给ALE端口一个锁存信号,就可以选择左上角的哪个INx通道信号输入比较器,经过DAC内部的加权电阻网络,不断输出电压与输入电压进行比较,直到DAC的输出电压与外部输入的电压近似相等,再将DAC的值通过三态锁存缓冲器输出。与此同时,产生EOC结束信号。

2.2 ADC模块总体结构

从图中可以发现,除了对通道的选择外,STM32还对转换的通道进行了分组:注入通道 和 规则通道。下表是他们的不同点:

重点注意事项:

  • 注入组的优先级 比 规则组的优先级更高,可以打断规则组的采集。
  • 注入组的四个通道 正好 对应四个数据寄存器,不会出现数据被别的通道覆盖的现象,但规则组则是16个通道共用一个数据寄存器,需要及时把数据移走,不然在进行多个规则组通道采样时,会出现数据覆盖现象。最好配合DMA来进行,至于什么是DMA?我们后续章节再进行讲解。

总结:

规则组适用于:定期采集多个通道的数据,处理量较大但实时性要求较低的情况。

注入组适用于:实时性要求高的关键信号采集,通常用于紧急处理场景。

三.ADC配置

3.1 时钟源的配置

参考手册的时钟树:

假设当经过AHB分频后的时钟频率为72MHz,则ADC预分频器只能进行 6/8分频,因为这里的ADC最大只能接受14HMz的时钟频率,为什么最大只能接收14HMz的时钟频率呢?还记得我们之前提到的,ADC的最短转换时间是1us吗?

ADC的转换时间计算公式为:

                                Tconv = 采样时间 + 12.5个周期;

当ADC的时钟频率为最大14HMz时,参考手册:
 

此时采样时间为1.5个周期,所以 Tconv = 采样时间 + 12.5个周期 = 1.5 + 12.5 = 14 个周期,

又因为时钟频率为14HMz,所以总时间为 T = 14 * (1/14 HMz),也就是1us。与ADC的最短转换时间1us不谋而合。

3.2 ADC触发源选择

3.2.1 软件触发

通过调用封装好的标准库函数,直接进行软件触发。

3.2.2 定时器定时触发

可以在定时器的中断里触发,但不推荐这种做法,因为会导致程序频繁的进入中断,会影响到程序的正常运行,更推荐的做法是:将定时器的更新事件映射到TRGO引脚,选择为触发ADC转换,这样就可以实现硬件层面的自动触发。

3.3.3 外部中断触发

通过外部中断,会产生一个脉冲信号,触发ADC转换,具体什么是外部中断,请参考外部中断EXTI篇STM32单片机快速入门——(外部)中断篇_stm32 hall外部中断初始化-CSDN博客

3.3 ADC转化模式

ADC总共有四种转换模式,分别是:

  • 单次转换,非扫描模式
  • 单次转换,扫描模式
  • 连续转换,非扫描模式
  • 连续转换,扫描模式

我们分开进行讲解:

  • 转换
    • 单次:只转换一次
    • 连续:只要一开启转换,就会不断的进行。
  • 非扫描:一次只转换一个通道
  • 扫描:一次性可同时按顺序转换多个通道

进行排列组合,便可以得到以下模式:

3.4 ADC对齐模式

对齐模式有:

  • 左对齐
  • 右对齐

STM32F103C8T6芯片的ADC为12位的,但是数据寄存器为16位的,选择 左对齐 相当于把结果左位移了4位,将AD采集结果扩大了2^4倍。选择 右对齐 则读出的数据就是正常的原始数据。所以我们选择右对齐居多。

3.5 ADC校准

为什么要进行ADC的校准?

因为:ADC内部存在硬件偏差(Offset Error),导致零输入信号时转换结果并非0。校准可以修正这些偏差,使得零输入时输出接近真实值。温度、供电电压等环境因素会影响ADC性能,通过校准可以在不同条件下确保一致性

3.6  ADC配置流程

四.ADC代码示例

4.1 ADC单通道+单次转换

#include "stm32f10x.h"

void ADC_Config(void);
uint16_t ADC_Read(void);

int main(void)
{
    uint16_t adc_value;

    // 配置ADC
    ADC_Config();

    while (1)
    {
        // 读取ADC值
        adc_value = ADC_Read();
    }
}

void ADC_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    ADC_InitTypeDef ADC_InitStructure;
    
    // 1. 启用时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);

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

    // 3. 配置ADC参数
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;          // 单通道非扫描模式
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;    // 单次转换模式
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // 软件触发
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; // 数据右对齐
    ADC_InitStructure.ADC_NbrOfChannel = 1;               // 转换通道数量为1
    ADC_Init(ADC1, &ADC_InitStructure);

    // 4. 配置ADC通道
    ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);

    // 5. 启用ADC并进行校准
    ADC_Cmd(ADC1, ENABLE);
    ADC_ResetCalibration(ADC1);       // 重置校准
    while (ADC_GetResetCalibrationStatus(ADC1));
    ADC_StartCalibration(ADC1);       // 开始校准
    while (ADC_GetCalibrationStatus(ADC1));
}

uint16_t ADC_Read(void)
{
    // 启动ADC转换
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);

    // 等待转换完成
    while (!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));

    // 读取转换结果
    return ADC_GetConversionValue(ADC1);
}

4.2 多通道连续转换(带DMA)

#include "stm32f10x.h"

#define ADC1_DR_Address ((uint32_t)0x4001244C)

uint16_t ADC_ConvertedValue[2];

void ADC_DMA_Config(void);

int main(void)
{
    // 配置ADC和DMA
    ADC_DMA_Config();

    while (1)
    {
        // ADC_ConvertedValue中保存了两个通道的转换结果
        uint16_t value0 = ADC_ConvertedValue[0];
        uint16_t value1 = ADC_ConvertedValue[1];
    }
}

void ADC_DMA_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    ADC_InitTypeDef ADC_InitStructure;
    DMA_InitTypeDef DMA_InitStructure;

    // 1. 启用时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

    // 2. 配置GPIO为模拟输入模式
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // 3. 配置DMA
    DMA_DeInit(DMA1_Channel1);
    DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC_ConvertedValue;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_BufferSize = 2;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel1, &DMA_InitStructure);
    DMA_Cmd(DMA1_Channel1, ENABLE);

    // 4. 配置ADC
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
    ADC_InitStructure.ADC_ScanConvMode = ENABLE;            // 扫描模式
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;      // 连续转换模式
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // 软件触发
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;  // 数据右对齐
    ADC_InitStructure.ADC_NbrOfChannel = 2;                // 转换通道数量为2
    ADC_Init(ADC1, &ADC_InitStructure);

    // 5. 配置ADC通道
    ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);
    ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5);

    // 6. 启用ADC DMA
    ADC_DMACmd(ADC1, ENABLE);

    // 7. 启用ADC并进行校准
    ADC_Cmd(ADC1, ENABLE);
    ADC_ResetCalibration(ADC1);
    while (ADC_GetResetCalibrationStatus(ADC1));
    ADC_StartCalibration(ADC1);
    while (ADC_GetCalibrationStatus(ADC1));

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

五.附STM32F103C8T6引脚定义表

标签:DMA,转换,STM32,单片机,InitStructure,ADC,ADC1,GPIO
From: https://blog.csdn.net/2301_81633842/article/details/145309352

相关文章

  • STM32学习笔记-创建工程模版
    1、通过Keil创建新项目。2、在创建的项目文件夹下分别建立Strat、Library、User文件夹。3、在Start文件夹中放入以下固件库中的文件。启动文件:\固件库\STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup\arm外设文件:\固件库\ST......
  • 必须知道!单片机原理及应用的关键知识点
    大家好!今天,咱们来聊聊一个听起来就特别技术范儿,但实际上和我们每个人的生活都息息相关的话题——单片机原理及应用。别急,我知道你们可能已经在心里默念:“这不就是那些技术宅才关心的事儿嘛,跟我有啥关系?”别走开,我保证,这事儿比你想象的有意思多了,而且说不定还能让你在朋友面......
  • STM32之FreeRTOS开发介绍(十九)
    STM32F407系列文章- freertos(十九)目录前言一、简述二、开源网址三、原理及功能特性1.原理2.功能3.特点4.优缺点四、参考书籍五、实现方式总结前言FreeRTOS是一个免费的、开源的实时操作系统,专为微控制器和嵌入式系统设计,它以其轻量级、高效、易于移植和强大......
  • STM32 中 GPIO 的八种工作模式介绍
    STM32的GPIO有八种工作模式,分为输入模式和输出模式,以下是详细介绍:输入模式1. 浮空输入(GPIO_Mode_IN_FLOATING)• 工作原理:引脚不连接内部上拉或下拉电阻,完全依赖外部电路来确定电平。引脚电平状态不确定,容易受外界干扰。• 适用场景:适用于连接高阻抗输出的外部设备,如......
  • 记录STM32串口通信调试的若干问题(基于HAL库)(一)硬件选型和编程环境配置
    由于遇人不淑,项目经验坑爹(永远不要指望学校和导师),本电子类科班生硬是被整成了四不像工程师,不得不自学来找到对口的工作。本文记录STM32开发的历程,有一样的初学者可以参考借鉴。一.硬件设施1.STM32F103C8T6最小系统系统板采用stm32f103c8t6最小系统板,某宝某猫上一杯奶茶的钱......
  • Silicon Labs C8051F020 单片机 USB Debug Adapter适配器调试无法连接问题
    在做单片机大作业,使用Keil,使用USB连接开发板。想要进入到调试或烧录功能时总是报错:CannotconnecttotheselectedUSBdebugadapterToolStickbaseadapter.Pleasecheckthatthedeviceispluggedinandnotalreadyinuse如图:首先按照老师发的教程逐个复查,排除了驱......
  • STM32江科大————DMA数据转运(实现AD多通道)
    声明:本人跟随b站江科大学习,本文章是观看完视频后的一些个人总结和经验分享,也同时为了方便日后的复习,如果有错误请各位大佬指出,如果对你有帮助可以点个赞小小鼓励一下,本文章建议配合原视频使用❤️如果你也正在学习STM32可以订阅本专栏,后续将不定期更新(˘³˘)❤️......
  • 基于单片机自动售货机系统设计(论文+源码)
    1系统方案设计本设计自动售货机系统的系统架构设计如图所示,其采用STM32F103单片机作为控制器,结合ESP8266WiFi通信模块、SG90舵机、OLED液晶、按键、LED灯等构成整个系统。用户在使用时,可以通过按键选择相应的商品(可乐、雪碧、水),并进行投币(1元、5元、10元),当确认购买后舵机转......
  • 基于单片机的智能家居火灾报警系统设计
    1.引言随着科技的迅速发展,智能家居在我们的生活中越来越普及,火灾报警系统作为其中的重要一环,对保护家庭安全、保障人们生命财产安全具有至关重要的作用。传统的火灾报警系统往往存在着反应迟钝、故障率较高和易受环境干扰等问题。为了提高火灾报警系统的灵敏度和可靠性,本......
  • STM32之CubeMX新建工程操作(十八)
    STM32F407系列文章- STM32CubeMX(十八)目录前言一、STM32CubeMX二、新建工程​编辑1.创建工程2.选择芯片型号3.Pinout引脚分配1.SYS配置2.RCC配置3.定时器配置4.GPIO引脚配置5.中断配置6.通讯接口配置7.插件Middleware配置4.Clock时钟树配置5.工程管理Proje......