CCS5.4+Proteus8的F28027實踐課七、ADC
吃完飯回來了,現在開始我們的ADC實踐操作。
直奔主題我們,那就是ADC程式設計操作流程是怎麼樣的。
其實通過上節理論課的學習,大家心裡都應該有了模糊的感覺,一般的步驟如下:
1、使能ADC模組時鐘( PCLKCR0.ADCENCLK =1)
2、啟動類比電路、帶隙和參考源,ADCCTL1暫存器(ADCPWDN, ADCBGPWD, ADCREFPWD位=1)
3、使能ADC模組(ADCCTL1.ADCENABLE=1)
4、ADC中斷相關設定(參考PIE)
5、模擬IO引腳複用設定(AIOMUX1)
6、SOC配置(觸發、通道、取樣視窗)
7、編寫中斷ISR(讀取ADC結果)
瞭解了操作步驟,那我們就要了解相關的暫存器,由於暫存器又比較多,我這裡就不一一講述,大家直接去看手冊就行了
瞭解了暫存器,下面就要看下具體的操作時序圖了:
順序取樣的遲中斷
順序取樣的早中斷
同步取樣的遲中斷
同步取樣的早中斷
好了,時序圖也看完了,我們現在來參考時序圖寫程式了。
我們先來個簡單的,順序取樣的遲中斷。
既然是ADC,那我們這節課肯定用到了TI提供的F2802x_Adc.c檔案,另外,還要顯示,也需要把我們上節課整理的F2802x_LCD12864.c檔案。
首先我們一起來看下ADC初始化函式InitAdc()
void InitAdc(void)
{
extern void DSP28x_usDelay(Uint32 Count);
// *IMPORTANT*
// The Device_cal function, which copies the ADC calibration values from TI reserved
// OTP into the ADCREFSEL and ADCOFFTRIM registers, occurs automatically in the
// Boot ROM. If the boot ROM code is bypassed during the debug process, the
// following function MUST be called for the ADC to function according
// to specification. The clocks to the ADC MUST be enabled before calling this
// function.
// See the device data manual and/or the ADC Reference
// Manual for more information.
EALLOW;
SysCtrlRegs.PCLKCR0.bit.ADCENCLK = 1;
(*Device_cal)();
EDIS;
// To powerup the ADC the ADCENCLK bit should be set first to enable
// clocks, followed by powering up the bandgap, reference circuitry, and ADC core.
// Before the first conversion is performed a 5ms delay must be observed
// after power up to give all analog circuits time to power up and settle
// Please note that for the delay function below to operate correctly the
// CPU_RATE define statement in the DSP2802x_Examples.h file must
// contain the correct CPU clock period in nanoseconds.
EALLOW;
AdcRegs.ADCCTL1.bit.ADCBGPWD = 1; // Power ADC BG
AdcRegs.ADCCTL1.bit.ADCREFPWD = 1; // Power reference
AdcRegs.ADCCTL1.bit.ADCPWDN = 1; // Power ADC
AdcRegs.ADCCTL1.bit.ADCENABLE = 1; // Enable ADC
AdcRegs.ADCCTL1.bit.ADCREFSEL = 0; // Select interal BG
EDIS;
DELAY_US(ADC_usDELAY); // Delay before converting ADC channels
}
初始化函式已經把我們的前三步都做完了,也就是使能時鐘、上電、使能ADC模組;
那我們現在來進行SOC相關設定,也就是:觸發源、取樣時隙、通道選擇。
觸發源我們選擇定時器0,因為我們做測試肯定輸入一個穩定的直流電壓,那用定時器最方便。
AdcRegs.ADCSOC0CTL.bit.TRIGSEL = 1;
取樣時隙就用最短時隙,也就是AdcRegs.ADCSOC0CTL.bit.ACQPS = 6;
由於TI那個實驗板只引出了幾個ADC引腳而已,我們就用ADCINA1,也就是AdcRegs.ADCSOC0CTL.bit.CHSEL = 1;
另外,我們說了,我們本次的實驗是順序取樣,遲中斷,那就是:
AdcRegs.ADCSAMPLEMODE.bit.SIMULEN0 = 1;
AdcRegs.ADCCTL1.bit.INTPULSEPOS = 1;
到這裡SOC相關設定就完成了,我們現在開始要對PIE中斷就行相應的設定了。
我們這裡採用簡單的中斷1,EOC脈衝觸發ADCINTx脈衝
AdcRegs.INTSEL1N2.bit.INT1SEL = 0;
AdcRegs.INTSEL1N2.bit.INT1CONT = 1;
AdcRegs.INTSEL1N2.bit.INT1E = 1;
最後還要再PIE組裡面開啟ADCINT1開關:PieCtrlRegs.PIEIER1.bit.INTx1 = 1;
ADC中斷函式就一個置位:
interrupt void ADCINT1_ISR(void) // ADC (Can also be ISR for INT10.1 when enabled)
{
// Insert ISR Code here
// To receive more interrupts from this PIE group, acknowledge this interrupt
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
// Next two lines for debug only to halt the processor here
// Remove after inserting ISR Code
//asm (" ESTOP0");
//for(;;);
}
ADC中斷也說完了,還有定時器設定,這個就參考我們前面寫的那個程式,一模一樣,也就是說取樣時隙是1ms
首先是CPU.c檔案
void InitCpuTimers(void)
{
// CPU Timer 0
// Initialize address pointers to respective timer registers:
CpuTimer0.RegsAddr = &CpuTimer0Regs;
// Initialize timer period to maximum:
CpuTimer0Regs.PRD.all = 1000;
// Initialize pre-scale counter to divide by 1 (SYSCLKOUT):
CpuTimer0Regs.TPR.bit.TDDR = 59;
CpuTimer0Regs.TPRH.bit.TDDRH = 0;
// Make sure timer is stopped:
CpuTimer0Regs.TCR.bit.TSS = 1;
// Reload all counter register with period value:
CpuTimer0Regs.TCR.bit.TRB = 1;
// Reset interrupt counters:
CpuTimer0.InterruptCount = 0;
// CpuTimer 1 and CpuTimer2 are reserved for DSP BIOS & other RTOS
// Do not use these two timers if you ever plan on integrating
// DSP-BIOS or another realtime OS.
//
// Initialize address pointers to respective timer registers:
CpuTimer1.RegsAddr = &CpuTimer1Regs;
CpuTimer2.RegsAddr = &CpuTimer2Regs;
// Initialize timer period to maximum:
CpuTimer1Regs.PRD.all = 0xFFFFFFFF;
CpuTimer2Regs.PRD.all = 0xFFFFFFFF;
// Initialize pre-scale counter to divide by 1 (SYSCLKOUT):
CpuTimer1Regs.TPR.all = 0;
CpuTimer1Regs.TPRH.all = 0;
CpuTimer2Regs.TPR.all = 0;
CpuTimer2Regs.TPRH.all = 0;
// Make sure timers are stopped:
CpuTimer1Regs.TCR.bit.TSS = 1;
CpuTimer2Regs.TCR.bit.TSS = 1;
// Reload all counter register with period value:
CpuTimer1Regs.TCR.bit.TRB = 1;
CpuTimer2Regs.TCR.bit.TRB = 1;
// Reset interrupt counters:
CpuTimer1.InterruptCount = 0;
CpuTimer2.InterruptCount = 0;
}
然後是定時中斷函式
interrupt void TINT0_ISR(void) // CPU-Timer 0
{
// Insert ISR Code here
// To receive more interrupts from this PIE group, acknowledge this interrupt
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
// Next two lines for debug only to halt the processor here
// Remove after inserting ISR Code
// asm (" ESTOP0");
// for(;;);
}
最後是相關中斷設定
CpuTimer0Regs.TCR.bit.TIE = 1;
StartCpuTimer0();
EALLOW;
PieCtrlRegs.PIEIER1.bit.INTx7 = 1;
PieCtrlRegs.PIECTRL.bit.ENPIE = 1;
IER |= 0x0001;
EINT;
EDIS;
現在定時中斷也寫完了,就剩下ADC處理顯示函數了
while(1)
{
if(AdcRegs.ADCSOCFLG1.bit.SOC0==1)
{
while(AdcRegs.ADCSOCFLG1.bit.SOC0==1);
AdcRegs.ADCINTFLGCLR.bit.ADCINT1 = 1;
DELAY_US(10);
sum+=AdcResult.ADCRESULT0;
i++;
}
if(i==100)
{
sum/=100;
vol=sum*3.3/4095;
WRITECMD_LCD12864(0x01);
DISLPLAY_LONGSTRING(2,0,sum);
DISLPLAY_FLOATSTRING(3,0,vol);
WRITEDATA_LCD12864('v');
sum=0;
i=0;
}
}
我是直接寫在while死迴圈裡面的,然後去捕捉轉換標誌位,取樣100次,取平均值。
下載程式驗證,成功,呵呵,上大家上效果圖
突然想到一個剛才除錯的問題,就是提示我.text段超出空間,我把段大小相應調整了下
.text : > PRAML0, PAGE = 0
PRAML0 : origin = 0x008000, length = 0x000c00
DRAML0 : origin = 0x008c00, length = 0x000400
具體的程式碼我會傳到下載庫和QQ群裡面,大家有需要的話自行下載
菜鳥交流qq群107691092