cubemx 配置多通道ADC進行ADC採樣

cubemx 配置多通道ADC進行ADC採樣

AD的基礎知識

AD很複雜,其實也不復雜,因爲我們用的不多。

  • AD:模擬量轉換數字量(模擬信號轉換數字信號)。

  • ADC:模擬量轉數字量的轉換器。

  • 爲什麼需要AD呢?

    自然界宏觀的物理量都是連續的。而機器識別的信號0與1是離散的。爲了讓機器能夠採集、分析、儲存這些連續的量,所以要把需要被模擬的量轉換爲數字量。

  • 主要的參數:採樣精度與轉換速度。

  • 採樣精度,也叫作分辨率。如果0-100攝氏度用8位AD來儲存的話,精度計算?

0000 0000 —— 0攝氏度 ; 1111 1111 —— 100攝氏度;100/256 = 0.39攝氏度,0.39就是最小份的分辨率,也就是採樣精度.沒有辦法表>現出0.2度。100/65536 = 0.0015,16位的AD,精度就很高了。

  • 轉換速度

從啓動到出結果用的時間,一般來說越快越好。與精度不可兼得。被單位時間採樣數量影響。採樣多,速度不會很快。

STM32F4使用的AD是逐次逼近型ADC,它產生一系列比較電壓VR,但它是逐個產生比較電壓,逐次與輸入電壓分別比較,以逐漸逼近的方式進行模數轉換的。它比並聯比較型ADC的轉換速度慢,比雙分積型ADC要快得多,屬於中速ADC器件。

多通道AD採集需要使用DMA

在STM32的手冊中,我們發現,不論是單次採集還是多次採集,轉換完成的數據都會放在同一個地方。
ADC
由於ADC_DR寄存器不是一個數組,而是一個16位的變量,所以只能保存最新的轉換結果。例如,通道1和通道2都使用,通道1的轉換結果放在DR寄存器。通道2轉換完畢以後,就會覆蓋通道1的結果。

程序裏,當然可以通過一些處理,讓通道1的結果在被覆蓋之前就保存好。不過,運用STM32的DMA功能,可以更好地解決結果被覆蓋的問題。
ADC
重點:用於高速搬運數據,還無需CPU干預。 因此在多通道採集模擬量是,我們可以建立一個數組,用於儲存AD轉換的數據。一旦ADC_DR寄存器裏有了新的數據,就把新數據放在數組裏。一會兒ADC_DR有了一個新的數據,就放在數組下一位。數組裝滿以後?根據需求來。我們設置的是循環模式,也就是再來一遍,覆蓋之前的數據。

STM32F4xx系列一般都有3個ADC,這些ADC可以獨立使用,也可以使用雙重/三重模式(提高採樣率)。STM32F4的ADC是12位逐次逼近型的模擬數字轉換器。它有19個通道,可測量16個外部源、2個內部源和Vbat通道的信號。這些通道的A/D轉換可以單次、連續、掃描或間斷模式執行。ADC的結果可以左對齊或右對齊方式存儲在16位數據寄存器中。模擬看門狗特性允許應用程序檢測輸入電壓是否超出用戶定義的高/低閥值。
STM32F407ZGT6包含有3個ADC。STM32F4的ADC最大的轉換速率爲2.4Mhz,也就是轉換時間爲0.41us(在ADCCLK=36M,採樣週期爲3個ADC時鐘下得到),不要讓ADC的時鐘超過36M,否則將導致結果準確度下降。

cubemx 配置DMA+多通道ADC(ADC1的4個通道)

1. 環境:

  • packages版本(STM32F4 1.21)
  • cubemx版本(version4.27.0 && STM32Cube v1.0)
  • MDK版本(KEIL5 V5.23.0.0)

packages版本
cubemx版本
KEIL5版本

2. cubemx配置主要內容

ADC1引腳配置

ADC1引腳配置

ADC1參數配置

ADC1參數配置

ADC中斷配置

ADC中斷配置

ADC1的DMA配置

ADC1的DMA配置

說明一個問題
這裏ADC的DMA設置的是循環模式,數據寬度是字(32位),由於STM32F407存儲ADC的結果爲一個16位的數據寄存器,故這裏可以設置爲半字(16位)。已經實際測試,效果是一樣的。

生成代碼

3. 完善代碼

3.1 定義變量

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
#define ADC_CHANNEL_CNT 4 	//採樣通道數
#define ADC_CHANNEL_FRE 100	//單個通道採樣次數,用來取平均值
uint32_t adc1_val_buf[400]; //傳遞給DMA存放多通道採樣值的數組
uint16_t i,j;
uint32_t adc1_aver_val[ADC_CHANNEL_CNT] = {0}; //保存多通道的平均採樣值的數組
uint32_t dma_cnt1 = 0;
/* USER CODE END PV */

3.2 開啓ADC1的DMA轉換

/* USER CODE BEGIN 2 */
HAL_ADC_Start_DMA(&hadc1,(uint32_t*) &adc1_val_buf, (ADC_CHANNEL_CNT*ADC_CHANNEL_FRE));
HAL_Delay(100);
/* USER CODE END 2 */

這裏解釋一下HAL_ADC_Start_DMA()函數,第一個參數是ADC的操作句柄;第二個參數是用來保存ADC轉換結果的數組的地址,是內容的copy所以要傳遞數組的地址;第三個參數是轉換的數據長度。

3.3 完善主函數

while (1)
{

/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */
  /* 清除adc採樣平均值變量 */
for(i=0;i<ADC_CHANNEL_CNT;i++)
{
  adc1_aver_val[i] = 0;
}
/* 在採樣值數組中分別取出每個通道的採樣值並求和 */
for(i=0;i<ADC_CHANNEL_FRE;i++)
{
  adc1_aver_val[0] +=  adc1_val_buf[i*4+0];
  adc1_aver_val[1] +=  adc1_val_buf[i*4+1];
  adc1_aver_val[2] +=  adc1_val_buf[i*4+2];
  adc1_aver_val[3] +=  adc1_val_buf[i*4+3];
}
/* 依次對每個通道採樣值求平均值 */
for(i=0;i<ADC_CHANNEL_CNT;i++)
{
  adc1_aver_val[i] /=ADC_CHANNEL_FRE;
}
printf("\n\r ***** START PRINTF ADC INFO ******** \r\n\n");
for(i=0;i<ADC_CHANNEL_CNT;i++)
{
  printf("ADC1[%02d] Sampling voltage = %1.3f V Sampling value = %04d\r\n",i,adc1_aver_val[i]*3.30f/4095,adc1_aver_val[i]);
}
printf("DMA CNT = %06d\r\n",dma_cnt1);
dma_cnt1 = 0;
printf("\n\r END PRINTF ADC INFO \r\n\n");

HAL_Delay(1000);
HAL_GPIO_TogglePin(GPIOF,GPIO_PIN_10);  
}

3.4 ADC轉換完成回調函數完善

一次ADC轉換完成回調函數,可以在裏面操作記錄DMA搬移數據的次數

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
	if(hadc==(&hadc1))
	{
		dma_cnt1++;
	}   
}

3.5 串口打印效果:

串口打印效果

公衆號二維碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章