【问题标题】:Calculating signal Frequency using Fixed-Point rather than Float使用定点而不是浮点计算信号频率
【发布时间】:2021-04-07 04:53:47
【问题描述】:

希望有人可以提供帮助...我正在寻找使用定点算法而不是我当前实现和工作的浮点数来计算捕获信号周期的频率,因为我知道这将是一种资源密集度较低的方法;我正在使用频率计数器来测量音频频率。我是 PIC 编程的初学者,对定点概念非常陌生,但希望得到任何指导。

我正在使用 PIC18F13K22,内部时钟为 4Mhz(其他内部时钟选项:16Mhz、8Mhz 等),处于捕捉模式,使用定时器 3,频率为 1 Mhz (Fosc/4) ;因此每个捕获的计数周期为 1E-6 秒。例如:125Hz = 1E6 / 125 = 8,000 个计数的输入频率

下面是我的代码sn-p,使用C和XC8编译器:

volatile char buffer[5];
volatile uint16_t t1;
volatile uint16_t t2;
volatile uint16_t period;
volatile float freq;

void main() {
    
    t1 = 0x0;
    t2 = 0x0;
    period = 0x0;
    freq = 0.0;
    
    int status;
    char *text;

    // Init
    sys_init();
    capture_init();
    LCD_Initialize();
    
    LCDPutStr("Frequency:");
    LCDGoto(0,1);
    LCDPutStr("0");
    LCDGoto(14,1);
    LCDPutStr("Hz");
        
    while(1) {
        TMR3L = 0x00;
        TMR3H = 0x00;
        
        T3CONbits.TMR3ON = 1; // Timer3 on
        while(PIR1bits.CCP1IF==0);  // Wait for first rising edge
        PIR1bits.CCP1IF = 0;
        t1 = CCPR1;
        while(PIR1bits.CCP1IF==0); // Wait for second rising edge
        PIR1bits.CCP1IF = 0;
        t2 = CCPR1;
        T3CONbits.TMR3ON = 0; // Timer3 off
        
        if (t1 < t2) {
            period = t2 - t1;
            freq = 1000000 / period;

            text=ftoa(freq,&status);

            LCDGoto(0,1);
            LCDPutStr(text);
        }
    }
}

当前变量freq 被定义为Double 数据类型。希望采用尽可能有效的方法,因此对以定点计算和表示频率感兴趣;还热衷于确保尽可能准确,同时保持内部时钟和捕获方法的使用。

谢谢, 亚历克斯

【问题讨论】:

  • 请告诉我们minimal reproducible example,以便定义可见。比如period是什么类型?
  • 相应地更新了代码 sn-p - 希望更清晰。
  • 表达式1000000 / period 产生一个int 类型的值。

标签: c embedded frequency pic fixed-point


【解决方案1】:

这个想法是创建一种 Microclock 整数类型,其定义大于时钟。定义的差异可能是 2 的幂,以使转换尽可能快。让我们举一个定义乘以 256 的例子:

typedef UInt32 Microclock;
static inline Microclock clock2microclock(UInt16 clock) { return clock << 8; }
static inline UInt16 microclock2clock(UInt16 clock) { return clock >> 8; }
static inline Microclock microclock2fractional(UInt16 clock) { return clock  % 256; }
static const Microclock SecondInMicroclock = 256000000;

那么你可以这样做:

volatile Microclock freq;
freq = SecondInMicroclock / period;

结果将等效于具有 256 个值的小数部分的浮点数。我举个例子:

1000000 / 421.f = 2375.29688;
256000000 / 421 = 608076;

您可以通过再次转换为浮点数来观察定义的差异:

608076 / 256.f  = 2375.296875;

虽然丢失不是很重要,但您可以通过选择例如 65536 而不是 256 来增加清晰度。

但很自然地,在代码中你只会使用整数(但如果不知道你在用这个频率变量做什么,就很难给出一个使用示例):

UInt16 ifreq    = microclock2clock (608076);      // 2375
Microclock rest = microclock2fractional(608076);  // 76 (76/256)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-17
    • 2013-10-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多