如何检测C中数字引脚是否闪烁(从高到低)?

问题描述 投票:0回答:1

我正在编写一个固件应用程序。我必须读取连接到智能电池的 GPIO 引脚,该引脚传达电池的状态。引脚中的高值表示电池处于未知状态,低值表示电池已断开连接,并且通过 2.5 Hz 闪烁指示错误。到目前为止,我已经成功地使用以下函数检测断开连接和未知状态:

void Check_Bat_Connected(void)
{ 
static int Low_Level_debounce = 0
if(IOPORT_LEVEL_LOW == Pin_Level)
    {
        if(25 == Low_Level_debounce)
        {
            BAT_Status = BAT_Not_Connect;
        }
        else if(Low_Level_debounce < 25)
        {
            Low_Level_debounce++;
        }
        else
        {
            /**/
        }
    }
    else
    {
        Low_Level_debounce = 0;
        BAT_Status_1 = BAT_Unknown;
    }
}

此函数由电池处理程序循环调用,其作用是获取有关电池的信息。我添加了一个去抖变量,以提高针对电池错误断开的鲁棒性。

我现在的问题是,如何检测 LED 是否以 2.5 Hz 的频率闪烁?即使我假设频率远高于 2.5 Hz,我也没有关于两次调用 Check_Bat_Connected 函数之间经过多长时间的信息。我怎样才能以稳健的方式实施最后的检查?

c port gpio battery firmware
1个回答
0
投票

如果您需要“高精度”读取经过的时间,那么边沿触发的输入捕获中断是唯一的方法。但是,如果 GPIO 信号出现潜在噪声中断,就会出现问题,因此在这种情况下,可以考虑使用外部 RC 低通滤波器来消除尖峰。 否则,如果边沿触发中断不可行(信号噪声太大等),最可靠的方法是使用循环定时器中断触发,假设频率比预期频率高 10 倍。所以 1/2.5 = 400ms,让中断每 40ms 触发一次。

从 ISR 内部将结果存储在一个位字段中。例如,我们可以使用

unsigned int

来存储样本的位字段。概念伪代码:

static volatile pin_status = UNKNOWN; 

void isr (void)
{
  static unsigned int samples = 0;

  volatile bool pin_level = some_gpio_pin;
  samples <<= 1;
  samples |= pin_level;

  static const ten_samples = 0x3FFu;
  pin_status = lookup_table [samples & ten_samples]; 
}

(查找表会占用大量闪存,但还有许多其他方法可以做到这一点。您还可以将样本存储在 RAM 字节数组中,并使用 memcmp() 来查找某些模式 - 速度较慢且消耗 RAM,但不占用任何闪光灯。)

samples

最终会得到每 40ms 采样一次的比特流,因此 1 1 1...(10 次)的二进制序列对应于高位,0 0 0...(10 次)的序列对应于高位到一个低点。您可以建立 10 个样本 +/-1 左右的容差,具体取决于您的挑剔程度。由于这个计时器运行得很慢,我们会隐式地进行去抖...LED 不会反弹,因此我们本质上只是在这里进行某种软件 EMI 滤波。

请记住系统时钟的不准确性,特别是当您使用内部振荡器而不是外部石英运行时。

© www.soinside.com 2019 - 2024. All rights reserved.