今天分享一下STM32读取ADC数据时使用连续模式,介绍几种方案和注意事项;
STM32微控制器的ADC(模数转换器)模块支持多种转换模式,其中连续转换模式是常用的一种。在该模式下,ADC会自动连续进行转换,无需每次手动触发。以下是对STM32 ADC连续转换功能的详细讲解:
一. ADC连续转换模式概述:
连续转换模式:在该模式下,ADC会不断进行转换,一旦完成一次转换,立即开始下一次转换,无需外部触发。我们在软件上处理时候,只需要清除 ADC_FLAG_EOC的标志位即可。
适用场景:适用于需要持续采集模拟信号的场景,如实时监控电压、温度等。
二:STM32cube MX的软件配置:
如上图所示:需要在图形化配置软件中,将连续采集模式打开。
三:具体和大家分享一下STM32 ADC的连续采集模式下的基本步骤和软件编写方法:
3.1 启动ADC的时钟
我们需要确定当前使用的ADC通道,例如:本次使用,使用ADC1我们通过RCC寄存器启动相对应的时钟
/* Peripheral clock enable */ __HAL_RCC_ADC_CLK_ENABLE();
3.2 配置所使用的ADC的引脚功能
这里我们使用的是PA4引脚:这里需要注意下,将ADC使用的引脚设置为输入模式,否则无法正常读取到ADC的数值
/**ADC1 GPIO Configuration PA4 ------> ADC1_IN8 */ GPIO_InitStruct.Pin = GPIO_PIN_4; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
3.3 初始化ADC的一些参数:
例如配置ADC的工作模式:包括分辨率、数据对齐方式、扫描模式、触发模式、ADC外设时钟等等;
hadc1.Instance = ADC1; hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; hadc1.Init.Resolution = ADC_RESOLUTION_12B; hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE; hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV; hadc1.Init.LowPowerAutoWait = DISABLE; hadc1.Init.LowPowerAutoPowerOff = DISABLE; hadc1.Init.ContinuousConvMode = ENABLE; hadc1.Init.NbrOfConversion = 1; hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; hadc1.Init.DMAContinuousRequests = DISABLE; hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN; hadc1.Init.SamplingTimeCommon1 = ADC_SAMPLETIME_79CYCLES_5; hadc1.Init.SamplingTimeCommon2 = ADC_SAMPLETIME_1CYCLE_5; hadc1.Init.OversamplingMode = DISABLE; hadc1.Init.TriggerFrequencyMode = ADC_TRIGGER_FREQ_HIGH; if (HAL_ADC_Init(&hadc1) != HAL_OK) { Error_Handler(); }
3.4 配置ADC通道
这里需要将外部引脚和ADC通道对应好
sConfig.Channel = ADC_CHANNEL_8; sConfig.Rank = ADC_REGULAR_RANK_1; sConfig.SamplingTime = ADC_SAMPLINGTIME_COMMON_1; if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) { Error_Handler(); }
3.5 启动连续转换模式:
if (HAL_ADC_PollForConversion(&hadc1, 10) != HAL_OK) { /* End Of Conversion flag not set on time */ Error_Handler(); }
3.6 读取转换的结果
在连续转换模式下,ADC会不断更新数据寄存器,我们可以通过以下读取转换的结果
uint32_t HAL_ADC_GetValue(const ADC_HandleTypeDef *hadc) { /* Check the parameters */ assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance)); /* Note: EOC flag is not cleared here by software because automatically */ /* cleared by hardware when reading register DR. */ /* Return ADC converted value */ return hadc->Instance->DR; }
几个重要代码如下:
使能ADC1自动校准功能、开启ADC自动转化模式、等待ADC的连续开启模式
/* Perform ADC calibration */ if (HAL_ADCEx_Calibration_Start(&hadc1) != HAL_OK) { /* Calibration Error */ Error_Handler(); } /* Start ADC group regular conversion */ if (HAL_ADC_Start(&hadc1) != HAL_OK) { /* ADC conversion start error */ Error_Handler(); } /* Wait for ADC conversion completed */ if (HAL_ADC_PollForConversion(&hadc1, 10) != HAL_OK) { /* End Of Conversion flag not set on time */ Error_Handler(); }
主代码程序如下:
/* Retrieve ADC conversion data */ uhADCxConvertedData = HAL_ADC_GetValue(&hadc1); /* Computation of ADC conversions raw data to physical values */ /* using helper macro. */ uhADCxConvertedData_Voltage_mVolt = __LL_ADC_CALC_DATA_TO_VOLTAGE(VDDA_APPLI, uhADCxConvertedData, LL_ADC_RESOLUTION_12B); /* Toggle LED at each ADC conversion data retrieved */ BSP_LED_On(LED4); HAL_Delay(LED_BLINK_SLOW); BSP_LED_Off(LED4); HAL_Delay(LED_BLINK_SLOW); /* For this example purpose, check that conversion data has been updated using flag ADC group regular end of unitary conversion */ if(__HAL_ADC_GET_FLAG(&hadc1, ADC_FLAG_EOC) == 0) { Error_Handler(); } __HAL_ADC_CLEAR_FLAG(&hadc1, ADC_FLAG_EOC);
主程序执行过程如下:从主程序执行开始,ADC 软件启动执行一次,ADC 组定期自动、无限期地连续执行所选通道的转换。软件会轮询第一次转化完成,然后随意检索(在本例中为每秒一次)转化数据。
程序仿真效果如下:
实物如下:
四:其他方案读取ADC数值
中断:可以启用ADC转换完成中断,在每次转换完成后触发中断处理。
DMA:在连续转换模式下,结合DMA可以自动将转换结果传输到指定内存区域,减少CPU负担。
4.1 中断配置
启用ADC转换完成中断
ADC_ITConfig(ADC1, ADC_IT_EOC, ENABLE); // 启用转换完成中断 NVIC_EnableIRQ(ADC1_IRQn); // 启用ADC中断
在中断服务程序中读取数据
void ADC1_IRQHandler(void) { if (ADC_GetITStatus(ADC1, ADC_IT_EOC) == SET) { uint16_t adc_value = ADC_GetConversionValue(ADC1); // 处理ADC数据 ADC_ClearITPendingBit(ADC1, ADC_IT_EOC); // 清除中断标志 } }
4.2 DMA配置如下:
启动DMA自动传输数据,为CPU减轻负担
DMA_InitTypeDef DMA_InitStruct; DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&(ADC1->DR); DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)&adc_buffer; DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStruct.DMA_BufferSize = BUFFER_SIZE; DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStruct.DMA_Mode = DMA_Mode_Circular; // 循环模式 DMA_InitStruct.DMA_Priority = DMA_Priority_High; DMA_InitStruct.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA1_Channel1, &DMA_InitStruct); DMA_Cmd(DMA1_Channel1, ENABLE); ADC_DMACmd(ADC1, ENABLE); // 启用ADC DMA请求
在编写ADC通道时,需要注意以下几个方面:
采样时间:根据信号特性选择合适的采样时间,避免信号失真。
参考电压:确保参考电压稳定,以获得准确的转换结果。
噪声抑制:在高速连续转换时,注意电源和信号噪声的影响。
通过上述几种,不同的配置,STM32的ADC可以在连续模式下工作,满足用户实时读取采集数据的需求。