简体   繁体   English

在纯 C 中在 atmega328 上设置中断

[英]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 PB0BP7设置为ONOFF

  • 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:更准确地说:

  • The function play() is called函数play()被调用
  • LEDs are starting to blink one after other LED 开始一个接一个地闪烁
  • If I press the BUTTON the 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 会ONOFF

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM