Я намерен использовать дальномер для оцифровки 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мкс достигается в прерывании по таймеру. Если меньше уже не вытягивает и ошибок больше.
Вот такие дела. Рад пообщаться с коллегами