Термометр с беспроводной передачей данных
…на ультрадешевых радиомодулях по 5 долларов за пучок.Комплект содержит радиопередатчик и сверхрегенеративный приемник. Количество контактов, фактически по 3 штуки, два из которых питание, намекает на крайнюю простоту работы с ними. Правда комплект больше ориентируется на дистанционное управление и чаще используется в паре с кодерами и декодерами на специализированных микросхемах, но мы это упустим, т.к. свой велосипед всегда дороже.Передатчик с амплитудной модуляцией на частоту 433 МГц, частота стабилизирована ПАВ. Передатчик близкий родственник всяким одно-, двух-, трехтранзисторным жучкам и маячкам, которые делали все, кто когда-либо занимался радиотехникой (много схем на vrtp.ru). Питание на передатчик допускается до 12 В. Вход data фактически открывает транзистор и запускает генерацию, при низком уровне на входе генерация прекращается. Соответственно выставляя Hi и Lo на входе с определенной частотой мы можем передавать данные.
Приемник относится к классу сверхрегенеративных. Нынче такая схема практически полностью вышла из употребления и заменена супергетеродинными, но десятилетия назад на ней выпускали даже промышленные приемники для прослушивания радиоэфира.Сверхрегенерат это дальнейшее развитие приемника прямого усиления. Во входной контур за счет положительной обратной связи в прерывистом режиме, на частотах десятки кГц, вносится энергия источника питания в виде колебаний той же частоты, на которую настроен контур. Этим компенсируются потери в контуре и улучшается его добротность. На выходе радиомодуля стоит компаратор, выдающий на линию Data Hi или Lo.
Достоинства сверхрегенеративных приемников:
Простота и дешевизны конструкции Очень высокая чувствительность Широкая полоса пропускания Автоматическая регулировка усиления Недостатки, вытекающие из достоинств: Широкая полоса пропускания, в которую всегда что-то попадает. Величина порядке единиц МГц. Высокая чувствительность, хоть передатчик включен, хоть выключен, на выходе приемника всегда есть какой-то шум (см. далее). Сложность в настройке, т.к. сверхрегенеративный каскад выполняет одновременно две-три функции (усилитель, генератор, детектор). Но нам-то уже настраивать ничего не надо. На обоих модулях оставлено отверстие под антенну. После того как рядом лежащие модули, были наконец разнесены, я понял, что без антенны делать нечего и прицепил к модулям в качестве антенн под руку попавшие крокодильчики с проводками. В таком виде дальность действия собранных устройств составила свыше 10 метров по прямой при питании передатчика от Кроны 9В. Напоминаю, что в качестве антенны может использоваться кусок провода равный примерно ¼ или ½ длины волны, в нашем случае будет 17 или 34 см. Общий провод (GND), если есть возможность, лучше подключить к противовесу, которым может быть металлический корпус или другой кусок провода, направленный в противоположную от антенны сторону.
Эта картинка при удалении передатчика на 10 метров. Несмотря на то, что мощность сигнала визуально сильно уменьшилась, приемный модуль данные получает уверенно.
Теперь непосредственно к передаче данных. Как же наивен я был когда подключил передатчик к UART на одном контроллере, и к UART на другом. Я увидел переданный байт, хотя он и был в окружении десятков лишних! Посмотрите следующую картинку, приемник всегда что-то ловит. И только когда есть устойчивый периодический (!) сигнал, он четко проявляется во всем входящем мусоре. UART передает данные побитно, без разделения каждого бита, если передается 0×00, то это будет низкий уровень на всем протяжении передачи байта, т.е. передатчик будет просто отключен, а если передается 0xff, то это будет высокий уровень, но и при этом приемник вскоре начнет видеть в нем неоднородности и выдавать случайную последовательность.
Т.е. я включаю передатчик, сажу линию данных на питание, передатчик во всю мощь передает несущую, а на приемнике я вижу несколько единиц, а потом мусор 11111111110100101001. Отпускаю линию данных, появляются нули и снова мусор 000000000110101010. Вывод: приемнику нужны периодические перепады уровня.
И такой код есть у нас. Манчестерский. В манчестерском коде биты кодируются перепадом из низкого уровня вверх (пусть будет 1), или из верхнего вниз (пусть будет 0). Соответственно перед началом передачи каждого бита уровень должен быть выставлен в начальное положение, а в середине измениться. Опытным путем выяснено, что оптимальная скорость передачи данных примерно 5–10–20 килобит в секунду. Это позволит добиться достаточно устойчивого приема, и будет использоваться в прототипе устройства, которое я и начну далее описывать.
Традиционно это будет термометр, но теперь с беспроводной передачей данных. По условию задачи на грядке под пленкой лежит передатчик, а в доме приемник, который, так сказать собирается данные с датчиков, ну с одного датчика, и строит гистограмму. Т.е. если я вижу, что ночью там было 0 градусов, я понимаю от чего вся рассада замерзла и остается только отыскать виновника.
Передатчик собран на контроллере Attiny13, с термодатчиком LM335. Термодатчик аналоговый, выдает 100 мВ на 1К. Источник опорного напряжения МК используется внутренний 1,1В.Т. к. значения с датчика свыше 3В, то данные на АЦП передаются через делитель. Контроллер просыпается раз в 30 минут, а в режиме отладки раз в 4 секунды, подает питание на термодатчик, включает передатчик, и в течение примерно 1–2 секунд передает текущую температуру тысячу раз. Да! Именно тысячу раз подряд, т.к. даже со 100 подряд передачами я пропускал данные в некоторых сеансах. Современные города, с десятками автомобильных сигналок на 433МГц не самое спокойное место.Температура передается в виде одного единственного байта с манчестерским кодированием.
0b10101011 на стороне приемника превратиться в 21°С.
Передача байта void send1() { PORT_TX&=~B_TX; _delay_us (DELAY_US); PORT_TX|=B_TX; _delay_us (DELAY_US); }
void send0() { PORT_TX|=B_TX; _delay_us (DELAY_US); PORT_TX&=~B_TX; _delay_us (DELAY_US); }
void send (char c)
{
send1();
for (uint8_t i=128; i>0; i>>=1)
{
if (c & i) send1();
else send0();
}
PORT_TX&=~B_TX;
}
Засыпание после передачи данных до поступления прерывания от сторожевого таймера
if (debug_mode)
{
cli ();
wdt_reset ();
WDTCR=1< Схема передатчика, как не надо делать!
Приемник собран на базе Attiny85 с дисплеем от Nokia 5110. Верхняя строка отведена под индикацию текущей температуры, нижняя показывает наибольшую и наименьшую. Центральная область 84×32 отображает гистограмму от 0 до 32С. Все что свыше или ниже просто обрезается. Прием ведется непрерывно. При переходе на линии приема с Lo в Hi делается попытка принять 8 бит данных. В первоначальном варианте прием бит выглядел примерно так: т.к. первый переход с Lo в Hi это середина стартового бита 1, то от него отмеряется время немногим меньше длительности бита, фиксируется значение на входе, а чуть погодя, когда наступает время прихода второй половины бита, снова фиксируется значение на порту. Таким образом определяется переход к верхнему или нижнему уровню. Дальше видно, что это сработало плохо. Схема приемника
Для отсеивания мусора я ожидаю три посылки подряд, и если они совпадают, то это и будет текущая температура. При этом она отображается и на 0,5 сек. отображается индикатор приема. Раз в 15 минут гистограмма сдвигается, а если в течение 45 минут не было получено новой температуры, то индикация текущей температуры гаснет, а гистограмма продолжит сдвигаться с пустой колонкой. Если бы char в настройках GCC не оказался unsigned, то все заработало бы с пол пинка, но странные глюки до ночи выклевывали мне мозг. А по утру включив приемник, при выключенном передатчике, я в течение получаса словил помеху, получив -91 градус.Тогда я не растерялся и сделал ожидание четырех посылок подряд. И словил ложную посылку опять в течение получаса. Я сделал ожидание двух подряд одинаковых байт и подтверждение их CRC8. И через часок опять словил ложную температуру, все согласно теореме о бесконечных обезьянах.«Полдюжины обезьян, будь у них пишущие машинки и одна-другая вечность в запасе, создадут все книги, которые хранятся сегодня в Британском музее«И, наконец, вернувшись к тройной посылке, но изменив алгоритм приема отдельных битов, я вроде успокоился, хотя понимаю, что обезьяны не дремлют. В измененном алгоритме при приеме каждого бита делается несколько промежуточных чтений порта и если происходит несвоевременный переход уровней, то прием прерывается. Было
int8_t read_bit ()
{
_delay_us (160); // ожидаем середины бита
char rx=PIN_RX & B_RX; // после этого ждем переход
for (uint8_t i=0; i<6; i++)
{
if((PIN_RX & B_RX) != rx)
{
if(rx) return 0;
else return 1;
}
}
return -1;
}
Стало
int8_t read_bit()
{
char rx=PIN_RX & B_RX;
for(uint8_t i=0; i<5; i++)
{
if((PIN_RX & B_RX) != rx) return -1; // несвоевременный переход
}
_delay_us(40); // здесь граница бит и может быть переход rx=PIN_RX & B_RX;
for (uint8_t i=0; i<5; i++)
{
if((PIN_RX & B_RX) != rx) return -1; // несвоевременный переход
}
rx=PIN_RX & B_RX; for (uint8_t i=0; i<6; i++) // здесь ожидаем переход вверх или вниз
{
if((PIN_RX & B_RX) != rx)
{
if(rx) return 0;
else return 1;
}
}
return -1;
}
Несмотря на то, что для серьезного применения в качестве модулей передачи данных эти радиомодули вряд ли годятся, но для сбора статистики, с последующие обработкой и отбраковкой явно недостоверных данных вполне. Т.к. устройства носят лишь демонстрационную функцию, то печатные платы я намеренно не выкладываю, тем более их стоит переразвести для исправления багов.Исходный криворукий Си-код и hex файлы в архиве. Fuse-биты по-умолчанию.