两种测量正弦波的频率的方法分享

电子说

1.3w人已加入

描述

  最近一直尝试各种方法测量一个正弦波的频率,可是都不太理想,老差几个hz,尤其中频,现在先将自己的方法供大家研讨。

  第一种方法:

  比较笨的方法,使用了回调函数,但是要设一个变量判断,是否符合条件。

  #define F_CPU sysclk_get_main_hz()

  #include

  uint32_t frequence;

  static void my_frq_test_callback(void)

  {

  if(frequence》100)

  {

  //如果想看结果的话,可以设置一个断点

  asm(“nop”);

  PORTA.INT0MASK=~PIN1_bm;

  PORTA.INTCTRL=PORT_INT0LVL_OFF_gc;

  tc_write_clock_source(&TCC0,TC_CLKSEL_OFF_gc);

  /*这里不用tc_disable(&TCC0),好像定时器也关掉了,再次使用时,必须使能定时器,tc_enable(&TCC0) ,然后再用tc_write_clock_source(&TCC0, TC_CLKSEL_DIV1_gc);启动定时器就行了*/

  frequence=0;

  }

  }

  int main(void)

  {

  sysclk_init();

  pmic_init();

  //这里的IOPORT_PULL_UP加上后,不知道为什么会先产生个中断,也请分析一下

  ioport_configure_pin(IOPORT_CREATE_PIN(PORTA,1),IOPORT_DIR_INPUT|IOPORT_BOTHEDGES|IOPORT_PULL_UP);

  //这里的定义不知道能否加到上面的定义中,请给点建议

  PORTA.INT0MASK=PIN1_bm;

  PORTA.INTCTRL=PORT_INT0LVL_MED_gc;

  tc_enable(&TCC0);

  tc_set_wgm(&TCC0, TC_WG_NORMAL);

  tc_write_period(&TCC0,40000);

  tc_set_overflow_interrupt_callback(&TCC0, my_frq_test_callback);

  tc_set_overflow_interrupt_level(&TCC0, TC_INT_LVL_LO);

  cpu_irq_enable();

  do

  {}while(1);

  }

  ISR(PORTA_INT0_vect)

  {

  if(frequence==0)

  {

  tc_write_clock_source(&TCC0, TC_CLKSEL_DIV1_gc);

  }

  else

  {

  frequence++;

  }

  }

  第二种方法:

  用2个定时器,因为定时器的period的值是uint16_t的,如果超限,会引起程序工作不正常,所以用2个定时器解决一下,第二个定时器一第一个定时器的溢出为时钟信号,没有用到回调函数,简单代码如下:#define F_CPU sysclk_get_main_hz()

  #include

  uint32_t frq;

  int main (void)

  {

  /* Insert system clock initialization code here (sysclk_init())。 */

  board_init();

  pmic_init();

  sysclk_init();

  //定义管脚中断

  PORTA.DIRCLR=PIN1_bm;

  PORTA.PIN1CTRL=PORT_ISC_BOTHEDGES_gc;//|PORT_OPC_PULLUP_gc 此处还是不知道用不用上拉

  PORTA.INT0MASK=PIN1_bm;

  PORTA.INTCTRL=PORT_INT0LVL_MED_gc;

  //设置及使能事件

  sysclk_enable_module(SYSCLK_PORT_GEN, SYSCLK_EVSYS);

  EVSYS.CH0MUX = EVSYS_CHMUX_TCC0_OVF_gc;

  //TCC0为第一个定时器,它的溢出提供给TCD0做为事件时钟

  tc_enable(&TCC0);

  tc_enable(&TCD0);

  tc_set_wgm(&TCD0,TC_WG_NORMAL);

  tc_set_wgm(&TCC0,TC_WG_NORMAL);

  //因为系统时钟用的是内部2M的时钟,除以50后,一个是好算事件,一个是最接近时钟溢出的period,period不能超过65535,能有别的好方法 //也希望能指点一下

  tc_write_period(&TCC0,sysclk_get_main_hz()/50);

  tc_write_period(&TCD0,1000);

  tc_set_overflow_interrupt_level(&TCC0,TC_INT_LVL_LO);

  tc_enable_delay(&TCD1);

  tc_write_clock_source(&TCD0,TC_CLKSEL_EVCH0_gc) ;

  cpu_irq_enable();

  do

  {

  } while (tc_is_overflow(&TCD0)==0);

  frq/=4;

  //可以在这里设置一个断点看结果,应该在后面对frq置0,方便后面的程序调用,可是如果后面我把frq置0,此时就看到的值也为0,也希望给点 //建议

  asm(“nop”);

  /* Insert application code here, after the board has been initialized. */

  do

  {

  } while (1);

  }

  ISR(PORTA_INT0_vect)

  {

  asm(“nop”);

  if(frq==0)

  {

  tc_write_clock_source(&TCC0,TC_CLKSEL_DIV1_gc);

  }

  frq++;

  }

  以上就是2种测量方法的代码,第二个方法比第一个要快。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分