前言#
如果您未看过笔者之前写的 "第一步配置" 和 "MSPM0 教程之调用 SYSCONFIG 以及配置 GPIO 输出和输入",强烈建议您将这两篇先看了,以免出现配置错误,如果您已经完成了 SYSCONFIG 的配置,请继续往下看
创易栈 MSPM0 开发板参考电压选择#
根據創易栈的用戶手冊,板載 VREF2.5V,我們把板子上的撥碼開關撥到 ON 即可
SYSCONFIG 配置#
在 keil 內打開 empty.syscfg, 然後調用 SYSCONFIG 工具
進入 SYSCONFIG,我們再添加 ADC,先看看他的介紹
在基本配置中,用戶可以:
- 配置采樣時鐘和采樣模式:這些參數影響了 ADC 的采樣率,即每秒鐘對輸入信號進行采樣的次數。
- 配置 ADC 轉換內存:存儲從模擬信號轉換得到的數字數據。
- 啟用 / 禁用以下功能:
- 硬件平均模式:通過對多次采樣結果進行平均,減少隨機噪聲的影響。
- 使用燒耗電流源:可能用於在 ADC 轉換過程中提供穩定的參考電壓。
- 窗口比較器模式:只有當輸入信號在一個指定的範圍內時,才進行 ADC 轉換。
- 觸發模式:可以設置 ADC 轉換只在接收到一個特定的觸發信號時開始。
在高級配置中,用戶可以:
- 配置轉換頻率 / 分辨率:影響了 ADC 轉換的精度和速度。
- 啟用 FIFO 模式:在這種模式下,ADC 可以連續進行多次轉換,並將結果存入一個先進先出(FIFO)的隊列中,方便後續處理。
- 配置電源下降模式:在不需要進行 ADC 轉換時,可以降低 ADC 模塊的電源,以節省能源。
- 指定采樣時間:對於快速變化的模擬信號,可能需要更短的采樣時間。
ADC 參數#
如參考手冊所示,該 ADC 的在不同分辨率下的轉換周期
如果我們使用 ULPCLK,可以繞過這個采樣延遲
勾選重複采樣模式
在 SYSCONFIG 中配置觸發源,我設置為事件觸發,這個事件由定時器發布
Conversion Data Format 這個選項中選擇無符號右對齊
在高級設置這裡,我們可以通過設置采集的時間來確定采樣率 (12bit 上限為 1.45M),采樣率等於 32 (時鐘頻率)/(1 / 采樣時間 + 轉換時間 (12bit 分辨率 為 14 個時鐘周期)),通過計算可以得到,將采樣時間設置為 250ns(即八個 (32M) 時鐘周期), 此時采樣率就為 32/(8+14)=1.45M
然後我們先去配置定時器,定時器配置如圖,確保設置好對應的觸發事件
接著再回到 ADC 配置頁,設置好訂閱事件
然後打開 DMA 傳輸,設置好 DMA 的參數,包括觸發源,數據長度和傳輸地址模式設置以及傳輸模式
傳輸模式定義了數據如何從源地址傳輸到目標地址,有四種模式:
-
Single Transfer:這種模式下,每次傳輸都需要一個觸發信號。當按照 "Transfer Size" 設定的次數完成傳輸後,DMA 將被禁用。
-
Block Transfer:這種模式下,一個觸發信號就能傳輸完整的數據塊,數據塊的大小由 "Transfer Size" 決定。每次傳輸結束後,DMA 將被禁用。
-
Repeated Single Transfer:這種模式下,每次傳輸都需要一個觸發信號,但在所有傳輸完成後,DMA 仍然保持啟用狀態。
-
Repeated Block Transfer:這種模式下,一個觸發信號就能傳輸完整的數據塊,數據塊的大小由 "Transfer Size" 決定。和 "Repeated Single Transfer" 一樣,所有傳輸完成後,DMA 仍然保持啟用狀態。
選擇哪種傳輸模式取決於你的具體需求。例如,如果你需要連續傳輸大量數據,可以選擇 "Block Transfer" 或 "Repeated Block Transfer" 模式;如果你需要精細地控制每次的數據傳輸,可以選擇 "Single Transfer" 或 "Repeated Single Transfer" 模式。
點擊 FILE-save, 然後到 keil 中編譯,導入配置
main 相關代碼#
#define ADCSize 128
typedef enum ADCFlag
{
ADCFlagDmaStart = 0,
ADCFlagDmaDone,
ADCFlagConversionDone,
ADCFlagConversionStart
}ADCFlag;
unsigned short ADCResult[ADCSize];//定義ADC接收緩衝區
ADCFlag adcflag;//定義枚舉變量adcflag
void UART1SendString(char *str)
{
while(*str != '\0')
{
DL_UART_transmitDataBlocking(UART1_INST, *str);
str++;
}
}
void UART1SendChar(char c)
{
DL_UART_transmitDataBlocking(UART1_INST, c);
}
void strreverse(char* begin, char* end) {
char aux;
while(end>begin)
aux=*end, *end--=*begin, *begin++=aux;
}
/**
* @brief 將整數值轉換為指定基數的空終止字符串,並將結果存儲在由str參數給出的數組中。
*
* @param value: 要轉換為字符串的值。
* @param str: 用於存儲結果的空終止字符串的數組。該數組應足夠長,以容納結果字符串(包括空字符)。
* @param base: 要轉換的數字的基數。它必須在[2, 36]範圍內。對於大於10的基數,此函數使用小寫字母。
*
* @note 如果基數為10且value為負,則結果字符串前會帶有負號(-)。對於任何其他基數,value始終被視為無符號。
*
* @note 如果基數不在[2, 36]範圍內,函數將不執行任何操作,str將是一個空字符串。
*
* @note 該函數不處理"unsigned long"數字 - 它將把它們視為"long"。因此,對於大於2147483647的值,該函數不適用於大於10的基數。
*
* @return 無。
*/
void itoa(int value, char* str, int base) {
static char num[] = "0123456789abcdefghijklmnopqrstuvwxyz";
char* wstr = str;
int sign;
// Validate base
if (base < 2 || base > 35) { *wstr = '\0'; return; }
// Take care of sign
if ((sign=value) < 0) value = -value;
// Conversion. Number is reversed.
do *wstr++ = num[value%base]; while(value/=base);
if(sign<0) *wstr++='-';
*wstr='\0';
// Reverse string
strreverse(str,wstr-1);
}
/**
* @brief 處理ADC結果的函數
*
* @param adcflag: 指向ADC標誌的指針,當ADC完成數據轉換後,該標誌會被設置為ADCFlagDmaDone
* @param ADCResult: 指向存儲ADC結果的數組的指針
* @param resultSize: ADC結果數組的大小
*
* @note 當adcflag指向的值為ADCFlagDmaDone時,函數會停止定時器和ADC的數據轉換,然後遍歷ADCResult數組,
* 並使用itoa函數將每個結果轉換為字符串,然後通過UART發送出去。在發送完所有的結果後,函數會將adcflag指向的值設置為ADCFlagConversionStart,
* 表示ADC可以開始新一輪的數據轉換。注意,在發送字符串時,每個結果後面都會發送一個換行符,以便接收端能夠正確地識別每個結果的邊界。
*
* @return 無。
*/
void processADCResults(ADCFlag* adcflag, unsigned short* ADCResult, int resultSize)
{
if (*adcflag == ADCFlagDmaDone)
{
DL_Timer_stopCounter(TIMER_0_INST);
DL_ADC12_stopConversion(ADC12_0_INST);
volatile int i;
for ( i = 0; i < resultSize; i++)
{
char buffer[12]; // Buffer for integer to string conversion, max size for int32 is 11 characters + null terminator
itoa(ADCResult[i], buffer, 10);
UART1SendString(buffer);
UART1SendString("\r\n");
}
*adcflag = ADCFlagConversionStart;
i = 0;
}
}
void setupDMA(DMA_Regs *dma, uint8_t channelNum, unsigned int srcAddr, unsigned int destAddr, unsigned int transferSize)
{
DL_DMA_setSrcAddr(dma, channelNum, (unsigned int) srcAddr);
DL_DMA_setDestAddr(dma, channelNum, (unsigned int) destAddr);
DL_DMA_setTransferSize(dma, channelNum, transferSize);
DL_DMA_enableChannel(dma, channelNum);
}
int main(void)
{
SYSCFG_DL_init();
NVIC_EnableIRQ(UART1_INT_IRQn);
NVIC_EnableIRQ(ADC0_INT_IRQn);
adcflag = ADCFlagConversionStart;
setupDMA(DMA,DMA_CH0_CHAN_ID,(unsigned int) & (ADC0->ULLMEM.MEMRES[0]),(unsigned int) &ADCResult,ADCSize);
if(adcflag == ADCFlagConversionStart)
{
DL_Timer_startCounter(TIMER_0_INST);
DL_ADC12_startConversion(ADC12_0_INST);
}
while (1)
{
processADCResults(&adcflag, ADCResult, ADCSize);
}
}
實際演示#
因為我每次只采 128 個點,並且不是連續采樣,所以每次重新 RST,采樣的信號肯定不和上次連續,就會出現下面這種尖點,從一次連續信號的角度來看,效果還不錯
转载请標明出处
by <a href=https://www.cnblogs.com/jiongsheng > QDU_jiongsheng