问题
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.
My project which I am working should work like this:
Set LEDs
PB0toBP7ONandOFF.Set interrupt on PD2 connected to a Button.
When the Button is pressed the LEDs should STOP (pause).
When the Button is pressed Again the LEDs should turn
ONagain
starting from the last LED which wasOFF.
To be more precise:
- The function
play()is called - LEDs are starting to blink one after other
- If I press the BUTTON the
play()function should STOP
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.
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.
回答1:
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. check it out. Change if there is anything. I just gave the idea. hope it helps :)
回答2:
I managed to fix it with the help of @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;
}
}
来源:https://stackoverflow.com/questions/54331621/setting-up-interrupts-on-atmega328-in-pure-c