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. PORTA | PIN # | INTERRUPT | ADCAPOS/GAINPOS | ADCB POS | ADCA NEG | ADCA GAINNEG | ACA POS | ACA NEG | ACA OUT | DACA | REFA | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
Table 33-2. Port B - alternate functions. PORTB | PIN# | INTERRUPT | ADCAPOS | ADCBPOS/ GAINPOS | ADCB NEG | ADCB GAIN NEG | ACB POS | ACB NEG | ACB OUT | | REFB | JTAG | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 state s=SREG; // Disable interrupts #asm("cli") // Disable and reset the timer/counter just to be sure tc0_disable(&TCF0); // Clock source: ClkPer/2 TCF0.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: Off TCF0.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: None TCF0.CTRLD=TC_EVACT_OFF_gc | TC_EVSEL_OFF_gc; // Set Timer/Counter in Normal mode TCF0.CTRLE=TC_BYTEM_NORMAL_gc; // Overflow interrupt: Low Level // Error interrupt: Disabled TCF0.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: Disabled TCF0.INTCTRLB=TC_CCDINTLVL_OFF_gc | TC_CCCINTLVL_OFF_gc | TC_CCBINTLVL_OFF_gc | TC_CCAINTLVL_OFF_gc; // High resolution extension: Off HIRESF.CTRLA&= ~HIRES_HREN0_bm; // Clear the interrupt flags TCF0.INTFLAGS=TCF0.INTFLAGS; // Set Counter register TCF0.CNT=0x0000; // Set Period register TCF0.PER=0x9C3F; //设置定时器周期2.5ms // Set channel A Compare/Capture register TCF0.CCA=0x0000; // Set channel B Compare/Capture register TCF0.CCB=0x0000; // Set channel C Compare/Capture register TCF0.CCC=0x0000; // Set channel D Compare/Capture register TCF0.CCD=0x0000; // Restore interrupts enabled/disabled state SREG=s; } // Timer/Counter TCF0 Overflow/Underflow interrupt service routine interrupt [TCF0_OVF_vect] 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[1:0] | PRIMODE[1:0] 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[40][4]; 共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 ADCB 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_CH1_TRFCNT=320; //int adcb_result[40][4]; 共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[j]; 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[j][i-4]; 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 mode signed char adca_offset; // ADCA initialization void 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 row ADCA.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: signed ADCA.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 kHz ADCA.PRESCALER=ADC_PRESCALER_DIV256_gc; // Reference: Internal Vcc/1.6 ,用这个不准确 // Temperature reference: Off ADCA.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 0 ADCA.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 offset ADCA.CTRLA|=ADC_ENABLE_bm;//|ADC_DMASEL_gm; //ADCA四个通道都DMA 请求 // Insert a delay to allow the ADC common mode voltage to stabilize delay_us(2); // Perform several offset measurements and store the mean value offs=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 ADC ADCA.CTRLA&= ~ADC_ENABLE_bm; // Store the mean value of the offset adca_offset=(signed char) (offs/16); //求出零点偏移量,后面实际ADC结果要减去这个量 // Initialize the ADC Compare register ADCA.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: intGND ADCA.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 signal ADCA.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 signal ADCA.CH1.MUXCTRL=ADC_CH_MUXPOS_PIN1_gc|ADC_CH_MUXNEGL_GND_gc; // // ADC channel 2 gain: 1 // ADC channel 2 input mode: Differential input signal ADCA.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 ground ADCA.CH2.MUXCTRL=ADC_CH_MUXPOS_PIN2_gc | ADC_CH_MUXNEGL_GND_gc; // ADC channel 3 gain: 1 // ADC channel 3 input mode: Differential input signal ADCA.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 ground ADCA.CH3.MUXCTRL=ADC_CH_MUXPOS_PIN3_gc | ADC_CH_MUXNEGL_GND_gc; // Channel 0 interrupt: OFF // Channel 0 interrupt mode: Conversion Complete ADCA.CH0.INTCTRL=ADC_CH_INTMODE_COMPLETE_gc | ADC_CH_INTLVL_OFF_gc; // Channel 1 interrupt: OFF // Channel 1 interrupt mode: Conversion Complete ADCA.CH1.INTCTRL=ADC_CH_INTMODE_COMPLETE_gc | ADC_CH_INTLVL_OFF_gc; // Channel 2 interrupt: OFF // Channel 2 interrupt mode: Conversion Complete ADCA.CH2.INTCTRL=ADC_CH_INTMODE_COMPLETE_gc | ADC_CH_INTLVL_OFF_gc; // Channel 3 interrupt: OFF // Channel 3 interrupt mode: Conversion Complete ADCA.CH3.INTCTRL=ADC_CH_INTMODE_COMPLETE_gc | ADC_CH_INTLVL_OFF_gc; // Free Running mode: On //ADCA.CTRLB|=ADC_FREERUN_bm; // Enable the ADC ADCA.CTRLA|=ADC_ENABLE_bm;//|ADC_DMASEL_gm; // Insert a delay to allow the ADC common mode voltage to stabilize delay_us(2); } //ADCB的初始化 // Variable used to store the ADC offset // for 12 Bit Signed conversion mode signed 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 row ADCB.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: Signed ADCB.CTRLB=(1<<ADC_IMPMODE_bp) | ADC_CURRLIMIT_NO_gc | (1<<ADC_CONMODE_bp) | ADC_RESOLUTION_12BIT_gc; // Clock frequency: 125.000 kHz ADCB.PRESCALER=ADC_PRESCALER_DIV256_gc; // Reference: Internal Vcc/1.6 // Temperature reference: Off ADCB.REFCTRL=ADC_REFSEL_VCC_gc | (0<<ADC_TEMPREF_bp) | (0<<ADC_BANDGAP_bp); // Read and save the ADC offset using channel 0 ADCB.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 offset ADCB.CTRLA|=ADC_ENABLE_bm; // Insert a delay to allow the ADC common mode voltage to stabilize delay_us(2); // Perform several offset measurements and store the mean value offs=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 ADC ADCB.CTRLA&= ~ADC_ENABLE_bm; // Store the mean value of the offset adcb_offset=(signed char) (offs/16); // Initialize the ADC Compare register ADCB.CMPL=0x00; ADCB.CMPH=0x00; // ADC channel 0 gain: 1 // ADC channel 0 input mode: Differential input signal ADCB.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 ground ADCB.CH0.MUXCTRL=ADC_CH_MUXPOS_PIN12_gc | ADC_CH_MUXNEGL_GND_gc; // ADC channel 1 gain: 1 // ADC channel 1 input mode: Differential input signal ADCB.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 ground ADCB.CH1.MUXCTRL=ADC_CH_MUXPOS_PIN13_gc | ADC_CH_MUXNEGL_GND_gc; // ADC channel 2 gain: 1 // ADC channel 2 input mode: Differential input signal ADCB.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 ground ADCB.CH2.MUXCTRL=ADC_CH_MUXPOS_PIN14_gc | ADC_CH_MUXNEGL_GND_gc; // ADC channel 3 gain: 1 // ADC channel 3 input mode: Differential input signal ADCB.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 ground ADCB.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 Complete ADCB.CH0.INTCTRL=ADC_CH_INTMODE_COMPLETE_gc | ADC_CH_INTLVL_OFF_gc; // Channel 1 interrupt: OFF // Channel 1 interrupt mode: Conversion Complete ADCB.CH1.INTCTRL=ADC_CH_INTMODE_COMPLETE_gc | ADC_CH_INTLVL_OFF_gc; // Channel 2 interrupt:OFF // Channel 2 interrupt mode: Conversion Complete ADCB.CH2.INTCTRL=ADC_CH_INTMODE_COMPLETE_gc | ADC_CH_INTLVL_OFF_gc; // Channel 3 interrupt:OFF // Channel 3 interrupt mode: Conversion Complete ADCB.CH3.INTCTRL=ADC_CH_INTMODE_COMPLETE_gc | ADC_CH_INTLVL_OFF_gc; // Enable the ADC ADCB.CTRLA|=ADC_ENABLE_bm; // Insert a delay to allow the ADC common mode voltage to stabilize delay_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, 3 ADCA.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, 3 ADCB.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, Pin7 EVSYS.CH0MUX=EVSYS_CHMUX_PORTD_PIN7_gc; // Event System Channel 1 source: Port F, Pin0 EVSYS.CH1MUX=EVSYS_CHMUX_PORTF_PIN0_gc; // Event System Channel 2 source: Port F, Pin1 EVSYS.CH2MUX=EVSYS_CHMUX_PORTF_PIN1_gc; // Event System Channel 3 source: Port F, Pin2 EVSYS.CH3MUX=EVSYS_CHMUX_PORTF_PIN2_gc; // Event System Channel 4 source: Port F, Pin6 EVSYS.CH4MUX=EVSYS_CHMUX_PORTF_PIN6_gc; // Event System Channel 4 source: None EVSYS.CH4MUX=EVSYS_CHMUX_OFF_gc; // Event System Channel 5 source: None EVSYS.CH5MUX=EVSYS_CHMUX_OFF_gc; // Event System Channel 6 source: None EVSYS.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: Off EVSYS.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 Sample EVSYS.CH1CTRL=EVSYS_DIGFILT_1SAMPLE_gc; // Event System Channel 2 Digital Filter Coefficient: 1 Sample // Quadrature Decoder: Off EVSYS.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 Sample EVSYS.CH3CTRL=EVSYS_DIGFILT_1SAMPLE_gc; // Event System Channel 4 Digital Filter Coefficient: 1 Sample // Quadrature Decoder: Off EVSYS.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 Sample EVSYS.CH5CTRL=EVSYS_DIGFILT_1SAMPLE_gc; // Event System Channel 6 Digital Filter Coefficient: 1 Sample EVSYS.CH6CTRL=EVSYS_DIGFILT_1SAMPLE_gc; // Event System Channel 7 Digital Filter Coefficient: 1 Sample EVSYS.CH7CTRL=EVSYS_DIGFILT_1SAMPLE_gc; // Event System Channel output: Disabled PORTCFG.CLKEVOUT&= ~PORTCFG_EVOUT_gm; PORTCFG.EVOUTSEL&= ~PORTCFG_EVOUTSEL_gm; } 在tcf0_init()中禁用溢出中断 // Timer/Counter TCF0 initialization 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 state s=SREG; // Disable interrupts #asm("cli") // Disable and reset the timer/counter just to be sure tc0_disable(&TCF0); // Clock source: ClkPer/2 TCF0.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: Off TCF0.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: None TCF0.CTRLD=TC_EVACT_OFF_gc | TC_EVSEL_OFF_gc; // Set Timer/Counter in Normal mode TCF0.CTRLE=TC_BYTEM_NORMAL_gc; // Overflow interrupt: Disabled // Error interrupt: Disabled TCF0.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: Disabled TCF0.INTCTRLB=TC_CCDINTLVL_OFF_gc | TC_CCCINTLVL_OFF_gc | TC_CCBINTLVL_OFF_gc | TC_CCAINTLVL_OFF_gc; // High resolution extension: Off HIRESF.CTRLA&= ~HIRES_HREN0_bm; // Clear the interrupt flags TCF0.INTFLAGS=TCF0.INTFLAGS; // Set Counter register TCF0.CNT=0x0000; // Set Period register TCF0.PER=0x9C3F; // Set channel A Compare/Capture register TCF0.CCA=0x0000; // Set channel B Compare/Capture register TCF0.CCB=0x0000; // Set channel C Compare/Capture register TCF0.CCC=0x0000; // Set channel D Compare/Capture register TCF0.CCD=0x0000; // Restore interrupts enabled/disabled state SREG=s; } 成功实现8个通道ADC转换,不使用中断。 |