//
// 定序器將被其中一個通用定時器觸發
//
ADCSoftwareOversampleConfigure(ADC_BASE, 0, 8);
ADCSoftwareOversampleStepConfigure(ADC_BASE, 0, 0, (ADC_CTL_CH1
| ADC_CTL_IE | ADC_CTL_END));
//
// 初始化定時器0,每隔10ms觸發一次ADC轉換
//
TimerConfigure(TIMER0_BASE, TIMER_CFG_32_BIT_PER);
TimerLoadSet(TIMER0_BASE, TIMER_A, SysCtlClockGet() / 100);
TimerControlTrigger(TIMER0_BASE, TIMER_A, true);
代碼段1.b ADC中斷處理程序
void
ADCIntHandler(void)
{
long lStatus;
//
// 清除ADC中斷
//
ADCIntClear(ADC_BASE, 0);
//
// 獲得ADC的平均數據
//
lStatus = ADCSoftwareOversampleDataGet(ADC_BASE, 0, g_ulAverage);
//
// 佔位符,供ADC處理數據
//
}
在將配置步驟和中斷處理程序放在適當位置後,啟動轉換處理。定時器打開(開始計數)之前,ADC定序器和中斷必須使能(見代碼段1.c)。
代碼段1.c 使能ADC和中斷
//
// 使能ADC定序器0及其中斷 (在ADC和NVIC中)
//
ADCSequenceEnable(ADC_BASE, 0);
ADCIntEnable(ADC_BASE, 0);
IntEnable(INT_ADC0);
//
//使能定時器並啟動轉換處理
//
TimerEnable(TIMER0_BASE, TIMER_A);
使用多個定序器或一個定時器實現大於8倍的過採樣
驅動庫的過採樣函數最大只能進行8倍過採樣(根據採樣定序器的硬體限制),因此需要更大過採樣因子的應用必須使用其它的實現。本小節將描述如何使用下面的兩種方法:在過採樣頻率下運行的多個採樣定序器和一個定時器來解決這個問題。
例2:使用多個採樣定序器的16x過採樣
採樣定序器的靈活性允許對其進行多種配置。將採樣定序器0-2累積起來可獲得16個採樣(8+4+4),因此使用採樣定序器0-2可實現16倍過採樣。為使該級別的過採樣能夠工作,定序器中的所有階段必須設置為對相同的模擬輸入進行採樣,這意味著丟棄了使用一個定序器採樣多個輸入的功能。
代碼段2.a使用定序器0-2配置一個10ms的周期轉換。使用一個定時器觸發就可啟動所有3個定序器的採樣操作,而無需複雜的觸發配置。為獲得所需的結果,要對採樣定序器的優先級進行配置,這樣,採樣定序器2的優先級最低(即它最後採樣),並且在採樣定序器2的最後一步之後,配置為發出一個「轉換結束」中斷。
代碼段2.a ADC配置-多個採樣定序器
//
// 初始化ADC,以便使用定序器0-2對通道1進行16x過採樣
// 轉換操作通過GPTM觸發
//
ADCSequenceConfigure(ADC_BASE, 0, ADC_TRIGGER_TIMER, 0);
ADCSequenceConfigure(ADC_BASE, 1, ADC_TRIGGER_TIMER, 1);
ADCSequenceConfigure(ADC_BASE, 2, ADC_TRIGGER_TIMER, 2);
//
// 配置定序器0的序列步驟(sequence step)
//
ADCSequenceStepConfigure(ADC_BASE, 0, 0, ADC_CTL_CH1);
ADCSequenceStepConfigure(ADC_BASE, 0, 1, ADC_CTL_CH1);
ADCSequenceStepConfigure(ADC_BASE, 0, 2, ADC_CTL_CH1);
ADCSequenceStepConfigure(ADC_BASE, 0, 3, ADC_CTL_CH1);
ADCSequenceStepConfigure(ADC_BASE, 0, 4, ADC_CTL_CH1);
ADCSequenceStepConfigure(ADC_BASE, 0, 5, ADC_CTL_CH1);
ADCSequenceStepConfigure(ADC_BASE, 0, 6, ADC_CTL_CH1);
ADCSequenceStepConfigure(ADC_BASE, 0, 7, (ADC_CTL_CH1 | ADC_CTL_END));
//
//配置定序器1的序列步驟
//
ADCSequenceStepConfigure(ADC_BASE, 1, 0, ADC_CTL_CH1);
ADCSequenceStepConfigure(ADC_BASE, 1, 1, ADC_CTL_CH1);
ADCSequenceStepConfigure(ADC_BASE, 1, 2, ADC_CTL_CH1);
ADCSequenceStepConfigure(ADC_BASE, 1, 3, (ADC_CTL_CH1 | ADC_CTL_END));
//
//配置定序器2的序列步驟
//
ADCSequenceStepConfigure(ADC_BASE, 2, 0, ADC_CTL_CH1);
ADCSequenceStepConfigure(ADC_BASE, 2, 1, ADC_CTL_CH1);
ADCSequenceStepConfigure(ADC_BASE, 2, 2, ADC_CTL_CH1);
ADCSequenceStepConfigure(ADC_BASE, 2, 3, (ADC_CTL_CH1 | ADC_CTL_IE
| ADC_CTL_END));
//
// 初始化定時器0,每隔10ms觸發一次ADC轉換
//
TimerConfigure(TIMER0_BASE, TIMER_CFG_32_BIT_PER);
TimerLoadSet(TIMER0_BASE, TIMER_A, SysCtlClockGet() / 100);
TimerControlTrigger(TIMER0_BASE, TIMER_A, true);
在代碼段2.b中,中斷處理程序必須收集FIFO的數據並進行平均計算。因為不需要處理函數開銷就可以獲得所需的結果,所以不使用ADCSequenceDataGet函數,並且使用直接的寄存器讀操作來清空定序器的FIFO。而使用ADCSequenceDataGet時,要求函數定義一個額外的8入口採樣緩衝區,即使使用直接的寄存器讀操作,中斷處理程序中執行的總和計算和平均計算仍然會有可計算的開銷。
代碼段2.b ADC中斷處理程序
void
ADCIntHandler(void)
{
unsigned long ulIdx;
unsigned long ulSum = 0;
//
// 清除中斷
//
ADCIntClear(ADC_BASE, 2);
//
// 獲得來自定序器0的數據
//
for(ulIdx = 8; ulIdx; ulIdx--)
{
ulSum += HWREG(ADC_BASE + ADC_O_SSFIFO0);
}
//
// 獲得來自定序器1和2的數據
//
for(ulIdx = 4; ulIdx; ulIdx--)
{
ulSum += HWREG(ADC_BASE + ADC_O_SSFIFO1);
ulSum += HWREG(ADC_BASE + ADC_O_SSFIFO2);
}
//
// 將過採樣的數據進行平均
//
g_ulAverage = ulSum >> 4;
//
// 佔位符,以便ADC處理代碼
//
}
在啟動轉換處理之前,將採樣定序器和中斷使能(見代碼段2.c)。
代碼段2.c 使能ADC和中斷
//
// 使能定序器和中斷
//
ADCSequenceEnable(ADC_BASE, 0);
ADCSequenceEnable(ADC_BASE, 1);
ADCSequenceEnable(ADC_BASE, 2);
ADCIntEnable(ADC_BASE, 2);
IntEnable(INT_ADC2);
//
// 使能定時器並啟動轉換處理
//
TimerEnable(TIMER0_BASE, TIMER_A);
例3 使用在fOS下運行的定時器進行16x過採樣
另一個實現16x過採樣的方法(無需消耗ADC定序器的大部分資源)是使用一個在過採樣頻率下運行的周期定時器。例如,如果轉換處理每10ms必須返回到主應用程式並且即將進行16倍過採樣,則能夠將定時器配置為每625µs獲得一個採樣值。讓定時器在過採樣頻率下觸發一次轉換明顯地產生了額外的ADC中斷,這必須在應用程式中說明。
將ADC和定時器配置為執行上述操作的代碼見代碼段3.a。
代碼段3.a ADC配置-在fOS下運行的定時器
//
// 初始化ADC,以便在檢測到一次觸發時在通道1、定序器3上獲得一個採樣值。
//
//
ADCSequenceConfigure(ADC_BASE, 3, ADC_TRIGGER_TIMER, 0);
ADCSequenceStepConfigure(ADC_BASE, 3, 0, (ADC_CTL_CH1 | ADC_CTL_IE
| ADC_CTL_END));
//
//初始化定時器0,每625µs觸發一次ADC轉換
//
TimerConfigure(TIMER0_BASE, TIMER_CFG_32_BIT_PER);
TimerLoadSet(TIMER0_BASE, TIMER_A, SysCtlClockGet() / 1600);
TimerControlTrigger(TIMER0_BASE, TIMER_A, true);
既然ADC在過採樣頻率下進行採樣操作,中斷處理程序必須知道已獲得的採樣數以及總和(見代碼段3.b)。在累積了16次轉換後,將這16個採樣值進行平均,並清除全局採樣計數變量和總和變量。
代碼段3.b ADC中斷處理程序
void
ADCIntHandler(void)
{
//
// 清除中斷
//
ADCIntClear(ADC_BASE, 3);
//
// 將新的採樣值加到全局總和中
//
g_ulSum += HWREG(ADC_BASE + ADC_O_SSFIFO3);
//
// g_ucOversampleCnt加1
//
g_ucOversampleCnt++;
//
// 如果累積了16個採樣值,則將它們平均並將全局變量復位
//
if(g_ucOversampleCnt == 16)
{
g_ulAverage = g_ulSum >> 4;
g_ucOversampleCnt = 0;
g_ulSum = 0;
}
//
// 佔位符,以便ADC處理代碼
//
}
最後,在使能定時器之前,將定序器3及其中斷使能,並清除全局計數器和總和變量(見代碼段3.c)。
代碼段3.c 使能ADC、中斷並清除全局變量
//
// 使能定序器和中斷
//
ADCSequenceEnable(ADC_BASE, 3);
ADCIntEnable(ADC_BASE, 3);
IntEnable(INT_ADC3);
//
// 將過採樣計數器和總和變量清零
//
g_ucOversampleCnt = 0;
g_ulSum = 0;
//
// 使能定時器並啟動轉換處理
//
TimerEnable(TIMER0_BASE, TIMER_A);
使用滑動平均進行過採樣
當採樣頻率接近ADC的最大採樣率時,滑動平均非常有用。滑動平均應用中的主要元件是採樣緩衝區,它在每次轉換完成時減去/加上數據。
例4將ADC配置為每隔100µs進行一次採樣,採樣緩衝區含有16個入口。注意:應用程式不向採樣緩衝區預先填充有效的數據,這樣,前16個採樣值必須相應地由軟體來處理。ADC配置為在定時器觸發時採樣,並在每次轉換之後將處理器中斷。
例4 使用滑動平均每100µs過採樣
代碼段4.a ADC配置-滑動平均
//
// 初始化ADC,以便在檢測到觸發時在通道1、定時器3上獲得一個採樣值。
//
//
ADCSequenceConfigure(ADC_BASE, 3, ADC_TRIGGER_TIMER, 0);
ADCSequenceStepConfigure(ADC_BASE, 3, 0, (ADC_CTL_CH1 | ADC_CTL_IE
| ADC_CTL_END));
//
// 初始化定時器0,每100µs觸發一次ADC轉換
//
TimerConfigure(TIMER0_BASE, TIMER_CFG_32_BIT_PER);
TimerLoadSet(TIMER0_BASE, TIMER_A, SysCtlClockGet() / 10000);
TimerControlTrigger(TIMER0_BASE, TIMER_A, true);
中斷處理程序必須更新採樣緩衝區並進行平均計算(見代碼段4.b)。在每次ADC中斷時,去掉採樣緩衝區中的最後一個元素,緩衝區中剩下的數據移動一個位置。然後,在計算平均值之前將新的轉換結果放在採樣緩衝區的開始處。中斷處理程序中執行的額外計算又一次增加了開銷,這一點必須要考慮到。
代碼段4.b ADC中斷處理程序
void
ADCIntHandler(void)
{
//
// 清除中斷
//
ADCIntClear(ADC_BASE, 3);
//
// 檢查g_ucOversampleIdx,確保它的值在範圍內
//
if(g_ucOversampleIdx == 16)
{
g_ucOversampleIdx = 0;
}
//
// 從全局總和中減去最早的值
//
g_ulSum -= g_ulSampleBuffer[g_ucOversampleIdx];
//
// 用新的採樣值代替最早的值
//
g_ulSampleBuffer[g_ucOversampleIdx] = HWREG(ADC_BASE + ADC_O_SSFIFO3);
//
// 將新的採樣值加到總和中
//
g_ulSum += g_ulSampleBuffer[g_ucOversampleIdx];
//
// g_ucOversampleIdx加1
//
g_ucOversampleIdx++;
//
// 從採樣緩衝區的數據中獲得平均值
//
g_ulAverage = g_ulSum >> 4;
//
// 佔位符,供ADC處理代碼
//
}
在啟動定時器之前,使能定時器及其中斷(見代碼段4.c)。
代碼段4.c 使能ADC和中斷
//
// 使能定序器和中斷
//
ADCSequenceEnable(ADC_BASE, 3);
ADCIntEnable(ADC_BASE, 3);
IntEnable(INT_ADC3);
//
// 使能定時器並啟動轉換處理
//
TimerEnable(TIMER0_BASE, TIMER_A);
需考慮的問題
結論