最近使用dsPIC33F系列单片机。学习配置了ADC触发及轮询方式。相关心得记录在下,方便以后回忆,请大家多多指导。
1、对dsPIC系统时钟的配置
1 PLLFBD = 2; // M = PLLFBD + 2 内部FRC=7.37MHz 2 CLKDIVbits.PLLPRE = 0; // N1 = 2 3 CLKDIVbits.PLLPOST = 0; // N2 = 2 4 5 __builtin_write_OSCCONH(0x01); // 新振荡器 FRC+PLL 6 __builtin_write_OSCCONL(0x01); // 允许切换晶振 7 8 while(OSCCONbits.COSC != 0b001); // 等待振荡器 FRC+PLL 9 while(OSCCONbits.LOCK != 1); // 等待振荡器稳定
dsPIC时钟来源可以参考dsPIC官方资料。这配置没有多少困难。
2、对ADC模块的配置
2.1 轮询方式
1 void ADC1_Init(void) 2 { 3 ADCONbits.FORM = 0; // Output in Integer Format 4 ADCONbits.EIE = 0; // Enable Early Interrupt 5 ADCONbits.ORDER = 1; // Normal Order of conversion 6 ADCONbits.SEQSAMP = 0; // Simultaneous sampling 7 ADCONbits.ASYNCSAMP = 1; // Asynchronous sampling 8 ADCONbits.SLOWCLK = 0; // High Frequency Clock input 9 ADCONbits.ADCS = 5; // Clock divider selection 10 11 //使用软件触发,这里务必设为独立软件触发 12 ADCPC3bits.TRGSRC7= 1; // ADC独立软件触发事件 13 14 ADPCFGbits.PCFG15 = 0; 15 ADCONbits.ADON = 1; // Enable the ADC 16 }
2.2 中断方式
1 void ADC1_Init(void) 2 { 3 ADCONbits.FORM = 0; // Output in Integer Format 4 ADCONbits.EIE = 0; // Enable Early Interrupt 5 ADCONbits.ORDER = 1; // Normal Order of conversion 6 ADCONbits.SEQSAMP = 0; // Simultaneous sampling 7 ADCONbits.ASYNCSAMP = 1; // Asynchronous sampling 8 ADCONbits.SLOWCLK = 0; // High Frequency Clock input 9 10 ADCONbits.ADCS = 5; // Clock divider selection 11 ADCPC3bits.TRGSRC7= 1; // ADC独立软件触发事件 12 13 ADPCFGbits.PCFG15 = 0; 14 //配置中断优先级及使能,中断优先级数值越低,优先级越高 15 IPC29bits.ADCP7IP = 0x01; // Set ADC Pair 7 Interrupt Priority (Level 2) 16 IFS7bits.ADCP7IF = 0; // Clear ADC Pair 7 Interrupt Flag 17 IEC7bits.ADCP7IE = 1; // Enable ADC Pair 7 Interrupt 18 19 20 ADCONbits.ADON = 1; // Enable the ADC 21 }
3、main函数内触发及处理
3.1 轮询方式
轮询方式需要等待ADC采样完成,才能获取采样后转换的值。获取后,需要手动清除采样完成的标志。
1 ADC1_Init(); //ADC模块初始化 2 while(1) 3 { 4 ADCPC3bits.SWTRG7 = 1; //Trigger the ADC 5 while(ADSTATbits.P7RDY == 0); //Wait until the ADC finish 6 ADCValue = ADCBUF15; //Get the ADC Value 7 ADSTATbits.P7RDY = 0; //Clear the last finish flag 8 delay(65535); //stop a moment 9 }
3.2 中断方式
1 //等待一段时间就触发采样 2 while(1) 3 { 4 ADCPC3bits.SWTRG7 = 1; 5 delay(65534); 6 } 7 //采样完成自动进入中断服务函数 8 void __attribute__((interrupt, no_auto_psv)) _ADCP7Interrupt(void) 9 { 10 11 IFS7bits.ADCP7IF = 0; // Clear ADC Pair 7 Interrupt Flag 12 ADCValue = ADCBUF15; 13 ADSTATbits.P7RDY = 0; 14 }
4、区别
使用轮询方式需要不断判断采样是否完成,
使用中断方式采样完成后会自动进入中断服务函数。节约CPU资源。
5、曾经犯过的错误
错误的代码逻辑如下:
1 while(1) 2 { 3 ADCPC3bits.SWTRG7 = 1; 4 while(ADSTATbits.P7RDY == 0); 5 delay(65534); 6 } 7 8 9 void __attribute__((interrupt, no_auto_psv)) _ADCP7Interrupt(void) 10 { 11 IFS7bits.ADCP7IF = 0; // Clear ADC Pair 7 Interrupt Flag 12 ADCValue = ADCBUF15; 13 ADSTATbits.P7RDY = 0; 14 }
dsPIC33F处理逻辑:采样转换完成后ADSTAT相应的位会配置为1.通过判断这个位来判断采样转换是否完成。
上面的代码错误的逻辑为:
第3行触发ADC采样转换,
第12行获取采样转换的结果后,
第13行将采样转换完成的标准位清零,
然后,
程序回到了第四行一直等待,卡死在这里。
解决办法:
将第四行或者第13行去掉就行。
其实,当独立软件触发SWTRG为1的时候,采样完成标志位PEND,由硬件自动清零。