好久沒寫博客了,最近挺忙的。近來有些好玩的實現,網上的資料並不是非常詳細,打算慢慢寫下來,希望別人能少走一點彎路。 因為希望提高ADC的採樣率,這次我試著實現了一下三重ADC交替採樣+DMA搬運至記憶體+TIM的TRGO觸發採樣(環境是stm32cubemx 6.5.0和keil 5) 首先打開cub ...
好久沒寫博客了,最近挺忙的。近來有些好玩的實現,網上的資料並不是非常詳細,打算慢慢寫下來,希望別人能少走一點彎路。 因為希望提高ADC的採樣率,這次我試著實現了一下三重ADC交替採樣+DMA搬運至記憶體+TIM的TRGO觸發採樣(環境是stm32cubemx 6.5.0和keil 5)
首先打開cubemx進行基礎設置(設置時鐘樹,RCC,SYS)
然後設置ADC1(下圖為具體設置,僅供參考)
此處我們將ADC_Mode設置為Triple regular simultaneous mode only,並打開DMA連續請求(為了使DMA能夠填滿數組,按照我們的預期工作)
外部觸發源設置為TIM2的TRGO
由於已經設置了ADC模式,ADC2和ADC3是跟隨ADC1的,所以他們的模式是不能改變的,和ADC1一樣設置就可以了
接下來我們設置DMA,記住要設置成circular模式,不然他就只會傳輸一次,選擇一次傳輸Half Word,從外設搬運到記憶體
主要的設置就這些,串口的初始化已經省略了,後面我們將用串口重定向列印數據至串口(詳見我之前的博客串口重定向發送和接收)
現在我們只需要生成代碼,打開工程
這裡有個小細節:DMA和ADC的初始化順序不能錯了,要先初始化DMA再初始化ADC(其實用到DMA傳輸數據的外設都要在DMA初始化之後再進行初始化,因為不先初始化DMA的話,在初始化其他外設時,當配置到DMA相關的設置時會出現錯亂,導致外設無法正常工作,比如ADC就會傳輸數據失敗,但是DMA一直是處於busy狀態)
下麵我們進行垃圾核心代碼的編寫
我的初始化順序(僅供參考)
1 MX_GPIO_Init(); 2 MX_DMA_Init(); 3 MX_ADC1_Init(); 4 MX_ADC2_Init(); 5 MX_ADC3_Init(); 6 MX_DAC_Init(); 7 MX_TIM2_Init(); 8 MX_USART1_UART_Init();
主函數當中編寫的代碼如下:
1 HAL_ADC_Start(&hadc1); 2 HAL_ADC_Start(&hadc2); 3 HAL_ADC_Start(&hadc3);//啟動ADC 4 HAL_ADCEx_MultiModeStart_DMA(&hadc1,(uint32_t *)ADC_value,3000); 5 HAL_TIM_Base_Start(&htim2);//啟動TIM2,用於觸發ADC採樣
對於數據的處理,我更傾向於寫在回調函數裡面
1 void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) 2 { 3 int i; 4 for(i = 0;i < 1000;i++) 5 { 6 printf("%f,%f,%f\n",ADC_value[3 * i] * 3 / 4096.0,ADC_value[3 * i + 1] * 3 / 4096.0,ADC_value[3 * i + 2] * 3 / 4096.0); 7 } 8 return; 9 }
我們再編譯,燒錄程式。 至此,我們就可以實現ADC三重交替採樣了
/*------------------------------------------------------------------------分割線------------------------------------------------------------------------*/
我思來想去感覺還是在回調函數裡面改變一個標誌位就可以了,把這麼一大段處理放進去不太好,容易出現中斷嵌套等我們不希望出現的現象
儘量把處理的步驟寫到函數裡面去執行,只需通過判斷標誌位即可達到同等效果