C 打开和关闭闪烁Led程序

C 打开和关闭闪烁Led程序,c,embedded,avr,C,Embedded,Avr,我的目标是:制作一个可以打开和关闭“闪烁LED”程序的按钮。 PortD只有输出LED。 PORTBO有输入按钮。 微控制器:Atmega328p 问题:当前,当我按下开关的case1按钮时,“闪烁LED”程序启动。但我不能用按钮关闭LED 注意:我是一个初学者,我想我可能不得不以某种方式使用中断,但不确定 #include <avr/io.h> // header file file for input output pins #include <util/delay.h&g

我的目标是:制作一个可以打开和关闭“闪烁LED”程序的按钮。 PortD只有输出LED。 PORTBO有输入按钮。 微控制器:Atmega328p

问题:当前,当我按下开关的case1按钮时,“闪烁LED”程序启动。但我不能用按钮关闭LED

注意:我是一个初学者,我想我可能不得不以某种方式使用中断,但不确定

#include <avr/io.h> // header file file for input output pins
#include <util/delay.h> // header file for delay.
#define DEBOUNCE_TIME 25 // time to wait while "de-bouncing" button

void init_ports_mcu()
{ /* set pin 5 of PORTB for output*/
    DDRD = 0xFF;
    PORTD = 0x00;
    PORTB |= (1 << DDB0);
}

unsigned char button_state()
{
    if( !(PINB & 0x01) )
    {
        _delay_ms( DEBOUNCE_TIME );
        if( (PINB & 0x01) ) return 1;
    }
    return 0;
}

int main( void )
{
    init_ports_mcu();
    unsigned char n_led = 1;

    while( 1 )
    {
        if( button_state() )
        {
            switch( n_led )
            {
                case 1:
                    while( 2 )
                    {
                        PORTD |= 0xFF;
                        _delay_ms( 1000 ); //delay 1 second

                        PORTD &= ~0xFF;
                        _delay_ms( 1000 );

                        if( button_state() ) // If the button is pressed break while loop
                        {
                            break;
                        }
                    }
                    break;
                case 2:
                    PORTD |= 0x00;
                    _delay_ms( 5000 ); //delay 1 second
                    n_led--; // swtiches back to case1 LED number
                    break;
            }
            //n_led ++;
        }
    }
    return 0;
}
#包含//输入输出引脚的头文件
#包含//头文件以进行延迟。
#定义“反弹跳”按钮时的反弹跳时间25//等待时间
void init_port_mcu()
{/*为输出设置端口B的引脚5*/
DDRD=0xFF;
端口D=0x00;

PORTB |=(1有很多问题。你的去盎司逻辑似乎有缺陷,它说:

如果按钮未按下,等待20毫秒,然后查看是否按下

最好说:

如果按钮状态已更改,请等待25毫秒,然后查看是否仍有更改

这仍然是一种相当粗糙的去盎司方法,但可能已经足够了。使用边缘中断和定时器中断是一种更稳健的解决方案()

在你的主体中,你最大的问题是,当你在拖延的时候,你没有处理任何其他事情——拖延是“忙碌的等待”。毫无疑问,逻辑上还有其他缺陷,但坦率地说,列举这些缺陷是徒劳的。需要重新设计

在不引入库代码或现有代码中未包含的硬件资源的情况下,我建议使用状态机循环,延迟为1,并使用计数器跟踪时间。状态为闪烁/不闪烁,子状态为LED on/LED off:

上面提到的一个问题是,无论循环体执行多长时间,滴答计数间隔都会延长。在按钮按下或释放的情况下,这将包括去盎司延迟,但在这种情况下,这不是一个特别的问题。在实时/时间关键型应用中,需要考虑这一点

通过定时器中断增加
滴答声
计数,而不是依赖延迟和循环体执行时间,可以实现改进和简化。或者,您可以使用定时器中断直接切换LED,只需打开/关闭定时器,或设置一个标志,阻止其在底座上切换LED在新闻发布会上


是的,你可以广泛使用中断和定时器硬件来实现这一点,你可以用很多方法来实现,但这并不是必须的。

不能说我遵循逻辑,代码格式也没有帮助。但是,
main
无符号字符n\u led=1;开始;
和唯一的时间
 n_led
之后的变化是
n_led-->
。我不知道
开关(n_led)
如何达到
案例2:
按钮状态()
函数是一个边缘检测器。为了使该函数返回1,需要在25毫秒的延迟时间内按下按钮。当代码执行
时,(1)
循环,大部分时间花费在
\u延迟(去盎司时间)
调用中,因此可以识别按钮按下。但是在
while(2)
循环中,大部分时间花费在
\u延迟(1000)中
呼叫,因此您需要将按钮按下的时间降到毫秒。祝您好运!概率是40比1。这里有一个有趣的尝试。删除秒延迟(1000)
。将
DEBOUNCE_TIME
更改为1000。现在,当您按下按钮时,LED将开始闪烁。如果您在LED亮起时按下按钮,LED将继续闪烁。但如果您在LED熄灭时按下按钮,LED将停止闪烁。请注意,此处显示的代码均未经过测试或编译,请将其视为已编译“说明性”,您可能仍然需要调试它。谢谢Clifford!
unsigned char button_state()
{
    static unsigned last_state = (PINB & 0x01) ;

    unsigned new_state = (PINB & 0x01) ;
    if( last_state != new_state )
    {
        _delay_ms( DEBOUNCE_TIME ) ;

        if( (PINB & 0x01) == new_state ) last_state = new_state ;
    }

    return last_state ;
}
int main( void )
{
    #define FLASH_INTERVAL 1000 ;

    init_ports_mcu();
    unsigned char flashing = 0 ;
    unsigned char led_state = 0 ;
    unsigned long tick = 0 ;
    unsigned flash_time = FLASH_INTERVAL ;
    unsigned char button_down = 0 ;

    for(;;)
    {
        // Toggle indication state on button-down event
        unsigned char btn = button_state() ;
        if( !button_down && btn )
        {
            button_down = 1 ;

            // Toggle LED mode
            flashing = flashing == 0 ? 1 : 0 ;

            // Initialise the flashing starting with LED on
            flash_time = FLASH_INTERVAL ;
            led_state = flashing ;
        }
        else if( !btn )
        {
            // Button released
            button_down = 0 ;
        }

        // If flashing "ON"...
        if( flashing )
        {
            // Set the LED state
            if( led_state ) 
            {
                PORTD |= 0xFF ;
            }
            else
            {
                PORTD &= 0xFF ;
            }

            // Toggle the LED state when the flash interval has elapsed
            flash_time-- ;
            if( flash_time == 0 )
            {
                flash_time = FLASH_INTERVAL ;
                led_state = led_state ? 0 : 1 ;
            }
        }
        else // flashing off
        {
            PORTD &= ~0xFF;
        }

        // Increment tick every ms
        _delay_ms(1) ;
        tick++ ;
    }

    return 0;
}