如何解决看门狗和电压控制不工作微控制器[AVR128DB48 Curiosity Nano]
嗨,我正在使用看门狗来控制 LED 灯。微控制器通过电缆连接到笔记本电脑。微控制器的输入为 5V。现在在引脚上有一个引脚 PB2
,它是直接连接到输入的 5V
。如果我从 LED 关闭 PB2
移除那根 5V 母对公线,我想这样做。当我用 PB2
再次插入时,指示灯亮起,然后看门狗每 4 秒调用一次并关闭红灯
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/wdt.h>
#define WDTO_4S 8
void fun_red(){
PORTB.IN=0x04; // PB2 as input
PORTB.DIR=0x09; // PB0 and PB3 output
PORTB.OUTCLR=0x00; // Green
PORTB.OUTSET=0x01;
wdt_enable(WDTO_4S);
do
{
if (PORTB.IN)
{
PORTB.OUTCLR=0x00; // red
}
else{
PORTB.OUTSET=0x08;
}
} while(1);
wdt_reset();
}
int main(void)
{
fun_red();
}
解决方法
好的,所以在编辑中,您似乎希望使用 PB2 作为输入来控制 PB3 上的 LED - 对吗?
您不应该考虑电压,这些是数字 I/O,它们具有高状态和低状态以及两者之间的阈值。您的输入将在高于 0.8 伏时变高。但是,如果您启用了内部上拉,那么通过断开电线来移除输入电压将没有任何效果,如果您没有启用,它将浮动并且可能不会触发逻辑 0(零)。
您要么需要一个外部下拉电阻,要么启用内部上拉并反转逻辑 - 即当输入低时 LED 亮,输入高时 LED 关闭。然后,不是将 PB2 连接到 5V,而是将其连接到 GND。由于内部上拉,去掉 GND 连接将导致逻辑状态变为 1。此外,这更安全,因为它避免了对输入施加过高电压和损坏处理器的任何风险。
鉴于您明显缺乏电子知识,我还想问一下您是如何连接 LED 的。您应该有一个限流串联电阻,并以正确的方式连接 LED。
目前尚不清楚看门狗的目的是什么。它没有任何作用,但如果您启用它,您必须维护它以防止处理器重置。看门狗的目的是在软件停止正常运行时通过在正常的软件执行路径中定期复位处理器来复位处理器,因此如果正常路径停止执行则系统重新启动。
首先阅读这篇入门应用笔记:Getting Started with GPIO
首先,你误解了GPIO寄存器的功能。 PORTB.IN
读取配置为输入的 PORTB 引脚的输入状态。它是只读,所以:
PORTB.IN=0x04; // PB2 as input
没有效果,当然不会将引脚配置为输入。这是由 DDR
完成的,所以:
PORTB.DIR=0x09; // PB0 and PB3 output
将 PB0 和 PB3 设置为输出,任何不是输出的都是输入 - 因此 PB2 凭借这条线成为输入。
现在,如果您按照我的建议进行操作并使用 PB2 的内部上拉,您必须在 PIN2CTRL
寄存器中启用它:
PORTB.PIN2CTRL = 0x08 ; // PULLUPEN
顺便说一句,所有这些位都定义了符号,因此您应该能够编写:
PORTB.PIN2CTRL = PORT_PULLUPEN_bm ;
这也使得注释变得不必要。
寄存器 OUTSET
和 OUTCLR
分别设置(逻辑 1/高)和清除(逻辑 0/低)。要设置/清除的引脚由传入的位掩码决定。因此:
PORTB.OUTCLR=0x00; // Green
什么都不做,它将无引脚设置为低电平状态。将红色 LED(我假设为 PB3)关闭并打开绿色 LED (PB0):
PORTB.OUTCLR = PIN3_bm ;
PORTB.OUTSET = PIN0_bm ;
现在,您对 PORTB.IN
的测试就好像它是布尔值一样在这种情况下会起作用,因为您只有一个输入。但是如果你有多个输入,它就不会区分 then,无论如何使用整数表达式就像是布尔值一样是一个坏习惯。您应该明确测试 PB2 的状态:
// If PB2 is low (GND wire connected)
if( (PORTB.IN & PIN2_bm) == 0 )
{
PORTB.OUTSET = PIN3_bm ; // red on
}
else
{
PORTB.OUTCLR = PIN3_bm ; // red off
}
看门狗定时器的目的是在软件无法正常运行时重置处理器。您设置了超时,然后您需要在代码中定期重置它以防止重置。这不是您用于延迟的通用目的。为此,您将使用硬件计时器。不幸的是,它变得有点复杂;对于运行在 24MHz 的电路板,16 位 TIMER1 的最大定时器周期约为 2.8 秒。为了获得更大的灵活性,您通常会实现一个定时器中断来计算多个较小周期并计算定时器重新加载的次数。例如:
volatile unsigned tick = 0 ;
ISR (TIMER1_OVF_vect) // Timer1 ISR
{
tick++ ;
}
void tickStart()
{
TCCR1B = (1<<CS11) // Prescaler 24MHz / 8
TCNT1 = 3000 ; // 1 ms at 24MHz/8
TCCR1A = 0x00;
TIMSK = (1 << TOIE1) ; // Enable timer1 overflow interrupt(TOIE1)
sei(); // Enable global interrupts
}
unsigned getTick()
{
unsigned t = 0 ;
do
{
t = tick ;
} while( tick != t ) ;
return t ;
}
然后在监视 P2 的同时延迟 4 秒,您可能会这样做:
// Wait 4 seconds or until PB2 disconnected
unsigned start = getTick() ;
while( getTick() - start < 4000 &&
(PORTB.IN & PIN2_bm) != 0 )
{
// waiting
}
最后评论你的代码。它将让您了解您正在尝试做什么,并且当您发布问题时,它会告诉其他人您正在尝试做什么,并且通过将解释与代码一致,它会使您的问题变得更简单,因此它是不仅要清楚你想让代码做什么,还要清楚你认为它是如何做的。
综合起来,以下更合理:
void fun_red( void )
{
// Initialise I/O
PORTB.PIN2CTRL = PORT_PULLUPEN_bm ;
PORTB.DIR = PIN0_bm | PIN3_bm ;
PORTB.OUTSET = PIN0_bm ; // Green on
for(;;)
{
// Red off
PORTB.OUTCLR = PIN3_bm ;
// Wait for PB2 to be connected (to GND)
while( (PORTB.IN & PIN2_bm) == 0 )
{
// waiting
}
// Red on
PORTB.OUTSET = PIN3_bm ;
// Wait 4 seconds or until PB2 disconnected
unsigned start = getTick() ;
while( getTick() - start < 4000 &&
(PORTB.IN & PIN2_bm) != 0 )
{
// waiting
}
// Wait for PB2 to be reconnected
while( (PORTB.IN & PIN2_bm) != 0)
{
// waiting
}
}
}
int main( void )
{
tickStart() ;
fun_red() ;
}
请记住,您将 PB2 连接到 GND(0 伏)而不是 5V/Vcc。问题中的要求并不完全清楚,但这会做什么(未经测试 - 我没有硬件)是:
- 当 PB2 断开连接时,LED 将熄灭,
- 连接 PB2 时,LED 将亮起 4 秒或直到 PB2 重新连接。
虽然这不是它的预期目的,也不是真正用于通用目的,因为这个要求非常简单,我们可以通过看门狗定时器实现所需的行为,如下所示:
void fun_red()
{
// Initialise I/O
PORTB.PIN2CTRL = PORT_PULLUPEN_bm ;
PORTB.DIR = PIN0_bm | PIN3_bm ;
// Green on
PORTB.OUTSET = PIN0_bm ;
// Red off
PORTB.OUTCLR = PIN3_bm ;
// Enable watchdog
wdt_enable(WDTO_4S);
for(;;)
{
// Maintain watchdog while waiting for
// PB2 to be connected (to GND)
while( (PORTB.IN & PIN2_bm) == 0 )
{
wdt_reset() ;
}
// Red on
PORTB.OUTSET = PIN3_bm ;
// Maintain watchdog while waiting for
// PB2 to be disconnected (from GND)
while( (PORTB.IN & PIN2_bm) != 0)
{
wdt_reset() ;
}
// Red off
PORTB.OUTCLR = PIN3_bm ;
// Wait for PB2 to be reconnected (to GND)
// without maintaining watchdog. Will reset after 4 seconds
// if not reconnected.
while( (PORTB.IN & PIN2_bm) != 0)
{
// do nothing
}
}
}
这里在 PB2 断开后,看门狗不保持,因此 4 秒后将发生复位并重新启动程序并等待 PB2 连接。我想我应该把这样的代码归类为“肮脏的把戏”,而不是被认为是正常或特别有用的东西。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。