AVR定时器有外部中断错误

时间:2018-06-06 04:32:08

标签: timer interrupt avr atmega lcd

我遇到了一个项目,我想打印从超声波传感器测量的距离到LCD。设计原理图如下:

Schematic

相应的代码:

    /*
C Program for Distance Measurement using Ultrasonic Sensor and AVR Microocntroller
 */ 

#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 1000000
#include <util/delay.h>
#include <stdlib.h>

#define enable            5
#define registerselection 6

void send_a_command(unsigned char command);
void send_a_character(unsigned char character);
void send_a_string(char *string_of_characters);

static volatile int pulse = 0;
static volatile int i = 0;

int main(void)
{
    DDRA = 0xFF;
    DDRB = 0xFF;
    DDRD = 0b11111011;
    _delay_ms(50);

    GICR|=(1<<INT0);
    MCUCR|=(1<<ISC00);

    TCCR1A = 0;

    int16_t COUNTA = 0;
    char SHOWA [16];


    send_a_command(0x01); //Clear Screen 0x01 = 00000001
    _delay_ms(50);
    send_a_command(0x38);
    _delay_ms(50);
    send_a_command(0b00001111);
    _delay_ms(50);

    sei();

    while(1)
    {
        PORTD|=(1<<PIND0);
        _delay_us(15);
        PORTD &=~(1<<PIND0);

        COUNTA = pulse/58;
        send_a_string ("CIRCUIT DIGEST");
        send_a_command(0x80 + 0x40 + 0);
        send_a_string ("DISTANCE=");
        itoa(COUNTA,SHOWA,10);
        send_a_string(SHOWA);
        send_a_string ("cm    ");
        send_a_command(0x80 + 0);

    }
}

ISR(INT0_vect)
{
    if (i==1)
    {
        TCCR1B=0;
        pulse=TCNT1;
        TCNT1=0;
        i=0;
    }
    if (i==0)
    {
        TCCR1B|=(1<<CS10);
        i=1;
    }
}

void send_a_command(unsigned char command)
{
    PORTB = command;
    PORTD &= ~ (1<<registerselection);
    PORTD |= 1<<enable;
    _delay_ms(8);
    PORTD &= ~1<<enable;
    PORTB = 0;
}

void send_a_character(unsigned char character)
{
    PORTB = character;
    PORTD |= 1<<registerselection;
    PORTD |= 1<<enable;
    _delay_ms(8);
    PORTD &= ~1<<enable;
    PORTB = 0;
}
void send_a_string(char *string_of_characters)
{
    while(*string_of_characters > 0)
    {
        send_a_character(*string_of_characters++);
    }
}

设计规格和代码取自此处: https://circuitdigest.com/microcontroller-projects/distance-measurement-using-hc-sr04-avr

我对这段代码的ISR部分感到困惑。这里编码的方式,当声纳的回声从HIGH变为LOW时,定时器再次启动,因为它进入第二个if块也是,我认为这是不必要的。但是,如果我只是将第二个if块作为else if应该没问题,那么模拟会表现得很奇怪并且输出的输出不正确和变化。

ISR(INT0_vect)
{
    if (i==1)
    {
        TCCR1B=0;
        pulse=TCNT1;
        TCNT1=0;
        i=0;
    }
    else if (i==0)
    {
        TCCR1B|=(1<<CS10);
        i=1;
    }
}

这种变化会产生不稳定和不断变化的输出:

Wrong output

i = 1代码必须跳转到第二个块时,它似乎正常工作。为什么使用else if会产生错误的结果?任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:0)

几点:

  • 原始代码中的ISR对我没有意义。您的更改应该会产生预期的行为。

  • 可以是 uint8_t 而不是int

  • 脉冲应该是 uint16_t 而不是(签名)int

  • 由于 pulse 是一个多字节变量,它是从ISR和main()访问的,所以当从“主线程”访问时,应该(必须)禁用中断。

像这样:

cli();
COUNTA = pulse/58;
sei();

甚至更好地使用“util / atomic.h”中的宏

ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
     COUNTA = pulse/58;
}

否则您在访问期间可能会得到错误的结果。