【问题标题】:WatchDog and Voltage control did not work microcontroller[AVR128DB48 Curiosity Nano]看门狗和电压控制微控制器不起作用[AVR128DB48 Curiosity Nano]
【发布时间】:2021-09-18 21:31:21
【问题描述】:

您好,我正在使用看门狗来控制 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();
}

【问题讨论】:

  • 你永远不会到达wdt_reset()。另外,你为什么要定义#define WDTO_4S 8?您应该使用来自&lt;avr/wdt.h&gt; 的宏。
  • 另外,我不清楚你为什么要使用看门狗。
  • @ThomasJager 我想看 LED 4 秒变红灯,然后将电压调低并关闭
  • @ThomasJager 我正在使用 AVR128DB48 Curiosity Nano
  • 这些都没有任何意义,我什至不知道你在做什么。如果您尝试使用看门狗来实现应用程序功能,那么您应该忘记这是一个非常糟糕的主意。

标签: c embedded microcontroller avr watchdog


【解决方案1】:

好的,所以在编辑中,您似乎希望使用 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 ;

这也使得评论变得不必要。

寄存器OUTSETOUTCLR,分别设置(逻辑1/高)和清除(逻辑0/低)。要设置/清除的引脚由传入的位掩码确定。因此:

PORTB.OUTCLR=0x00; // Green

什么都不做,它将 no pins 设置为低电平状态。关闭红色 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连接。我想我应该把这样的代码归类为“肮脏的伎俩”,而不是被认为是正常或特别有用的东西。

【讨论】:

  • OP 需要阅读此内容,也许您也阅读过 Clifford,这是一个现成的板。 PB2 记录在 PB2 和地之间通过一个开关连接(假设为常开瞬时 SPST)。它说不需要上拉就可以在单片机中启用上拉。这意味着 PB2 通常为高电平(确切的电压值无关紧要,在 gpio 中读取为 1)并且按下时读取为低电平。 LED 通过一个电阻连接在 vcc_target 和 pb3 之间,这意味着写入 0 使 LED 点亮,写入 1 使其熄灭。
  • 如问题和答案中所写,它将简单地反映按钮。如果在问题的最后,您希望按下按钮时 LED 亮 4 秒钟,您需要做更多的工作,并且您不想使用 WDT 使用其他计时器。或者如果您使用 wdt 然后如果按下按钮(如果 pb2 为低电平)然后打开 LED 并进入不调用 wdt 重置的无限​​循环,并将 wdt 设置为 4 秒...
  • @old_timer 您参考的是什么文档?我确实引用了Curiosity Nano datasheet,板载开关位于 PC7 上,LED 位于 PC6 上。提出了一个问题,但是为什么这段代码不会同时使用板载开关和板载 LED - 至少是为了避免需要了解电子设备。
  • 我已经说过需要使用内部上拉 - 我不明白你的意思 - 你的评论重复了我的大部分答案(也许 可能会阅读那个 ;-)。如果您有一个答案,如果 this 答案有问题,请具体说明 - 我会解决它(已经很晚了)。
  • 我确实错过了大约 4 秒的要点——尽管在编辑中也澄清了这一点(有点)。 OP 代码似乎没有表明这一点,看门狗定时器显然是无关紧要的。会修复的。
猜你喜欢
  • 2021-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-09
  • 1970-01-01
  • 1970-01-01
  • 2013-09-07
相关资源
最近更新 更多