我正在写一个固件应用程序。我必须读取连接到智能电池的GPIO引脚,它可以传达电池的状态。引脚中的高值表示电池处于未知状态,低值表示电池已断开连接,错误由2.5 Hz Flink 指示。到目前为止,我已经成功地检测到断开连接和未知状态与以下函数:
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 = BAT_Unknown;
}
}
此函数由电池处理程序在循环中调用,电池处理程序的作用是获取有关电池的信息。我添加了一个反跳变量,以增加对错误断开电池的鲁棒性。
我现在的问题是,我如何检测LED是否以2.5 Hz Flink ?我没有任何关于两次调用Check_Bat_Connected函数之间的时间间隔的信息,即使我假设频率远高于2.5 Hz。如何以稳健的方式实现最后一个检查?
2条答案
按热度按时间5anewei61#
假设硬件可以在相当合理的时间间隔内提供中断,那么就有一种方法可以去抖动并检测2.5Hz信号。
使用
static unsigned
32位变量通过左移和“或”运算来累积信号样本(0或1):想象一个2.5Hz的方波,采样时间约为15 ms(您需要32个样本来捕获略多于一个周期的输入信号):
该示例数据捕获了从高到低的最近转变。如果转换是从低到高,这也同样有效。请相信以下
while()
循环在移位时检测到5个置位或5个复位位作为低阶位:一旦你有一个稳定的值在低位,异或“一个位向左在1/2的周期的信号将比较稳定的值。
如果XOR的结果为1,则信号 Flink 。
如果XOR的结果是0,则信号是稳定的(可以是高,可以是低)。
range
计数器是必要的,以防止一个信号,这是从移位足够远,导致前置零的移位被考虑。如果该检测是关键的,则可以涉及更多比特被XOR以形成关于输入信号是否交替高/低的多数决定。
vaj7vani2#
如果你需要一个 * 高精度 * 的阅读时间流逝,那么边沿触发输入捕获中断是唯一的方法。但是,GPIO信号上的中断可能存在噪声,因此在这种情况下,可以考虑使用外部RC低通滤波器来消除尖峰。
否则,如果边沿触发中断是不可行的(信号太嘈杂等),最可靠的方法将是有一个循环定时器中断触发,比方说比预期频率高10倍。因此,1/2.5 = 400 ms,让中断每40 ms触发一次。
从ISR存储器内部返回一个位字段。例如,我们可以使用
unsigned int
来存储样本的位字段。概念伪代码:(查找表会占用大量的flash,但还有很多其他方法可以做到这一点。您还可以将样本存储在RAM字节数组中,并使用memcmp()查找某些模式-速度较慢,占用RAM,但不占用任何闪存。
samples
将结束每40 ms取得的样本的比特流,因此111.(10次)对应于高和序列0 0 0...(10倍)对应于低。你可以建立一个10个样本+/-1左右的公差,这取决于你有多挑剔。由于这个计时器运行得很慢,我们会隐式地去抖动。LED不会反弹,所以我们基本上只是在这里做一些软件EMI滤波的方式。请记住系统时钟不准确,特别是如果您使用内部振荡器而不是外部石英。