6.1.ADC 基礎知識
12 位逐次逼近式模數轉換器模塊(ADC),可以采樣來自于外部輸入通道、內部輸入通道的模擬信號,采樣轉換后,轉換結果可以按照最低有效位對齊或最高有效位對齊的方式保存在相應的數據寄存器中。
6.2.GD32 ADC 外設原理
GD32 ADC 主要特性
? 高性能:
– ADC采樣分辨率: 12位、 10位、 8位、或者6位分辨率;
– 前置校準功能;
– 可編程采樣時間;
– 數據存儲模式:最高有效位對齊和最低有效位對齊;
– 支持規則數據轉換的DMA請求。
? 模擬輸入通道:
– 16個外部模擬輸入通道;
– 1個內部溫度傳感器輸入通道(VSENSE);
– 1個內部參考電壓輸入通道(VREFINT)。
? 轉換開始的發起:
– 軟件觸發;
– 硬件觸發。
? 轉換模式:
– 轉換單個通道,或者掃描一序列的通道;
– 單次運行模式,每次觸發轉換一次選擇的輸入通道;
– 連續運行模式,連續轉換所選擇的輸入通道;
– 間斷運行模式;
– 同步模式(適用于具有兩個或多個ADC的設備)。
? 轉換結果閾值監測器功能: 模擬看門狗。
? 中斷的產生:
– 常規序列轉換結束;
– 模擬看門狗事件。
? 過采樣:
– 16位的數據寄存器;
– 可調整的過采樣率,從2x到256x;
– 高達8位的可編程數據移位。
? ADC供電要求:
– 2.4V到3.6V,一般供電電壓為3.3V。
? ADC輸入范圍: VREF- ≤VIN ≤VREF+。
– VREF- : ADC 負參考電壓, VREF- = VSSA
– VREF+ : ADC 正參考電壓, 2.6 V ≤ VREF+ ≤ VDDA
ADC 結構框圖介紹
6.3.硬件連接說明
ADC的檢測需要將輸入阻抗和采樣周期保持一定的關系,下表列出了以GD32E103為例子
6.4.軟件配置說明
查詢法
查詢法采用的是轉換單個通道,或者掃描一序列的通道,通過不斷切換通道的方式去讀取對應通道的ADC數值。我們介紹使用庫函數來設置 ADC0 的通道來進行 AD 轉換的步驟,下面講解其詳細設置步驟:
開啟 GPIO口時鐘和 ADC0 時鐘,設置GPIO口為模擬輸入。
rcu_periph_clock_enable(RCU_GPIOA); /* enable GPIOB clock */ rcu_periph_clock_enable(RCU_GPIOB); /* enable ADC0 clock */ rcu_periph_clock_enable(RCU_ADC0); /* config ADC clock */ rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV4); /* enable alternate function clock */ rcu_periph_clock_enable(RCU_AF); //使能 GPIO 口復用
這里需要說明一下, ADC 的通道與引腳的對應關系在數據手冊可以查到
(1)配置 ADC 輸入時鐘分頻,模式為獨立模式,轉換長度以及觸發方式等
/* reset ADC */ adc_deinit(ADC0); /* ADC mode config */ adc_mode_config(ADC_MODE_FREE); //獨立模式 /* ADC continous function enable */ adc_special_function_config(ADC0, ADC_SCAN_MODE, ENABLE) /* ADC data alignment config */ adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT); //ADC 數據右對齊 adc_special_function_config(ADC0,ADC_CONTINUOUS_MODE,DISABLE); /* ADC channel length config */ adc_channel_length_config(ADC0, ADC_REGULAR_CHANNEL, 1);//設置 ADC 轉換的通道數量 /* ADC trigger config */ adc_external_trigger_source_config(ADC0,ADC_REGULAR_CHANNEL,ADC0_1_EXTTRIG_REGULAR_NONE); //通過軟件觸發 ADC 轉換 adc_external_trigger_config(ADC0, ADC_REGULAR_CHANNEL, ENABLE);
(2)開啟 AD 轉換器
在設置完了以上信息后,我們就開啟 AD 轉換器了
/* enable ADC interface */ adc_enable(ADC0); delay_1ms(1);//延遲 等待穩定 /* ADC calibration and reset calibration */ adc_calibration_enable(ADC0);//使能 ADC 校準
(3)讀取 ADC 值 在上面的步驟完成后, ADC 就算準備好了。所謂的查詢法就是不斷地進行通道切換
unsigned short adc0_transfer(unsigned char adc_channel) { uint16_t ADC_temp; /* ADC regular channel config */ adc_regular_channel_config(ADC0, 0, adc_channel, ADC_SAMPLETIME_55POINT5); adc_software_trigger_enable(ADC0,ADC_REGULAR_CHANNEL); while(!adc_flag_get(ADC0, ADC_FLAG_EOC));//等待轉換完成 /* clear the end of conversion flag */ adc_flag_clear(ADC0, ADC_FLAG_EOC); ADC_temp=adc_regular_data_read(ADC0); return ADC_temp; }
這里還需要說明一下ADC的參考電壓,是以Vref作為參考電壓。
常規通道轉換 DMA 搬運
通過ADC轉換,在ADC 轉換完成后 觸發DMA 進行數據搬運。
DMA 請求,可以通過設置 ADC_CTL1 寄存器的 DMA 位來使能,它用于規則組多個通道的轉換結果。 ADC 在規則組一個通道轉換結束后產生一個 DMA 請求, DMA 接受到請求后可以將轉換的數據從 ADC_RDATA 寄存器傳輸到用戶指定的目的地址。
在和查詢法一節的差別,主要在于ADC 的配置方面和DMA的配置
(1)ADC 的配置
/* ADC channel length config */ adc_channel_length_config(ADC0, ADC_REGULAR_CHANNEL, 4);//常規通道長度配置 /* ADC regular channel config */ adc_regular_channel_config(ADC0, 0, ADC_CHANNEL_4, ADC_SAMPLETIME_55POINT5); adc_regular_channel_config(ADC0, 1, ADC_CHANNEL_5, ADC_SAMPLETIME_55POINT5); adc_regular_channel_config(ADC0, 2, ADC_CHANNEL_6, ADC_SAMPLETIME_55POINT5); adc_regular_channel_config(ADC0, 3, ADC_CHANNEL_7, ADC_SAMPLETIME_55POINT5); /* ADC trigger config */ adc_external_trigger_source_config(ADC0,ADC_REGULAR_CHANNEL, ADC0_1_EXTTRIG_REGULAR_NONE); adc_external_trigger_config(ADC0, ADC_REGULAR_CHANNEL, ENABLE); /* ADC DMA function enable */ adc_dma_mode_enable(ADC0);//使能 DMA 模式 /* enable ADC interface */ adc_enable(ADC0); delay_1ms(1); /* ADC calibration and reset calibration */ adc_calibration_enable(ADC0);
(2)DMA的配置
/* ADC_DMA_channel configuration */ dma_parameter_struct dma_data_parameter; /* ADC DMA_channel configuration */ dma_deinit(DMA0, DMA_CH0); /* initialize DMA single data mode */ dma_data_parameter.periph_addr = (uint32_t)(&ADC_RDATA(ADC0)); //外設地址 dma_data_parameter.periph_inc = DMA_PERIPH_INCREASE_DISABLE; dma_data_parameter.memory_addr = (uint32_t)(&adc_value); //搬運目標地址 dma_data_parameter.memory_inc = DMA_MEMORY_INCREASE_ENABLE; dma_data_parameter.periph_width = DMA_PERIPHERAL_WIDTH_16BIT; dma_data_parameter.memory_width = DMA_MEMORY_WIDTH_16BIT; dma_data_parameter.direction = DMA_PERIPHERAL_TO_MEMORY; dma_data_parameter.number = 4; dma_data_parameter.priority = DMA_PRIORITY_HIGH; dma_init(DMA0, DMA_CH0, &dma_data_parameter); /* enable DMA circulation mode */ dma_circulation_enable(DMA0, DMA_CH0); /* enable DMA channel */ dma_channel_enable(DMA0, DMA_CH0);
(3)觸發ADC 轉換
adc_software_trigger_enable(ADC0,ADC_REGULAR_CHANNEL);
注入通道-中斷
在和查詢法一節的差別,主要在于ADC 的配置方面和注入通道會產生中斷
(1)ADC 的配置
/* reset ADC */ adc_deinit(ADC0); /* ADC mode config */ adc_mode_config(ADC_MODE_FREE); /* ADC continous function enable */ adc_special_function_config(ADC0, ADC_SCAN_MODE, ENABLE); /* ADC data alignment config */ adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT); /* ADC channel length config *//注入通道配置 adc_channel_length_config(ADC0, ADC_INSERTED_CHANNEL, 4);//注入通道長度配置 /* ADC inserted channel config */ adc_inserted_channel_config(ADC0, 0, ADC_CHANNEL_0, ADC_SAMPLETIME_55POINT5); adc_inserted_channel_config(ADC0, 1, ADC_CHANNEL_1, ADC_SAMPLETIME_55POINT5); adc_inserted_channel_config(ADC0, 2, ADC_CHANNEL_2, ADC_SAMPLETIME_55POINT5); adc_inserted_channel_config(ADC0, 3, ADC_CHANNEL_3, ADC_SAMPLETIME_55POINT5); /* ADC trigger config */ //通過 EXTI 15 進行觸發 adc_external_trigger_source_config(ADC0,ADC_INSERTED_CHANNEL,ADC0_1_EXTTRIG_INSERTED_EXTI_15); /* ADC external trigger enable */ adc_external_trigger_config(ADC0, ADC_INSERTED_CHANNEL, ENABLE); /* clear the ADC flag */ adc_interrupt_flag_clear(ADC0, ADC_INT_FLAG_EOC); adc_interrupt_flag_clear(ADC0, ADC_INT_FLAG_EOIC); /* enable ADC interrupt */ adc_interrupt_enable(ADC0, ADC_INT_EOIC);//使能注入通道的中斷 /* enable ADC */ adc_enable(ADC0); delay_1ms(1); /* ADC calibration and reset calibration */ adc_calibration_enable(ADC0);
(2)ADC 注入通道轉換完成服務函數
void ADC0_1_IRQHandler(void) { /* clear the ADC flag */ adc_interrupt_flag_clear(ADC0, ADC_INT_FLAG_EOIC);//清除注入通道轉換完成標志位 /* read ADC inserted group data register */ inserted_data[0] = adc_inserted_data_read(ADC0, ADC_INSERTED_CHANNEL_0); inserted_data[1] = adc_inserted_data_read(ADC0, ADC_INSERTED_CHANNEL_1); inserted_data[2] = adc_inserted_data_read(ADC0, ADC_INSERTED_CHANNEL_2); inserted_data[3] = adc_inserted_data_read(ADC0, ADC_INSERTED_CHANNEL_3); }
6.5.ADC 使用注意事項
1、ADC通道的采集引腳未配置為模擬輸入,GD32要求通道IO口必須配置為模擬輸入;
2、ADC時鐘過高,ADC采樣時鐘高于ADC最高采樣時鐘獲取到的數據不具有參考意義,需要手動分頻到合適的ADC 要求的頻率;
3、ADC采樣值偏小或不穩定,應該適當的降低ADC時鐘,加大采樣周期的值;
4、ADC的查詢法在獲取ADC數值的時候,不允許重入,即不允許在同一時間調用ADC的數據讀取函數;
5、ADC在使能之后需要進行短暫的延時,時間周期約為2毫秒左右,以保證ADC能正常啟動。
-
單片機
+關注
關注
6043文章
44621瀏覽量
638562 -
mcu
+關注
關注
146文章
17319瀏覽量
352649 -
嵌入式
+關注
關注
5092文章
19177瀏覽量
307676 -
adc
+關注
關注
99文章
6533瀏覽量
545757 -
開發板
+關注
關注
25文章
5121瀏覽量
98195
發布評論請先 登錄
相關推薦
評論