GD32E230 系列只有 1 路 ADC,有如下特征:,
-
高達 2 MSPS
-
一共 12 路模擬通道
- 10 路外部通道 (AIN0 - AIN9)
- 1 路內部溫度傳感器(AIN16)
- 1 路內部參考電壓(AIN17)
-
可選分辨率:12-bit、10-bit、8-bit or 6-bit
-
支持模擬看門狗
轉換通道選擇 ,有 2 種方式:
-
規則組
規則組支持最多 16 通道,對於所使用的通道可以指定轉換順序,觸發方式可以是硬件、軟件,因為規則組數據寄存器只有一個,如果使用大於一個通道的話,就必須得配合 DMA,不然從數據寄存器讀出來得始終是最后采樣的那個通道得數據,
-
注入組
最多支持 4 通道,同樣支持對所使用得通道指定轉換順序,支持硬件、軟件觸發,不過注入組有 4 個數據寄存器,注入組里面得每個通道都有對應得數據寄存器,
間斷模式
規則組 跟 注入組都支持間斷模式(Discontinuous mode),如果使用了間斷模式,一次轉換不是轉換所使用的所有通道,詳情如下:
- 規則
每次轉換所使用得通道(ADC_RSQ0~ADC_RSQ2 中配置得通道)中的 n (n<=8 )個通道,n 由DISNUM[2:0] bits 設定,然后繼續轉換規則組中的接下來的 n 個通道,直到規則組中的所有通道都轉換完,如:
ADC_RSQ0 的 RL 為 8 ,意思是規則組中有 8 個通道,DISNUM 為 3,表示每次轉換 3 個通道,沒觸發一次轉換 3 通道,直到 8 個通道都完成轉換
- 注入
每次轉換注入組中的一個通道直到所有轉換完成
模擬看門狗
GD32E230的 ADC 還有模擬看門狗的功能,該 ADC 有低閾值和高閾值寄存器,當 ADC 采樣的值低於低閾值數值或者高於高閾值數值時,如果相應中斷使能的話,會產生中斷,
內部參考電壓
該 ADC 有個內部參考電壓,第 17 通道接到了這個內部參考電壓,這電壓是多少呢?一開始我以為是 VDD,可是我看 ADC 采集到參考電壓對於 channal 的值不對,於是我查手冊,可是,我找遍了 GD32E230 的 datasheet 跟 參考手冊 ADC 部分,都沒提到這個值是多少,直到我在 datasheet 中搜關鍵詞 reference ,發現了個線索:
然后我在 GD32E230 的參考手冊 CMP 部分找到了:
翻遍手冊,就發現這里有標明,我不知道這個參數重不重要,反正我找了下,找的好辛苦
讀取可調電阻
這個模塊有 3 個接口,一個接電源正極、一個接負極、還有一個輸出,旋轉旋鈕時,輸出口的電壓會從 電壓正極 到 電源負極改變,
如果要知道旋轉的時候,輸出時多少該怎么做呢?
這里只需要一路 ADC 通道,可是使用 ADC 的連續采集功能,也可以使用一個定時器定時觸發 ADC 采集,
具體要怎么實現呢?我看了下 SDK 給出的例程,里面有個 Timer_trigger_injected_channel
例子,從這里例子名字來看應該時滿足這個需求:
看了下源碼,里面實現了定時器 2 定時觸發一個有 4 通道的注入組,我只要把這個歷程改為 1 通道就可以滿足我的需求了
把可變電阻器兩端分別接到 電源 跟 地,輸出接到 GD32E230 的 PA0,對應 ADC 的 IN0。
為了方便查看運行結果,把這個例程往之前實現了串口輸出的工程移植,
例子中,定時器部分先不變,修改 GPIO 跟 ADC 初始化部分,改為 1 通道:
/*!
\brief configure the GPIO peripheral
\param[in] none
\param[out] none
\retval none
*/
void gpio_config(void)
{
/* config the GPIO as analog mode */
gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_0);
}
/*!
\brief configure the ADC peripheral
\param[in] none
\param[out] none
\retval none
*/
void adc_config(void)
{
/* ADC continous function enable */
adc_special_function_config(ADC_SCAN_MODE, ENABLE);
/* ADC trigger config */
adc_external_trigger_source_config(ADC_INSERTED_CHANNEL, ADC_EXTTRIG_INSERTED_T2_CH3);
/* ADC data alignment config */
adc_data_alignment_config(ADC_DATAALIGN_RIGHT);
/* ADC channel length config */
adc_channel_length_config(ADC_INSERTED_CHANNEL, 1U);
/* ADC inserted channel config */
adc_inserted_channel_config(0U, ADC_CHANNEL_0, ADC_SAMPLETIME_55POINT5);
/* ADC external trigger enable */
adc_external_trigger_config(ADC_INSERTED_CHANNEL, ENABLE);
/* enable ADC interface */
adc_enable();
delay_1ms(1U);
/* ADC calibration and reset calibration */
adc_calibration_enable();
}
然后是讀取轉換結果,看了下例程,居然沒有這部分內容,
自己把 ADC 中斷部分加上,然后在中斷讀取轉成的數值,把如下添加到 ADC 初始話函數:
adc_interrupt_enable(ADC_INT_EOC);
nvic_irq_enable(ADC_CMP_IRQn, 0U);
然后再 中斷處理函數中讀取數值,這里只是通過串口輸出 ADC 采集到的數值:
////////////////////////////////////////////////
/* ADC */
/*!
\brief this function handles ADC exception
\param[in] none
\param[out] none
\retval none
*/
void ADC_CMP_IRQHandler(void)
{
/* clear the ADC interrupt or status flag */
adc_interrupt_flag_clear(ADC_INT_EOC);
printf("%d\n",adc_inserted_data_read(ADC_INSERTED_CHANNEL_0));
}
運行結果為:
從結果來看好像不是太直觀。
突然想起之前使用過一個串口調試工具-- SerialPlot,支持把接收到的數據用折線圖(曲線圖)顯示出來,試了下,效果不錯:
這部分完整代碼在:main_adjust_res.c
游戲搖桿模塊 Joystick
還有這么一個東西,跟可調電阻一樣,不過這個有 2 個可調電阻組成,有 2 個模擬兩輸出,可以根據 2 個可調電阻輸出的值反映搖桿的位置。我手上的長這樣子:
這里嘗試下規則組,根據 SDK 給出的 Regular_channel_with_DMA
來修改。
分別把這 2 個模擬輸出接到 PA0、PA1,對應 ADC 的 IN0、IN1,還是在之前實現了串口輸出的工程里面該,修改下 ADC 初始化函數,實現 2 通道規則組:
/*!
\brief configure the GPIO peripheral
\param[in] none
\param[out] none
\retval none
*/
void gpio_config(void)
{
/* config the GPIO as analog mode */
gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_0 | GPIO_PIN_1 );
}
/*!
\brief configure the ADC peripheral
\param[in] none
\param[out] none
\retval none
*/
void adc_config(void)
{
/* ADC contineous function enable */
adc_special_function_config(ADC_SCAN_MODE, ENABLE);
adc_special_function_config(ADC_CONTINUOUS_MODE, ENABLE);
/* ADC trigger config */
adc_external_trigger_source_config(ADC_REGULAR_CHANNEL, ADC_EXTTRIG_REGULAR_NONE);
/* ADC data alignment config */
adc_data_alignment_config(ADC_DATAALIGN_RIGHT);
/* ADC channel length config */
adc_channel_length_config(ADC_REGULAR_CHANNEL, 2U);
/* ADC regular channel config */
adc_regular_channel_config(0U, ADC_CHANNEL_0, ADC_SAMPLETIME_55POINT5);
adc_regular_channel_config(1U, ADC_CHANNEL_1, ADC_SAMPLETIME_55POINT5);
adc_external_trigger_config(ADC_REGULAR_CHANNEL, ENABLE);
/* enable ADC interface */
adc_enable();
delay_1ms(1U);
/* ADC calibration and reset calibration */
adc_calibration_enable();
/* ADC DMA function enable */
adc_dma_mode_enable();
/* ADC software trigger enable */
adc_interrupt_enable(ADC_INT_EOC);
nvic_irq_enable(ADC_CMP_IRQn, 0U);
adc_software_trigger_enable(ADC_REGULAR_CHANNEL);
}
然后修改下 DMA 初始化部分:
uint16_t adc_value[2];
/*!
\brief configure the DMA peripheral
\param[in] none
\param[out] none
\retval none
*/
void dma_config(void)
{
/* ADC_DMA_channel configuration */
dma_parameter_struct dma_data_parameter;
/* ADC DMA_channel configuration */
dma_deinit(DMA_CH0);
/* initialize DMA single data mode */
dma_data_parameter.periph_addr = (uint32_t)(&ADC_RDATA);
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 = 2U;
dma_data_parameter.priority = DMA_PRIORITY_HIGH;
dma_init(DMA_CH0, &dma_data_parameter);
dma_circulation_enable(DMA_CH0);
/* enable DMA channel */
dma_channel_enable(DMA_CH0);
}
定義一個 2 個 uint16_t
的數組用來存儲轉換出來的數據,
例程中使用了一個通道,這里使用 2 個通道,需要對例程中的 DMA 配置進行修改,改動部分如下:
dma_data_parameter.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_data_parameter.number = 2U;
轉換結果還是通過串口輸出:
void ADC_CMP_IRQHandler(void)
{
/* clear the ADC interrupt or status flag */
adc_interrupt_flag_clear(ADC_INT_EOC);
printf("%d,%d\n",adc_value[0],adc_value[1]);
}
轉換出來的數據在 SerialPlot 中用折線圖顯示出來為:
上圖雖然可以直觀的顯示數據的變化,可是並不能反映搖桿的變化,有沒有什么現成工具可以滿足這個需求呢?
我沒找到,不過可以自己做個,用 processing 很容易實現,這里我用 processing 實現了一個 圓形 隨着采集到 搖桿數據改變而改變位置的小程序,代碼如下,:
import processing.serial.*;
int bgcolor; // Background color
int fgcolor; // Fill color
Serial myPort; // The serial port
int[] serialInArray = new int[3]; // Where we'll put what we receive
int serialCount = 0; // A count of how many bytes we receive
int xpos, ypos; // Starting position of the ball
boolean firstContact = false; // Whether we've heard from the microcontroller
int lf = 10; // ASCII linefeed
String inString; // Input string from serial port
void setup() {
size(512, 512); // Stage size
noStroke(); // No border on the next thing drawn
// Set the starting position of the ball (middle of the stage)
xpos = width/2;
ypos = height/2;
// Print a list of the serial ports, for debugging purposes:
printArray(Serial.list());
String portName = Serial.list()[0];
myPort = new Serial(this, portName, 115200);
myPort.bufferUntil(lf);
}
void draw() {
background(255,255,255);
fill(255,0,0);
ellipse(xpos, ypos, 20, 20);
}
void serialEvent(Serial p) {
inString = p.readString();
//print(inString);
String[] list = split(inString, ',');
if(list.length >= 3)
{
for(int i=0;i<list.length;i++)
// print("["+ i + ":" + list[i] + "],");
xpos = int(list[0]) / 8;
ypos = int(list[1]) / 8;
println(xpos + "," + ypos);
// Draw the shape
}
}
運行結果為:
是不是很直觀啊,使用不到 100 行的代碼就可以實現,實在是方便,
不過這遙感有個缺點,用網友的話來說:
然而這種搖桿模塊的模擬輸出並不隨搖桿角度線性變化。從中點到端點是躍變的,很是令人抓狂。
摘自:https://www.arduino.cn/thread-98802-1-1.html
並不能很精確的反應搖桿的位置,
這部分完整代碼在這:Joystick.c