Таймер AVR с внешней ошибкой прерывания - PullRequest
0 голосов
/ 06 июня 2018

Я наткнулся на проект, в котором я хочу напечатать измеренное расстояние от ультразвукового датчика до ЖК-дисплея.Схема конструкции выглядит следующим образом:

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, который должен был быть в порядке.:

Wrong output

Кажется, что для правильной работы он работает, когда i = 1 код также должен перейти ко второму блоку.Почему использование else if дает неверные результаты?Любая помощь будет высоко ценится.

1 Ответ

0 голосов
/ 06 июня 2018

Несколько моментов:

  • ISR из исходного кода не имеет смысла для меня.Ваши изменения должны привести к предполагаемому поведению.

  • i может быть uint8_t вместо int

  • импульс должен быть uint16_t вместо (со знаком) int

  • , поскольку pulse является многобайтовой переменнойи к нему обращаются из ISR и из main (), прерывания должны (должны) быть отключены при доступе к нему из «основного потока».

Примерно так:

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

или еще лучше использовать макросы из "util / atomic.h"

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

В противном случае вы можетеполучить неверные результаты во время доступа.

...