Машинка на ДУ управлении своими руками — Программная реализация — приёмник (AVR)

На этом уроке мы продолжим разбираться с программной реализацией протокола обмена, напишем программу приёмника.

Перед тем, как мы начнём необходимо внести некоторые исправления.

Во первых стартовая пауза показалась мне коротковатой. Чтобы избежать ложных сработок я увеличил её длительность на 100 отсчётов. Соответственно все отметки начала импульсов сместились. Все изменения внесены в проект.

Во вторых я ошибся при измерении длительностей стартовой паузы и как следствие всей посылки в целом. Пояснения даны в видео.

В третьих способ детектирования информационной посылки приёмником посредством отсчётов даст неверное значение, т.к. реальная длинна пауз и импульсов на самом деле больше.

Вот теперь можем приступать… Начнём с настроек периферии. В нашей программе, кроме таймера 2, который формирует ШИМ последовательность будет использоваться 16 битный таймер 1 для измерения длительностей. Инициализация таймера выглядит следующим образом.

//Timer1 — 16bit || …
TCNT1 = 0;
OCR1A = 0;
OCR1B = 0;

TCCR1A = (0 << COM1A1)| // Bit 7 – Compare Output Mode for Channel A
(0 << COM1A0)| // Bit 6 – Compare Output Mode for Channel A
(0 << COM1B1)| // Bit 5 – Compare Output Mode for Channel B
(0 << COM1B0)| // Bit 4 – Compare Output Mode for Channel B
(0 << FOC1A)| // Bit 3 – Force Output Compare for channel A
(0 << FOC1B)| // Bit 2 – Force Output Compare for channel B
(0 << WGM11)| // Bit 1 – Waveform Generation Mode
(0 << WGM10); // Bit 0 – Waveform Generation Mode

TCCR1B = (0 << ICNC1)| // Bit 7 – Input Capture Noise Canceler
(0 << ICES1)| // Bit 6 – Input Capture Edge Select
(0 << WGM13)| // Bit 4 – Waveform Generation Mode
(0 << WGM12)| // Bit 3 – Waveform Generation Mode
(0 << CS12)| // Bit 2 – Clock Select
(0 << CS11)| // Bit 1 – Clock Select
(0 << CS10); // Bit 0 – Clock Select

На самом деле никаких изменений в секцию инициализации таймера 1 вносить не нужно. Таймер работает в режиме обычного счёта. Мы лишь лишь включаем его и выключаем.

Начало декодирования посылки начинается с поиска стартовой паузы. Начнём с ожидания «ноля»…

//Начало декодирования посылки
while(PINB & (1 << PB0)); //Ждём логического ноля

…после нахождения паузы измеряем её длительность. Вначале обнулим счётный регистр таймера…

TCNT1 = 0; //Сбросить счётчик отсчётов

…далее включаем таймер и ждём пока пауза не закончится…

TCCR1B |= (0 << CS02)|(1 << CS01)|(0 << CS00); //Включить таймер
while(!(PINB & (1 << PB0))); //Считаем, пока принимаем логический ноль

…выключаем таймер…

TCCR1B &= ~(0 << CS02|1 << CS01|0 << CS00); //Выключить таймер

Теперь нам необходимо сравнить измеренное значение с известной длительностью паузы. Разберём этот момент подробнее. При тактовой частоте 16МГц длительность одного такта составляет 62,5нс. Значит наша пауза в 9,13мс длится 146080 тактов. Т.к. счётный регистр нашего таймера 16 битный, вершина счёта будет равна 65535 тактов. Этого явно не хватает! Потому мы будем использовать таймер с предделителем на восемь. В результате это даст нам…

146.080 тактов / 8 = 18260 отсчётов

Произведём сравнение полученного результата…

if (TCNT1 < 18000) continue; //Если пауза не выдержана…

Если пауза длилась менее 18000 отсчётов, значит это не начало посылки и поиск повторится. Если больше, идём дальше…

Фронт первого импульса сформировался несколько тактов назад. Потому измерение его длительности будет произведено с небольшой ошибкой, но на работу нашего приёмника это не повлияет…

//Декодирование первого импульса
TCNT1 = 0; //Сбросить счётчик отсчётов
TCCR1B |= (0 << CS02)|(1 << CS01)|(0 << CS00); //Включить таймер
while(PINB & (1 << PB0)); //Считаем, пока принимаем логическую единицу
TCCR1B &= ~(0 << CS02|1 << CS01|0 << CS00); //Выключить таймер

…по окончании измерения загружаем измеренное значение в OCR2…

OCR2 = TCNT1/47; // Загружаем скважность ШИМ

Максимальная длительность импульса составляет 5,81мс и длится он 92960 тактов, с учётом делителя на восемь результат составит 11620. OCR2 — 8 битный регистр, максимальное число, которое мы можем загрузить в него равно 255. Смаштабируем результат таким образом, чтобы он укладывался в диапазон 0..255. Для этого разделим измеренный результат на 47.

Известно, что между импульсами присутствуют паузы, поэтому декодирование второго импульса начинается с ожидания его фронта…

while(!(PINB & (1 << PB0))); //Ждём логическую единицу

…обнуляем счетный регистр таймера, далее включаем его, ждём пока пауза не закончится и выключаем…

TCNT1 = 0; //Сбросить счётчик отсчётов
TCCR1B |= (0 << CS02)|(1 << CS01)|(0 << CS00); //Включить таймер
while(PINB & (1 << PB0)); //Считаем, пока принимаем логическую единицу
TCCR1B &= ~(0 << CS02|1 << CS01|0 << CS00); //Выключить таймер

…преобразуем измеренное значение в выходные сигналы управления исполнительными устройствами.

Декодирование третьего импульса происходит аналогичным способом. По окончании пакета данных процедура декодирования повторяется!

На сегодня всё! До новых встреч!!

ПРОЕКТ С ИСХОДНЫМ КОДОМ И СИМУЛЯЦИЯ В PROTEUS во вложении.


Прикрепленные файлы:

Добавить комментарий

Ваш адрес email не будет опубликован.