【问题标题】:AVR - Interrupt Vector and Global VariableAVR - 中断向量和全局变量
【发布时间】:2011-05-31 13:14:04
【问题描述】:

我正在使用 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;
}

好的,我找到了导致问题的有问题的代码,但我不确定它为什么会导致它。 当我从主 while 循环中删除 loadValue(studentID[i]) 时,代码按预期工作。但是当我把它放回去时,它又坏了。

【问题讨论】:

  • 顺便说一句。我假设您使用 C 代码。 C++ 不支持默认整数。
  • 对于这个极短的程序,我真的建议你阅读生成的汇编代码。
  • 您说“timer0 溢出到中断,它的工作原理可预测且完美”。你真的验证了吗?如果没有,我建议在 ISR 中插入一些代码来切换输出行并用范围观察它。
  • @Oliver:我会冒险猜测_delay_ms 函数在某种程度上弄乱了中断掩码。尝试将代码简化为更简单的应用程序,看看是否仍然存在问题。
  • @Oli Charlesworth。看来你是对的,当我注释掉所有 _delay_ms 函数时,代码按预期工作,只有当我将它们放入它们时,它们才会与全局变量混淆。我不确定,但也许是由于 isSampling 的原子性质?请回答问题,以便我接受。谢谢。

标签: c++ c gcc avr atmega


【解决方案1】:

_delay_ms(500) 行导致了 Oli Charlesworth 所述的问题。 _delay_ms() 函数如果设置为高(超过 250 毫秒)可能会导致不可预知的行为。

【讨论】:

  • 你认为为什么会有不可预知的行为? Source: "最大可能延迟为 262.14 ms / F_CPU in MHz。当用户请求延迟超过最大可能延迟时,_delay_ms() 提供降低分辨率功能。在此模式下,_delay_ms() 将以 1 的分辨率工作/10 毫秒,提供高达 6.5535 秒的延迟(与 CPU 频率无关)。用户不会被告知分辨率降低。"
【解决方案2】:

不确定它是否能解释问题,但您是否有意在每个 switch case 值之后不休息?

【讨论】:

  • 这是一个错误,这是肯定的。每次他尝试发送一封信的摩尔斯电码时,他最终都会发送该信之后的所有信件。
【解决方案3】:

char数组的定义出现问题

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

【讨论】:

  • -1:这不是问题的原因。仔细看看开关盒。
  • 实际上,错误被传播到 switch 语句,所以没有伤害没有犯规。我相信其他东西可能正在破坏。
猜你喜欢
  • 2021-12-15
  • 1970-01-01
  • 1970-01-01
  • 2011-12-29
  • 2021-03-30
  • 2023-03-14
  • 1970-01-01
  • 2019-04-04
  • 2013-10-06
相关资源
最近更新 更多