C 打开和关闭闪烁Led程序
我的目标是:制作一个可以打开和关闭“闪烁LED”程序的按钮。 PortD只有输出LED。 PORTBO有输入按钮。 微控制器:Atmega328p 问题:当前,当我按下开关的case1按钮时,“闪烁LED”程序启动。但我不能用按钮关闭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
#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;
}