ToB企服应用市场:ToB评测及商务社交产业平台

标题: STM32的HAL库开发---单通道ADC采集实验 [打印本页]

作者: 三尺非寒    时间: 2025-2-19 12:45
标题: STM32的HAL库开发---单通道ADC采集实验
一、实验简要

1、功能形貌
通过ADC1通道1(PA1)采集电位器的电压,并表现ADC转换的数字量及换算后的电压值

2、确定最小刻度

VREF+ = 3.3V ---》 0V ≤ VIN ≤  3.3V ---》最小刻度 = 3.3 / 4096 ,F1的分辨率是12位的,也就是把3.3V分为4096份。F4/F7/H7还可以自己配置分辨率,比方H7可以把分辨率配置为16位的,也就是把3.3V举行65536等分。

3,确定转换时间

采样时间239.5个ADC时钟周期为例,可以得到转换时间为21us。比方配置为最长的采样时间239.5个采样周期,那么采样时间就是239.5 + 12.5  = 252个时钟周期。配置ADC的时钟的12M,则转换时间为252 * (1 / 12000000) = 21us

4、模式组合

单次转换模式、不使用扫描模式

二、ADC寄存器先容

2.1 ADC_CR1寄存器 

这个实验只用的了SCAN位,因为是单通道,所以不须要扫描模式,将SCAN位设置为0.

同时CR1寄存器里边的双模式选择要设置为独立模式,因为只使用了一个ADC。 

2.2 ADC_CR2寄存器 


SWSTART位:开启转换规则通道,置为1,再=在单次转换模式下,即可触发一次转换,转换开始后,硬件会把这位置0。想再次转换,再次置1.
EXTTRIG位:使能外部触发,也就是定时器大概外部停止触发那些。这个实验里选择的软件触发,所以设置为0
EXTSE位:选择外部的触发源,这里选用软件触发。

ALIGN:设置数据对齐方式,由于ADC数据位为12位,而数据寄存器是16位的,所以将12位数据放到16位寄存器里边,涉及数据对齐题目,一般选择右对齐。
DMA位:设置是否启用DMA,本实验没有使用,设置为0。
RSTCAL位:ADC在转换之前,起首举行校准, 这个位是初始化校准寄存器的。
CAL位:软件设置为1后,ADC开始校准,校准完成后,硬件会把这位清0.
ADON位:设置开启照旧关闭ADC的。这一位在F1系列,还有触发规则组转换的功能,其他系列没有。
注意:一般操纵次序是,先把ADON位置1,开启ADC,然后把RSTCAL位设置为1,初始化校准寄存器。 然会将CAL位设置为1,举行ADC校准,校准完成后,CAL位会硬件置0,可以在软件里判断这位,开ADC是否校准完成。
CONT位:设置单次转换照旧连续转换。设置为0是单次转换模式,设置为1是连续转换模式。
2.3 ADC_SMPR1寄存器


SMPR1设置通道10到通道17采样时间的设置,而且采样时间是每个通道都可以单独设置的。如果想设置通道12,就往SMP12里边写即可。 
2.4 ADC_SMPR2寄存器


SMPR2设置通道0到通道9采样时间的设置,而且采样时间是每个通道都可以单独设置的。本实验使用通道1,采样时间设置为最大,也就是将SMP0设置为111.
2,5 ADC_SQR1寄存器


本实验只有一个转换,只须要将L位设置为0即可。然后将第一个转化位置设置为通道1.
2.6  ADC_SQR2寄存器


这个寄存器用于配置序列里的第7个到第12个。
 2.7  ADC_SQR3寄存器


这个寄存器是用来设置规则序列里的第一个到第6个。本实举动单通道,直接把SQ1设置为1即可,代表第一个转化次序为通道1. 
2.8 ADC_DR寄存器


这个寄存器是有32位的,其中低16位用于存储规则转换数据的,高16位是用于双ADC模式的。读数据的时候直接读取低16位即可。
三、单通道ADC采集实验配置步骤 

1、HAL_ADC_Init()函数,用于初始化ADC,配置ADC工作参数。
2、HAL_ADCEx_Calibration_Start()函数,用于ADC校准的。
3、HAL_ADC_MspInit()函数, 配置NVIC、CLOCK、GPIO
4、HAL_ADC_ConfigChannel()函数,配置ADC相应通道相关参数
5、HAL_ADC_Start()函数,启动A/D转换
6、HAL_ADC_PollForConversion()函数,等待规则通道转换完成
7、HAL_ADC_GetValue()函数,获取规则通道A/D转换结果

四、程序

1、寄存器版本
  1. #include "./BSP/ADC/adc.h"
  2. void ADC_Init(void)
  3. {
  4.         //开启ADC1时钟
  5.         RCC->APB2ENR |= (1 << 9);
  6.        
  7.         //设置ADC时钟分频系数为6
  8.         RCC->CFGR |= (1 << 15);
  9.        
  10.         //SCAN位  关闭扫描模式
  11.         ADC1->CR1 &= ~(1 << 8);       
  12.        
  13.         //EXTTRIG 开启规则通道的外部触发
  14.         //ADC1->CR2 &= ~(1 << 20)
  15.         ADC1->CR2 |= (1 << 20);
  16.        
  17.         //EXTSEL 设置为SWSTART软件触发
  18.         ADC1->CR2 |= (0X07 << 17);
  19.        
  20.         //ALIGN 设置数据对齐为右对齐模式
  21.         ADC1->CR2 &= ~(1 << 11);
  22.        
  23.         //ADCON 开启ADC
  24.         ADC1->CR2 |= (1 << 0);
  25.        
  26.        
  27.         //CONT 开启连续转化模式
  28.         //ADC1->CR2 |= (1 << 1);
  29.        
  30.         //SMP1 ADC1_CH1 设置采样时间为239.5个时钟周期
  31.         ADC1->SMPR2 |= (0X07 << 3);
  32.        
  33.         //L 设置规则通道转换数为1
  34.         ADC1->SQR1 &= (0X0F << 20);
  35.        
  36.         //SQ1 设置第一个转化为ADC通道1
  37.         ADC1->SQR3 |= (1 << 0);
  38.        
  39.         //开启GPIOA时钟
  40.         RCC->APB2ENR |= (1 << 2);       
  41.        
  42.         //设置PA1位模拟输入模式
  43.         GPIOA->CRL &= ~(0X03 << 4);
  44.         GPIOA->CRL &= ~(0X03 << 6);
  45.        
  46.         //RSTCAL 初始化校准寄存器
  47.         ADC1->CR2 |= (1 << 3);
  48.        
  49.         /*********************注意***************/
  50.         //第一个不写会出问题
  51.         //这必须要等待两次  一个是等待校准寄存器初始化完成之后  ,再开启校准
  52.         //第二个是等待校准完成再开始转换
  53.         //等待校准完成
  54.         while(ADC1->CR2 & (1 << 3));
  55.        
  56.         //CAL 开始校准
  57.         ADC1->CR2 |= (1 << 2);
  58.        
  59.         //等待校准完成
  60.         while(ADC1->CR2 & (1 << 2));
  61.        
  62.         //SWSTART 开启规则通道软件触发
  63.         ADC1->CR2 |= (1 << 22);
  64. }
复制代码
再配过程中发现,最开始就算接3.3,采集的数据总时跟0XFFF差一点,电压表现为3.26左右。厥后发现必须等待校准寄存器初始化完成后,再开启校准,同时等待校准完成后,再开启转换。 
2、库函数版本
adc.h头文件
  1. #ifndef __ADC_H
  2. #define __ADC_H
  3. #include "stm32f1xx.h"
  4. void ADC_Init(void);
  5. void get_value_ADC(void);
  6. #endif
复制代码
adc.c源文件
  1. #include "./BSP/ADC/adc.h"
  2. #include "./SYSTEM/sys/sys.h"
  3. ADC_HandleTypeDef hadc;
  4. void ADC_Init(void)
  5. {
  6.         hadc.Instance = ADC1;
  7.        
  8.         //设置连续转换模式还是单次转换模式
  9.         hadc.Init.ContinuousConvMode = DISABLE;
  10.         hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  11.         //关闭间断模式
  12.         hadc.Init.DiscontinuousConvMode = DISABLE;
  13.         //设置ADC触发源
  14.         hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  15.         //设置转换数量
  16.         hadc.Init.NbrOfConversion = 1;
  17.         //设置间断模式数量
  18.         hadc.Init.NbrOfDiscConversion = 0;
  19.         hadc.Init.ScanConvMode = ADC_SCAN_DISABLE;
  20.         HAL_ADC_Init(&hadc);
  21.        
  22.         ADC_ChannelConfTypeDef sConfig;
  23.        
  24.         sConfig.Channel = ADC_CHANNEL_1;
  25.         sConfig.Rank = ADC_REGULAR_RANK_1;
  26.         sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;
  27.         HAL_ADC_ConfigChannel(&hadc, &sConfig);
  28.        
  29.         //开启ADC校准
  30.         HAL_ADCEx_Calibration_Start(&hadc);
  31.        
  32.         //开启ADC
  33.         HAL_ADC_Start(&hadc);
  34. }
  35. void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
  36. {
  37.         //开启ADC1时钟
  38.         __HAL_RCC_ADC1_CLK_ENABLE();
  39.        
  40.         //开启GPIOA时钟
  41.         __HAL_RCC_GPIOA_CLK_ENABLE();
  42.        
  43.        
  44.         //设置PA1为模拟输入模式
  45.         GPIO_InitTypeDef GPIO_Init;
  46.        
  47.         GPIO_Init.Mode = GPIO_MODE_ANALOG;
  48.         GPIO_Init.Pin = GPIO_PIN_1;
  49.         GPIO_Init.Pull = GPIO_NOPULL;
  50.         GPIO_Init.Speed = GPIO_SPEED_FREQ_LOW;
  51.         HAL_GPIO_Init(GPIOA,&GPIO_Init);
  52.        
  53.         RCC_PeriphCLKInitTypeDef  PeriphClkInit;
  54.        
  55.         PeriphClkInit.PeriphClockSelection =RCC_PERIPHCLK_ADC;
  56.         //设置ADC时钟分频系数为6
  57.         PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
  58.         HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);
  59. }
  60. uint32_t value = 0;
  61. void get_value_ADC(void)
  62. {
  63.         //主要用于软件触发转换 用于ADC采集
  64.         HAL_ADC_Start(&hadc);
  65.         //用于ADC转换
  66.         HAL_ADC_PollForConversion(&hadc,10);
  67.         value = HAL_ADC_GetValue(&hadc);
  68.         value &= 0X0FFF;
  69.        
  70.         printf("ADC:%f\r\n",((double)value * 3.3 ) / 4096);
  71. }
复制代码
main.c主函数
  1. #include "./SYSTEM/sys/sys.h"
  2. #include "./SYSTEM/usart/usart.h"
  3. #include "./SYSTEM/delay/delay.h"
  4. #include "./BSP/LED/led.h"
  5. #include "./BSP/ADC/adc.h"
  6. uint16_t ADC_Voyage = 0;
  7. int main(void)
  8. {
  9.     HAL_Init();                         /* 初始化HAL库 */
  10.         sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
  11.     delay_init(72);                     /* 延时初始化 */
  12.     led_Init();                         /* LED初始化 */
  13.         usart_init(115200);
  14.         ADC_Init();
  15.     while(1)
  16.     {
  17.                 LED0(1);
  18.                 LED1(0);
  19.                 delay_ms(500);
  20.                
  21.                 LED0(0);
  22.                 LED1(1);
  23.                 delay_ms(500);
  24.                
  25.                 get_value_ADC();
  26.     }
  27. }
复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4