熱門: 51單片機(jī) | 24小時(shí)必答區(qū) | 單片機(jī)教程 | 單片機(jī)DIY制作 | STM32 | Cortex M3 | 模數(shù)電子 | 電子DIY制作 | 音響/功放 | 拆機(jī)樂園 | Arduino | 嵌入式OS | 程序設(shè)計(jì)
![]() |
發(fā)布時(shí)間: 2024-10-21 16:10
正文摘要:/** **************************************************************************************************** * @file adc.c * @author ... |
調(diào)整了以下幾點(diǎn)代碼,看可否解決DMA傳輸數(shù)據(jù)為0的問題。修改點(diǎn)包括: 1. **確保DMA和ADC的初始化順序正確**。 2. **添加調(diào)試日志,監(jiān)控DMA傳輸狀態(tài)和數(shù)據(jù)**。 3. **確保DMA中斷優(yōu)先級(jí)和中斷處理函數(shù)工作正常**。 4. **保證ADC DMA啟動(dòng)后的數(shù)據(jù)讀取流程正確**。 ### 修改后的代碼如下: ```c #include "./BSP/ADC/adc.h" #include "./SYSTEM/delay/delay.h" #include "./SYSTEM/usart/usart.h" ADC_HandleTypeDef g_adc_handle; /* ADC句柄 */ DMA_HandleTypeDef g_dma_adc_handle; /* 與ADC關(guān)聯(lián)的DMA句柄 */ uint8_t g_adc_dma_sta = 0; /* DMA傳輸狀態(tài)標(biāo)志, 0,未完成; 1, 已完成 */ uint16_t g_adc_value[ADC_CH_NUM * ADC_COLL] = {0}; /* 存儲(chǔ)ADC原始值 */ uint16_t g_adc_val[ADC_CH_NUM] = {0}; /* 存儲(chǔ)處理后的ADC平均值 */ /********************************************************************/ /** * @brief ADC初始化函數(shù) * @retval 無 */ void adc_init(void) { ADC_ChannelConfTypeDef sConfig = {0}; g_adc_handle.Instance = ADC_ADCX; g_adc_handle.Init.ContinuousConvMode = ENABLE; g_adc_handle.Init.DataAlign = ADC_DATAALIGN_RIGHT; g_adc_handle.Init.DiscontinuousConvMode = DISABLE; g_adc_handle.Init.ExternalTrigConv = ADC_SOFTWARE_START; g_adc_handle.Init.NbrOfConversion = ADC_CH_NUM; g_adc_handle.Init.ScanConvMode = ENABLE; HAL_ADC_Init(&g_adc_handle); HAL_ADCEx_Calibration_Start(&g_adc_handle); // ADC校準(zhǔn) sConfig.Channel = ADC_ADCX_CH4; sConfig.Rank = 1; sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5; HAL_ADC_ConfigChannel(&g_adc_handle, &sConfig); sConfig.Channel = ADC_ADCX_CH5; sConfig.Rank = 2; sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5; HAL_ADC_ConfigChannel(&g_adc_handle, &sConfig); } /********************************************************************/ /** * @brief DMA初始化函數(shù) * @retval 無 */ void adc_dma_init(void) { if ((uint32_t)ADC_ADCX_DMACx > (uint32_t)DMA1_Channel7) /* 大于DMA1_Channel7, 則為DMA2的通道了 */ { __HAL_RCC_DMA2_CLK_ENABLE(); /* DMA2時(shí)鐘使能 */ } else { __HAL_RCC_DMA1_CLK_ENABLE(); /* DMA1時(shí)鐘使能 */ } g_dma_adc_handle.Instance = DMA1_Channel1; g_dma_adc_handle.Init.Direction = DMA_PERIPH_TO_MEMORY; g_dma_adc_handle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; g_dma_adc_handle.Init.MemInc = DMA_MINC_ENABLE; g_dma_adc_handle.Init.Mode = DMA_CIRCULAR; // 設(shè)置為循環(huán)模式,確保DMA持續(xù)工作 g_dma_adc_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; g_dma_adc_handle.Init.PeriphInc = DMA_PINC_DISABLE; g_dma_adc_handle.Init.Priority = DMA_PRIORITY_MEDIUM; HAL_DMA_Init(&g_dma_adc_handle); __HAL_LINKDMA(&g_adc_handle, DMA_Handle, g_dma_adc_handle); // 關(guān)聯(lián)DMA和ADC } /********************************************************************/ /** * @brief DMA傳輸完成中斷處理函數(shù) * @retval 無 */ void ADC_ADCX_DMASX_IRQHandler(void) { HAL_DMA_IRQHandler(&g_dma_adc_handle); g_adc_dma_sta = 1; // 標(biāo)記DMA傳輸完成 } /********************************************************************/ /** * @brief ADC轉(zhuǎn)換完成回調(diào)函數(shù) * @retval 無 */ void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) { if (hadc->Instance == ADC_ADCX) { HAL_ADC_Stop_DMA(hadc); // 停止DMA,防止數(shù)據(jù)被覆蓋 calc_adc_val(g_adc_val); // 計(jì)算ADC平均值 g_adc_dma_sta = 1; // 標(biāo)記DMA傳輸完成 HAL_ADC_Start_DMA(hadc, (uint32_t *)g_adc_value, ADC_CH_NUM * ADC_COLL); // 重新啟動(dòng)DMA } } /********************************************************************/ /** * @brief 計(jì)算ADC的平均值(濾波) * @param *p : 存放ADC值的指針地址 * @retval 無 */ void calc_adc_val(uint16_t *p) { uint32_t temp[ADC_CH_NUM] = {0}; /* 緩存數(shù)組 */ for (int i = 0; i < ADC_COLL; i++) { for (int j = 0; j < ADC_CH_NUM; j++) { temp[j] += g_adc_value[j + i * ADC_CH_NUM]; /* 累加 */ } } for (int j = 0; j < ADC_CH_NUM; j++) { p[j] = temp[j] / ADC_COLL; /* 計(jì)算平均值 */ } } int main(void) { HAL_Init(); /* 初始化HAL庫(kù) */ sys_stm32_clock_init(RCC_PLL_MUL9); /* 設(shè)置時(shí)鐘, 72Mhz */ delay_init(72); /* 延時(shí)初始化 */ usart_init(115200); /* 串口初始化為115200 */ adc_init(); // 初始化ADC adc_dma_init(); // 初始化DMA // 啟動(dòng)DMA if (HAL_ADC_Start_DMA(&g_adc_handle, (uint32_t *)g_adc_value, ADC_CH_NUM * ADC_COLL) != HAL_OK) { printf("ADC DMA start failed\r\n"); } while (1) { if (g_adc_dma_sta) // DMA傳輸完成 { g_adc_dma_sta = 0; // 重置標(biāo)志位 printf("ADC Value Channel 1: %d, Channel 2: %d\r\n", g_adc_val[0], g_adc_val[1]); } } } ``` ### 程序修改了: 1. **DMA初始化**:確保正確初始化DMA,并關(guān)聯(lián)到ADC句柄。 2. **DMA模式**:將DMA模式設(shè)置為 `DMA_CIRCULAR`,這樣DMA會(huì)持續(xù)工作,而不需要手動(dòng)重新啟動(dòng)。 3. **中斷處理**:在 `ADC_ADCX_DMASX_IRQHandler()` 中設(shè)置DMA傳輸完成標(biāo)志位,并在 `HAL_ADC_ConvCpltCallback()` 中處理傳輸完成的邏輯。 4. **ADC轉(zhuǎn)換完成處理**:在回調(diào)函數(shù) `HAL_ADC_ConvCpltCallback()` 中停止DMA、計(jì)算ADC平均值,并重新啟動(dòng)DMA。 5. **主循環(huán)**:通過輪詢 `g_adc_dma_sta` 檢測(cè)DMA傳輸完成,并在主循環(huán)中打印ADC轉(zhuǎn)換后的數(shù)據(jù)。 ### 調(diào)試提示: - 在 `HAL_ADC_Start_DMA()` 后面添加錯(cuò)誤處理,確保DMA和ADC啟動(dòng)正常。 - 你可以通過串口日志查看 `g_adc_val[]` 是否有正確的值輸出。如果還存在問題,可以進(jìn)一步調(diào)試DMA的中斷是否正確觸發(fā)。 |
Powered by 單片機(jī)教程網(wǎng)