脉冲宽度测量
Pulse width measurment
我想测量脉冲持续时间,但我需要测量 4 个信号,所以我不能使用定时器捕获中断,因为只有 1 个引脚 ICP1 提供该选项(或者可以?)。所以我尝试实现类似 arduino pulseIn 的东西,不同之处在于我使用计时器(arduino 有一些其他实现但非常相似)。
实际问题是 pulseIn 没有 return 任何东西,只是在无限循环中继续工作。
使用 ATmega16。
现在只在 PB2 上测试。
unsigned long pulseIn()
{
unsigned long duration = 0;
DDRB = 0x00;
/* Initiate timer and wait for the end of previous pulse*/
initTime1();
while(getPortBPin(2) == 1);
/* Wait for current pulse begin */
while(getPortBPin(2) != 1);
/* Time before previous pulse ended */
TCNT1 = 0;
overflowCounter = 0;
/* Wait for current pulse end */
while(getPortBPin(2) == 1);
/* Closk freq is 2 MHz = 1/2 us per tick */
duration = (TCNT1+overflowCounter*65536)/2;
overflowCounter = 0;
stopTimer1();
return duration;
}
void initTime1()
{
/* Noise filtering */
TCCR1B = (1 << ICNC1);
/* Set prescaling factor to 8 */
TCCR1B |= (1 << CS11);
/* Enable overflow interruption */
TIMSK = (1 << TOIE1);
/* Clear counter */
TCNT1 = 0;
}
void stopTimer1()
{
TCCR1B = 0;
TIMSK = 0;
TCNT1 = 0;
}
uint8_t getPortBPin(uint8_t pin)
{
if(pin < 0 || pin > 8)
{
return 0;
}
return (uint8_t)((PINB >> pin) & 0x01);
}
更新
这是我的 proteus 方案。信号来自发电机。频率为 1kHz,宽度为 50%。幅度为 5 伏。
更新
抱歉,这是一个愚蠢的错误。它工作正常。调试我没有按预期工作的东西。
我找不到你的代码哪里有问题。但这里有一些我可以遵循的调试步骤:
1) pin 总是读什么?逻辑1
或0
,可能是脉冲电压不够高,AVR感应不到。
2) duration = (TCNT1+overflowCounter*65536 - timestamp)/2;
中的乘法占用了很多 CPU 时间,可能比脉冲需要更多时间,因此在 AVR 进入最后一个 while
循环之前脉冲变低.当然,这取决于脉冲是连续的还是只有一个脉冲。我也不知道你为什么要使用 timestamp
因为你已经清除了 overflowcounter
。我认为应该删除这一行。
更新
测量四个信号脉冲,我推荐使用PORTB变化中断,当中断发生时,你可以屏蔽端口以查看哪个信号发生变化并计算它的持续时间。
我想测量脉冲持续时间,但我需要测量 4 个信号,所以我不能使用定时器捕获中断,因为只有 1 个引脚 ICP1 提供该选项(或者可以?)。所以我尝试实现类似 arduino pulseIn 的东西,不同之处在于我使用计时器(arduino 有一些其他实现但非常相似)。
实际问题是 pulseIn 没有 return 任何东西,只是在无限循环中继续工作。
使用 ATmega16。 现在只在 PB2 上测试。
unsigned long pulseIn()
{
unsigned long duration = 0;
DDRB = 0x00;
/* Initiate timer and wait for the end of previous pulse*/
initTime1();
while(getPortBPin(2) == 1);
/* Wait for current pulse begin */
while(getPortBPin(2) != 1);
/* Time before previous pulse ended */
TCNT1 = 0;
overflowCounter = 0;
/* Wait for current pulse end */
while(getPortBPin(2) == 1);
/* Closk freq is 2 MHz = 1/2 us per tick */
duration = (TCNT1+overflowCounter*65536)/2;
overflowCounter = 0;
stopTimer1();
return duration;
}
void initTime1()
{
/* Noise filtering */
TCCR1B = (1 << ICNC1);
/* Set prescaling factor to 8 */
TCCR1B |= (1 << CS11);
/* Enable overflow interruption */
TIMSK = (1 << TOIE1);
/* Clear counter */
TCNT1 = 0;
}
void stopTimer1()
{
TCCR1B = 0;
TIMSK = 0;
TCNT1 = 0;
}
uint8_t getPortBPin(uint8_t pin)
{
if(pin < 0 || pin > 8)
{
return 0;
}
return (uint8_t)((PINB >> pin) & 0x01);
}
更新
这是我的 proteus 方案。信号来自发电机。频率为 1kHz,宽度为 50%。幅度为 5 伏。
更新
抱歉,这是一个愚蠢的错误。它工作正常。调试我没有按预期工作的东西。
我找不到你的代码哪里有问题。但这里有一些我可以遵循的调试步骤:
1) pin 总是读什么?逻辑1
或0
,可能是脉冲电压不够高,AVR感应不到。
2) duration = (TCNT1+overflowCounter*65536 - timestamp)/2;
中的乘法占用了很多 CPU 时间,可能比脉冲需要更多时间,因此在 AVR 进入最后一个 while
循环之前脉冲变低.当然,这取决于脉冲是连续的还是只有一个脉冲。我也不知道你为什么要使用 timestamp
因为你已经清除了 overflowcounter
。我认为应该删除这一行。
更新
测量四个信号脉冲,我推荐使用PORTB变化中断,当中断发生时,你可以屏蔽端口以查看哪个信号发生变化并计算它的持续时间。