STM32-ADC(模拟数字转换器)
本文最后更新于39 天前,其中的信息可能已经过时,如有错误请发送邮件到3014096835@qq.com

ADC结构

stm32ADC电器参数

  • 12位逐次逼近型ADC,1us转换时间
  • 输入电压范围:0~3.3V,转换结果范围0~4095
  • 18个输入通道,可测量16个外部和2个内部信号源
  • 规则组和注入组两个转换单元
  • 模拟看门狗自动监测输入电压范围

逐次逼近型ADC

在逐次逼近型ADC中有一个电压比较器,和一个DAC,通过对DAC赋值可以得到DAC的输出电压,将DAC的输出电压与ADC的输入电压进行比较,便可以得到DAC输入电压所对应的数据,此时使用二分法不断查询DAC与ADC的大小,直到DAC输出电压与ADC输入电压相等时,就得到ADC转换后的数据。

stm32ADC结构


stm32ADC数据由GPIO口输入后,进入模拟至数字转换器,在转换器内部分为注入通道和规则通道,其中注入通道可以一次申请4组数据,规则通道可以一次申请16组数据,但规则通道数据寄存器仅有16位,需先将规则通道数据寄存器内的数据转运出去后,才能接收后面的数据,而注入通道数据寄存器有4*16位可以一次性拿去4组16位数据。
下面为ADC的触发模式,可以由软件触发,也可以由硬件触发,如定时器,外部引脚。

转换模式

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

单次转换,非扫描模式

在16组通道内,只转换其中一组,并只转换一次,转换完后置标志位转换结束。

连续转换,非扫描模式

在16组通道内,只转换其中一组,但持续多次转换,转换完后自动下一次转换。

单次转换,扫描模式

在16组通道内,将指定的通道依次进行转换,并只转换一次,转换完后置标志位转换结束。

连续转换,扫描模式

在16组通道内,将指定的通道一次进行转换,并持续多次转换,转换完后自动下一次转换。在规则组通道下,由于规则通道数据寄存器仅有16位,因此需要在一次转换后使用[[STM32-DMA|DMA]]立即将数据转运出去。

间断模式

自行查阅手册

触发控制

数据对齐


一般情况下,我们使用数据右对齐,当数据左对齐时,低位被补0,此时ADC的数据会偏大。

校准

  • ADC有一个内置自校准模式。模式可大幅减小因内部电容器组的变化而造成的准精度误差。校准期间,在每个电容器上都会计算出一个误差修正码(数字值),这个码用于消除在随后的转换中每个电容器上产生的误差
  • 建议每次上电后执行一次校准
  • 启动校准前,ADC必须处于关电状态超过至少两个ADC时钟周期。

硬件电路

ADC标准库代码

ADC单通道

/**
  * 函    数:AD初始化
  * 参    数:无
  * 返 回 值:无
  */
void AD_Init(void)
{
    /*开启时钟*/
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);    //开启ADC1的时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);   //开启GPIOA的时钟

    /*设置ADC时钟*/
    RCC_ADCCLKConfig(RCC_PCLK2_Div6);                       //选择时钟6分频,ADCCLK = 72MHz / 6 = 12MHz

    /*GPIO初始化*/
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);                  //将PA0引脚初始化为模拟输入

    /*规则组通道配置*/
    ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);     //规则组序列1的位置,配置为通道0

    /*ADC初始化*/
    ADC_InitTypeDef ADC_InitStructure;                      //定义结构体变量
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;      //模式,选择独立模式,即单独使用ADC1
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;  //数据对齐,选择右对齐
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //外部触发,使用软件触发,不需要外部触发
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;     //连续转换,失能,每转换一次规则组序列后停止
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;           //扫描模式,失能,只转换规则组的序列1这一个位置
    ADC_InitStructure.ADC_NbrOfChannel = 1;                 //通道数,为1,仅在扫描模式下,才需要指定大于1的数,在非扫描模式下,只能是1
    ADC_Init(ADC1, &ADC_InitStructure);                     //将结构体变量交给ADC_Init,配置ADC1

    /*ADC使能*/
    ADC_Cmd(ADC1, ENABLE);                                  //使能ADC1,ADC开始运行

    /*ADC校准*/
    ADC_ResetCalibration(ADC1);                             //固定流程,内部有电路会自动执行校准
    while (ADC_GetResetCalibrationStatus(ADC1) == SET);
    ADC_StartCalibration(ADC1);
    while (ADC_GetCalibrationStatus(ADC1) == SET);
}

/**
  * 函    数:获取AD转换的值
  * 参    数:无
  * 返 回 值:AD转换的值,范围:0~4095
  */
uint16_t AD_GetValue(void)
{
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);                 //软件触发AD转换一次
    while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); //等待EOC标志位,即等待AD转换结束
    return ADC_GetConversionValue(ADC1);                    //读数据寄存器,得到AD转换的结果
}

ADC多通道

/**
  * 函    数:AD初始化
  * 参    数:无
  * 返 回 值:无
  */
void AD_Init(void)
{
    /*开启时钟*/
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);    //开启ADC1的时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);   //开启GPIOA的时钟

    /*设置ADC时钟*/
    RCC_ADCCLKConfig(RCC_PCLK2_Div6);                       //选择时钟6分频,ADCCLK = 72MHz / 6 = 12MHz

    /*GPIO初始化*/
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);                  //将PA0、PA1、PA2和PA3引脚初始化为模拟输入

    /*不在此处配置规则组序列,而是在每次AD转换前配置,这样可以灵活更改AD转换的通道*/

    /*ADC初始化*/
    ADC_InitTypeDef ADC_InitStructure;                      //定义结构体变量
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;      //模式,选择独立模式,即单独使用ADC1
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;  //数据对齐,选择右对齐
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //外部触发,使用软件触发,不需要外部触发
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;     //连续转换,失能,每转换一次规则组序列后停止
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;           //扫描模式,失能,只转换规则组的序列1这一个位置
    ADC_InitStructure.ADC_NbrOfChannel = 1;                 //通道数,为1,仅在扫描模式下,才需要指定大于1的数,在非扫描模式下,只能是1
    ADC_Init(ADC1, &ADC_InitStructure);                     //将结构体变量交给ADC_Init,配置ADC1

    /*ADC使能*/
    ADC_Cmd(ADC1, ENABLE);                                  //使能ADC1,ADC开始运行

    /*ADC校准*/
    ADC_ResetCalibration(ADC1);                             //固定流程,内部有电路会自动执行校准
    while (ADC_GetResetCalibrationStatus(ADC1) == SET);
    ADC_StartCalibration(ADC1);
    while (ADC_GetCalibrationStatus(ADC1) == SET);
}

/**
  * 函    数:获取AD转换的值
  * 参    数:ADC_Channel 指定AD转换的通道,范围:ADC_Channel_x,其中x可以是0/1/2/3
  * 返 回 值:AD转换的值,范围:0~4095
  */
uint16_t AD_GetValue(uint8_t ADC_Channel)
{
    ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_55Cycles5);   //在每次转换前,根据函数形参灵活更改规则组的通道1
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);                 //软件触发AD转换一次
    while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); //等待EOC标志位,即等待AD转换结束
    return ADC_GetConversionValue(ADC1);                    //读数据寄存器,得到AD转换的结果
}
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇