看门狗和电压控制不工作微控制器 [AVR128DB48 Curiosity Nano]
WatchDog and Voltage control did not work microcontroller[AVR128DB48 Curiosity Nano]
您好,我正在使用 Watchdog 来控制 LED 灯。微控制器通过电缆连接到笔记本电脑。微控制器的输入是 5V。现在在引脚上有一个引脚 PB2
5V
直接连接到输入。如果我从 PB2
移除 5V 母对公电线,我想这样做,LED 将关闭。当我用 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/低)。 set/clear 的引脚由传入的 位掩码 决定。因此:
PORTB.OUTCLR=0x00; // Green
什么都不做,它将 no pins 设置为低状态。关闭红色 LED(我假设是 PB3)并打开绿色 LED(PB0):
PORTB.OUTCLR = PIN3_bm ;
PORTB.OUTSET = PIN0_bm ;
现在,在这种情况下,您对 PORTB.IN
的测试就好像它是布尔值一样有效,因为您只有一个输入。但是如果你有多个输入,那么它就不会区分,并且在任何情况下都将整数表达式当作布尔值来使用是一个坏习惯。您应该明确测试 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 秒。为了获得更大的灵活性,您通常会实现一个定时器中断来计算 smaller 周期的数量并计算定时器重新加载的次数。例如:
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
}
最后 评论您的代码。它会让你明白你正在尝试做什么,当你 post 一个问题时,它会告诉其他人你正在尝试做什么,它会让你的问题更简单,因为解释与代码,因此不仅清楚您希望代码做什么,而且清楚您认为它是如何做到的。
综上所述,以下比较合理:
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断开后,watchdog不维护,所以4秒后会reset,然后重启程序,等待PB2连接上。我想我应该 class 这样的代码作为“肮脏的把戏”,而不是被认为是正常或特别有用的东西。
您好,我正在使用 Watchdog 来控制 LED 灯。微控制器通过电缆连接到笔记本电脑。微控制器的输入是 5V。现在在引脚上有一个引脚 PB2
5V
直接连接到输入。如果我从 PB2
移除 5V 母对公电线,我想这样做,LED 将关闭。当我用 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/低)。 set/clear 的引脚由传入的 位掩码 决定。因此:
PORTB.OUTCLR=0x00; // Green
什么都不做,它将 no pins 设置为低状态。关闭红色 LED(我假设是 PB3)并打开绿色 LED(PB0):
PORTB.OUTCLR = PIN3_bm ;
PORTB.OUTSET = PIN0_bm ;
现在,在这种情况下,您对 PORTB.IN
的测试就好像它是布尔值一样有效,因为您只有一个输入。但是如果你有多个输入,那么它就不会区分,并且在任何情况下都将整数表达式当作布尔值来使用是一个坏习惯。您应该明确测试 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 秒。为了获得更大的灵活性,您通常会实现一个定时器中断来计算 smaller 周期的数量并计算定时器重新加载的次数。例如:
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
}
最后 评论您的代码。它会让你明白你正在尝试做什么,当你 post 一个问题时,它会告诉其他人你正在尝试做什么,它会让你的问题更简单,因为解释与代码,因此不仅清楚您希望代码做什么,而且清楚您认为它是如何做到的。
综上所述,以下比较合理:
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断开后,watchdog不维护,所以4秒后会reset,然后重启程序,等待PB2连接上。我想我应该 class 这样的代码作为“肮脏的把戏”,而不是被认为是正常或特别有用的东西。