首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用8051单片机进行频率测量

用8051单片机进行频率测量
EN

Stack Overflow用户
提问于 2018-09-28 10:49:12
回答 2查看 491关注 0票数 1

我只想连续计算正弦信号的频率与比较器的输入(在下降的边缘)。有效目标频率约为122 Hz,我的实现大部分时间都在工作,但有时它计算错误的频率总是在~61 Hz左右(这是不可能的,我用示波器验证了这一点)。

我的实现似乎有一个弱点,可能是竞赛状态或误用计时器,因为它使用并发中断服务例程并手动启动和停止计时器。

我还认为这个bug与测量到的大约122 is的频率相关,因为一个计时器溢出几乎是一样的:

一个计时器溢出=1/ (1/8 MHz * 2^16位)= 122.0703125 Hz

我使用的是8051微控制器(硅实验室C8051F121),代码如下:

代码语言:javascript
复制
// defines 
#define PERIOD_TIMER_FREQ 8000000.0 // Timer 3 runs at 8MHz

#define TMR3_PAGE      0x01 /* TIMER 3 */
#define CP1F_VECTOR    12   /* comparator 1 falling edge */
#define TF3_VECTOR     14   /* timer3 reload timer   */

sfr TMR3CN        = 0xC8; /* TIMER 3 CONTROL */
sfr TMR3L         = 0xCC; /* TIMER 3 LOW BYTE */
sfr TMR3H         = 0xCD; /* TIMER 3 HIGH BYTE */

// global variables
volatile unsigned int xdata timer3_overflow_tmp; // temporary counter for the current period
volatile unsigned int xdata timer3_lastValue; // snapshot of the last timer value
volatile unsigned int xdata timer3_overflow; // current overflow counter, used in the main routine
volatile unsigned int xdata tempVar; // temporary variable
volatile unsigned long int xdata period; // the caluclated period
volatile float xdata period_in_SI; // calculated period in seconds
volatile float xdata frequency; // calculated frequency in Hertz

// Comparator 1 ISR has priority "high": EIP1 = 0x40
void comp1_falling_isr (void) interrupt CP1F_VECTOR
{
  SFRPAGE = TMR3_PAGE;
  TMR3CN &= 0xfb;      // stop timer 3

  timer3_lastValue = (unsigned int) TMR3H;
  timer3_lastValue <<= 8;
  timer3_lastValue |= (unsigned int) TMR3L;

  // check if timer 3 overflow is pending 
  if (TMR3CN & 0x80)
  {
    timer3_overflow_tmp++; // increment overflow counter
    TMR3CN &= 0x7f; // Clear over flow flag. This will also clear a pending interrupt request.
  } 

  timer3_overflow = timer3_overflow_tmp;

  // Reset all the timer 3 values to zero
  TMR3H = 0;
  TMR3L = 0;
  timer3_overflow_tmp = 0;
  TMR3CN |= 0x04;     // restart timer 3
}

// Timer 3 ISR has priority "low", which means it can be interrupted by the
// comparator ISR: EIP2 = 0x00
// Timer 3 runs at 8MHz in 16 bit auto-reload mode
void timer3_isr(void) interrupt TF3_VECTOR using 2
{      
  SFRPAGE = TMR3_PAGE;
  timer3_overflow_tmp++;
  TMR3CN &= 0x7f; // Clear over flow flag. This will also clear a pending interrupt request.
}

void main(void)
{
  for(;;)
  {
    ...

calcFrequencyLabel: // this goto label is a kind of synchronization mechanism
                    // and is used to prevent race conditions caused by the ISRs
                    // which invalidates the current copied timer values

    tempVar = timer3_lastValue;
    period  = (unsigned long int)timer3_overflow;
    period  <<= 16;
    period  |= (unsigned long int)timer3_lastValue;

    // If both values are not equal, a race condition has been occured.
    // Therefore the the current time values are invalid and needs to be dropped.
    if (tempVar != timer3_lastValue) 
      goto calcFrequencyLabel;

    // Caluclate period in seconds
    period_in_SI = (float) period / PERIOD_TIMER_FREQ;

    // Caluclate period in Hertz
    frequency = 1 / period_in_SI; // Should be always stable about ~122Hz

    ...
  }  
}

有人能帮我找到我的实现中的漏洞吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-09-28 13:46:58

我不能指出特定的错误,但是这段代码中有一些问题。

主要的问题是8051不是一台PC,而是成为主流的最可怕的8位单片机。这意味着你应该拼命避免32位整数和浮点之类的东西。如果你拆开这段代码,你就会明白我的意思。

完全没有理由在这里使用浮点。32位变量可能也可以避免。您应该尽可能使用uint8_t,并避免使用unsigned int。您的C代码不需要知道时间(以秒为单位)或频率(以赫兹为单位),而只需要关注计时器周期的数量。

你有多个种族状况缺陷。您的goto黑客主要是一个肮脏的解决方案-相反,您应该防止比赛条件发生在第一。在ISRs和timer3_overflow_tmp之间还有另一个竞赛条件。

在ISR和main之间共享的每个变量,或者具有不同优先级的两个不同的ISR之间的变量,都必须受到保护,以避免竞争条件的影响。这意味着您必须确保原子访问或使用某种形式的保护机制。在这种情况下,您可能只需使用"poor man's mutex" bool标志即可。另一种选择是更改为8位变量,并在内联汇编程序中编写访问它的代码。通常,您不能在8位核上的unsigned int上使用原子访问.

票数 2
EN

Stack Overflow用户

发布于 2018-09-28 13:48:55

对于低频正弦和输入滞后不足(默认为无)的慢边,一个上升的边缘看起来像下降的边缘,只需要一点噪声就可以得到一半的频率。

代码片段不包括设置迟滞的CPT1CN设置。对于您的信号,您可能需要最大限度的它,并确保在您的信号的峰值-峰值噪声是小于30毫伏。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52553731

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档