1 STM32C071-nucleo开发板ADC功能介绍
TM32C071 Nucleo 开发板是一款基于 STM32C071xx 微控制器的高性价比开发平台,它提供了丰富的外设接口,其中就包括了 ADC(模数转换器)功能。
ADC 功能概述:
STM32C071xx 微控制器集成了 12 位 ADC,支持单次转换和连续转换模式。
ADC 拥有多个通道,可以配置为单通道模式或多通道模式。
支持 16 个外部通道和 2 个内部通道(如 VREFINT 和 VBAT)。
ADC 特性:
12 位分辨率。
最高转换速率为 1 MSPS(兆采样/秒)。
支持扫描模式,可以连续转换多个通道。
支持注入通道,允许在正常转换过程中插入高优先级转换。
具有可编程的数据对齐方式(左对齐或右对齐)。
支持温度传感器测量。
具有可编程的采样时间,以适应不同的输入信号。
ADC 配置:
通过 STM32CubeMX 或直接编写代码进行配置。
可以配置 ADC 的时钟、分辨率、采样时间、转换模式等参数。
可以选择输入通道,配置外部触发源(如定时器)。
2 代码和逻辑设计
2.1 本示例基于 STM32C0xx ADC LL API,使用 ADC 外设连续转换单个通道,并从软件启动。
配置:
ADC 配置为转换单个通道,在连续转换模式下,使用软件触发。
执行:
从主程序执行中,执行一次 ADC 软件启动,ADC 常规组会自动连续、无限地转换所选通道。
软件轮询第一次转换完成,然后按需(本示例中每秒)检索转换数据。LED1 用于监视程序执行状态:
正常操作:
可以通过 LED 切换观察到 ADC 常规组的活动:
检索 ADC 转换数据:LED 切换一次(每 1 秒)
错误:LED 保持点亮
调试:使用调试器监视的变量:
"uhADCxConvertedData":ADC 常规组缓冲区转换数据(12 位分辨率)
"uhADCxConvertedData_Voltage_mVolt":计算为电压值(单位:mV)的 ADC 常规组缓冲区转换数据
使用的其他外设:
1 个 GPIO 用于 LED1
1 个 GPIO 用于模拟输入:ADC 通道 4 在引脚 PA.04(Arduino 连接器 CN8 引脚 3 A2,Morpho 连接器 CN7 引脚 32)
2.2 主要代码
int main(void)
{
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SYSCFG);
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR);
NVIC_SetPriority(SysTick_IRQn, 3);
SystemClock_Config();
MX_GPIO_Init();
MX_ADC1_Init();
ADC_Activate(); */
ConversionStartPoll_ADC_GrpRegular();
while (1)
{
uhADCxConvertedData = LL_ADC_REG_ReadConversionData32(ADC1);
while(LL_ADC_IsActiveFlag_EOC(ADC1) == 0);
LL_ADC_ClearFlag_EOC(ADC1);
uhADCxConvertedData_Voltage_mVolt = __LL_ADC_CALC_DATA_TO_VOLTAGE(VDDA_APPLI, uhADCxConvertedData, LL_ADC_RESOLUTION_12B);
LED_On();
LL_mDelay(LED_BLINK_SLOW);
LED_Off();
LL_mDelay(LED_BLINK_SLOW);
}
}
关于ADC的配置如下
static void MX_ADC1_Init(void)
{
LL_ADC_InitTypeDef ADC_InitStruct = {0};
LL_ADC_REG_InitTypeDef ADC_REG_InitStruct = {0};
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
LL_RCC_SetADCClockSource(LL_RCC_ADC_CLKSOURCE_SYSCLK);
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_ADC);
LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOA);
GPIO_InitStruct.Pin = LL_GPIO_PIN_4;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
#define ADC_CHANNEL_CONF_RDY_TIMEOUT_MS ( 1U)
#if (USE_TIMEOUT == 1)
uint32_t Timeout ; /* Variable used for Timeout management */
#endif /* USE_TIMEOUT */
ADC_InitStruct.Clock = LL_ADC_CLOCK_SYNC_PCLK_DIV4;
ADC_InitStruct.Resolution = LL_ADC_RESOLUTION_12B;
ADC_InitStruct.DataAlignment = LL_ADC_DATA_ALIGN_RIGHT;
ADC_InitStruct.LowPowerMode = LL_ADC_LP_MODE_NONE;
LL_ADC_Init(ADC1, &ADC_InitStruct);
LL_ADC_REG_SetSequencerConfigurable(ADC1, LL_ADC_REG_SEQ_FIXED);
ADC_REG_InitStruct.TriggerSource = LL_ADC_REG_TRIG_SOFTWARE;
ADC_REG_InitStruct.SequencerLength = LL_ADC_REG_SEQ_SCAN_DISABLE;
ADC_REG_InitStruct.ContinuousMode = LL_ADC_REG_CONV_CONTINUOUS;
ADC_REG_InitStruct.DMATransfer = LL_ADC_REG_DMA_TRANSFER_NONE;
ADC_REG_InitStruct.Overrun = LL_ADC_REG_OVR_DATA_OVERWRITTEN;
LL_ADC_REG_Init(ADC1, &ADC_REG_InitStruct);
LL_ADC_REG_SetSequencerScanDirection(ADC1, LL_ADC_REG_SEQ_SCAN_DIR_FORWARD);
LL_ADC_SetOverSamplingScope(ADC1, LL_ADC_OVS_DISABLE);
LL_ADC_SetTriggerFrequencyMode(ADC1, LL_ADC_CLOCK_FREQ_MODE_HIGH);
LL_ADC_REG_SetSequencerChAdd(ADC1, LL_ADC_CHANNEL_4);
/* Poll for ADC channel configuration ready */
#if (USE_TIMEOUT == 1)
Timeout = ADC_CHANNEL_CONF_RDY_TIMEOUT_MS;
#endif /* USE_TIMEOUT */
while (LL_ADC_IsActiveFlag_CCRDY(ADC1) == 0)
{
#if (USE_TIMEOUT == 1)
/* Check Systick counter flag to decrement the time-out value */
if (LL_SYSTICK_IsActiveCounterFlag())
{
if(Timeout-- == 0)
{
Error_Handler();
}
}
#endif /* USE_TIMEOUT */
}
LL_ADC_ClearFlag_CCRDY(ADC1);
LL_ADC_SetSamplingTimeCommonChannels(ADC1, LL_ADC_SAMPLINGTIME_COMMON_1, LL_ADC_SAMPLINGTIME_79CYCLES_5);
LL_ADC_DisableIT_EOC(ADC1);
LL_ADC_DisableIT_EOS(ADC1);
LL_ADC_EnableInternalRegulator(ADC1);
uint32_t wait_loop_index;
wait_loop_index = ((LL_ADC_DELAY_INTERNAL_REGUL_STAB_US * (SystemCoreClock / (100000 * 2))) / 10);
while(wait_loop_index != 0)
{
wait_loop_index--;
LL_ADC_EnableIT_EOC(ADC1);
LL_ADC_EnableIT_OVR(ADC1);
}
3 演示效果
编译和下载

这个正常的运行就是每次采样成功后,led闪一次。如果采样失败就保持始终是亮着。
运行显示,led断续点亮,说明运行成功。
4 小结
对于ADC的采样,使用的是底层LL层的代码,这样可以保证采样的时序和稳定性,可以用在多种工程项目。