AVR单片机之ATXMEGA系列的ADC研究
AVR单片机之ATXMEGA系列的ADC研究本文中的源代码采用CodeVision3.12编辑编译。采用的MCU 型号是Atxmega128A3U。实际使用测试运行正常。1、关于ADCA和ADCB的输入引脚问题输入引脚用于单端和差动输入,内部输入直接内部连接设备。如果设备含有两个ADC,端口A引脚用于ADCA的ADC0-ADC7,也可用于ADCB的ADC8-ADC15,端口B的引脚用于ADCB的ADC0-ADC7,也可用于ADCA的ADC8-ADC15。所有输入引脚可作为同相输入,输入引脚ADC0-ADC3可作为不带增益时的反相输入,输入引脚ADC4-ADC7可作为带增益时的反相输入。注意:ADCA和ADCB的输入引脚ADC0-ADC15的定义位置是不同的。当使用差动输入时,ADC必须设置位signed模式(有符号模式)。难怪ADCB没有结果。原来不能用。Table 33-1. Port A - alternate functions.PORTAPIN #INTERRUPTADCAPOS/GAINPOSADCB POSADCA NEGADCAGAINNEGACAPOS ACANEG ACAOUTDACAREFA
GND93
AVCC94
PA095SYNCADC0ADC8ADC0 AC0AC0 AREF
PA196SYNCADC1ADC9ADC1 AC1AC1
PA297SYNC/ASYNCADC2ADC10ADC2 AC2 DAC0
PA398SYNCADC3ADC11ADC3 AC3AC3 DAC1
PA499SYNCADC4ADC12 ADC4AC4
PA5100SYNCADC5ADC13 ADC5AC5AC5
PA61SYNCADC6ADC14 ADC6AC6 AC1OUT
PA72SYNCADC7ADC15 ADC7 AC7AC0OUT
Table 33-2. Port B - alternate functions.
PORTBPIN#INTERRUPTADCAPOSADCBPOS/GAINPOSADCBNEGADCBGAIN NEGACBPOSACBNEGACBOUT REFBJTAG
GND3
AVCC4
PB05SYNCADC8ADC0ADC0 AC0AC0 AREF
PB16SYNCADC9ADC1ADC1 AC1AC1
PB27SYNC/ASYNCADC10ADC2ADC2 AC2 DAC0
PB38SYNCADC11ADC3ADC3 AC3AC3 DAC1
PB49SYNCADC12ADC4 ADC4AC4 TMS
PB510SYNCADC13ADC5 ADC5AC5AC5 TDI
PB611SYNCADC14ADC6 ADC6AC6 AC1OUT TCK
PB712SYNCADC15ADC7 ADC7 AC7AC0OUT TDO
2、ADC转换的触发方式方法ADC转换如果采用自由运行模式free-running, 通道sweep,并且每个通道转换完成产生中断,在中断处理程序中处理转换结果。那么中断次数会非常多,严重影响程序正常运行。经过分析后,决定采用软件启动ADC转换,启动指令的发出由TCF0定时器溢出中断程序发出,TCF0溢出频率400Hz,每中断一次启动一次一个ADC通道的转换,8次中断完成ADCA四个通道和ADCB四个通道的启动。这个中断程序只负责启动ADC转换。void tcf0_init(void){unsigned char s; // Note: The correct PORTF direction for the Compare Channels// outputs is configured in the ports_init function. // Save interrupts enabled/disabled states=SREG;// Disable interrupts#asm("cli") // Disable and reset the timer/counter just to be suretc0_disable(&TCF0);// Clock source: ClkPer/2TCF0.CTRLA=TC_CLKSEL_DIV2_gc; //设置定时器时钟16MHz// Mode: Normal Operation, Overflow Int./Event on TOP// Compare/Capture on channel A: Off// Compare/Capture on channel B: Off// Compare/Capture on channel C: Off// Compare/Capture on channel D: OffTCF0.CTRLB=(0<<TC0_CCDEN_bp) | (0<<TC0_CCCEN_bp) | (0<<TC0_CCBEN_bp) | (0<<TC0_CCAEN_bp) | TC_WGMODE_NORMAL_gc;// Capture event source: None// Capture event action: NoneTCF0.CTRLD=TC_EVACT_OFF_gc | TC_EVSEL_OFF_gc; // Set Timer/Counter in Normal modeTCF0.CTRLE=TC_BYTEM_NORMAL_gc; // Overflow interrupt: Low Level// Error interrupt: DisabledTCF0.INTCTRLA=TC_ERRINTLVL_OFF_gc | TC_OVFINTLVL_LO_gc; // Compare/Capture channel A interrupt: Disabled// Compare/Capture channel B interrupt: Disabled// Compare/Capture channel C interrupt: Disabled// Compare/Capture channel D interrupt: DisabledTCF0.INTCTRLB=TC_CCDINTLVL_OFF_gc | TC_CCCINTLVL_OFF_gc | TC_CCBINTLVL_OFF_gc | TC_CCAINTLVL_OFF_gc; // High resolution extension: OffHIRESF.CTRLA&= ~HIRES_HREN0_bm; // Clear the interrupt flagsTCF0.INTFLAGS=TCF0.INTFLAGS;// Set Counter registerTCF0.CNT=0x0000;// Set Period registerTCF0.PER=0x9C3F; //设置定时器周期2.5ms// Set channel A Compare/Capture registerTCF0.CCA=0x0000;// Set channel B Compare/Capture registerTCF0.CCB=0x0000;// Set channel C Compare/Capture registerTCF0.CCC=0x0000;// Set channel D Compare/Capture registerTCF0.CCD=0x0000; // Restore interrupts enabled/disabled stateSREG=s;} // Timer/Counter TCF0 Overflow/Underflow interrupt service routineinterrupt void tcf0_overflow_isr(void){// Write your code here static int flag; if(flag<7)flag++; else flag=0; switch(flag) { case 0: // Start the AD conversion on channel 0 ADCA.CH0.CTRL|= 1<<ADC_CH_START_bp;//启动ADCA的通道0 break; case 1: ADCA.CH1.CTRL|= 1<<ADC_CH_START_bp; //启动ADCA的通道1 break; case 2: ADCA.CH2.CTRL|= 1<<ADC_CH_START_bp; //启动ADCA的通道2 break; case 3: ADCA.CH3.CTRL|= 1<<ADC_CH_START_bp; //启动ADCA的通道3 break; case 4: ADCB.CH0.CTRL|= 1<<ADC_CH_START_bp; //启动ADCB的通道0 break; case 5: ADCB.CH1.CTRL|= 1<<ADC_CH_START_bp; //启动ADCB的通道1 break; case 6: ADCB.CH2.CTRL|= 1<<ADC_CH_START_bp; //启动ADCB的通道2 break; case 7: ADCB.CH3.CTRL|= 1<<ADC_CH_START_bp; //启动ADCB的通道3 break; default: break; }}3、ADC转换结果通过DMA方式直接写入内存由DMA由四个独立的通道,这里只用两个通道:通道0和通道1。DMA通道0由ADCA的通道3转换完成事件触发,DMA通道1由ADCB的通道3转换完成触发。DMA的程序如下:void dma_init(void){ DMA_CTRL =DMA_ENABLE_bm;//使能DMA控制系统 0x80; //ENABLE |RESET | –| -|DBUFMODE | PRIMODE DMA_CTRL |=DMA_DBUFMODE_DISABLED_gc|DMA_PRIMODE_RR0123_gc;//禁用双缓冲,Round Robin 循环轮询模式 DMA_CH0_ADDRCTRL=DMA_CH_SRCRELOAD_BURST_gc|DMA_CH_SRCDIR_INC_gc|DMA_CH_DESTRELOAD_BLOCK_gc|DMA_CH_DESTDIR_INC_gc;//0x95;//源地址每次Burst transfer之后加一重载,目的地址每次Block transfer之后加一重载 DMA_CH0_TRIGSRC=0x13; //0x10 ADCA ADCA DMA triggers base value +0x00 CH0 ADC/DAC channel 0 // +0x01 CH1 ADC/DAC channel 1 // +0x02 CH2(1) ADC channel 2 // +0x03 CH3 ADC channel 3 // +0x04 CH4(2) ADC channel 0, 1, 2, 3 DMA_CH0_TRFCNT=320; //int adca_result; 共320个字节 DMA_CH0_REPCNT=0x00; DMA_CH0_SRCADDR0=0x10; //#define ADCA_CH0_RES_SFR_MEM16(0x0224) // #define ADCA_CH0RES_SFR_MEM16(0x0210) // #define ADCA_CH1RES_SFR_MEM16(0x0212) // #define ADCA_CH2RES_SFR_MEM16(0x0214) // #define ADCA_CH3RES_SFR_MEM16(0x0216) DMA_CH0_SRCADDR1=0x02; DMA_CH0_SRCADDR2=0x00; DMA_CH0_DESTADDR0=((unsigned int)adca_result)&0xff; DMA_CH0_DESTADDR1=((unsigned int)adca_result>>8)&0xff; DMA_CH0_DESTADDR2=((unsigned char)adca_result>>16)&0xff; DMA_CH0_CTRLA =DMA_CH_ENABLE_bm|DMA_CH_REPEAT_bm|DMA_CH_SINGLE_bm|DMA_CH_BURSTLEN_8BYTE_gc; // REPEAT| SINGLE| REPCNT| Trigger | Flag set after |Channel disabled after // 0 | 0| 0|Block | 1block |1 block // 0 | 0| 1| Block | 1 block | 1 block // 0 | 0| n > 1 | Block | 1 block | 1 block // 0 | 1| 0 |BURSTLEN | 1 block | 1 block // 0 | 1| 1 |BURSTLEN | 1 block | 1 block // 0 | 1| n > 1 |BURSTLEN | 1 block | 1 block // 1 | 0| 0 | Block | Each block | Each block // 1 | 0| 1 |Transaction| 1 block | 1 block // 1 | 0| n > 1 |Transaction| n blocks |n blocks // 1 | 1| 0 |BURSTLEN | Each block |Never *************** // 1 | 1| 1 |BURSTLEN | 1 block |1 block // 1 | 1| n > 1 |BURSTLEN | n blocks |n blocks //DMA通道1 DMA_CH1_ADDRCTRL=DMA_CH_SRCRELOAD_BURST_gc|DMA_CH_SRCDIR_INC_gc|DMA_CH_DESTRELOAD_BLOCK_gc|DMA_CH_DESTDIR_INC_gc;//0x95;//源地址每次Burst transfer之后加一重载,目的地址每次Block transfer之后加一重载 DMA_CH1_TRIGSRC=0x23; //0x20 ADCB ADCBDMA triggers base value +0x00 CH0 ADC/DAC channel 0 // +0x01 CH1 ADC/DAC channel 1 // +0x02 CH2(1) ADC channel 2 // +0x03 CH3 ADC channel 3 // +0x04 CH4(2) ADC channel 0, 1, 2, 3 DMA_CH1_TRFCNT=320; //int adcb_result; 共320个字节 DMA_CH1_REPCNT=0x00; DMA_CH1_SRCADDR0=0x50; //#define ADCB_CH0_RES_SFR_MEM16(0x0264) // #define ADCB_CH0RES_SFR_MEM16(0x0250) // #define ADCB_CH1RES_SFR_MEM16(0x0252) // #define ADCB_CH2RES_SFR_MEM16(0x0254) // #define ADCB_CH3RES_SFR_MEM16(0x0256) DMA_CH1_SRCADDR1=0x02; DMA_CH1_SRCADDR2=0x00; DMA_CH1_DESTADDR0=((unsigned int)adcb_result)&0xff; DMA_CH1_DESTADDR1=((unsigned int)adcb_result>>8)&0xff; DMA_CH1_DESTADDR2=((unsigned char)adcb_result>>16)&0xff; DMA_CH1_CTRLA =DMA_CH_ENABLE_bm|DMA_CH_REPEAT_bm|DMA_CH_SINGLE_bm|DMA_CH_BURSTLEN_8BYTE_gc; //通道2 //通道3// DMA_CH2_ADDRCTRL=DMA_CH_SRCRELOAD_BURST_gc|DMA_CH_SRCDIR_INC_gc|DMA_CH_DESTRELOAD_BLOCK_gc|DMA_CH_DESTDIR_INC_gc;//0x95;//源地址每次Burst transfer之后加一重载,目的地址每次Block transfer之后加一重载}4、主程序中的处理//**********************ADCA预处理*********************** for(i=0;i<4;i++){ adc_value_sum=0; for(j=0;j<40;j++) adc_value_sum +=adca_result; adc_value=adc_value_sum/40-adca_offset;//零点修正 adc_value *= COEFFICENT; } //**********************ADCB预处理*********************** for(i=4;i<8;i++){ adc_value_sum=0; for(j=0;j<40;j++) adc_value_sum +=adcb_result; adc_value=adc_value_sum/40-adcb_offset;//零点修正 adc_value *= COEFFICENT; }5、ADCA和ADCB的初始化程序//以上是老的ADCA初始化,下面要改成新的#pragma optsize_default// Variable used to store the ADC offset// for 12 Bit Signed conversion modesigned char adca_offset; // ADCA initializationvoid adca_init(void){unsigned char i;int offs;// ADCA is enabled// Resolution: 12 Bits// Load the calibration value for 12 Bit resolution// from the signature rowADCA.CALL=read_calibration_byte(PROD_SIGNATURES_START+ADCACAL0_offset);ADCA.CALH=read_calibration_byte(PROD_SIGNATURES_START+ADCACAL1_offset); // Gain stage impedance mode: High-impedance sources// Current consumption: No limit//// Conversion mode: Unsigned//ADCA.CTRLB=(0<<ADC_IMPMODE_bp) | ADC_CURRLIMIT_NO_gc | (0<<ADC_CONMODE_bp) | ADC_RESOLUTION_12BIT_gc;// Conversion mode: signedADCA.CTRLB=(0<<ADC_IMPMODE_bp) | ADC_CURRLIMIT_NO_gc | (1<<ADC_CONMODE_bp) | ADC_RESOLUTION_12BIT_gc;// Clock frequency: 62.500 kHz//ADCA.PRESCALER=ADC_PRESCALER_DIV512_gc;// Clock frequency: 125.000 kHzADCA.PRESCALER=ADC_PRESCALER_DIV256_gc; // Reference: Internal Vcc/1.6 ,用这个不准确// Temperature reference: OffADCA.REFCTRL=ADC_REFSEL_VCC_gc | (0<<ADC_TEMPREF_bp) | (0<<ADC_BANDGAP_bp);//参考电压选择内部1V精确电压源,使能带隙电压//ADCA.REFCTRL=ADC_REFSEL_INT1V_gc | (0<<ADC_TEMPREF_bp) | (1<<ADC_BANDGAP_bp);// Read and save the ADC offset using channel 0ADCA.CH0.CTRL=(0<<ADC_CH_START_bp) | ADC_CH_GAIN_1X_gc | ADC_CH_INPUTMODE_DIFF_gc;ADCA.CH0.MUXCTRL=ADC_CH_MUXPOS_PIN0_gc | ADC_CH_MUXNEG_PIN0_gc;// Enable the ADC in order to read the offsetADCA.CTRLA|=ADC_ENABLE_bm;//|ADC_DMASEL_gm;//ADCA四个通道都DMA 请求// Insert a delay to allow the ADC common mode voltage to stabilizedelay_us(2);// Perform several offset measurements and store the mean valueoffs=0;for (i=0; i<16; i++) { // Start the AD conversion on channel 0 ADCA.CH0.CTRL|= 1<<ADC_CH_START_bp; // Wait for the AD conversion to complete while ((ADCA.CH0.INTFLAGS & ADC_CH_CHIF_bm)==0); // Clear the interrupt flag ADCA.CH0.INTFLAGS=ADC_CH_CHIF_bm; // Read the offset offs+=(signed char) ADCA.CH0.RESL; }// Disable the ADCADCA.CTRLA&= ~ADC_ENABLE_bm;// Store the mean value of the offsetadca_offset=(signed char) (offs/16);//求出零点偏移量,后面实际ADC结果要减去这个量 // Initialize the ADC Compare registerADCA.CMPL=0x00;ADCA.CMPH=0x00; // ADC channel 0 gain: 1// ADC channel 0 input mode: Differential input signal//ADCA.CH0.CTRL=(0<<ADC_CH_START_bp) | ADC_CH_GAIN_1X_gc | ADC_CH_INPUTMODE_SINGLEENDED_gc;//差分输入,不带增益,输入2V,参考电压3.3/1.6V,ADCA.CH0.CTRL=(0<<ADC_CH_START_bp) | ADC_CH_GAIN_1X_gc | ADC_CH_INPUTMODE_DIFF_gc; // ADC channel 0 positive input: ADC0 pin// ADC channel 0 negative input: intGNDADCA.CH0.MUXCTRL=ADC_CH_MUXPOS_PIN0_gc|ADC_CH_MUXNEGL_GND_gc;//ADC_CH_MUXNEGH_GND_gc // ADC channel 1 gain: 1// ADC channel 1 input mode: Differential input signalADCA.CH1.CTRL=(0<<ADC_CH_START_bp) | ADC_CH_GAIN_1X_gc | ADC_CH_INPUTMODE_DIFF_gc; // ADC channel 1 gain: 1// ADC channel 1 input mode: Differential input signalADCA.CH1.MUXCTRL=ADC_CH_MUXPOS_PIN1_gc|ADC_CH_MUXNEGL_GND_gc; //// ADC channel 2 gain: 1// ADC channel 2 input mode: Differential input signalADCA.CH2.CTRL=(0<<ADC_CH_START_bp) | ADC_CH_GAIN_1X_gc | ADC_CH_INPUTMODE_DIFF_gc; // ADC channel 2 positive input: ADC2 pin// ADC channel 2 negative input: Internal groundADCA.CH2.MUXCTRL=ADC_CH_MUXPOS_PIN2_gc | ADC_CH_MUXNEGL_GND_gc; // ADC channel 3 gain: 1// ADC channel 3 input mode: Differential input signalADCA.CH3.CTRL=(0<<ADC_CH_START_bp) | ADC_CH_GAIN_1X_gc | ADC_CH_INPUTMODE_DIFF_gc; // ADC channel 3 positive input: ADC3 pin// ADC channel 3 negative input: Internal groundADCA.CH3.MUXCTRL=ADC_CH_MUXPOS_PIN3_gc | ADC_CH_MUXNEGL_GND_gc; // Channel 0 interrupt: OFF// Channel 0 interrupt mode: Conversion CompleteADCA.CH0.INTCTRL=ADC_CH_INTMODE_COMPLETE_gc | ADC_CH_INTLVL_OFF_gc;// Channel 1 interrupt: OFF// Channel 1 interrupt mode: Conversion CompleteADCA.CH1.INTCTRL=ADC_CH_INTMODE_COMPLETE_gc | ADC_CH_INTLVL_OFF_gc;// Channel 2 interrupt: OFF// Channel 2 interrupt mode: Conversion CompleteADCA.CH2.INTCTRL=ADC_CH_INTMODE_COMPLETE_gc | ADC_CH_INTLVL_OFF_gc;// Channel 3 interrupt: OFF// Channel 3 interrupt mode: Conversion CompleteADCA.CH3.INTCTRL=ADC_CH_INTMODE_COMPLETE_gc | ADC_CH_INTLVL_OFF_gc; // Free Running mode: On//ADCA.CTRLB|=ADC_FREERUN_bm; // Enable the ADCADCA.CTRLA|=ADC_ENABLE_bm;//|ADC_DMASEL_gm;// Insert a delay to allow the ADC common mode voltage to stabilizedelay_us(2);}//ADCB的初始化// Variable used to store the ADC offset// for 12 Bit Signed conversion modesigned char adcb_offset; void adcb_init(void){unsigned char i;int offs; // ADCB is enabled// Resolution: 12 Bits// Load the calibration value for 12 Bit resolution// from the signature rowADCB.CALL=read_calibration_byte(PROD_SIGNATURES_START+ADCBCAL0_offset);ADCB.CALH=read_calibration_byte(PROD_SIGNATURES_START+ADCBCAL1_offset); // Free Running mode: Off// Gain stage impedance mode: Low-impedance sources// Current consumption: No limit// Conversion mode: SignedADCB.CTRLB=(1<<ADC_IMPMODE_bp) | ADC_CURRLIMIT_NO_gc | (1<<ADC_CONMODE_bp) | ADC_RESOLUTION_12BIT_gc; // Clock frequency: 125.000 kHzADCB.PRESCALER=ADC_PRESCALER_DIV256_gc; // Reference: Internal Vcc/1.6// Temperature reference: OffADCB.REFCTRL=ADC_REFSEL_VCC_gc | (0<<ADC_TEMPREF_bp) | (0<<ADC_BANDGAP_bp); // Read and save the ADC offset using channel 0ADCB.CH0.CTRL=(0<<ADC_CH_START_bp) | ADC_CH_GAIN_1X_gc | ADC_CH_INPUTMODE_DIFF_gc;ADCB.CH0.MUXCTRL=ADC_CH_MUXPOS_PIN0_gc | ADC_CH_MUXNEG_PIN0_gc;// Enable the ADC in order to read the offsetADCB.CTRLA|=ADC_ENABLE_bm;// Insert a delay to allow the ADC common mode voltage to stabilizedelay_us(2);// Perform several offset measurements and store the mean valueoffs=0;for (i=0; i<16; i++) { // Start the AD conversion on channel 0 ADCB.CH0.CTRL|= 1<<ADC_CH_START_bp; // Wait for the AD conversion to complete while ((ADCB.CH0.INTFLAGS & ADC_CH_CHIF_bm)==0); // Clear the interrupt flag ADCB.CH0.INTFLAGS=ADC_CH_CHIF_bm; // Read the offset offs+=(signed char) ADCB.CH0.RESL; }// Disable the ADCADCB.CTRLA&= ~ADC_ENABLE_bm;// Store the mean value of the offsetadcb_offset=(signed char) (offs/16); // Initialize the ADC Compare registerADCB.CMPL=0x00;ADCB.CMPH=0x00; // ADC channel 0 gain: 1// ADC channel 0 input mode: Differential input signalADCB.CH0.CTRL=(0<<ADC_CH_START_bp) | ADC_CH_GAIN_1X_gc | ADC_CH_INPUTMODE_DIFF_gc; // ADC channel 0 positive input: ADC12 pin// ADC channel 0 negative input: PAD groundADCB.CH0.MUXCTRL=ADC_CH_MUXPOS_PIN12_gc | ADC_CH_MUXNEGL_GND_gc; // ADC channel 1 gain: 1// ADC channel 1 input mode: Differential input signalADCB.CH1.CTRL=(0<<ADC_CH_START_bp) | ADC_CH_GAIN_1X_gc | ADC_CH_INPUTMODE_DIFF_gc; // ADC channel 1 positive input: ADC13 pin// ADC channel 1 negative input: PAD groundADCB.CH1.MUXCTRL=ADC_CH_MUXPOS_PIN13_gc | ADC_CH_MUXNEGL_GND_gc; // ADC channel 2 gain: 1// ADC channel 2 input mode: Differential input signalADCB.CH2.CTRL=(0<<ADC_CH_START_bp) | ADC_CH_GAIN_1X_gc | ADC_CH_INPUTMODE_DIFF_gc; // ADC channel 2 positive input: ADC14 pin// ADC channel 2 negative input: PAD groundADCB.CH2.MUXCTRL=ADC_CH_MUXPOS_PIN14_gc | ADC_CH_MUXNEGL_GND_gc; // ADC channel 3 gain: 1// ADC channel 3 input mode: Differential input signalADCB.CH3.CTRL=(0<<ADC_CH_START_bp) | ADC_CH_GAIN_1X_gc | ADC_CH_INPUTMODE_DIFF_gc; // ADC channel 3 positive input: ADC15 pin// ADC channel 3 negative input: PAD groundADCB.CH3.MUXCTRL=ADC_CH_MUXPOS_PIN15_gc | ADC_CH_MUXNEGL_GND_gc; // Event system channel: 7 sweeps ADC channel(s): 0, 1, 2, 3//ADCB.EVCTRL=ADC_SWEEP_0123_gc | ADC_EVSEL_7_gc | ADC_EVACT_SWEEP_gc; // Channel 0 interrupt: OFF// Channel 0 interrupt mode: Conversion CompleteADCB.CH0.INTCTRL=ADC_CH_INTMODE_COMPLETE_gc | ADC_CH_INTLVL_OFF_gc;// Channel 1 interrupt: OFF// Channel 1 interrupt mode: Conversion CompleteADCB.CH1.INTCTRL=ADC_CH_INTMODE_COMPLETE_gc | ADC_CH_INTLVL_OFF_gc;// Channel 2 interrupt:OFF// Channel 2 interrupt mode: Conversion CompleteADCB.CH2.INTCTRL=ADC_CH_INTMODE_COMPLETE_gc | ADC_CH_INTLVL_OFF_gc;// Channel 3 interrupt:OFF// Channel 3 interrupt mode: Conversion CompleteADCB.CH3.INTCTRL=ADC_CH_INTMODE_COMPLETE_gc | ADC_CH_INTLVL_OFF_gc; // Enable the ADCADCB.CTRLA|=ADC_ENABLE_bm;// Insert a delay to allow the ADC common mode voltage to stabilizedelay_us(2);}6、改为事件驱动ADC转换由于这个程序中的TCF0定时器溢出中断次数为每秒400次,一次启动8个ADC通道,每秒钟每个通道转换50次。TCF0的中断次数400次每秒也严重地占用了CPU资源。拟改为事件驱动ADC转换。这里将ADCA和ADCB都设置成通道扫描方式,单一事件启动ADC四个通道扫描一遍,扫描次序通道0、通道1、通道2和通道3.在上述adca_init()中添加:// Event system channel: 7 sweeps ADC channel(s): 0, 1, 2, 3ADCA.EVCTRL=ADC_SWEEP_0123_gc | ADC_EVSEL_7_gc | ADC_EVACT_SYNCHSWEEP_gc;在上述adcb_init()中添加:// Event system channel: 7 sweeps ADC channel(s): 0, 1, 2, 3ADCB.EVCTRL=ADC_SWEEP_0123_gc | ADC_EVSEL_7_gc | ADC_EVACT_SYNCHSWEEP_gc;在event_system_init()中添加:void event_system_init(void){// Event System Channel 0 source: Port D, Pin7EVSYS.CH0MUX=EVSYS_CHMUX_PORTD_PIN7_gc;// Event System Channel 1 source: Port F, Pin0EVSYS.CH1MUX=EVSYS_CHMUX_PORTF_PIN0_gc;// Event System Channel 2 source: Port F, Pin1EVSYS.CH2MUX=EVSYS_CHMUX_PORTF_PIN1_gc;// Event System Channel 3 source: Port F, Pin2EVSYS.CH3MUX=EVSYS_CHMUX_PORTF_PIN2_gc;// Event System Channel 4 source: Port F, Pin6EVSYS.CH4MUX=EVSYS_CHMUX_PORTF_PIN6_gc;// Event System Channel 4 source: NoneEVSYS.CH4MUX=EVSYS_CHMUX_OFF_gc;// Event System Channel 5 source: NoneEVSYS.CH5MUX=EVSYS_CHMUX_OFF_gc;// Event System Channel 6 source: NoneEVSYS.CH6MUX=EVSYS_CHMUX_OFF_gc;// Event System Channel 7 source: TCF0定时器溢出事件EVSYS.CH7MUX=EVSYS_CHMUX_TCF0_OVF_gc; // Event System Channel 0 source: Prescaler, divide by 32768//EVSYS.CH7MUX=EVSYS_CHMUX_PRESCALER_32768_gc;// Event System Channel 0 Digital Filter Coefficient: 8 Samples// Quadrature Decoder: OffEVSYS.CH0CTRL=(EVSYS.CH0CTRL & (~(EVSYS_QDIRM_gm | EVSYS_QDIEN_bm | EVSYS_QDEN_bm | EVSYS_DIGFILT_gm))) | EVSYS_DIGFILT_8SAMPLES_gc;// Event System Channel 1 Digital Filter Coefficient: 1 SampleEVSYS.CH1CTRL=EVSYS_DIGFILT_1SAMPLE_gc;// Event System Channel 2 Digital Filter Coefficient: 1 Sample// Quadrature Decoder: OffEVSYS.CH2CTRL=(EVSYS.CH2CTRL & (~(EVSYS_QDIRM_gm | EVSYS_QDIEN_bm | EVSYS_QDEN_bm | EVSYS_DIGFILT_gm))) | EVSYS_DIGFILT_1SAMPLE_gc;// Event System Channel 3 Digital Filter Coefficient: 1 SampleEVSYS.CH3CTRL=EVSYS_DIGFILT_1SAMPLE_gc;// Event System Channel 4 Digital Filter Coefficient: 1 Sample// Quadrature Decoder: OffEVSYS.CH4CTRL=(EVSYS.CH4CTRL & (~(EVSYS_QDIRM_gm | EVSYS_QDIEN_bm | EVSYS_QDEN_bm | EVSYS_DIGFILT_gm))) | EVSYS_DIGFILT_1SAMPLE_gc;// Event System Channel 5 Digital Filter Coefficient: 1 SampleEVSYS.CH5CTRL=EVSYS_DIGFILT_1SAMPLE_gc;// Event System Channel 6 Digital Filter Coefficient: 1 SampleEVSYS.CH6CTRL=EVSYS_DIGFILT_1SAMPLE_gc;// Event System Channel 7 Digital Filter Coefficient: 1 SampleEVSYS.CH7CTRL=EVSYS_DIGFILT_1SAMPLE_gc; // Event System Channel output: DisabledPORTCFG.CLKEVOUT&= ~PORTCFG_EVOUT_gm;PORTCFG.EVOUTSEL&= ~PORTCFG_EVOUTSEL_gm;}在tcf0_init()中禁用溢出中断// Timer/Counter TCF0 initializationvoid tcf0_init(void){unsigned char s; // Note: The correct PORTF direction for the Compare Channels// outputs is configured in the ports_init function. // Save interrupts enabled/disabled states=SREG;// Disable interrupts#asm("cli") // Disable and reset the timer/counter just to be suretc0_disable(&TCF0);// Clock source: ClkPer/2TCF0.CTRLA=TC_CLKSEL_DIV2_gc;// Mode: Normal Operation, Overflow Int./Event on TOP// Compare/Capture on channel A: Off// Compare/Capture on channel B: Off// Compare/Capture on channel C: Off// Compare/Capture on channel D: OffTCF0.CTRLB=(0<<TC0_CCDEN_bp) | (0<<TC0_CCCEN_bp) | (0<<TC0_CCBEN_bp) | (0<<TC0_CCAEN_bp) | TC_WGMODE_NORMAL_gc;// Capture event source: None// Capture event action: NoneTCF0.CTRLD=TC_EVACT_OFF_gc | TC_EVSEL_OFF_gc; // Set Timer/Counter in Normal modeTCF0.CTRLE=TC_BYTEM_NORMAL_gc; // Overflow interrupt: Disabled// Error interrupt: DisabledTCF0.INTCTRLA=TC_ERRINTLVL_OFF_gc | TC_OVFINTLVL_OFF_gc; // Compare/Capture channel A interrupt: Disabled// Compare/Capture channel B interrupt: Disabled// Compare/Capture channel C interrupt: Disabled// Compare/Capture channel D interrupt: DisabledTCF0.INTCTRLB=TC_CCDINTLVL_OFF_gc | TC_CCCINTLVL_OFF_gc | TC_CCBINTLVL_OFF_gc | TC_CCAINTLVL_OFF_gc;// High resolution extension: OffHIRESF.CTRLA&= ~HIRES_HREN0_bm;// Clear the interrupt flagsTCF0.INTFLAGS=TCF0.INTFLAGS;// Set Counter registerTCF0.CNT=0x0000;// Set Period registerTCF0.PER=0x9C3F;// Set channel A Compare/Capture registerTCF0.CCA=0x0000;// Set channel B Compare/Capture registerTCF0.CCB=0x0000;// Set channel C Compare/Capture registerTCF0.CCC=0x0000;// Set channel D Compare/Capture registerTCF0.CCD=0x0000; // Restore interrupts enabled/disabled stateSREG=s;}成功实现8个通道ADC转换,不使用中断。 单片机中的奢华品牌了。
页:
[1]