Мы довольно часто в повседневной жизни сталкиваемся, с использованием беспроводных передающих устройств. Эту тему нельзя было обойти стороной, поэтому в этом уроке речь пойдет об использовании инфракрасного (ик) передатчика и приемника, управляемых AVR микроконтроллером. Тема интересная и новая для меня, кроме того, хотелось чтобы она была понятна любому начинающему. Поэтому все варианты, использующие протоколы RC5 и т.п. не рассматривались, желающие могут самостоятельно их освоить, моя цель была понять принцип работы и, как результат, помигать светодиодом на расстоянии.
Решением стала статья с хабры (habrahabr.ru/post/82383), в которой для управления роботом использовался ик. Основная идея весьма проста — информация передается и принимается, как при обычной работе с UART, ик передатчик и приемник выполняют роль проводов. Единственная особенность, то что сигнал с UART должен быть промодулирован на определенной частоте.
Теперь обо всем подробнее, начнем с приемника.В качестве приемника использован TSOP4836. Как уже было сказано, приемник работает на определенной частоте, данный приемник работает на частоте 36кГц. Если принимаемый сигнал отклоняется от заданной частоты, то соответственно снижается чувствительность.
Схема приемника достаточна проста, как впрочем и просто использовать ее программно — достаточно просто ловить данные по UART никаких дополнительных действий. Также возможно подсоединить к FT232 и смотреть терминалкой приходящие данные, мне это очень помогло во время отладки.
Для управления светодиодом использована Atmega8, думаю пояснений по коду не требуется, единственное, на что стоит обратить внимание, это скорость UART-2400, она напрямую связана с частотой, на которой работает приемник «10/fo is recommended for optimal function»
#include <mega8.h> #include <stdio.h> void main(void) { char i; // Input/Output Ports initialization // Port B initialization // Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out // State7=0 State6=0 State5=0 State4=0 State3=0 State2=0 State1=0 State0=0 PORTB=0x00; DDRB=0xFF; // Port D initialization // Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In // State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T PORTD=0x00; DDRD=0x00; // USART initialization // Communication Parameters: 8 Data, 1 Stop, No Parity // USART Receiver: On // USART Transmitter: Off // USART Mode: Asynchronous // USART Baud Rate: 2400 UCSRA=0x00; UCSRB=0x10; UCSRC=0x86; UBRRH=0x00; UBRRL=0xCF; while (1) { i=getchar(); if(i=='0') { PORTB.0=0; } if(i=='1') { PORTB.0=1; } }; } |
Теперь перейдем разберемся с передатчиком, в качестве которого использован инфракрасный диод TSAL6200. В целом ничего сложного, задействована ножка Tx, для передачи данных из UART, ножка PB1 нужна для формирования несущей частоты, т.е. она дрыгается с частотой 36кГц.
Основной проблемой, в данной схеме, является то, что ик диод потребляет порядка 100мА, поэтому, если дать полный ток, то ножка мк может сгореть. Поэтому ток ограничен, соответственно в ущерб излучаемой мощности. Можно схему переделать и придумать как от этого избавиться, однако для учебных целей схема вполне годна и наглядна.
Теперь пару слов о формировании несущей частоты, ножка таймера T1А включена в режим Toggle, это значит что при достижении таймером величины указанной в OCR1A, состояние ножки изменится на противоположное, подобное мы делали в уроке про генерацию звука.
Частота, которую можно получить на ножке таким способом определяется по формуле из даташита:
Focn — частота, с которой должна дрыгаться ножка;
Fclk — частота таймера;
N — частота предделителя таймера;
OCRn — значение регистра сравнения;
В остальном исходный код для передатчика, ничем не отличается, от ранее изученного нами, в статье про передачу данных по UART. Для удобства повесил 2 кнопки PB2 передает ‘1’ — соответственно зажигает светодиод, PB0 передает ‘0’ — гасит светодиод.
#include <mega8.h> #include <stdio.h> void main(void) { bit ps=0; // Input/Output Ports initialization // Port B initialization // Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=Out Func0=In // State7=T State6=T State5=T State4=T State3=T State2=P State1=0 State0=P PORTB=0x05; DDRB=0x02; // Port D initialization // Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=Out Func0=In // State7=T State6=T State5=T State4=T State3=T State2=T State1=0 State0=T PORTD=0x00; DDRD=0x02; // Timer/Counter 1 initialization // Clock source: System Clock // Clock value: 8000,000 kHz // Mode: CTC top=OCR1A // OC1A output: Toggle // OC1B output: Discon. // Noise Canceler: Off // Input Capture on Falling Edge // Timer 1 Overflow Interrupt: Off // Input Capture Interrupt: Off // Compare A Match Interrupt: Off // Compare B Match Interrupt: Off TCCR1A=0x40; TCCR1B=0x09; TCNT1H=0x00; TCNT1L=0x00; ICR1H=0x00; ICR1L=0x00; OCR1A=0x6E; OCR1B=0x00; // USART initialization // Communication Parameters: 8 Data, 1 Stop, No Parity // USART Receiver: Off // USART Transmitter: On // USART Mode: Asynchronous // USART Baud Rate: 2400 UCSRA=0x00; UCSRB=0x08; UCSRC=0x86; UBRRH=0x00; UBRRL=0xCF; while (1) { if((PINB.0==0) && (ps==0)) { putchar('0'); ps=1; } if((PINB.2==0) && (ps==0)) { putchar('1'); ps=1; } if((PINB.0==1)&&(PINB.2==1)) { ps=0; } }; } |
На железке все работало стабильно, глюков замечено не было, в пределах 1,5-2 метров прием устойчивый под разными углами, дальше — нужно целиться. В пределах 3-4 метров все работает нормально, дальше нет возможности проверить.
Исходники доступны здесь
Не бывает. Просто мы чего-то не знаем либо не учитываем…
Например, при каждом вызове прерывания в счетный регистр заносится наше расчитаное число- сколько тактов процессор на это тратит и как это влияет в итоге на частоту?
Протеус, кстати, при расчете берет «идеальную» частоту- но тем не менее вместо ожидаемых 38.095 КГц упорно показывает на выходе OC0A 35.037 КГц, что для «дальнобойности» ИК уже значимо.
Окей, предположим что визард код-вижна неидеален и ставит «неправильное» число (хотя вряд ли погрешность больше значения младшего разряда), модель tiny в протеусе неидеальна и часотомер тоже не идеален- и потому кажет что попало… Я согласен с вашими аргументами- в теории. Однако, я верю глазам своим. Факт пока остается фактом- подобраное по протеусу значение дало лучший результат, нежели «расчитаное». Я ни в коем случае не утверждаю что Протеус непогрешим- я просто даю пищу для размышления… 😉
Очень жаль что у нас нет частотомера. 🙁 Я бы тупо замерял частоту от кварцованого 2313 и ясность стала бы полной…
ЗЫ: извините за флуд…
Очевидно вы не правильно считаете или не правильно задаете частоты в CAVR или протеусе. При 38кГц (подчеркну) несущей, у вас никак не может получиться 0x8C на 9.6МГц. Если режим CTC, то таймер должен вызывать прерывания в 2 раза чаще, т.е. все тупо 9600 делим на 76 и получаем OCR, внутри прерывания дрыгаем ногой. Если использовать режим toggle то правила те же, но нога дрыгается аппаратно, без прерывания.
UPD: только что зачекал, все совпадает на 100%, ищите ошибку.
Привет админ! Пожалуйста объясни как сделать расчет я чет так и не понял.
Вот у меня Atmega8 8 МГц
Как расчитать 36 кгц?
Focn — частота, с которой должна дрыгаться ножка OC1(PB1) — здесь мы дожны 36 кгц получить, я понял, но в каких единицах? 36? или же 36000? по формуле
Fclk — частота таймера — это есть частота мк да? на фото Clock source? 8000? или 8000 000? в формуле?
N — частота предделителя таймера — на фото это есть clock value? в каких он единицах будет в формуле?
OCRn — значение регистра сравнения — это значение вводится на фото в comp A? да?
Пожалуйста поясните… жду ответа
частоты переводите в герцы и подставляете в формулы
6E для «Comp.A» я ставлю.
ИК светодиод напрямую цепляю одним контактом к выходу UartTX, а другим контактом к выходу с таймером.
без транзистора скорее всего не будет работать