Обработка нескольких прерываний в avr - PullRequest
0 голосов
/ 10 октября 2018

Я новичок в программировании AVR, поэтому извините, если вопрос тривиален.

Использование:

  1. ОС: Windows7
  2. IDE: Atmel studio
  3. uC = m328p

Пины:

  1. Сигнал АЦП - ADC0 / PC0
  2. LED_values ​​- (PB0 - PB7)
  3. LED_START - PD1
  4. LED_LIGHT - PD0
  5. КНОПКА - PD2

Цель: при нажатии кнопки включается LED_START, и ее необходимо начать с преобразования.AVR получает прерывание и начинает преобразование АЦП.В основном программа имеет два прерывания.Я знаю, что прерывание INT0 имеет наивысший приоритет.

Я не знаю, как с ними справиться.Я пробовал несколько вещей, таких как добавление глобальной переменной «start» и ее изменение.А также, когда я только устанавливаю LED START, он включается и остается в этом состоянии до тех пор, пока LED_values ​​не достигнет определенного значения, тогда LED START сам выключается.

Так, пожалуйста, вы можете показать мне, как обрабатывать два прерывания, чтобы выполнить поставленную цель, и объяснить, что я делаю неправильно.

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

#define F_CPU 1000000UL
#define BIT_IS_SET(byte, bit) (byte & (1 << bit))
#define BIT_IS_CLEAR(byte, bit) (!(byte & (1 << bit)))

typedef enum{false, true} bool;

bool previousState = false;
bool start = false;

char num;

void setup();
void loop();
void ADC_init();
void EI_init(); // External Interrupt

int main(void)
{
    setup();
    loop();
}

void setup(){
    DDRC &= ~(0x1); // LDR Input
    DDRB = 0xFF; //LEDs value Output
    DDRD |= 0x3; //LED light LED start Output
    DDRD &= ~(1 << PIND2); //Button Input
}

void loop(){
    PORTD |= (1 << PIND2);
    EI_init();
    ADC_init();
    sei();
    if(start){
        ADCSRA |= (1 << ADSC);  
    }
    while(1){}

}

void ADC_init(){
    ADMUX = 0x60;
    ADCSRA = 0x8B;
    ADCSRB = 0x0;
    ADCH = 0x0;
}

ISR(ADC_vect) {
    PORTB = ADCH;   // assign contents of ADC high register to Port D pins
    int b = (int)ADCH;
    if(b > 180) { //100
        PORTD = 0x1;
    }else{
        PORTD &= ~(0x1);
    }
    _delay_ms(100);
    ADCSRA |= (1 << ADSC);      // start next ADC
}

void EI_init(){
    EIMSK |= (1 << INT0); // Interrupt enabled
    EICRA |= (1 << ISC00); // any state change
}

ISR(INT0_vect){
    if(BIT_IS_CLEAR(PORTD,PIND2)){
        start = true;
    }else{
    start = false;
    }
}

Вот схема: схема

1 Ответ

0 голосов
/ 10 октября 2018

Прежде всего, вы должны сделать start равным volatile, так как он используется как главным циклом, так и прерыванием.Ключевое слово volatile сообщает компилятору о том, что переменная может быть изменена вне ее контроля, поэтому она не может оптимизировать чтение или запись в переменную:

volatile bool start = false;

Во-вторых, вы, вероятно, захотите удалить эту строку, которую вы написали в конце loop:

while(1){}

Эта строка плохая, поскольку она заставляет вашу программу идти в бесконечный цикл, где она ничего не делает.Я думаю, что вы действительно хотите, чтобы код, который вы написали об этом в функции loop, выполнялся несколько раз.

Во-вторых, после того, как вы обнаружите, что установлен флаг start, вам, вероятно, нужно установить его на0, иначе это будет просто навсегда.

В-третьих, установка start в false в INT0 ISR может быть плохой идеей, потому что она может быть установлена ​​в false, прежде чем у вашего основного цикла появится шанснаблюдать, как это правда, и справиться с событием.Я думаю, это действительно зависит от того, что вы пытаетесь сделать.Вы можете попытаться добавить детали к своему вопросу о том, какую именно проблему вы пытаетесь решить с помощью AVR.См. В чем проблема XY? .

Вероятно, существуют другие проблемы с вашим кодом, которые необходимо отладить.Можете ли вы придумать какие-нибудь способы сделать это проще?Может быть, вы можете уменьшить количество используемых прерываний.Для отладки вы можете попробовать мигать несколькими светодиодами, чтобы выяснить, какие части вашей программы выполняются.

...