roboforum.ru

Технический форум по робототехнике.

 

Каллибровка ультразвукового дальномера AVR C

Программирование микроконтроллеров AVR, PIC, ARM.
Разработка и изготовление печатных плат для модулей.

Каллибровка ультразвукового дальномера AVR C

Сообщение progressman » 27 апр 2014, 20:47

Добрый день Всем Роботостроителям :)

Я намерен использовать дальномер для оцифровки 2д периметра помещения. Вполне возможно что это не самый эффективный вариант, но самый простой по идее. Для начала необходимо откаллибровать показатели, терминал протеуса показывает не совсем красивые данные (см Рис 1 во вложении)

Следующий этап развития - прикрутить к дальномеру компас с батарейкой и зафиксировать это дело на валу моторчика. Данные отправлять по UART на компютер, где рисуем 2D карту в С++.

Среда разработки = СodeVision
Камень = ATMega 8
Генератор = внутренний 8 мгц
Дальномер = ультразвуковой US-020 (аналог HC-SR04, только расстояние до 7ми метров)

Для замера расстояния УЗ дальномером необходимо отправить сигнал и словить его сощитав длинну.

Алгоритм работы следующий:
1. Смотрим что прошло первых 60мс (if (tim0_tiker==2) - переменная нулевого таймера по 30мс плюсанулась 2 раза)Отправляем импульс на Trig вход дальномера длительностью 10мкс, флаг статуса замера переводиться в единицу **строка 90** Это значит, что если с Echo выхода прийдет импульс на INT0 и сработает прерывание, то надо включить счет таймера **строка 19**
2. После того как импульс с Echo закончился - срабатывает снова прерывание INT0 и теперь уже выключает таймер подсчета секунд, записывает значение в переменную и выставляет флаг отправки по UART **строка 18**
3. Данные отправляются по UART, переменная отправки обнуляется **строка 92**

Код: Выделить всёРазвернуть
#include <mega8.h>
#include <delay.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int mks_10x = 0;   // переменная которая тикает с шагом в 15мкс (больше не вытягивает МК)
int mks_zamer = 0; // переменная в которой отображаем переменную выше в микросекундах   mks_zamer=mks_10x*15
int sm = 0;        // эта переменная используется для занесения вычислений расстояния в сантиметрах - SM=mks_zamer\58
char tim0_tiker = 0; // тикает в таймере_0 два раза по 30мс - получается один период
_Bool status = 1;    // флаг статуса замера
_Bool send = 1;      // флаг отправления по УАРТ
unsigned char string[10]; // передаем данные по УАРТ для отображения в протеусе

interrupt [EXT_INT0] void ext_int0_isr(void)
{
// Place your code here
if (status==0) {TIMSK &= ~(1<<TOIE1); mks_zamer = mks_10x*15; send=1; mks_10x=0;}   //вырубить таймер если переменная статус обнуленная и сработало прерывание
if (status==1) {TIMSK |= (1<<TOIE1); status=0;  }    //врубить таймер если сработал импульс 10мкс и переменная обратилась в один
}

interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
TCNT0 = 21;
tim0_tiker++;
}

interrupt [TIM1_OVF] void timer1_ovf_isr(void)
{
TCNT1 = 65520; //выставляем начальное значение TCNT1
mks_10x++;
//PORTC=~PORTC;
}

// Declare your global variables here

void main(void)
{
// Declare your local variables here

PORTC=0b00000000;
DDRC=0b11111111;
PORTB=0b00000000;
DDRB=0b11111111;

PORTD.2=1; // int0 выставляем на вход
DDRD.2=0;

//*******Настраиваем таймер_1, который выполняет функцию подсчета времени обратного импульса
//Частота таймера счетчика = Тактовая частота/Делитель =  8000000/8 = 1000000 Гц
//Длительность периода( тика ) =  1/1000000 = 0,000001 секунды = 1 мкс
//TCCR1B = (0<<CS12)|(1<<CS11)|(0<<CS10); // настраиваем делитель на 8 (табличка:http://mainloop.ru/avr-atmega/avr-timer-counter.html)
TCCR1B &= ~(1<<CS12); //так записываются нули )
TCCR1B |= (1<<CS11); //вот записываются единицы
TCCR1B &= ~(1<<CS10);
//TIMSK |= (1<<TOIE1); // разрешаем прерывание по переполнению таймера
//TIMSK &= ~(1<<TOIE1); // запрещаем прерывание по переполнению таймера
TCNT1 = 65520;       // выставляем начальное значение TCNT1   65535-65520=15тактов=15мкс

//*******Настраиваем таймер_0, который выполняет функцию подсчета времени периода
//Частота таймера счетчика = Тактовая частота/Делитель =  8000000/1024 = 7812.5 Гц
//Длительность периода( тика ) =  1/7812.5 = 0,000128 секунды = 128 мкс
TCCR0 |= (1<<CS02); //вот записываются единицы
TCCR0 &= ~(1<<CS01); //так записываются нули )
TCCR0 |= (1<<CS00); //вот записываются единицы
TIMSK |= (1<<TOIE0); // разрешаем прерывание по переполнению таймера
TCNT0 = 21;       // выставляем начальное значение 255 максимум 255-234=21 234 тика это*128= 29952мкс=30мс

GICR |= (1<<INT0);// разрешить внешние прерывания
MCUCR |= (1<<ISC00);  //вот записываются единицы
MCUCR &= ~(1<<ISC01); //так записываются нули )

// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: Off
// USART Transmitter: On
// USART Mode: Asynchronous
// USART Baud Rate: 9600
UCSRA=0x00;
UCSRB=0x08;
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x33;

#asm("sei") // Global enable interrupts

while (1)
      {

        if (tim0_tiker==2) {tim0_tiker=0; PORTB=~PORTB; PORTC.0=1; delay_us(10); PORTC.0=0; status=1;}
                         
        if (send==1)
        {
            send=0;
            sm = mks_zamer/58;
            if (sm>=1) // это для того что бы не отправляло нули, если нету данного условия, то много нулей бывает
            {
            itoa(sm, string);
            strcat(string, "\n\r");
            puts(string);
            }

        }

      }
}


Собственно вопрос: каким образом максимально ээфективно откаллибровать показания, ибо при статическом положении разброс данных присутствует конкретный?

Есть только один вариант решения - это повысить частоту микроконтроллера до 16мгц хотя бы, поскольку дискретность замера миниумм 15мкс достигается в прерывании по таймеру. Если меньше уже не вытягивает и ошибок больше.

Вот такие дела. Рад пообщаться с коллегами :beer:
Вложения
Рис 1.png
Рис 1
progressman
 
Сообщения: 2
Зарегистрирован: 27 апр 2014, 20:03

Re: Каллибровка ультразвукового дальномера AVR C

Сообщение legion » 28 апр 2014, 09:31

Мне сложно ориентироваться в C коде, но при 8 Мгц "не вытягивает больше 15 мкс" звучит странно. Это же целых 120 тактов!)

На самом деле тут надо делать по-другому. Для точных замеров времени надо использовать Input Capture Unit таймера. Как это работает?

    -1) Читаешь в даташите секцию про Input Capture Unit, обращаешь внимание на режимы таймера и его взаимодействие с регистром ICR (Input Capture Register), там есть некоторые нюансы, нужно выбрать правильный режим.

    0) Настраиваешь таймер, разрешаешь при этом прерывание Input Capture Interrupt (Timer/Counter Capture Event в таблице векторов прерываний), настраиваешь захват по фронту или спаду сигнала, как тебе нужно.

    1) Обнуляешь счетный регистр таймера

    2) Запускаешь таймер в момент начала временного отрезка, который ты измеряешь.

    3) Когда произойдет запланированное изменение логического уровня на ноге ICP, текущее значение счетного регистра скопируется в регистр ICR, и одновременно с этим установится флаг прерывания Input Capture.

    4) В прерывании считываешь значение ICR (если используешь 16бит таймер, то обрати внимание на порядок чтения байтов) и делаешь все остальное, что тебе нужно. Например инициируешь новый замер (не забудь обнулить счетный регистр).

Таким образом можно замерять длительность сигнала с точностью до длительности одного такта МК, т.е. до 125 наносекунд при 8 МГц. Нанотехнологии!

На что надо обратить внимание:
1) Нужно чтобы сигнал полностью уложился в максимальный интервал замера таймера. Т.е. либо настраиваем предделитель таким образом, либо используем дополнительную переменную-счетчик и увеличиваем ее при переполнении счетчика таймера.
2) Если отправляешь данные по УАРТ, то убедись, что его скорости хватает при минимальном временном интервале.
3) Если используешь таймер с предделителем, то можно увеличить немного точность сбрасывая значение счетчика предделителя, иначе показания могут плавать на время от 0 до (время такта счетчика)-(время такта МК). Смотреть в даташите Prescaler Reset.
legion
 
Сообщения: 736
Зарегистрирован: 24 апр 2010, 14:47
Откуда: Уфа
прог. языки: avr asm

Re: Каллибровка ультразвукового дальномера AVR C

Сообщение citizen » 30 апр 2014, 11:38

прикрутить к дальномеру компас с батарейкой и зафиксировать это дело на валу моторчика

Компас не будет рад близкому соседству с мотором.
Для получения данных об угле поворота лучше использовать шаговый двигатель или серву.
Замечу, что карту помещения с помощью УЗ-дальномера построить сложно - у дальномера широкая диаграмма направленности.
Аватара пользователя
citizen
 
Сообщения: 315
Зарегистрирован: 12 окт 2008, 12:40
Откуда: Красногорск, Подмосковье

Re: Каллибровка ультразвукового дальномера AVR C

Сообщение avr123.nm.ru » 30 апр 2014, 11:59

от стен рядом сбоку сигнал может приходить раньше чем от дальней стены по направлению измерения. получается надо еще и силу сигнала учитывать.
Читайте !
Аватара пользователя
avr123.nm.ru
отсылающий читать курс
 
Сообщения: 14200
Зарегистрирован: 06 ноя 2005, 04:18
Откуда: Москва
Предупреждения: -8

Re: Каллибровка ультразвукового дальномера AVR C

Сообщение progressman » 02 май 2014, 04:21

Разброс показателей уменьшается конкретно с расстоянием и зависит от угла плоскости замеряемой плоскости. До метра где-то вполне нормально замеряет. По этому для оцифровки периметра ультразвуковой дальномер точно не подойдет, а для дистанционных бесконтактных переключателей очень даже ничего!

зы что еще возможно использовать для ебсконтактных переключателей с настраиваемым расстоянием?
progressman
 
Сообщения: 2
Зарегистрирован: 27 апр 2014, 20:03

Re: Каллибровка ультразвукового дальномера AVR C

Сообщение avr123.nm.ru » 02 май 2014, 09:54

Диаграмму направленности наверно можно сузить значительно по принципу направленного микрофона - используя трубку с шумоизоляцией снаружи.
Читайте !
Аватара пользователя
avr123.nm.ru
отсылающий читать курс
 
Сообщения: 14200
Зарегистрирован: 06 ноя 2005, 04:18
Откуда: Москва
Предупреждения: -8

GrammarNazi to the resque

Сообщение elmot » 17 май 2014, 10:54

Каллибровка - Кал - понятно, но что такое что "либровка" - это от фр. libre - "свобода", или от лат. libro - "книга", или от "либрация" (сиречь полет) ?
Аватара пользователя
elmot
 
Сообщения: 5674
Зарегистрирован: 10 ноя 2011, 12:02
Откуда: Turku, Finland
Skype: elmot73
прог. языки: Java и все-все=все
ФИО: Илья


Вернуться в Микроконтроллеры

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 4

Mail.ru counter