- Лоботрясы

Поиск
Перейти к контенту

Главное меню:

Датчики и модули

Читать в Яндекс.Подписках



    Радиомодули RF. Часть 3 Мучаем RF дальше. Реализация простейшего протокола связи
Просмотров: 4661
     Продолжаю заниматься моветоном – уверенной передачей приёмнику радиокоманд, основанных не на изменении уровня передаваемых логических сигналов или манчестерском кодировании, а на банальной передаче уровней логических “0” и “1” :-)
     На сей раз я пытался установить связь между радиомодулями (а точнее, микроконтроллерами) на основе программного кода, минуя аппаратный модуль UART приёмника. Целью было создание простого и стабильного алгоритма приёма и распознавания передаваемых RF-передатчиком данных. Вообще, идея и реализация программы приёма получилась сама собой в результате не особо удачной попытки совместить аппаратный UART с возможностью синхронизации с началом приёма данных.
     Схему передатчика (да и приёмника) я оставил без изменений – всё тот же Attiny13 в связке с FS1000A, однако программный код немного изменил, чтобы облегчить приём и распознавание данных приёмником. Вместо стандартного фрейма данных UART, состоящего из 8 бит данных, 1 стартового и 1 стопового бита, я оставил только 8 бит самих данных, отправляемых байт за байтом в процессе передачи без всякой паузы или разделительного символа. Как же я в таком случае узнаю, что идёт передача, да и как вообще я распознаю биты данных?! Для распознавания битов данных я применил очень простой (и поэтому, не особо надёжный для дальней связи) алгоритм. Оставив частоту принимаемых и передаваемых данных на уровне 2400 бит/с (для этого поколдовав с таймерами микроконтроллеров), я организовал опрос входа микроконтроллера, подключённого к выходу приёмника XY-MK-5V, с частотой, в 8 раз превышающей частоту сигнала передаваемых данных. Или (короче, Склифосовский…), за период одного передаваемого бита я делаю 8 замеров (выборок или сэмплов) состояния входа. При таком подходе вопрос о синхронизации тоже не стоит, ибо её просто нет :-D
     Определение уровня логического сигнала (принимаемого бита, т.е.) определяется так: если из 8-ми выборок сигнала за временной промежуток, равный периоду одного бита пять или больше оказались с уровнем логической “1”, то мы приняли “1” (Das ist Fantastisch, правда?) Иначе – “0”. Так как передаваемые данные идут байт за байтом без старт и стоп битов, то даже при отсутствии синхронизации с первым битом начала передачи, каждый байт данных всё равно будет распознан. Ну, по крайней мере, на небольшом расстоянии между радиомодулями.
     Программная реализация передатчика не сильно отличается (но таки отличается!) от рассмотренной во 2-й части, поэтому я её отдельно приводить не буду (сами в исходнике посмотрите, если чо :-), а вот реализацию описанного выше алгоритма приёмника приведу.
 
     Взятие выборок логического сигнала с выхода приёмника происходит в процедуре обработки прерывания таймера, в моём примере – в режиме СТС.
 
// Прерывание по совпадению Таймера 0 (режим СТС)
interrupt [TIM0_COMP] void timer0_comp_isr(void)
{
    sample ++; // Счётчик количества замеров
 
    if(TX_PIN) // Если на входе присутствует "1"   
    { 
        pos_imp ++;  // Счётчик количества импульсов высокого уровня                  
    }              
  
    if (sample >= 8) // На один принимаемый бит приходится 8 сэмплов
    {
        recieve_bit >>= 1;  
       
        if(pos_imp >= 5) // Если выполняется условие – принята логическая "1"
        {                 
            recieve_bit |= 0x8000;
        }
       
        if(!(++bit_count%8)) // Если поступили 8 бит данных
        {
            data = recieve_bit >> 8; // Мне нужны только 8 бит даных...
            if (start_symbol) // Пошёл приём полезных данных
            { 
                if(check_address) // Если адрес совпал
                {  
                    if(!data_count)   size_rx_data = data;  // Первый байт данных - длина принимаемого сообщения (его не сохраняю в буфере)
           
                    if((size_rx_data >= MIN_LEN_SIZE)&&(size_rx_data <= MAX_LEN_SIZE)) // Если размер пакета полезных данных в допустимых пределах
                    {  
                        if(data_count) // Пропускаю байт длины сообщения (записываю только байты, идущие после него)  
                        {
                            rx_buffer[rx_write] = data;
                            if (++rx_write == RX_BUFFER_SIZE)   rx_write=0;
                            if (++rx_counter == RX_BUFFER_SIZE)   { rx_counter=0; rx_write=0; rx_read =0; }  // На всякий пожарный - Тоже защита от помех!!!
                        }
   
                        if(++data_count >= size_rx_data) //Если принято все количество size_rx_data полезных данных
                        {  
                            res_recieve = 1; //Строка принята!
                            start_symbol = 0;
                            data_count = 0;
                            check_address = 0;     
                        } 
                    }
                    else
                    {
                        start_symbol = 0;                   
                    }
                }
                // Проверяем адрес (какому устройству предназначена команда :-)
                if((data == ADDRESS_ID_1)&&(!check_address))    check_address = 1;
                else if((data != ADDRESS_ID_1)&&(!check_address))
                {
                    start_symbol = 0;               
                } 
            }
        }
       
        if(!start_symbol) // Ищу символ синхронизации (ключевое слово)
        {
            if(recieve_bit == 0x385b) //Если присутствует стартовое слово   
            {
                start_symbol = 1; //Разрешён приём данных
                data_count = 0;
                recieve_bit = 0; // Очистил приёмный буфер для приёма данных
                bit_count = 0; //Счётчик принятых битов для формирования байта  
            }
        }                                          
        sample = pos_imp = 0;      
    } 
}
 
     Приём данных происходит в кольцевой буфер rx_buffer[], из которого, по окончании приёма (о чём символизирует флаг res_recieve), они копируются в рабочий буфер и сравниваются с эталонными командами.
     Как видно по рисунку где представлен скринщот с программы Termite (сделал во время отладки с помощью UART-сообщений), где в переменной recieve_bit (в которую записываются принимаемые биты) ключевое слово 0x38 сменяется адресом приёмника 0x47, алгоритм работает:
     Непонятно, что приведено на рисунке? Тогда переведите шестнадцатеричный код в двоичный и поймёте :-)))
 
     А дальше, после сравнения принятого кода с эталонными командами, микроконтроллер приёмника мигает светодиодиками, включает какие-нибудь релюшки, открывает/закрывает двери и т.д. и т.п…
     Такой подход, несмотря на простоту и слабую помехозащищённость, вполне себя оправдывает на небольших расстояниях, например, в пределах комнаты/квартиры или дома. Код приёмника (несмотря на его «заточенность» для Atmega32) небольшой по размеру и поместится (с небольшими переделками, естественно) в Attiny13, что и было мною задумано.
     Такой миниатюрный микроконтроллер (Attiny13) в совокупности с FS1000A вполне подойдёт для передачи данных с какого-нибудь датчика, а в связке с RF-приёмником – для организации работы исполнительного устройства (реле, например).
     Однако, помимо хвалебных од и самопохвал, – и ложка дёгтя :-( Встроенный RC-генератор 13-й тиньки имеет такую особенность – при изменении окружающей температуры, колебаниях питающего напряжения, курса Доу Джонса…, его частота начинает плавать на какой-то там процент, нарушая длительность передаваемых битов, отчего длинный пакет данных в половине случаев пропадал в неизвестность. Долго не мог понять причину сего прискорбного события, пока не обнаружил плохой контакт электролитического конденсатора – фильтра источника питания макетной платы. После устранения неисправности, приём пошёл уверенно, но тем не менее, я сократил стартовую преамбулу передатчика до одного байта 0x55, а размер самих полезных данных (байт длины сообщения не в счёт!) ограничил четырьмя байтами! В принципе, для обмена данными между датчиками или для управления релюшками хватит вполне. Можно, правда, побаловаться и с количеством повторений передаваемой команды, чтоб она пришла уж наверняка :-)  После всех танцев, приёмник и передатчик наконец подружились :-D
     Теперь в перспективе опробовать, наконец, манчестерское кодирование :-D
     
     Скачать:

Опубликовано 4.02.2016
©Igoryosha, 2016
 
 
Назад к содержимому | Назад к главному меню