На этом уроке мы продолжим разбираться с программной реализацией протокола обмена, напишем программу приёмника.
Перед тем, как мы начнём необходимо внести некоторые исправления.
Во первых стартовая пауза показалась мне коротковатой. Чтобы избежать ложных сработок я увеличил её длительность на 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 во вложении.
Прикрепленные файлы:
- du12.rar (125 Кб)