在纯C语言中的atmega328上设置中断 [英] Setting up Interrupts on atmega328 in pure C

查看:223
本文介绍了在纯C语言中的atmega328上设置中断的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在使用Arduino Uno开发板,并且尝试使用纯C编写它而不使用Arduino的库.

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:

  • 将LEDs PB0设置为BP7 ONOFF.

在连接到Button的PD2上设置中断.

Set interrupt on PD2 connected to a Button.

按下按钮时,LED应当停止(暂停).

When the Button is pressed the LEDs should STOP (pause).

再次按下按钮时,LED应当再次转动ON
从最后一个LED开始,它是OFF.

When the Button is pressed Again the LEDs should turn ON again
starting from the last LED which was OFF.

更准确地说:

  • 函数play()被调用
  • LED开始互相闪烁
  • 如果按下按钮,play()功能应停止
  • The function play() is called
  • LEDs are starting to blink one after other
  • If I press the BUTTON the play() function should STOP

这意味着,如果连接到PB3的LED最后一个LED点亮,则当我再次按下按钮时,功能play()应该从PB4继续.

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

这时,功能play()会一直运行,如果我按下按钮,则连接到PD7的LED会变为ONOFF.

At this point the function play() runs forever and if I press the Button the LED connected to PD7 goes ON and OFF.

推荐答案

尝试类似的方法.

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

通过定义一个变量来保存打开的LED,然后每当恢复它时,它将从最后一个点亮的LED开始.一探究竟.如有任何更改.我只是提出了这个主意.希望对您有所帮助:)

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 :)

这篇关于在纯C语言中的atmega328上设置中断的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆