STM32学习笔记11:ADC的使用

芯片型号:STM32F103RC

软件开发包:标准外设库

一、ADC基本结构

ADC基本结构

先是输入通道,即 16 个 GPIO 口和 2 个内部通道。

经过选择开关后,进入 AD 转换器,有两个组,即规则组和注入组。规则组最多可以选中 16 个通道,注入组最多可以选中 4 个通道。然后转换的结果存放在 AD 数据寄存器,其中规则组只有一个数据寄存器,而注入组有 4 个。

下面是触发控制,提供了开始转换的 START 信号,有软件触发和硬件触发两种。右边是来自 RCC 的 ADC 时钟,ADC 逐次比较的过程就是有这个时钟驱动的。

然后上面,可以布置一个模拟看门狗用于检测转换结果的范围,如果超出设定的阈值,就通过中断输出控制,向 NVIC 申请中断。另外,规则组和注入组转换完成后会有 EOC 信号,它会置一个标志位,也可以通过中断输出控制,向 NVIC 申请中断。

最后右下角还有一个开关控制,在库函数中就是 ADC_Cmd 函数,用于给 ADC 上电的。

二、ADC 初始化结构体详解

typedef struct
{
    uint32_t ADC_Mode; 						// ADC 工作模式选择
    FunctionalState ADC_ScanConvMode; 		// ADC 扫描(多通道)或者单次(单通道)模式选择
    FunctionalState ADC_ContinuousConvMode; // ADC 单次转换或者连续转换选择
    uint32_t ADC_ExternalTrigConv; 			// ADC 转换触发信号选择
    uint32_t ADC_DataAlign; 				// ADC 数据寄存器对齐格式
    uint8_t ADC_NbrOfChannel; 				// ADC 采集通道数
} ADC_InitTypeDef;
  1. ADC_Mode:选择 ADC 的模式,当使用一个 ADC 时是独立模式,使用两个 ADC 时是双模式,在双模式下还有很多细分模式可选,一般使用一个 ADC 的独立模式。
  2. ADC_DataAlign:转换结果数据对齐模式,可选右对齐 ADC_DataAlign_Right 或者左对齐 ADC_DataAlign_Left。一般选择右对齐模式。
  3. ADC_ContinuousConvMode:可选参数为 ENABLE 和 DISABLE,配置是启动自动连续转换还是单次转换。使用 ENABLE 配置为自动连续转换;使用 DISABLE 配置为单次转换。
  4. ADC_ExternalTrigConv:外部触发选择,一般使用软件自动触发。
  5. ADC_ScanConvMode:可选参数为 ENABLE 和 DISABLE,配置是否使用扫描。如果是单通道 AD 转换使用 DISABLE,如果是多通道 AD 转换使用 ENABLE。
  6. ADC_NbrOfChannel: AD 转换通道数目,该参数仅在扫描模式下才需要用,如果是非扫描的模式,整个列表只有第一个序列有效,无论写多少数目,最终都是只有序列 1 有效。

三、编程要点

  1. 初始化 ADC 用到的 GPIO,配置为模拟输入;

  2. 设置 ADC 工作时钟;

    使用函数 RCC_ADCCLKConfig

  3. 配置选择开关,连接通道和组,一般使用规则组;

    规则组使用函数 ADC_RegularChannelConfig

  4. 初始化 ADC 结构体;

  5. 使能 ADC;

  6. 校准。

除此之外:

  • 如果需要模拟看门狗,可以使用相关函数配置阈值和检测通道;
  • 如果想开启中断,就使用中断控制函数开启对应的中断输出,然后配置 NVIC;
  • 如果想用软件触发转换,可以调用函数 ADC_SoftwareStartConvCmd

四、举例

4.1 AD 单通道,单次转换,非扫描模式

  1. 初始化 GPIO
void AD_GPIO_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; // 设置为模拟输入
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    GPIO_Init(GPIOC, &GPIO_InitStructure);
}
  1. 配置 ADC
void AD_Config(void)
{
    ADC_InitTypeDef ADC_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); // 使能ADC1时钟
    RCC_ADCCLKConfig(RCC_PCLK2_Div6);                    // 配置ADC时钟为PCLK2的6分频(72M/6 = 12MHz)

     // 配置ADC1的规则通道11,采样时间为55.5个周期
    ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 1, ADC_SampleTime_55Cycles5);

    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;                  // 设置ADC工作在独立模式
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;              // 数据右对齐
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // 禁用外部触发转换
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;                 // 使用单次转换模式
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;                       // 禁用扫描转换模式
    ADC_InitStructure.ADC_NbrOfChannel = 1;                             // 设置转换通道数量为1
    ADC_Init(ADC1, &ADC_InitStructure);

    ADC_Cmd(ADC1, ENABLE); // 使能ADC1

    ADC_ResetCalibration(ADC1);                                     // 复位ADC1的校准寄存器
    while (ADC_GetResetCalibrationStatus(ADC1) == SET);             // 等待复位校准结束
    ADC_StartCalibration(ADC1);                                     // 启动ADC1的校准
    while (ADC_GetCalibrationStatus(ADC1) == SET);                  // 等待校准完成
}
  1. 获取 ADC 的转换结果
uint16_t AD_GetValue(void)
{
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);                   // 启动ADC1的软件转换
    while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);   // 等待转换结束标志位置位
    return ADC_GetConversionValue(ADC1);                      // 获取ADC1的转换值
}

如果使用连续转换,非扫描模式,则需要做出以下变动:

因为连续转换在一次转换结束后不会停止,而是立刻开始下一轮的转换,所以可以将启动软件转换的代码放在配置 ADC 校准后面的,即放在 AD_Config 里。同时在读取 ADC 的转换结果时,也不需要判断标志位了,获取 ADC 的转换结果的函数改变如下,

uint16_t AD_GetValue(void)
{
    return ADC_GetConversionValue(ADC1);      // 获取ADC1的转换值
}

4.2 AD 多通道,单次转换,非扫描模式

使用单次转换,非扫描模式实现多通道,只需要在每次触发转换之前,手动更改一下列表第一个位置的通道就行了。

以使用两个通道为例,在 AD 单通道的基础上,需要做出如下更改:

  1. 为了方便,可以使用相邻的 GPIO,如 pc0 和 pc1,这样只需将 AD_GPIO_Config 中的
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;

改为

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;

这样就完成了 pc0 和 pc1 的初始化。

  1. pc0 和 pc1 分别对应 ADC_Channel_10ADC_Channel_11 ,对应通道不同,所以将函数 AD_Config 中的
ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 1, ADC_SampleTime_55Cycles5);

提出来放进 AD_GetValue 函数并进行改写

uint16_t AD_GetValue(uint8_t ADC_Channel)
{
    // 配置ADC的规则通道,采样时间为55.5个周期
    ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_55Cycles5); 
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);                   // 启动ADC1的软件转换
    while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);   // 等待转换结束标志位置位
    return ADC_GetConversionValue(ADC1);                      // 获取ADC1的转换值
}

实现在每次触发转换之前,手动更改一下列表第一个位置的通道。

参考视频源于B站up主: 野火科技、江协科技
参考文档:《STM32库开发实战指南——基于野火MINI开发板》

  • 28
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值