打印
[STM32F1]

STM32F103C8T6芯片ADC功能详细描述+通用模板+关键代码参数修改解析

[复制链接]
156|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tpgf|  楼主 | 2025-3-7 13:04 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
1. ​ADC核心特性
​分辨率:12位,输出范围 0~4095。
​转换速率:最高 ​1 MSPS​(ADC时钟为14MHz时,转换时间约1μs)。
​输入通道:
​16个外部通道​(实际可用数量受芯片引脚限制,例如PA0-PA7、PB0-PB1等)。
​2个内部通道:温度传感器(通道16)和内部参考电压 VREFINT(通道17)。
​工作模式:
​单次/连续转换:单次模式下只转换一次,连续模式下自动重启转换。
​扫描模式:自动按顺序转换一组预配置的通道。
​间断模式:通过触发信号分段转换通道。
​触发源:
软件触发、定时器触发、外部中断(如EXTI)。
​数据对齐:
右对齐(默认,结果直接为 0~4095)或左对齐(便于快速计算)。
​参考电压:
由 VDDA 和 VSSA 引脚提供,需稳定电源(通常接3.3V和GND)。
2. ​关键配置选项
​规则组与注入组:
​规则组:用于常规转换,支持多通道扫描。
​注入组:可打断规则组转换,支持高优先级任务。
​校准:
上电后需执行校准以减小误差(HAL库自动处理,寄存器操作需手动校准)。
​模拟看门狗:
可设置阈值范围,超出范围时触发中断。
3.上代码,复制可用,想修改数据的看代码下面的关键代码解析,根据介绍修改函数参数即可。
/* 头文件包含 */
#include "stm32f10x.h"         // 标准外设库
#include "stm32f10x_gpio.h"    // GPIO库
#include "stm32f10x_adc.h"     // ADC库
#include "stm32f10x_dma.h"     // DMA库
#include "stm32f10x_rcc.h"     // 时钟库

/* 全局变量定义 */
#define ADC1_DR_Address ((uint32_t)0x4001244C) // ADC1数据寄存器地址
uint16_t adc_dma_buffer[3];    // 存储3个通道ADC值的数组

/* 系统时钟配置 */
void RCC_Configuration(void)
{
    // 1. 使能外部高速时钟(HSE)
    RCC_HSEConfig(RCC_HSE_ON);             // 开启外部晶振
    while(RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET); // 等待HSE就绪

    // 2. 配置PLL(倍频至72MHz)
    RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); // HSE不分频,9倍频(8MHz*9=72MHz)

    // 3. 启动PLL并等待就绪
    RCC_PLLCmd(ENABLE);
    while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);

    // 4. 切换系统时钟源到PLL
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
    while(RCC_GetSYSCLKSource() != 0x08);  // 等待时钟切换完成

    // 5. 配置外设总线时钟
    RCC_HCLKConfig(RCC_SYSCLK_Div1);       // AHB时钟72MHz
    RCC_PCLK1Config(RCC_HCLK_Div2);        // APB1时钟36MHz
    RCC_PCLK2Config(RCC_HCLK_Div1);        // APB2时钟72MHz
}

/* ADC1单通道初始化(PA1) */
void ADC1_Single_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    ADC_InitTypeDef ADC_InitStructure;

    // 1. 使能GPIOA和ADC1时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE);

    // 2. 配置PA1为模拟输入模式
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    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;              // 转换通道数
    ADC_Init(ADC1, &ADC_InitStructure);

    // 4. 配置通道1(PA1)的采样时间
    ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_55Cycles5); // 55.5周期采样

    // 5. 开启ADC并校准
    ADC_Cmd(ADC1, ENABLE);                    // 使能ADC
    ADC_ResetCalibration(ADC1);               // 复位校准寄存器
    while(ADC_GetResetCalibrationStatus(ADC1)); // 等待复位完成
    ADC_StartCalibration(ADC1);               // 开始校准
    while(ADC_GetCalibrationStatus(ADC1));    // 等待校准完成
}

/* ADC1多通道DMA初始化(PA0,PA1,PA2) */
void ADC1_DMA_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    ADC_InitTypeDef ADC_InitStructure;
    DMA_InitTypeDef DMA_InitStructure;

    // 1. 使能GPIOA、ADC1和DMA1时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE);
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

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

    // 3. 配置DMA通道1(ADC1规则组)
    DMA_DeInit(DMA1_Channel1);
    DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address; // 外设地址
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)adc_dma_buffer; // 内存地址
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;         // 外设到内存
    DMA_InitStructure.DMA_BufferSize = 3;                      // 传输数据量
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 外设地址固定
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;     // 内存地址递增
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // 16位数据
    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);

    // 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 = 3;                     // 3个通道
    ADC_Init(ADC1, &ADC_InitStructure);

    // 5. 配置各通道顺序和采样时间
    ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); // PA0
    ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5); // PA1
    ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55Cycles5); // PA2

    // 6. 开启DMA和ADC
    DMA_Cmd(DMA1_Channel1, ENABLE);      // 使能DMA
    ADC_DMACmd(ADC1, ENABLE);            // ADC启用DMA传输
    ADC_Cmd(ADC1, ENABLE);               // 使能ADC

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

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

/* 单通道ADC读取函数 */
uint16_t ADC_ReadSingleChannel(void)
{
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);         // 启动转换
    while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));  // 等待转换完成
    return ADC_GetConversionValue(ADC1);            // 返回转换结果
}

/* 主函数 */
int main(void)
{
    // 1. 系统初始化
    RCC_Configuration();       // 配置系统时钟
    ADC1_Single_Init();        // 初始化单通道ADC
    // ADC1_DMA_Init();        // 如果需要多通道DMA,取消注释

    while(1)
    {
        // 2. 单通道读取示例
        uint16_t adc_value = ADC_ReadSingleChannel(); // 读取PA1电压值

        // 3. 多通道DMA数据访问(数据在adc_dma_buffer数组中)
        // 例如:
        // uint16_t ch0 = adc_dma_buffer[0];  // PA0
        // uint16_t ch1 = adc_dma_buffer[1];  // PA1
        // uint16_t ch2 = adc_dma_buffer[2];  // PA2

        // 4. 添加用户处理代码(例如电压转换)
        // float voltage = (adc_value / 4095.0) * 3.3;
    }
}

-------------------------------------------------------我是分割线---------------------------------------------------------

4.关键代码逐行解析
1. 系统时钟配置
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
将外部8MHz晶振作为PLL输入(不分频),9倍频后得到72MHz系统时钟
2. ADC单通道初始化
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_55Cycles5);
参数说明:
ADC1: 选择ADC1外设
ADC_Channel_1: 使用通道1(对应PA1)
1: 规则组转换序列中的第1个位置
ADC_SampleTime_55Cycles5: 采样时间为55.5个ADC时钟周期
3. DMA配置
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
循环模式:当DMA传输完成指定数量的数据后,自动重新开始传输
4. 多通道配置
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);
规则组转换顺序:
第1个转换:通道0(PA0)
第2个转换:通道1(PA1)
第3个转换:通道2(PA2)
5. 启动转换
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
软件触发启动ADC转换
在连续模式下只需调用一次即可持续转换
6.使用场景说明
​单通道模式:

适用于需要精确控制采样时机的场景(如按键触发采样)
典型应用:电池电压检测、电位器读取
​多通道DMA模式:

适用于需要同时监测多个传感器的场景
典型应用:
三相电压监测
多路温度传感器采集
工业控制中的多参数采集
7.注意事项
​电源稳定性:

// 建议在VDDA和VSSA之间并联10uF+0.1uF电容
​采样时间计算:

总转换时间 = 采样时间 + 12.5周期
当ADC时钟为12MHz时,55.5周期对应:tc​onv=(55.5+12.5)/12MHz≈5.67μs
​数据对齐:

// 若使用左对齐,数据寄存器高12位有效
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Left;
​内部参考电压:

// 读取VREFINT(通道17)可计算实际VDDA电压
ADC_RegularChannelConfig(ADC1, ADC_Channel_17, 1, ADC_SampleTime_239Cycles5);
​中断使用:

// 添加转换完成中断
ADC_ITConfig(ADC1, ADC_IT_EOC, ENABLE);
NVIC_EnableIRQ(ADC1_2_IRQn);
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/haoyangyun/article/details/145938483

使用特权

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

本版积分规则

2150

主题

16394

帖子

16

粉丝