AVR — вектор прерывания и глобальная переменная

Я использую ATmega32 для прерывания каждые 32 мс для выполнения каких-то произвольных действий, что на данный момент не очень важно.
Я использую переполнение таймера timer0 для прерывания, которое работает предсказуемо и идеально.

Моя проблема в том, что у меня есть глобальная переменная:

volatile int isSampling;

Это не записывается в векторе прерывания. Я читал, что целое число должно быть volatile, чтобы исключить возможность оптимизации компилятора, но я объявил его как volatile, и оно все еще не работает.

#include <AVR/IO.h>
#include <util/delay.h> 
#include <avr/interrupt.h>

char studentID[12]            = {'S',1,2,3,4,5,6,7,'A','B','C','D'};

char buffer[72]; //Max bitlength = 6. * studentID length
char repcount[72];
int pointer;

volatile int isSampling;

void setup(void);
void startup(void);
void loadValue(unsigned char loadedValue);
void processValue(unsigned char processedValue, short bitLength);
void sendDot(void);
void sendDash(void);



int main(){

    setup();
    while(1)
    {

        if (isSampling == 1){
            startup();
            int i;
            for (i = 0; i < 12; i++){
                loadValue(studentID[i]);
                //Flash lights after letter sent.
                _delay_ms(500);
                PORTB = 0xF0;
                _delay_ms(500);
            }
        }
    }   
}

void setup(void){
    DDRB = 0xFF;
    sei();  
    TCCR0 = TCCR0 | 0x05;                   
    TIMSK|=(1<<TOIE0);  
    TCNT0 = 0;
    pointer = 0; 
    isSampling = 1;
}

ISR(TIMER0_OVF_vect)
{   
    //Every 32ms this interrupt vector is called.
    isSampling = 0;
}

void startup(void){
    //Play LED startup pattern
    int i;
    for (i = 0; i < 4; i++){
        PORTB = 0b11110011; //Bit 5 is constantly sampled. 4 is output
        _delay_ms(250);
        PORTB = PORTB & 0x00;
        _delay_ms(250);
    }
    _delay_ms(500);
    _delay_ms(500);
}

void loadValue(unsigned char loadedValue){
    switch (loadedValue){
        case   1: processValue(0b01111000, 5);
        case   2: processValue(0b00111000, 5);
        case   3: processValue(0b00011000, 5);
        case   4: processValue(0b00001000, 5);
        case   5: processValue(0b00000000, 5);
        case   6: processValue(0b10000000, 5);
        case   7: processValue(0b11000000, 5);
        case   8: processValue(0b11100000, 5);
        case   9: processValue(0b11110000, 5);
        case   0: processValue(0b11111000, 5);
        case 'A': processValue(0b01000000, 2);
        case 'B': processValue(0b10000000, 4);
        case 'C': processValue(0b10100000, 4);
        case 'D': processValue(0b10000000, 3);
        case 'E': processValue(0b00000000, 1);
        case 'F': processValue(0b00100000, 4);
        case 'G': processValue(0b11000000, 3);
        case 'H': processValue(0b00000000, 4);
        case 'I': processValue(0b00000000, 2);
        case 'J': processValue(0b01110000, 4);
        case 'K': processValue(0b10100000, 3);
        case 'L': processValue(0b01000000, 4);
        case 'M': processValue(0b11000000, 2);
        case 'N': processValue(0b10000000, 2);
        case 'O': processValue(0b11100000, 3);
        case 'P': processValue(0b01100000, 4);
        case 'Q': processValue(0b11010000, 4);
        case 'R': processValue(0b01000000, 3);
        case 'S': processValue(0b00000000, 3);
        case 'T': processValue(0b10000000, 1);
        case 'U': processValue(0b00100000, 3);
        case 'V': processValue(0b00010000, 4);
        case 'W': processValue(0b01100000, 3);
        case 'X': processValue(0b10010000, 4);
        case 'Y': processValue(0b10110000, 4);
        case 'Z': processValue(0b11000000, 4);
        case '.': processValue(0b01010100, 6);
        case ',': processValue(0b11001100, 6);
        case '?': processValue(0b00110000, 6);
        case '!': processValue(0b00110000, 5);
        case ':': processValue(0b11100000, 6);
        case '=': processValue(0b10001000, 5);
    }
}

void processValue(unsigned char processedValue, short bitLength){
    unsigned char result;
    int i;
    //Enter Loop at the length of bits in numerical morse code
    for (i = 0; i < bitLength; i++){
        result = processedValue & 0x80;
        processedValue = processedValue << 1;
        if (result) sendDash();
        if (!result) sendDot();
        _delay_ms(1000);
    }
}

void sendDot(void){
    //Send Dot
    PORTB = 0x05;
    _delay_ms(250);
    PORTB = 0x00;
}

void sendDash(void){
    //Send Dash
    PORTB = 0x06;
    _delay_ms(750);
    PORTB = 0x00;
}

Хорошо, я нашел оскорбительный код, который вызывает проблему, но я не уверен, почему он ее вызывает. Когда я удаляю loadValue(studentID[i]) из основного цикла while, код работает, как и предполагалось. Но когда я ставлю его обратно, он снова ломается.


person Ospho    schedule 31.05.2011    source источник
comment
Кстати. Я предполагаю, что вы используете код C. C++ не поддерживает default-int.   -  person 0xbadf00d    schedule 31.05.2011
comment
Для этой чрезвычайно короткой программы я настоятельно рекомендую вам прочитать сгенерированный ассемблерный код.   -  person unwind    schedule 31.05.2011
comment
Вы сказали переполнение timer0 для прерывания, которое работает предсказуемо и отлично. Вы действительно это проверяли? Если нет, я предлагаю вставить в ISR некоторый код, который переключает строку вывода, и наблюдать за ним с помощью области видимости.   -  person Curd    schedule 31.05.2011
comment
Я думаю, проблема в том, что доступ для записи к isSampling не транслируется в основной цикл или никогда не записывается.   -  person 0xbadf00d    schedule 31.05.2011
comment
Хорошо, я добавил код в соответствии с просьбой. Я нашел оскорбительный код, похоже, это вызывается методом loadValue(studentID[i]). Я понятия не имею, почему, хотя...   -  person Ospho    schedule 31.05.2011
comment
И да, я могу проверить, что прерывания работают, 100%   -  person Ospho    schedule 31.05.2011
comment
@Oliver: рискну предположить, что функция _delay_ms каким-то образом возится с маской прерывания. Попробуйте упростить код до гораздо более простого приложения и посмотрите, не возникнет ли проблема.   -  person Oliver Charlesworth    schedule 31.05.2011
comment
Добавьте default: arm в свой оператор switch.   -  person John R. Strohm    schedule 31.05.2011
comment
@ Оли Чарльзворт. Кажется, вы правы, когда я комментирую все функции _delay_ms, код работает, как и предполагалось, и только после того, как я их поместил, они путаются с глобальной переменной. Я не уверен, но, возможно, это связано с атомарной природой isSampling? Пожалуйста, ответьте на вопрос, чтобы я мог принять. Спасибо.   -  person Ospho    schedule 01.06.2011
comment
@Oliver: я не понимаю, как _delay_ms может влиять на глобальную переменную; в лучшем случае я мог бы представить, что он очищает маску прерывания, так что ваш ISR некоторое время отключается.   -  person Oliver Charlesworth    schedule 01.06.2011


Ответы (3)


Строки _delay_ms(500) вызывают проблему, как заявил Оли Чарльзворт. Функция _delay_ms() может привести к непредсказуемому поведению, если установлено высокое значение (выше 250 мс).

person Ospho    schedule 03.09.2012
comment
Как вы думаете, почему существует непредсказуемое поведение? Источник: Максимально возможная задержка составляет 262,14 мс/F_CPU в МГц. Когда задержка запроса пользователя превышает максимально возможную, _delay_ms() предоставляет функциональность с уменьшенным разрешением. В этом режиме _delay_ms() будет работать с разрешением 1/10 мс, обеспечивая задержки до 6,5535 секунд (независимо от частоты процессора). Пользователь не будет проинформирован о снижении разрешения. - person Rev; 26.05.2016

Не уверен, что это объясняет проблему, но вы намеренно не делаете перерыв после каждого значения регистра переключения?

person Nick Gorham    schedule 20.06.2011
comment
Это баг, это точно. Каждый раз, когда он пытается отправить букву азбукой Морзе, он заканчивает тем, что отправляет все буквы после этой буквы. - person vhallac; 20.06.2011

проблема возникла при определении массива символов

char studentID[12]            = {'S',1,2,3,4,5,6,7,'A','B','C','D'};

числа 1,2,...,7 должны понравиться ниже

char studentID[12]            = {'S','1','2','3','4','5','6','7','A','B','C','D'};
person harvey    schedule 31.05.2011
comment
-1: Это не будет причиной проблемы. Присмотритесь к корпусам переключателей. - person Oliver Charlesworth; 31.05.2011
comment
На самом деле ошибка распространяется на оператор switch, так что никакого вреда нет. Я считаю, что что-то еще может быть Break-ing. - person Michael Dorgan; 31.05.2011