平台:STM32F103C8T6最小系统板
STM32CUBEMX-V6.1.2-1.8.4版本的F1固件包+MDK5.31
目录
单次转换模式
连续转换+DMA传输模式
遇到的问题
单次转换模式
以配置ADC1的IN0,IN1这两通道为例
1:勾选IN0,IN1
2:数据选择右对齐 3:选择是否使能规则转换因为我们采用单次转换模式,所以此选项可以先失能掉。
4:其它保持默认,完成时钟等其它配置后,生成代码
5:添加如下函数
6:通过调用上述函数传入ADC采集通道,就可以获取相应通道的ADC数据。/** * @brief 获取指定通道的ADC采集值 * @param channel 要采集的ADC通道 * @retval 采集到的ADC数据 */ uint16_t adc_get(uint32_t channel) { ADC_ChannelConfTypeDef sConfig = {0}; sConfig.Channel = channel; sConfig.Rank = ADC_REGULAR_RANK_1; sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5; if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) { Error_Handler(); } HAL_ADC_Start(&hadc1); HAL_ADC_PollForConversion(&hadc1,100); //等待规则组转换完成 return (uint16_t)HAL_ADC_GetValue(&hadc1); }
连续转换+DMA传输模式
以配置ADC1的IN0,IN1这两通道为例,重复的步骤看前面
1:扫描模式和连续转换模式都要使能
扫描模式在使能规则转换且转换数量大于1之后会自动使能
2:规则转换的配置如下 3:在DAM_Setting中配置如下mode选择Circular,这样才会循环的去搬运数据
搬运到地址空间的Data Width设置为字,也就是32位。这样方便后续的读数。若设置为半字,那么在后续读数的时候,需要将DMA的目标缓冲区(32位的)进行拆分后再进行读数。
4:生成代码,在开始读取数据之前加入如下代码
其中,之所以要失能DMA中断,是因为在CUBEMX配置DMA传输的时候会强制使能DMA Channel1 的全局中断,如图HAL_ADCEx_Calibration_Start(&hadc1); //执行ADC的自动校准 HAL_NVIC_DisableIRQ(DMA1_Channel1_IRQn); //失能DMA的中断 HAL_ADC_Start_DMA(&hadc1,(uint32_t *)ad_buf,2); //设置数据缓冲区 /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ My_Pri_log_x(1,"ad_va1:%d ",ad_buf[0]); My_Pri_log_x(1,"ad_va2:%d\r\n",ad_buf[1]); HAL_Delay(500); }
但我并不需要,所以将其关闭。
数据缓冲区 ad_buf 是一个32位两个元素的数组。
5:读取DMA传输目的地址 ad_buf 的值,就可以获得两个ADC通道的数据。
遇到的问题
现象:
无论是单次转换模式,还是连续转换+DMA传输的模式,都会遇到一个问题,那就是通道之间会相互干扰。即一个通道电压的变化会微量的影响到其它通道电压的变化。原因:
多个通道是通过模拟多路开关自动切换的,这就导致,在切换的瞬间上一个通道的电压值会干扰到下一个通道,切换速度越快,影响越大,切换的时间间隔越久,影响越小解决办法:
1:增大Sampling Time可以一定程度上减小影响
2:在单次转换模式中,可以在转换之间插入一定延时,也可以采用平均求值的方式
3:将通过1和通道2配置到ADC1和ADC2上面,彻底隔离,单次转换中试过此方法,连续转换+DMA中没试过,有待验证。
4:在AD通道管脚上并联一个100nf左右的电容,没试过,有待验证。