c-切换闪烁的程序打开和关闭

  • 本文关键字:程序 闪烁 c embedded avr
  • 更新时间 :
  • 英文 :


我的目标:制作一个可以打开和关闭"闪烁LED";程序端口D只有输出LED。PORTBO有输入按钮。微控制器:Atmega328p

问题:当前当我按下开关的按钮外壳1时;闪烁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;
}

存在许多问题。你的退出逻辑似乎有缺陷,它说:

如果按钮未按下,请等待20ms,然后查看是否按下。

更好地说:

如果按钮状态已更改,请等待25ms,然后查看是否保持更改

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 ;
}

这仍然是一种相当粗糙的去抖动方法,但可能已经足够了。使用边缘中断和定时器中断是一个更健壮的解决方案(例如伪代码(。

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

在不引入现有代码中没有的库代码或硬件资源的情况下,我建议使用一个延迟为1的状态机循环,并使用计数器来跟踪时间。状态为闪烁/不闪烁LED打开/LED关闭的子状态:

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;
}

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

可能通过定时器中断来增加tick计数,而不是依赖于延迟和循环体执行时间来进行改进和简化。或者,您可以使用定时器中断直接切换LED,只需打开/关闭定时器或设置一个标志,阻止其在按钮按下事件中切换LED。

所以,是的,你可以广泛使用中断和定时器硬件来实现这一点,有很多方法可以做到,但这绝对不是必要的。

最新更新