xmega频率测量

分享到:

最近一直尝试各种方法测量一个正弦波的频率,可是都不太理想,老差几个hz,尤其中频,现在先将自己的方法供大家研讨。
第一种方法:
比较笨的方法,使用了回调函数,但是要设一个变量判断,是否符合条件。

#define F_CPU        sysclk_get_main_hz()


#include <asf.h>


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 <asf.h>
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种测量方法的代码,第二个方法比第一个要快。

 

更多Atmel及科技资讯请关注:  
Atmel中文官网:https://www.atmel.com/zh/cn/
Atmel技术论坛:https://atmel.eefocus.com/
Atmel中文博客:https://blog.sina.com.cn/u/2253031744
Atmel新浪微博:https://www.weibo.com/atmelcn

继续阅读
ATxmega之实现实时系统

在xmega上实现一个简单的实时系统,对于一般的mcu已经够使用了。下面主要介绍一个简单实时调度系统的实现过程。

XMEGA PWM模块多通道的用法

本文介绍ASF中PWM模块同时使用多个通道的用法: 1、定义PWM变量,每个通道需要单独定义一个变量 2、使用pwm_init函数初始PWM。如果是同一个PWM模块(定时器),需要使用相同的频率参数。 3、设置每个通道的占空比

SKT之AVR硬件I2C的操作函数

STK600 之 Atmega128硬件I2C 读写高精度时钟芯片DS3231函数,STK600 用于程序的下载 连接JTAG口至mega128目标板即可,分享给大家参考。

XMEGA USART模块基本使用方法

在ASF中,USART有两种驱动,一种是USART - Serial interface(service)模块,另一种就是USART - Universal Synchronous/Asynchronous Receiver/Transmitter (driver)模块。本文将着重介绍第二种模块的使用方法。

XMEGA学习——DMA使用(含源代码)

测试了一下XMEGA的DMA模块,把一块内存中的数据DMA传输到另外一块内存,DMA传输完成后,在中断函数中显示“DMA Finished”,提示DMA成功完成数据传输。

©2019 Microchip Corporation
facebook google plus twitter linkedin youku weibo rss