PIC16F688的采样率

时间:2015-09-21 21:42:55

标签: microcontroller pic microchip

请我很难理解如何计算PIC16F688的ADC采样率。我的时钟频率(MCU)是8MHz。我将ADCON1配置为以下内容:

ADCON1 &= 0b01000000;      //clear bits 6 through 0
ADCON1 |= 0b01000000;     //set bits 6 though 0.

我是根据PIC的数据表做到的。因为它有内部振荡器,这意味着它可以在Fosc / 4上工作,并且根据表8-1。 所以我试图找到采样率。与之相关的代码是什么?我认为ADCON1是负责时钟周期的人。即采样率。

我不认为delay_ms(1000)在我的无限循环中是重要的。所以这不是我的采样率。 或者是UART1_Init(9600)。

你能不能帮我解决这个问题,我很感激。 谢谢。

    char temp[5];

    unsigned int adc_value;

    char uart_rd;
     int i;
     unsigned int d[10]={0};
     int average = 0;
     int counter =0;

     void main()
         {

          temp[0]='1';
          temp[1]='2';
          temp[2]='3';
          temp[3]='4';
          temp[4]=' ';
          OSCCON     = 0x77;         
          //ANSEL = 0;             
          ANSEL = 0b00000100;      
          CMCON0 = 0X07;   
          TRISA = 0b00001100;
          // ADCON0 =0b1011;
         // ADCON1 &= 0b01000000;       
         //ADCON1 |= 0b01000000;      
         UART1_Init(9600);               
         Delay_ms(100);                   
          while (1)
                {
                average=0;
                for(i=0;i<10;i++)
                    {
                   average+= ADC_Read(2);
                }
         average/=10;
        temp[0] = average/1000+48;
        temp[1] = (average/100)%10+48;
        temp[2] = (average/10)%10+48;
        temp[3] = average%10+48;
        for (i=0;i<5; i++)
           {
           UART1_Write(temp[i]);
       }
   }
 }




 //Updated the code using Interrupt.// But have problem reading from ANS2.


enter code here
char temp[5];
unsigned int adc_value;
int i;
unsigned int d[10]={0};
int average = 0;
void interrupt(){
       if (INTCON.T0IF) {
          INTCON.T0IF = 0 ;// clear T0IF (Timer interrupt flag).
          average= ADC_Read(2);
          temp[0] = average/1000+48;
          temp[1] = (average/100)%10+48;
          temp[2] = (average/10)%10+48;
          temp[3] = average%10+48;
          for (i=0;i<5; i++)
              {
              UART1_Write(temp[i]);
              }
       }
     TMR0 = 178;

  }

 void main() {

      temp[0]='1';
      temp[1]='2';
      temp[2]='3';
      temp[3]='4';
      temp[4]=' ';
      OSCCON= 0x77;        //8MHz
      ANSEL = 0b00000100;  //ANS2  
      CMCON0 = 0X07;  //
      TRISA = 0b00001100;
      UART1_Init(9600);    
      TMR0 = 178 ;
      // CMCON0 = 0X04; // turn off compartor.
      OPTION_REG = 0x87;   //
      INTCON =0xA0;
      while(1);

    }

2 个答案:

答案 0 :(得分:2)

如果您在PIC16F688 datasheet中了解了ADC,则可以通过设置ADCON1&lt; 4:6&gt;来确定您可以选择转换时钟f_AD。从您的问题看来,您似乎打算将其设置为f_OSC / 4,尽管从两行代码中不清楚您已经添加了这实际发生的情况。试试这个:

ADCON1 = 0b01000000; // set conversion clock to F_osc/4

但这有点搁浅。回到数据手册,您可以在8.1.4节转换时钟中看到,完成单个位转换的时间是T_AD,转换完整的10位样本是11 T_AD。

我的Microchip数据手册中不太擅长的一件事是明确说明T_AD = 1 / conversion_clock之类的关系。但是,您可以从数据表中推断出这一点,例如表8-1,您可以看到,例如,如果f_OSC为8 MHZ,转换时钟f_AD为f_OSC / 4,即2 MHz,则T_AD为500 ns ,即1 / f_AD。 另请注意,表8-1中这超出了ADC的建议范围。 (见下文)

如上所述,完整10位样本的转换时间T_S是11 T_AD = 5.5 us。采样率f_S则为1 / T_S或181.818 kHZ(也可以计算为f_AD / 11)

这是ADC外设能够做的理论最大采样率,但它不一定是系统的采样率。如果您对多个通道进行采样,则将该理论最大值除以外设,因此如果您有两个可在其间切换的通道,则理论最大值为每通道约90 kHz。但是,设置转换和读取结果以及为保持电容充电也会产生开销,这会降低实际最大采样率低于理论值。除此之外,还有您的代码所做的其他事情,这可能会进一步降低您的实际采样率。

如果您还使用表14-9中定义的推荐T_AD,则您的最小T_AD为1.6 us,给出ADC外设f_S的理论最大采样频率为56.8 kHz。 /强>

在看到关于这个问题的一些额外评论之后编辑。

这些计算仅涉及最小转换时间(以及最大理论采样频率),它是实际采样频率的上限。如果实际采样频率远低于最大采样频率,则不是问题,但只能通过ADC外设寄存器来控制实际采样频率。例如,您可以配置一个以100 Hz的所需采样频率中断的定时器,并在计时器的ISR中启动一次转换。

2015年12月1日评论后编辑: 我认为这是一个完全不同的问题。但简而言之,根据您发布的代码作为另一个答案,您的主循环没有延迟。代码基本上可以尽可能快地完成10个样本(如果你允许循环和函数调用的一点开销,你可能在60 us,或~666 kHz中进行10个样本)。然后对样本进行平均,转换为ASCII并进行传输。传输大约需要5ms(5个字节@ 9600,假设为8N1)。因此,你会得到一连串的样本,然后是更长的停顿等。平均而言,传输时间占主导地位,因此您可以获得~190 Hz的采样率。 作为快速而肮脏的变化,您可以按如下方式更改采样循环:

average=ADC_Read(2); // was 0, but we're doing one less iteration of the loop
for(i=0;i<9;i++)
{
    delay_ms(10); // 10ms delay to get 100 Hz sampling
    average+= ADC_Read(2);
}
delay_ms(5); // together with the UART transmission time, we get 10 ms here as well

现在,这并没有考虑进行分割所需的时间,而且#34;爆发中的样本之间的间隔仍然存在差异。以及一次爆发中最后一个样本与下一个样本中的第一个样本之间的间隔。如果在调用ADC_Read()时将引脚设置为高电平,并在返回时将其设置为低电平,则可以检查范围上的时序和间隔。

为了做得更彻底,我要为100 Hz中断设置一个片上定时器,并检查主循环中的中断标志(不需要使用ISR)。当设置定时器中断标志时,清除它,重新初始化定时器,获取一个样本并进行处理。在每十个样本中,进行平均和传输。当标志清楚时,什么也不做。

答案 1 :(得分:0)

{{1}}