完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
非中断和非DMA方式可以用于特殊场景,比如其它外设占据DMA负担比较重而CPU又比较清闲的时候。
1. STM32F429的AD转换最高12bit 12位分辨率意味着我们采集电压的精度可以达到:Vref /4096。 采集电压 = Vref * ADC_DR / 4096; Vref:参考电压 ADC_DR:读取到ADC数据寄存器的值 一般使用3.3V为参考电压,则采集到的电压 = ADC_DR*3.3/4096 。 2. STM32F4的ADC转换不需要做程序校准。 这在HAL库里也可以看出来,官方没有HAL_ADCEx_Calibration_Start();这个校准函数。 3. STM32F4的ADC时钟最大36M。 STM32F1为14M,STM32F4快了2倍多。 4. 两个以上通道必须开启scan扫描模式。 ADC_ScanConvMode = ENABLE。 因为转换结果都在同一个寄存器里,所以单个通道转换完成后必须读走数据再启动转换下一个通道。 5. 不使用DMA不需要开连续方式。 ADC_ContinuousConvMode = DISABLE。 连续转换ENABLE后,也就是只需要启动(触发)转换一次,后面就不用再次启动(触发)就可以连续工作了。 单次转换DISABLE:也就是根据一次转换完后需要再次启动(触发)才能工作。 6. 触发方式一般选用软件触发。 7. 对齐方式一般选右对齐。 8. 通道数就是你要转换的通道数量 通道数要和后面的规格组相符合。 9. 设置规则组通道 下面例子是设置 channel5 和 channel8连个通道,开启触发AD转换后,通道5是首先转换的,转换完成后,再次触发转换,就会自动转换通道8。一轮完成后,不需要STOP ADC,可以直接再次触发转换,此时又回到了转换通道5,开始新的循环。 /**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. */ sConfig.Channel = ADC_CHANNEL_5; sConfig.Rank = 1; sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES; if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } /**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. */ sConfig.Channel = ADC_CHANNEL_8; sConfig.Rank = 2; if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } 10. 规则组间断模式配置。 如果不使用DMA,这里必须要配置为1,也就是说每触发一次转换一条通道。否则,结果寄存器里只会是本组最后一次转换的通道电压值。具体可以看下图: 11. 其他ADC的基础配置见下面程序代码。 例子中单片机型号为STM32F429VIT6,代码全部经过实测,通过算法滤波,转换精度足够平常使用。而且有人提出多个通道之间会有干扰,此例未发现。选用的未PA5(ADC channel5)和PB0(ADC channel8)两个通道。 一、ADC配置 /* ADC1 init function */ void MX_ADC1_Init(void) { ADC_ChannelConfTypeDef sConfig; /**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) */ hadc1.Instance = ADC1; hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2; hadc1.Init.Resolution = ADC_RESOLUTION_12B; hadc1.Init.ScanConvMode = ENABLE; hadc1.Init.ContinuousConvMode = DISABLE; hadc1.Init.DiscontinuousConvMode = ENABLE; hadc1.Init.NbrOfDiscConversion = 1; hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc1.Init.NbrOfConversion = 2; hadc1.Init.DMAContinuousRequests = DISABLE; hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV; if (HAL_ADC_Init(&hadc1) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } /**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. */ sConfig.Channel = ADC_CHANNEL_5; sConfig.Rank = 1; sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES; if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } /**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. */ sConfig.Channel = ADC_CHANNEL_8; sConfig.Rank = 2; if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } } void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle) { GPIO_InitTypeDef GPIO_InitStruct; if(adcHandle->Instance==ADC1) { /* USER CODE BEGIN ADC1_MspInit 0 */ /* USER CODE END ADC1_MspInit 0 */ /* ADC1 clock enable */ __HAL_RCC_ADC1_CLK_ENABLE(); /**ADC1 GPIO Configuration PA5 ------> ADC1_IN5 PB0 ------> ADC1_IN8 */ GPIO_InitStruct.Pin = GPIO_PIN_5; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_0; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); /* USER CODE BEGIN ADC1_MspInit 1 */ /* USER CODE END ADC1_MspInit 1 */ } } 二、滤波算法处理 uint16_t adc_values_ch5[14] = {0}; uint16_t adc_values_ch8[14] = {0}; /*进行单次AD转换,50ms超时*/ uint32_t Perform_single_AD_conversion(void) { HAL_ADC_Start(&hadc1); HAL_ADC_PollForConversion(&hadc1, 50); uint8_t i=255; while (!HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC)) { i--; if (i ==0) { break; //防止AD死循环 } } uint32_t ad_Temp = HAL_ADC_GetValue(&hadc1); return ad_Temp; } /*对14次采样的电压按照从小到大进行排序*/ void Sort_ADC_Values(uint16_t *adc_nums) { int i, j, temp, isSorted; //优化算法:最多进行 n-1 轮比较 for(i=0; i<14-1; i++) { isSorted = 1; //假设剩下的元素已经排序好了 for(j=0; j<14-1-i; j++) { if(adc_nums[j] > adc_nums[j+1]) { temp = adc_nums[j]; adc_nums[j] = adc_nums[j+1]; adc_nums[j+1] = temp; isSorted = 0; //一旦需要交换数组元素,就说明剩下的元素没有排序好 } } if(isSorted) break; //如果没有发生交换,说明剩下的元素已经排序好了 } } /*去掉2个最大值,2个最小值,剩余10个值求平均数*/ uint16_t Find_Average_ADC_Values(uint16_t *adc_nums) { uint16_t sum = 0; for(uint8_t i=2; i<12; i++) { sum = sum + adc_nums; } return sum/10; } /*软件滤波求出ADC转换平均值*/ uint16_t Software_filtering_ADC(uint16_t *adc_nums) { uint16_t adc_avg = 0; Sort_ADC_Values(adc_nums); adc_avg = Find_Average_ADC_Values(adc_nums); return adc_avg; } void Get_Two_Channel_ADC_Votage(void) { float votage = 0.0; for(uint8_t i=0; i<14; i++) { adc_values_ch5 = Perform_single_AD_conversion(); printf("rnadc_values_ch5[%d] = %drn", i,adc_values_ch5); adc_values_ch8 = Perform_single_AD_conversion(); printf("rnadc_values_ch8[%d] = %drn", i,adc_values_ch8); } HAL_ADC_Stop(&hadc1); votage = Software_filtering_ADC(adc_values_ch5)*3.3/4096; printf("rnPA5采集电压: %f rn",votage); votage = Software_filtering_ADC(adc_values_ch8)*3.3/4096; printf("rnPB0采集电压: %f rn",votage); } 三、打印输出结果 在main函数的主循环while里调用Get_Two_Channel_ADC_Votage(),即可输出打印结果。 int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration----------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_DMA_Init(); MX_IWDG_Init(); MX_ADC1_Init(); MX_USART1_UART_Init(); /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { Get_Two_Channel_ADC_Votage(); HAL_Delay(2000); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ HAL_IWDG_Refresh(&hiwdg); //看门狗喂狗 } /* USER CODE END 3 */ } |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1777 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1621 浏览 1 评论
1080 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
728 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1678 浏览 2 评论
1938浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
731浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
570浏览 3评论
595浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
554浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-23 06:51 , Processed in 0.876717 second(s), Total 78, Slave 62 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号