Машинка на ДУ управлении своими руками — Программная реализация — приёмник (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 во вложении.