[英]Setting up Interrupts on atmega328 in pure C
I am currently working on an Arduino Uno Board and I am trying to write it in pure C
without the use of Arduino's Libraries.我目前正在开发一个 Arduino Uno 开发板,我试图在不使用 Arduino 库的情况下用纯C
编写它。
My project which I am working should work like this:我正在工作的项目应该是这样的:
Set LEDs PB0
to BP7
ON
and OFF
.将 LED PB0
至BP7
设置为ON
和OFF
。
Set interrupt on PD2 connected to a Button.在连接到按钮的 PD2 上设置中断。
When the Button is pressed the LEDs should STOP (pause).按下按钮时,LED 应停止(暂停)。
When the Button is pressed Again the LEDs should turn ON
again当再次按下按钮时,LED 应再次ON
starting from the last LED which was OFF
.从最后一个OFF
LED 开始。
To be more precise:更准确地说:
play()
is called函数play()
被调用play()
function should STOP如果我按下按钮play()
函数应该停止This means that if the LED connected to PB3
was last LED ON, when I press the Button again the function play()
should continue from PB4
.这意味着,如果连接到PB3
的 LED 上次 LED 亮起,当我再次按下按钮时,函数play()
应该从PB4
继续。
Here is what I have so far:这是我到目前为止所拥有的:
#ifndef F_CPU
#define F_CPU 16000000UL
#endif
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
void play( void );
volatile uint8_t buttonWasPressed = 0;
const unsigned char LEDS[] = { PB0, PB1, PB2, PB3, PB4, PB5 };
int main(void)
{
DDRB = 0xFF; /// Set PORTB as OUTPUT
DDRD |= ( 1 << PD7 ); /// Set PIN7 IN DDRD as INPUT
PORTD &= ~( 1 << PD7 ); /// Set PIN7 on PORTD to LOW
DDRD &= ~( 1 << PD2 ); // Clear the PD2 pin and set PD2 (PCINT0 pin) now as input
PORTD |= (1 << PD2); // Set PIN PD2 as INPUT with pull-up enabled
EICRA |= (1 << ISC00); // set INT0 to trigger on ANY logic change
EIMSK |= (1 << INT0); // Turns on INT0
sei(); // turn on interrupts
while(1)
{
play();
}
}
ISR (INT0_vect)
{
uint8_t buttonState = PIND & ( 1 << PD2 );
if ( buttonState )
{
if ( buttonWasPressed == 0 )
{
PORTD ^= ( 1 << PD7 ); /// SET PIN 4 IN PORT B TO LOW
_delay_ms( 200 );
buttonWasPressed = 1; /// update button state
}
}
else /// The button is not pressed
{
buttonWasPressed = 0; /// Update the button state
}
}
void play( void )
{
for ( uint8_t i = 0 ; i < 6 ; i++ )
{
PORTB |= ( 1 << LEDS[i] ); ///Turn LED ON
_delay_ms( 250 );
PORTB &= ~( 1 << LEDS[i] ); ///Turn LED OFF
_delay_ms( 250 );
}
}
At this point the function play()
runs forever and if I press the Button the LED connected to PD7
goes ON
and OFF
.此时,函数play()
将永远运行,如果我按下按钮,连接到PD7
的 LED 会ON
和OFF
。
Try something like this.尝试这样的事情。
#ifndef F_CPU
#define F_CPU 16000000UL
#endif
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
void play( unsigned int a );
ISR (INT0_vect);
volatile uint8_t buttonWasPressed = 0;
const unsigned char LEDS[] = { PB0, PB1, PB2, PB3, PB4, PB5 };
unsigned int ledNum = 0;
int main(void)
{
DDRB = 0xFF; /// Set PORTD as OUTPUT
DDRD |= ( 1 << PD7 ); /// Set PIN7 IN DDRD as INPUT
PORTD &= ~( 1 << PD7 ); /// Set PIN7 on PORTD to LOW
DDRD &= ~( 1 << PD2 ); // Clear the PD2 pin and set PD2 (PCINT0 pin) now as input
PORTD |= (1 << PD2); // Set PIN PD2 as INPUT with pull-up enabled
EICRA |= (1 << ISC00); // set INT0 to trigger on ANY logic change
EIMSK |= (1 << INT0); // Turns on INT0
sei(); // turn on interrupts
while(1)
{
if(buttonWasPressed == 1)
play(ledNum);
}
}
ISR (INT0_vect)
{
uint8_t buttonState = PIND & ( 1 << PD2 );
if ( buttonState )
{
if ( buttonWasPressed == 0 )
{
PORTD ^= ( 1 << PD7 ); /// SET PIN 4 IN PORT B TO LOW
_delay_ms( 200 );
buttonWasPressed = 1; /// update button state
}
}
else /// The button is not pressed
{
buttonWasPressed = 0; /// Update the button state
}
}
void play( unsigned int a )
{
for ( uint8_t i = a ; i < 6 ; i++ )
{
PORTB |= ( 1 << LEDS[i] ); ///Turn LED ON
_delay_ms( 250 );
PORTB &= ~( 1 << LEDS[i] ); ///Turn LED OFF
_delay_ms( 250 );
ledNum=i;
}
}
by defining a variable to save which LED it was on then whenever it is resumed it will start from the last lit LED.通过定义一个变量来保存它所在的 LED,然后每当它恢复时,它将从最后一个点亮的 LED 开始。 check it out.一探究竟。 Change if there is anything.有事就换。 I just gave the idea.我只是给出了想法。 hope it helps :)希望能帮助到你 :)
I managed to fix it with the help of @Althaf1467.我在@Althaf1467 的帮助下设法修复了它。
The working code is:工作代码是:
#ifndef F_CPU
#define F_CPU 16000000UL
#endif
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define LEDS_LENGTH 6
void play( void );
volatile uint8_t state = 0 ;
const unsigned char LEDS[] = { PB0, PB1, PB2, PB3, PB4, PB5 };
int main( void )
{
DDRB = 0xFF; /// Set PORTD as OUTPUT
DDRD |= ( 1UL << PD7 ); /// Set PIN7 IN DDRD as INPUT
PORTD &= ~( 1UL << PD7 ); /// Set PIN7 on PORTD to LOW
DDRD &= ~( 1UL << PD2 ); /// Clear the PD2 pin and set PD2 (PCINT0 pin) now as input
PORTD |= ( 1UL << PD2 ); /// Set PIN PD2 as INPUT with pull-up enabled
EICRA |= ( 1UL << ISC00 ); /// set INT0 to trigger on ANY logic change
EIMSK |= ( 1UL << INT0 ); /// Turns on INT0
sei(); /// turn on interrupts
while(1)
{
play();
}
}
ISR ( INT0_vect )
{
if ( PIND & ( 1UL << PD2 ) )
{
PORTD ^= ( 1UL << PD7 ); /// SET PIN 4 IN PORT B TO LOW
state ^= ( 1 << 0 ); /// Swap the Buton State from 0 to 1 and back to 0 ...
_delay_ms( 500 );
}
}
void play( void )
{
static uint8_t step = 0;
while( step < LEDS_LENGTH )
{
if ( state == 1 )
{
break;
}
PORTB |= ( 1UL << LEDS[ step ] ); /// Turn LED ON
_delay_ms( 250 );
PORTB &= ~( 1UL << LEDS[ step ] ); /// Turn LED OFF
_delay_ms( 250 );
step++;
}
if ( step == LEDS_LENGTH )
{
step = 0;
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.