Термометр з бездротовою передачею даних

    … На ультрадешевих радіомодулем по 5 доларів за пучок .
 
Комплект містить радіопередавач і сверхрегенератівниміпріємникамі приймач. Кількість контактів, фактично по 3 штуки, два з яких харчування, натякає на крайню простоту роботи з ними. Правда комплект більше орієнтується на дистанційне керування і частіше використовується в парі з кодерами і декодерами на спеціалізованих мікросхемах, але ми це упустимо, тому що свій велосипед завжди дорожче.
 
 
Передавач з амплітудною модуляцією на частоту 433 МГц, частота стабілізована ПАР. Передавач близький родич всяким одно-, двох-, трехтранзісторним жучкам і маячкам, які робили все, хто коли-небудь займався радіотехнікою (багато схем на vrtp.ru ). Харчування на передавач допускається до 12 В. Вхід data фактично відкриває транзистор і запускає генерацію, при низькому рівні на вході генерація припиняється. Відповідно виставляючи Hi і Lo на вході з певною частотою ми можемо передавати дані.
 
 
 
Приймач відноситься до класу сверхрегенератівниміпріємникамі. Нині така схема практично повністю вийшла з ужитку і замінена супергетеродині, але десятиліття тому на ній випускали навіть промислові приймачі для прослуховування радіоефіру.
Сверхрегенерат це подальший розвиток приймача прямого посилення. У вхідній контур за рахунок позитивного зворотного зв'язку в переривчастому режимі, на частотах десятки кГц, вноситься енергія джерела живлення у вигляді коливань тієї ж частоти, на яку налаштований контур. Цим компенсуються втрати в контурі і поліпшується його добротність. На виході радиомодуля варто компаратор, що видає на лінію Data Hi або Lo.
 
 
Переваги сверхрегенератівниміпріємникамі:
 
     
  • Простота і дешевизни конструкції
  •  
  • Дуже висока чутливість
  •  
  • Широка смуга пропускання
  •  
  • Автоматичне регулювання посилення
  •  
Недоліки, що випливають з достоїнств:
 
     
  • Широка смуга пропускання, в яку завжди щось потрапляє. Величина порядку одиниць МГц.
  •  
  • Висока чутливість, хоч передавач включений, хоч вимкнений, на виході приймача завжди є якийсь шум (див. далі).
  •  
  • Складність в налаштуванні, т.к. сверхрегенератівниміпріємникамі каскад виконує одночасно дві-три функції (підсилювач, генератор, детектор). Але нам-то вже налаштовувати нічого не треба.
  •  
 
На обох модулях залишено отвір під антену. Після того як поруч лежать модулі, були нарешті рознесені, я зрозумів, що без антени робити нічого і причепив до модулів в якості антен під руку потрапили крокодильчики з проводками. У такому вигляді дальність дії зібраних пристроїв склала понад 10 метрів по прямій при харчуванні передавача від Крони 9В. Нагадую, що в якості антени може використовуватися шматок дроту рівний приблизно ¼ або ½ довжини хвилі, в нашому випадку буде 17 або 34 см. Загальний провід (GND), якщо є можливість, краще підключити до противазі, яким може бути металевий корпус або інший шматок дроти, спрямований у протилежний від антени сторону.
 
Ця картинка при видаленні передавача на 10 метрів. Незважаючи на те, що потужність сигналу візуально сильно зменшилася, приймальний модуль дані отримує впевнено.
 
 
Тепер безпосередньо до передачі даних. Як же наївний я був коли підключив передавач до UART на одному контролері, і до UART на іншому. Я побачив переданий байт, хоча він і був в оточенні десятків зайвих! Подивіться наступну картинку, приймач завжди щось ловить. І тільки коли є стійкий періодичний (!) Сигнал, він чітко проявляється в усьому вхідному смітті. UART передає дані побитно, без поділу кожного біта, якщо передається 0x00, то це буде низький рівень на всьому протязі передачі байта, тобто передавач буде просто відключений, а якщо передається 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<<WDCE | 1<<WDTIE;
	WDTCR=1<<WDP3 | 1<<WDTIE;	// 4 секунды
	sei();
	MCUCR|=1<<SE | 1<<SM1;		// Режим сна Power-down
	sleep_cpu();
}
else for(uint8_t i=0; i<SLEEP_TIME; i++)
{
	cli();
	wdt_reset();
	WDTCR=1<<WDCE | 1<<WDTIE;
	WDTCR=1<<WDP3 | 1<<WDP0 | 1<<WDTIE;	// 8 секунд
	sei();
	MCUCR|=1<<SE | 1<<SM1;
	sleep_cpu();
}

 
 
Живлення здійснюється через ту ж саму Крону 9В, заміряне китайським тестером споживання в активному режимі 6мА, в режимі сну 0,2 мА. Не можу не приділити увагу схемою стабілізатора напруги. Контролер ж від 9В просто помре, а 5В і менш буде мало для передавача, тому знадобився перетворювач харчування. Підвищуючий імпульсний, можливо став би вносити перешкоди, і я з ним експериментувати не став. Простіше було поставити понижуючий лінійний, типу класичної 7805. Але несподівано я побачив, що у неї власне споживання 6 мА. Це означає, що поки контролер спить, вона сама зжере всю батарейку. Погуглити, я знайшов малопотребляющіх перетворювачі LP2950, ​​MCP1700… Але поблизу їх не було, а тут підвернулася ось така схема на парі транзисторів 7002. Номінали резисторів довелося зменшити навіть не до мегаом, а до сотень кіло, інакше вихідна напруга ніяк не піднімався вище 3 з невеликим вольт. Тепер воно стало приблизно 4,6 В, що цілком комфортно для контролера.
 
 Схема передавача, як не треба робити!
 
Приймач зібраний на базі 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-біти по-замовчуванням.
    
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.