STM32速成笔记(7)—ADC

发布者:technology78最新更新时间:2024-01-31 来源: elecfans关键字:STM32  ADC 手机看文章 扫描二维码
随时随地手机看文章

一、什么是ADC

ADC(Analogto-Digital Converter)模拟数字转换器,是将模拟信号转换成数字信号的一种外设。比如某一个电阻两端的是一个模拟信号,单片机无法直接采集,此时需要ADC先将短租两端的电压这个模拟信号转化成数字信号,单片机才能够进行处理。


二、ADC的用途

ADC具有将模拟信号转换成数字信号的能力,比如将模拟的电压转换成数字信号,单片机进行处理。可以用作温度监测或者电流监测等方面,用途极广。


三、STM32F103ZET6的ADC

根据中文参考手册介绍,STM32F103ZET6单片机有3个12位ADC,共有18个通道,可测量16个外部和2个内部信号源。各通道的A/D转换可以单次、连续、扫描或间断模式执行。ADC的结果可以左对齐或右对齐方式存储在16位数据寄存器中。ADC的输入时钟不得超过14MHz,它是由PCLK2经分频产生。


3.1 ADC通道对应引脚

STM32F103ZET6的ADC各通道对应IO如下

b68040f0303aa97bd6fe503f03733f8d_wKgZomU3I-2AUOauAAF0w3X6-gw219.jpg

a3de1f80ae8d5332768fb4f1991c06c1_wKgaomU3I_CAPIABAAA2z3zigGg217.jpg

3.2ADC时钟

ADC输入时钟ADC_CLK由APB2分频产生,最大值是14MHz。库函数提供了设置分频因子的函数


void RCC_ADCCLKConfig(uint32_t RCC_PCLK2)

可选的分频因子有


#define RCC_PCLK2_Div2                   ((uint32_t)0x00000000)

#define RCC_PCLK2_Div4                   ((uint32_t)0x00004000)

#define RCC_PCLK2_Div6                   ((uint32_t)0x00008000)

#define RCC_PCLK2_Div8                   ((uint32_t)0x0000C000)

APB2总线时钟为72MHz,而ADC的最大工作频率为14MHz,所以,分频因子一般设置为6,这样ADC的输入时钟频率为12MHz。


3.3 ADC工作模式

根据中文参考手册介绍,STM32F1的ADC有三种工作模式


• 单次转换模式 单次转换模式下,ADC只执行一次转换。该模式既可通过设置ADC_CR2寄存器的ADON位(只适用于规则通道)启动也可通过外部触发启动(适用于规则通道或注入通道),这时CONT位为0。


• 连续转换模式 在连续转换模式中,当前面ADC转换一结束马上就启动另一次转换。此模式可通过外部触发启动或通过设置ADC_CR2寄存器上的ADON位启动,此时CONT位是1。


• 扫描模式


33.4 ADC转换时间

ADC的总转换时间与时钟频率有关,总转换时间 = 采样时间 + 12.5个周期。其中,采样时间最短为1.5个周期,也就是最短转换时间为14个时钟周期。使用软件触发时,可选择的采样时间如下


#define ADC_SampleTime_1Cycles5                    ((uint8_t)0x00)

#define ADC_SampleTime_7Cycles5                    ((uint8_t)0x01)

#define ADC_SampleTime_13Cycles5                   ((uint8_t)0x02)

#define ADC_SampleTime_28Cycles5                   ((uint8_t)0x03)

#define ADC_SampleTime_41Cycles5                   ((uint8_t)0x04)

#define ADC_SampleTime_55Cycles5                   ((uint8_t)0x05)

#define ADC_SampleTime_71Cycles5                   ((uint8_t)0x06)

#define ADC_SampleTime_239Cycles5                  ((uint8_t)0x07)

3.5 ADC校准

使能ADC后,需要对ADC进行校准。使用库函数开发时,提供了ADC校准的函数


ADC_ResetCalibration(ADC1);//重置指定的ADC的校准寄存器

    while(ADC_GetResetCalibrationStatus(ADC1));//获取ADC重置校准寄存器的状态

    

    ADC_StartCalibration(ADC1);//开始指定ADC的校准状态

    while(ADC_GetCalibrationStatus(ADC1));//获取指定ADC的校准程序

3.6 ADC转换结果与实际电压的换算

获取到的AD转换结果并不是实际电压,如果想要得到实际电压,需要经过换算。上面介绍了,STM32的ADC为12位,也就是AD值取值范围为0~4095。采集电压范围为0到3.3V。AD值与实际电压之间存在比例关系。


实际电压 = (AD值 / 4095) * 3.3。单位为伏特(V)


四、ADC配置步骤

• 使能GPIO时钟和ADC时钟,设置引脚为模拟输入


• 设置ADC的分频因子


• 初始化ADC参数,包括ADC工作模式,规则序列等


• 使能ADC并校准


• 触发AD转换,读取AD转换值


五、ADC配置程序

55.1 ADC初始化程序

这里以配置ADC1的通道1为例,给出ADC的配置例程,分频因子设置为6,单次转换模式,软件触发。


/*

 *==============================================================================

 *函数名称:ADC1_Init

 *函数功能:初始化ADCx

 *输入参数:无

 *返回值:无

 *备  注:无

 *==============================================================================

 */

void ADC1_Init(void)

{

    // 结构体定义

    GPIO_InitTypeDef GPIO_InitStructure;

    ADC_InitTypeDef ADC_InitStructure;

    

    // 开启时钟

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1,ENABLE);

    

    // 设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M

    RCC_ADCCLKConfig(RCC_PCLK2_Div6);

    

    // GPIO配置

    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;   //ADC1通道1

    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;   // 模拟输入

    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

    GPIO_Init(GPIOA,&GPIO_InitStructure);

    

    // 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个转换在规则序列中 也就是只转换规则序列1 

    ADC_Init(ADC1, &ADC_InitStructure);   // ADC初始化

    

    ADC_Cmd(ADC1, ENABLE);   // 开启AD转换器

    

    // ADC校准

    ADC_ResetCalibration(ADC1);   // 重置指定的ADC的校准寄存器

    while(ADC_GetResetCalibrationStatus(ADC1));   // 获取ADC重置校准寄存器的状态

    

    ADC_StartCalibration(ADC1);   // 开始指定ADC的校准状态

    while(ADC_GetCalibrationStatus(ADC1));   // 获取指定ADC的校准程序


    ADC_SoftwareStartConvCmd(ADC1, ENABLE);   // 使能或者失能指定的ADC的软件转换启动功能

}

5.2 软件触发AD转换

库函数开发,配置为软件触发时,可以通过下面的函数触发AD转换


void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState)

5.3 读取AD转换结果

库函数提供了用于读取AD转换结果的函数


uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx)

这里给出另一个函数,用于软件触发AD转换并读取转换结果


/*

 *==============================================================================

 *函数名称:Get_ADC_Value

 *函数功能:读取某一规则通道AD值

 *输入参数:ch:规则通道ADC_Channel_x;times:读取次数

 *返回值:无

 *备  注:该函数配置好后,返回的结果是N次后的平均值

 *==============================================================================

 */

u16 Get_ADC_Value(u8 ch,u8 times)

{

    u32 temp_val = 0;

    u8 t;

    // 设置指定ADC的规则组通道,一个序列,采样时间

    // ADC1,ADC通道,239.5个周期,提高采样时间可以提高精确度

    ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5);       

    

    for(t=0;t< times;t++)

    {

        ADC_SoftwareStartConvCmd(ADC1, ENABLE);   // 使能指定的ADC1的软件转换启动功能 

        while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));   // 等待转换结束

        temp_val+=ADC_GetConversionValue(ADC1);

        delay_ms(5);

    }

    return temp_val/times;

}

六、实战项目

用ADC1的通道1采集某电阻两端电压(由于普中核心板没有可供采集的电阻,可以直接将采集引脚接到3.3V查看一下结果),将结果通过串口打印到电脑。其中关于串口的配置就不再做介绍,给出ADC的配置和main函数。


6.1 ADC初始化

/*

 *==============================================================================

 *函数名称:ADC1_Init

 *函数功能:初始化ADCx

 *输入参数:无

 *返回值:无

 *备  注:无

 *==============================================================================

 */

void ADC1_Init(void)

{

    // 结构体定义

    GPIO_InitTypeDef GPIO_InitStructure;

    ADC_InitTypeDef ADC_InitStructure;

    

    // 开启时钟

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1,ENABLE);

    

    // 设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M

    RCC_ADCCLKConfig(RCC_PCLK2_Div6);

    

    // GPIO配置

    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;   //ADC1通道1

    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;   // 模拟输入

    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

    GPIO_Init(GPIOA,&GPIO_InitStructure);

    

    // 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个转换在规则序列中 也就是只转换规则序列1 

    ADC_Init(ADC1, &ADC_InitStructure);   // ADC初始化

    

    ADC_Cmd(ADC1, ENABLE);   // 开启AD转换器

    

    // ADC校准

    ADC_ResetCalibration(ADC1);   // 重置指定的ADC的校准寄存器

    while(ADC_GetResetCalibrationStatus(ADC1));   // 获取ADC重置校准寄存器的状态

    

    ADC_StartCalibration(ADC1);   // 开始指定ADC的校准状态

    while(ADC_GetCalibrationStatus(ADC1));   // 获取指定ADC的校准程序


    ADC_SoftwareStartConvCmd(ADC1, ENABLE);   // 使能或者失能指定的ADC的软件转换启动功能

}

6.2 main函数

u16 gAdcAdValue = 0;   // 存储AD值

float gAdcVol = 0;   // 实际电压值


int main(void)

{

    Med_Mcu_Iint();   // 系统初始化

    

    while(1)

  {

        gAdcAdValue = Get_ADC_Value (ADC_Channel_1,10);   // 获取转换结果

        gAdcVol = (gAdcAdValue / 0xFFF) * 3.3;   // 计算实际电压

        printf ("Vol=%.1f Vrn",gAdcVol);   // 串口打印结果

        

        delay_ms (500);   // 防止打印过快

    }

}

七、拓展

7.1 定时器触发ADC采集

根据中文参考手册介绍,ADC可以通过定时器触发AD转换(只有PWM的上升沿可以触发AD转换)。触发方式有以下几种


• TIM1_CH1 :定时器 1 的通道 1 的 PWM 触发

• TIM1_CH2 : 定时器 2 的通道 2 的 PWM 触发

• TIM1_CH3: 定时器 1 的通道 3 的 PWM 触发

• TIM2_CH2 : 定时器 2 的通道 2 的 PWM 触发

• TIM3_TRGO: 定时器 3 触发

• TIM4_CH4 : 定时器 4 的通道 4 的 PWM 触发

fdec59476d98435fbd72e15e37310fe2_wKgaomU3I_OAcfFmAAGlffvYRw0365.jpg

ADC外部触发方式


这里以TIM4的通道4触发ADC采集为例,给出程序配置。


首先是定时器PWM的配置,不对引脚进行重映射。


/*

 *==============================================================================

 *函数名称:TIM4_CH4_PWM_Init

 *函数功能:初始化定时器4的PWM通道4

 *输入参数:per:自动重装载值;psc:预分频系数

 *返回值:无

 *备  注:无

 *==============================================================================

 */

void TIM4_CH4_PWM_Init (u16 per,u16 psc)

{

    // 结构体定义

    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;

    TIM_OCInitTypeDef TIM_OCInitStructure;

[1] [2]
关键字:STM32  ADC 引用地址:STM32速成笔记(7)—ADC

上一篇:STM32速成笔记(8)—DMA
下一篇:STM32外部中断

推荐阅读最新更新时间:2024-11-13 10:53

STM32 驱动无线NRF24L01 完成串口数据传输
2401 一个简单的SPI 接口的 2.4G 射频模块 淘宝价20¥,DIY 的17¥ ,算是廉价。 这个版本的稳定修正 http://ntn314.blog.163.com/blog/static/16174358420106211118944/ 接口CMOS电平3.3V STM32 可直接连接。接受完成 发送完成 出错 都有IRQ 低电平中断产生。程序中 我将其连接至一IO口在外部中断中处里各类事件 但也发现这种处理方式并不是特别灵活,或许直接判断更加灵活。 NRF20L01一次可以传输 1~32个字节比较灵活。最初我是根据字符串长来不停的转换每次传输的长度,这样做十分麻烦最后用截取有效串长的方法实现效果很好。
[单片机]
<font color='red'>STM32</font> 驱动无线NRF24L01 完成串口数据传输
STM32仿真按键控制led灯源程序
刚学习 课上做的一个小实验 保存一下 在GPIOC口,分别接有一个开关K1和两个指示灯LED1和LED2。两个灯一亮一灭,每按一下开关,两个灯的亮灭状态翻。 单片机源程序如下: #include stm32f10x.h #include led.h #include key.h int main(void) { u8 key; LED_Init(); KEY_Init(); while(1){ key = KEY_Scan(); switch(key){ case WK_UP: LED1=!LED1, LED0=!LED0; break; }
[单片机]
<font color='red'>STM32</font>仿真按键控制led灯源程序
Windows下stm32串口下载程序(DOS版本)
每次更新程序都需要用到stlink调试工具,感觉非常不方便,笔记本搬来搬去,帮客户更新程序也不方便使用别人的下载工具。 那么只能自己写一个下载工具了。 刚开始我是想研究一下stm32 BootLoader的官方协议,然后通过协议来写这个程序。 后面找到官方质料AN3155_USART protocol used in the STM32 bootloader_en.pdf(自行百度)。 全是英文,看了一天挺累的,进展也慢。 后面又了解到原来st公司自己写了一个BootLoader的库。根据网上找到的很多质料模仿大神们写了一个。 因为时间原因先完成一个DOS版本的,后面将继续完成MFC版本,方便使用。源码都会
[单片机]
Windows下<font color='red'>stm32</font>串口下载程序(DOS版本)
机智云平台+STM32+树莓派的草莓采摘机器人控制系统
一、前言 本草莓采摘机器人控制系统是由江西理工大学机械工程专业的程鹏胜设计开发完成。针对某草莓种植基地模块化种植的高架草莓人工采摘耗时长成本大的问题,提出了一种全向移动的草莓采摘机器人系统方案。 系统的硬件电路主要包括以STM32F407ZGT6为核心的主控制器、电源电路、WIFI模块、激光测距单元、电机驱动模块。系统的软件设计主要包括RT-thread实时操作系统在单片机上的移植调试、树莓派3B+视觉识别、树莓派与单片机数据传输的通讯调试、机智云物联网和WIFI模块在单片机上的接入以及树莓派上位机控制软件的实现。 通过利用深度学习算法实现草莓的识别与定位,将采摘信息以及采摘机器人的状态使用物联网技术传输到云端,实现草莓采摘机
[单片机]
机智云平台+STM32+树莓派的草莓采摘机器人控制系统
详解STM32开发板JLINK调试步骤
STM32调试步骤 调试前,首先跳线J9的2-3脚短接,跳线J4的右边两个脚短接,跳线J5短接,J8短接,J2的1-2短接,3-4短接。 将Jlink与学习板,USB延长线与学习板,串口延长线与学习板(或者USB转串口线与学习板)连接起来, 这时LED灯LED5,LED6都应该点亮,如果不亮,说明板子有问题。 打开串口助手,按照如下设置: 1、从桌面打开J-Flash ARM V4.02如图所示。 也可以按照如下顺序打开J-Flash ARM 。 “开始à程序àSEGGERàJ-Link ARM V4.02àJ-Flash ARM”,如下图所示。 2、打开J-Flash ARM后,先进行芯片选项设置,打开Options
[单片机]
详解<font color='red'>STM32</font>开发板JLINK调试步骤
STM32无法进入片上Bootloader的处理方法
当STM32芯片无法进入片上Bootloader时,我们需要采取一系列的处理方法来解决这个问题。以下将详细介绍一些常见的处理方法。 1.编程器选择问题 在尝试进入片上Bootloader之前,我们首先需要确认所使用的编程器是否支持该功能。有些低成本的编程器可能不支持进入片上Bootloader,因此我们可能需要更换更高级的编程器。 2.复位电路问题 如果芯片无法进入片上Bootloader,可能是由于复位电路出现问题导致的。我们可以检查外部复位电路是否正常工作,以及是否正确连接到芯片的复位引脚。同时也需要确保芯片的复位引脚没有被外部电路拉高或拉低。 3.芯片供电问题 另一个常见的原因是芯片供电不稳定或不足。我们需要检查芯片的供电电
[单片机]
STM32模拟I2C程序
/******************************************************************************* 测试平台:STM32F103ZET6最小系统 *******************************************************************************/ static void i2cDelay() { volatile int i = 7; while (i) i--; } // SCL高电平期间,SDA出现下降沿为起始信号 static bool i2cStart() { SDA_OUT;
[单片机]
stm32 中断串口控制LED灯
#include stm32f10x.h #include usart.h #include led.h #include stdio.h /*********************************************************************** ***********************************************************************/ void RCC_Configuration(void); void GPIO_Configuration(void); void NVIC_Configuration(void); //void d
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved