代码改变世界

dsPIC33F配置ADC软件触发轮询与采样中断的注意事项与区别

2021-07-08 15:49  斑鸠,一生。  阅读(1032)  评论(0编辑  收藏  举报

          最近使用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,由硬件自动清零