<?xml version="1.0"?>
<rss version="2.0"><channel><title>Arduino Latest Topics</title><link>https://it4it.club/forum/16-arduino/</link><description>Arduino Latest Topics</description><language>en</language><item><title>2.4 TFT Touch screen</title><link>https://it4it.club/topic/29-24-tft-touch-screen/</link><description><![CDATA[
<p>
	Забавный зверь но их много разных на одно лицо, может сделаем подборку ? Я на свой долго библиотеку искал а то что находил цвета были инвертированы и тачскрин был повернут на 90 градусов . То что заставило экранчик работать прекрепляю
</p>

<p>
	 
</p>

<p>
	<a class="ipsAttachLink ipsAttachLink_image" href="https://it4it.club/uploads/monthly_2016_02/Free-Shipping-1pcs-UNO-2-4-inch-TFT-touch-LCD-Screen-Module-For-Arduino-UNO-R3.jpg.0c9d06889431b3a1cc87c423f0d40b81.jpg"><img alt="Free-Shipping-1pcs-UNO-2-4-inch-TFT-touch-LCD-Screen-Module-For-Arduino-UNO-R3.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="244" src="https://it4it.club/uploads/monthly_2016_02/Free-Shipping-1pcs-UNO-2-4-inch-TFT-touch-LCD-Screen-Module-For-Arduino-UNO-R3.jpg.0c9d06889431b3a1cc87c423f0d40b81.jpg"></a>
</p>

<p>
	<a class="ipsAttachLink" href="https://it4it.club/applications/core/interface/file/attachment.php?id=245">Mcufriend_kbv_2.5.zip</a>
</p>
]]></description><guid isPermaLink="false">29</guid><pubDate>Sun, 21 Feb 2016 15:23:27 +0000</pubDate></item><item><title>&#x414;&#x43E;&#x43C;&#x430;&#x448;&#x43D;&#x44F;&#x44F; &#x43C;&#x435;&#x442;&#x435;&#x43E;&#x441;&#x442;&#x430;&#x43D;&#x446;&#x438;&#x44F; &#x43D;&#x430; Arduino &#x438; &#x43E;&#x442;&#x43F;&#x440;&#x430;&#x432;&#x43A;&#x430; &#x434;&#x430;&#x43D;&#x43D;&#x44B;&#x445; &#x43D;&#x430; "&#x41D;&#x430;&#x440;&#x43E;&#x434;&#x43D;&#x44B;&#x439; &#x43C;&#x43E;&#x43D;&#x438;&#x442;&#x43E;&#x440;&#x438;&#x43D;&#x433;"</title><link>https://it4it.club/topic/17-domashnyaya-meteostanciya-na-arduino-i-otpravka-dannyh-na-narodnyy-monitoring/</link><description><![CDATA[
<p>
	Это первая часть и соответственно первая версия метеостанции. Постепенно будем её улучшать обвешивая всяческими лампочками, свистульками и т.п. Текущий вариант протестирован и стабильно работает с июля 2015.
</p>

<p>
	Использованы:
</p>

<ol>
<li>
		Копия Arduino NANO на базе микроконтроллера ATmega328p
	</li>
	<li>
		Ethernet shield на базе чипа ENC28J60
	</li>
	<li>
		Датчик влажности AM2302, известный в народе как DHT22
	</li>
	<li>
		Барометр/Термометр GY-68 на базе сенсора фирмы BOSH - BMP180
	</li>
</ol>
<p>
	Все заказывалось в Китае. Думаю не имеет смысла кидать ссылки т.к они могут быть не актуальны через некоторое время после публикации.
</p>

<p>
	Также Вас может заинтересовать вариант метеостанции на ESP8266
</p>
<iframe data-embedcontent="" frameborder="0" src="https://it4it.club/topic/55-meteostantsiya-na-esp8266-ot-it4itclub/?do=embed"></iframe>

<p>
	<span style="color:#FF0000;"><strong>ВАЖНО!</strong></span>
</p>

<p>
	Я использовал в скетче сторожевой таймер (Watchdog timer). Для этого необходимо перепрошить загрузчик Arduino NANO (<span style="line-height:22.4px;">ATmega328p</span>) со стандартного на <a href="https://code.google.com/p/optiboot/" rel="external nofollow">Оptiboot</a> (как это сделать <a href="https://it4it.club/topic/19-%D0%BF%D0%B5%D1%80%D0%B5%D0%BF%D1%80%D0%BE%D1%88%D0%B8%D0%B2%D0%BA%D0%B0-bootloader-%D0%B7%D0%B0%D0%B3%D1%80%D1%83%D0%B7%D1%87%D0%B8%D0%BA%D0%B0/" rel="">описано тут</a>). Если залить выложенный ниже скетч в неподготовленный контроллер, получите "кирпич".
</p>

<p>
	Если Вы читаете эту часть уже после того как залили скетч, то необходимо перезапустить микроконтроллер по питанию (и только по питанию) и у Вас будет 8 сек. на перепрошивку его другой программой. Иначе "селяви", что в переводе с древнегреческого - НЕ ПОВЕЗЛО! Процедуру можно повторять сколько угодно раз, пока не восстановите беднягу.
</p>

<p>
	<strong>Вступительная часть окончена, переходим к делу</strong>
</p>

<p>
	Станция разделена на две части
</p>

<p>
	Первая находится дома, состоит из микроконтроллера и сетевого модуля, её задача производить все необходимые вычисления и держать связь с проектом "<a href="http://narodmon.ru/" rel="external nofollow">Народный мониторинг</a>".
</p>

<blockquote class="ipsStyle_spoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			<a class="ipsAttachLink ipsAttachLink_image" data-fileid="53" href="https://it4it.club/uploads/monthly_2015_09/2015-07-26_11.05.04.jpg.5a7609efd1496b7a5f740f0112bc987b.jpg" rel=""><img alt="2015-07-26 11.05.04.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="53" src="https://it4it.club/uploads/monthly_2015_09/2015-07-26_11.05.04.thumb.jpg.810f3f15362f56a4de3dbdf7f63596c2.jpg"></a>
		</p>
	</div>
</blockquote>

<p>
	Вторая часть состоит из двух датчиков описанных выше и размещенных на улице в продуваемом пластиковом корпусе, защищенным от прямых попаданий воды и солнечных лучей.
</p>

<blockquote class="ipsStyle_spoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			<a class="ipsAttachLink ipsAttachLink_image" data-fileid="58" href="https://it4it.club/uploads/monthly_2015_09/2015-07-26_11.05.16.jpg.1d4d21d90eb543857f1268b2d670c36b.jpg" rel=""><img alt="2015-07-26 11.05.16.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="58" src="https://it4it.club/uploads/monthly_2015_09/2015-07-26_11.05.16.thumb.jpg.e33190981cf1832afe7458b95612c624.jpg"></a>
		</p>
	</div>
</blockquote>

<p>
	На самом деле есть стандарты для размещения погодных станций и ни одно из изделий используемых в быту (пусть даже самое дорогое и крутое) никогда не покажет Вам точных данных. Это связано с местом её установки. Погодная станция должна стоять в чистом поле на высоте пары метров от земли и т.д и т.п. Вы это легко найдете в сети. Ну а нас интересуют приблизительные значения.
</p>

<p>
	Схема этого безобразия, за исключением Ethernet модуля (это просо "бутерброд"), выглядит так.
</p>

<p>
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="54" href="https://it4it.club/uploads/monthly_2015_09/arduino_weather_station1.png.96486e63a45570e8c34a9af8512f0832.png" rel=""><img alt="arduino_weather_station1.png" class="ipsImage ipsImage_thumbnailed" data-fileid="54" src="https://it4it.club/uploads/monthly_2015_09/arduino_weather_station1.thumb.png.2a64bda65ba35e00c2f40de9af274316.png"></a>
</p>

<p>
	На схеме использовал датчик BMP085 т.к другого я не нашел в Fritzing. На практике стоит BMP180 и подключен по 5V а не по 3.3V Т.к изучение китайской платы показало, что на борту имеется преобразователь.
</p>

<blockquote class="ipsStyle_spoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			<a class="ipsAttachLink ipsAttachLink_image" data-fileid="59" href="https://it4it.club/uploads/monthly_2015_09/2015-09-26_22.54.46.jpg.8b9b5a4730e74a950e1bda1086caffcc.jpg" rel=""><img alt="2015-09-26 22.54.46.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="59" src="https://it4it.club/uploads/monthly_2015_09/2015-09-26_22.54.46.thumb.jpg.090b4987d456e4306d8367e54bb8dfdd.jpg"></a>
		</p>
	</div>
</blockquote>

<p>
	Датчик DHT22 имеет обвязку в виде SMD резистора 0805 на 10kOm между двумя ногами - питание и 1-Wire. Но братья Китайцы могут продать датчик уже в обвязке по значительно завышенной ценой.
</p>

<blockquote class="ipsStyle_spoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			<a class="ipsAttachLink ipsAttachLink_image" data-fileid="57" href="https://it4it.club/uploads/monthly_2015_09/2015-07-05_20.10.13.jpg.911a01d600858e5ffb0dbc3d9628d6a0.jpg" rel=""><img alt="2015-07-05 20.10.13.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="57" src="https://it4it.club/uploads/monthly_2015_09/2015-07-05_20.10.13.thumb.jpg.711b41a00be8ee5898a15d2b53c6fd27.jpg"></a>
		</p>
	</div>
</blockquote>

<p>
	Для корпуса уличной части я выбрал пластиковую распределительную коробку со съемными заглушками. Датчики разместил в верхней части т.к там оставлены заглушки для зашиты от воды во время дождей. Остальные заглушки убраны для повышения точности измерений.
</p>

<p>
	Из-за того, что доступ у меня имеется только к солнечной стороне дома, пришлось спрятать коробку за WiFi тарелкой. Кстати это дополнительно дало возможность хоть немного отдалить сенсоры от самого здания, ведь ночью нагретый дом выделяет энергию в виде тепла и искажает показания. 
</p>

<p>
	Если следовать ГОСТу, то сенсоры должны быть размещены в тени в течение всего дня.
</p>

<blockquote class="ipsStyle_spoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			<a class="ipsAttachLink ipsAttachLink_image" data-fileid="55" href="https://it4it.club/uploads/monthly_2015_09/2015-07-05_20.09.56.jpg.39aec63538b42826cdc7f9e23639620e.jpg" rel=""><img alt="2015-07-05 20.09.56.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="55" src="https://it4it.club/uploads/monthly_2015_09/2015-07-05_20.09.56.thumb.jpg.901a5d68e366b7563448504e706b0500.jpg"></a>
		</p>
	</div>
</blockquote>

<blockquote class="ipsStyle_spoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			<a class="ipsAttachLink ipsAttachLink_image" data-fileid="56" href="https://it4it.club/uploads/monthly_2015_09/2015-07-05_20.10.05.jpg.853c006ad124683ff7d569147f9442ba.jpg" rel=""><img alt="2015-07-05 20.10.05.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="56" src="https://it4it.club/uploads/monthly_2015_09/2015-07-05_20.10.05.thumb.jpg.cecb3896114333a236722c64fe31f78c.jpg"></a>
		</p>
	</div>
</blockquote>

<p>
	Переходим к самому вкусному
</p>

<p>
	Необходимо зарегистрироваться на <a href="http://narodmon.ru/" rel="external nofollow">http://narodmon.ru/</a> и добавить Ваше устройство. В качестве идентификатора, чтобы не запутать себя, Вы можете использовать MAC адрес Ethernet модуля. В данном случае мы будем передавать данные по TCP на 8283 порт сервера. Телеграмма будет состоять из:
</p>

<ol>
<li>
		Идентификатора устройства (MAC адрес)
	</li>
	<li>
		Названия устройства
	</li>
	<li>
		GPS координаты для позиционирования на карте проекта (т.к станция стационарна, координаты указаны в скетче без использования GPS модуля)
	</li>
	<li>
		Показания со всех датчиков
	</li>
</ol>
<p>
	<strong>Программная часть</strong>
</p>

<p>
	Понадобятся библиотеки:
</p>

<ol>
<li>
		BMP180 (использует библиотеку BMP085) <a class="ipsAttachLink" data-fileid="68" href="https://it4it.club/applications/core/interface/file/attachment.php?id=68" rel="">bmp085.zip</a>
	</li>
	<li>
		DHT22 <a href="https://github.com/adafruit/DHT-sensor-library" rel="external nofollow">https://github.com/adafruit/DHT-sensor-library</a>
	</li>
	<li>
		UIPEthernet <a href="https://github.com/ntruchsess/arduino_uip" rel="external nofollow">https://github.com/ntruchsess/arduino_uip</a>
	</li>
	<li>
		1-Wire <a href="http://playground.arduino.cc/Learning/OneWire" rel="external nofollow">http://playground.arduino.cc/Learning/OneWire</a>
	</li>
</ol>
<p style="color:#272a34">
	<iframe allowtransparency="true" frameborder="0" height="198" scrolling="no" src="https://money.yandex.ru/quickpay/shop-widget?account=410014941215337&amp;quickpay=shop&amp;payment-type-choice=on&amp;mobile-payment-type-choice=on&amp;writer=seller&amp;targets=%D0%BF%D0%BE%D0%BA%D1%83%D0%BF%D0%BA%D0%B0+%D1%81%D0%B5%D1%80%D0%B2%D0%B5%D1%80%D0%B0&amp;targets-hint=&amp;default-sum=&amp;button-text=01&amp;successURL=" width="450"></iframe>
</p>

<p style="color:#272a34">
	<a href="https://paypal.me/kitsum" rel="external nofollow" style="color:#3c6994" target="_blank"><img alt="PayPal.png" src="https://it4it.club/PayPal.png"></a>
</p>

<p>
	<em>Скетч</em>
</p>

<blockquote class="ipsStyle_spoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5317_5">

<span class="com">#include</span><span class="pln"> </span><span class="str">&lt;avr/wdt.h&gt;</span><span class="pln">
</span><span class="com">#include</span><span class="pln"> </span><span class="str">&lt;Wire.h&gt;</span><span class="pln">
</span><span class="com">#include</span><span class="pln"> </span><span class="str">&lt;BMP085.h&gt;</span><span class="pln">
</span><span class="com">#include</span><span class="pln"> </span><span class="str">"DHT.h"</span><span class="pln">
</span><span class="com">#include</span><span class="pln"> </span><span class="str">&lt;UIPEthernet.h&gt;</span><span class="pln">

</span><span class="com">#define</span><span class="pln"> DHTTYPE DHT22
</span><span class="com">#define</span><span class="pln"> DHTPIN </span><span class="lit">5</span><span class="pln">

DHT dht</span><span class="pun">(</span><span class="pln">DHTPIN</span><span class="pun">,</span><span class="pln"> DHTTYPE</span><span class="pun">);</span><span class="pln">

byte mac</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="lit">0x54</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0x34</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0x31</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0x31</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0x31</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0x31</span><span class="pun">};</span><span class="pln">
</span><span class="kwd">char</span><span class="pln"> server</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"narodmon.ru"</span><span class="pun">;</span><span class="pln">
</span><span class="typ">int</span><span class="pln"> port </span><span class="pun">=</span><span class="pln"> </span><span class="lit">8283</span><span class="pun">;</span><span class="pln">

</span><span class="typ">IPAddress</span><span class="pln"> ip</span><span class="pun">(</span><span class="lit">192</span><span class="pun">,</span><span class="lit">168</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">201</span><span class="pun">);</span><span class="pln">
</span><span class="typ">EthernetClient</span><span class="pln"> client</span><span class="pun">;</span><span class="pln">

BMP085 dps </span><span class="pun">=</span><span class="pln"> BMP085</span><span class="pun">();</span><span class="pln">
</span><span class="kwd">long</span><span class="pln"> </span><span class="typ">Temperature</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Pressure</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">bool</span><span class="pln"> interval </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">void</span><span class="pln"> setup</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// Инициализация сторожевого таймера (Watchdog timer)</span><span class="pln">
  wdt_disable</span><span class="pun">();</span><span class="pln">
  delay</span><span class="pun">(</span><span class="lit">8000</span><span class="pun">);</span><span class="pln">
  wdt_enable</span><span class="pun">(</span><span class="pln">WDTO_8S</span><span class="pun">);</span><span class="pln">
  </span><span class="com">// Инициализация консоли</span><span class="pln">
  </span><span class="typ">Serial</span><span class="pun">.</span><span class="pln">begin</span><span class="pun">(</span><span class="lit">9600</span><span class="pun">);</span><span class="pln">
  </span><span class="com">// Инициализация датчика DHT</span><span class="pln">
  dht</span><span class="pun">.</span><span class="pln">begin</span><span class="pun">();</span><span class="pln">
  </span><span class="com">// Стартуем сеть, если не дождались данных с DHCP сервера то</span><span class="pln">
  </span><span class="com">// присваеваем себе адрес самостоятельно</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Ethernet</span><span class="pun">.</span><span class="pln">begin</span><span class="pun">(</span><span class="pln">mac</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="typ">Ethernet</span><span class="pun">.</span><span class="pln">begin</span><span class="pun">(</span><span class="pln">mac</span><span class="pun">,</span><span class="pln"> ip</span><span class="pun">);</span><span class="pln">
  </span><span class="com">// Инициализация 1-Wire</span><span class="pln">
  </span><span class="typ">Wire</span><span class="pun">.</span><span class="pln">begin</span><span class="pun">();</span><span class="pln">
  delay</span><span class="pun">(</span><span class="lit">200</span><span class="pun">);</span><span class="pln">
  
  </span><span class="com">// Инициализация BMP180 с корректировкой высоты</span><span class="pln">
  </span><span class="com">// dps.init(MODE_STANDARD, 3200, true);</span><span class="pln">
  
  </span><span class="com">// Инициализация BMP180</span><span class="pln">
  dps</span><span class="pun">.</span><span class="pln">init</span><span class="pun">();</span><span class="pln">

  </span><span class="com">// Отправляем первые данные сразу после включения устройства</span><span class="pln">
  send_info</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">// dewPoint function NOAA</span><span class="pln">
</span><span class="com">// reference (1) : http://wahiduddin.net/calc/density_algorithms.htm</span><span class="pln">
</span><span class="com">// reference (2) : http://www.colorado.edu/geography/weather_station/Geog_site/about.htm</span><span class="pln">
</span><span class="kwd">double</span><span class="pln"> dewPoint</span><span class="pun">(</span><span class="kwd">double</span><span class="pln"> celsius</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">double</span><span class="pln"> humidity</span><span class="pun">)</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
  </span><span class="com">// (1) Saturation Vapor Pressure = ESGG(T)</span><span class="pln">
  </span><span class="kwd">double</span><span class="pln"> RATIO </span><span class="pun">=</span><span class="pln"> </span><span class="lit">373.15</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="pun">(</span><span class="lit">273.15</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> celsius</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">double</span><span class="pln"> RHS </span><span class="pun">=</span><span class="pln"> </span><span class="pun">-</span><span class="lit">7.90298</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">(</span><span class="pln">RATIO </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">
  RHS </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">5.02808</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> log10</span><span class="pun">(</span><span class="pln">RATIO</span><span class="pun">);</span><span class="pln">
  RHS </span><span class="pun">+=</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1.3816e-7</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">(</span><span class="pln">pow</span><span class="pun">(</span><span class="lit">10</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="lit">11.344</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">(</span><span class="lit">1</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">/</span><span class="pln">RATIO </span><span class="pun">)))</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">;</span><span class="pln">
  RHS </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">8.1328e-3</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">(</span><span class="pln">pow</span><span class="pun">(</span><span class="lit">10</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(-</span><span class="lit">3.49149</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">(</span><span class="pln">RATIO </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)))</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">;</span><span class="pln">
  RHS </span><span class="pun">+=</span><span class="pln"> log10</span><span class="pun">(</span><span class="lit">1013.246</span><span class="pun">);</span><span class="pln">
  </span><span class="com">// factor -3 is to adjust units - Vapor Pressure SVP * humidity</span><span class="pln">
  </span><span class="kwd">double</span><span class="pln"> VP </span><span class="pun">=</span><span class="pln"> pow</span><span class="pun">(</span><span class="lit">10</span><span class="pun">,</span><span class="pln"> RHS </span><span class="pun">-</span><span class="pln"> </span><span class="lit">3</span><span class="pun">)</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> humidity</span><span class="pun">;</span><span class="pln">
  </span><span class="com">// (2) DEWPOINT = F(Vapor Pressure)</span><span class="pln">
  </span><span class="kwd">double</span><span class="pln"> T </span><span class="pun">=</span><span class="pln"> log</span><span class="pun">(</span><span class="pln">VP</span><span class="pun">/</span><span class="lit">0.61078</span><span class="pun">);</span><span class="pln">   </span><span class="com">// temp var</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="lit">241.88</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> T</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="pun">(</span><span class="lit">17.558</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> T</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">// delta max = 0.6544 wrt dewPoint()</span><span class="pln">
</span><span class="com">// 6.9 x faster than dewPoint()</span><span class="pln">
</span><span class="com">// reference: http://en.wikipedia.org/wiki/Dew_point</span><span class="pln">
</span><span class="kwd">double</span><span class="pln"> dewPointFast</span><span class="pun">(</span><span class="kwd">double</span><span class="pln"> celsius</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">double</span><span class="pln"> humidity</span><span class="pun">)</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">double</span><span class="pln"> a </span><span class="pun">=</span><span class="pln"> </span><span class="lit">17.271</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">double</span><span class="pln"> b </span><span class="pun">=</span><span class="pln"> </span><span class="lit">237.7</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">double</span><span class="pln"> temp </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">a </span><span class="pun">*</span><span class="pln"> celsius</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="pun">(</span><span class="pln">b </span><span class="pun">+</span><span class="pln"> celsius</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> log</span><span class="pun">(</span><span class="pln">humidity</span><span class="pun">*</span><span class="lit">0.01</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">double</span><span class="pln"> </span><span class="typ">Td</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">b </span><span class="pun">*</span><span class="pln"> temp</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="pun">(</span><span class="pln">a </span><span class="pun">-</span><span class="pln"> temp</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">Td</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">void</span><span class="pln"> send_info</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="typ">float</span><span class="pln"> H</span><span class="pun">,</span><span class="pln"> dP</span><span class="pun">,</span><span class="pln"> dPt</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">bool</span><span class="pln"> fail </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">

  </span><span class="kwd">while</span><span class="pun">(</span><span class="pln">fail</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// Пытаемся считать данные с датчика влажности DHT до тех пор, пока не получим </span><span class="pln">
    </span><span class="com">// результат. В 90% случаев все работает нормально, но нам нужны 100%</span><span class="pln">
    </span><span class="kwd">if</span><span class="pun">((</span><span class="pln">H </span><span class="pun">=</span><span class="pln"> dht</span><span class="pun">.</span><span class="pln">readHumidity</span><span class="pun">())</span><span class="pln"> </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="com">// Получение влажности и температуры с датчика BMP180</span><span class="pln">
      dps</span><span class="pun">.</span><span class="pln">getPressure</span><span class="pun">(&amp;</span><span class="typ">Pressure</span><span class="pun">);</span><span class="pln">
      dps</span><span class="pun">.</span><span class="pln">getTemperature</span><span class="pun">(&amp;</span><span class="typ">Temperature</span><span class="pun">);</span><span class="pln">
      </span><span class="com">// Подсчитываем точку росы, если температура на улице выше 0 градусов Цельсия</span><span class="pln">
      </span><span class="com">// и ожидаем результат выше 0, в противном случае выводим 0. Это необходимо</span><span class="pln">
      </span><span class="com">// чтобы не вводить в заблуждения в зимее время года.</span><span class="pln">
      dP </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Temperature</span><span class="pun">&gt;</span><span class="lit">0</span><span class="pun">?((</span><span class="pln">dPt</span><span class="pun">=</span><span class="pln">dewPoint</span><span class="pun">(</span><span class="typ">Temperature</span><span class="pun">*</span><span class="lit">0.1</span><span class="pun">,</span><span class="pln"> H</span><span class="pun">))&lt;</span><span class="lit">0</span><span class="pun">?</span><span class="lit">0</span><span class="pun">:</span><span class="pln">dPt</span><span class="pun">):</span><span class="lit">0</span><span class="pun">;</span><span class="pln">
      </span><span class="com">// Подключаемся к серверу "Народный мониторинг"</span><span class="pln">
      </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">client</span><span class="pun">.</span><span class="pln">connect</span><span class="pun">(</span><span class="pln">server</span><span class="pun">,</span><span class="pln"> port</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="com">// Начинаем передачу данных</span><span class="pln">
        </span><span class="com">// адрес_устройства_в_проекте, имя_устройства, GPS широта, GPS долгота</span><span class="pln">
        client</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln">F</span><span class="pun">(</span><span class="str">"#fe-31-31-0e-5a-3b#Arduino Nano#71.344699#27.200014\n"</span><span class="pun">));</span><span class="pln">
        </span><span class="com">// температура</span><span class="pln">
        client</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln">F</span><span class="pun">(</span><span class="str">"#T0#"</span><span class="pun">));</span><span class="pln">
        client</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="typ">Temperature</span><span class="pun">*</span><span class="lit">0.1</span><span class="pun">);</span><span class="pln">        
        client</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln">F</span><span class="pun">(</span><span class="str">"#Температура\n"</span><span class="pun">));</span><span class="pln">
        </span><span class="com">// Давление</span><span class="pln">
        client</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"#P1#"</span><span class="pun">);</span><span class="pln">
        client</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="typ">Pressure</span><span class="pun">/</span><span class="lit">133.3</span><span class="pun">);</span><span class="pln">
        client</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln">F</span><span class="pun">(</span><span class="str">"#Давление\n"</span><span class="pun">));</span><span class="pln">
        </span><span class="com">// Влажность</span><span class="pln">
        client</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"#H1#"</span><span class="pun">);</span><span class="pln">
        client</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln">H</span><span class="pun">);</span><span class="pln">
        client</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln">F</span><span class="pun">(</span><span class="str">"#Влажность\n"</span><span class="pun">));</span><span class="pln">
        </span><span class="com">// Точка росы</span><span class="pln">
        client</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"#T1#"</span><span class="pun">);</span><span class="pln">
        client</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln">dP</span><span class="pun">);</span><span class="pln">
        client</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln">F</span><span class="pun">(</span><span class="str">"#Точка росы\n"</span><span class="pun">));</span><span class="pln">
        </span><span class="com">// Отправляем конец телеграммы</span><span class="pln">
        client</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"##"</span><span class="pun">);</span><span class="pln">

        </span><span class="com">// Даем время отработать Ethernet модулю и разрываем соединение</span><span class="pln">
        delay</span><span class="pun">(</span><span class="lit">200</span><span class="pun">);</span><span class="pln">
        client</span><span class="pun">.</span><span class="pln">stop</span><span class="pun">();</span><span class="pln">
        </span><span class="com">// Останавливаем цикл, если передача завершена</span><span class="pln">
        fail </span><span class="pun">=</span><span class="pln"> </span><span class="pun">!</span><span class="pln">fail</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
      delay</span><span class="pun">(</span><span class="lit">250</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    delay</span><span class="pun">(</span><span class="lit">250</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">void</span><span class="pln"> loop</span><span class="pun">()</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
  </span><span class="com">// Каждые 3 секунды сбрасываем сторожевой таймер микроконтроллера</span><span class="pln">
  </span><span class="com">// Каждые 6 минут отправляем данные на "Народный мониторинг"</span><span class="pln">
  </span><span class="kwd">if</span><span class="pun">(!(</span><span class="pln">millis</span><span class="pun">()/</span><span class="lit">1000</span><span class="pun">%</span><span class="lit">30</span><span class="pun">))</span><span class="pln"> wdt_reset</span><span class="pun">();</span><span class="pln">
  </span><span class="kwd">if</span><span class="pun">(!(</span><span class="pln">millis</span><span class="pun">()/</span><span class="lit">1000</span><span class="pun">%</span><span class="lit">360</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">interval</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      send_info</span><span class="pun">();</span><span class="pln">
      interval </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">else</span><span class="pln"> interval </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln"> 
</span><span class="pun">}</span></pre>

		<p>
			 
		</p>
	</div>
</blockquote>

<p>
	Данные о температуре снимаются с датчика BOSH, они более точны.
</p>

<p>
	Точка росы рассчитывается исходя из текущих показаний температуры и влажности. В коде имеются две функции взятые с просторов интернета:
</p>

<ol>
<li>
		dewPoint
	</li>
	<li>
		dewPointFast
	</li>
</ol>
<p>
	Использовать можно любую. Также имеется проверка показаний точки росы. Вычисления не производятся при минусовой температуре и значение обнуляется при показаниях ниже нуля. Т.к это уже не точка росы, а точка образования инея. Если я не прав, то прошу меня поправить.
</p>

<p>
	Если желаете получать отрицательные показания, то необходимо заменить:
</p>

<pre class="ipsCode prettyprint prettyprinted">
<span class="pln">dP </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Temperature</span><span class="pun">&gt;</span><span class="lit">0</span><span class="pun">?((</span><span class="pln">dPt</span><span class="pun">=</span><span class="pln">dewPoint</span><span class="pun">(</span><span class="typ">Temperature</span><span class="pun">*</span><span class="lit">0.1</span><span class="pun">,</span><span class="pln"> H</span><span class="pun">))&lt;</span><span class="lit">0</span><span class="pun">?</span><span class="lit">0</span><span class="pun">:</span><span class="pln">dPt</span><span class="pun">):</span><span class="lit">0</span><span class="pun">;</span></pre>

<p>
	на
</p>

<pre class="ipsCode prettyprint prettyprinted">
<span class="pln">dP </span><span class="pun">=</span><span class="pln"> dewPoint</span><span class="pun">(</span><span class="typ">Temperature</span><span class="pun">*</span><span class="lit">0.1</span><span class="pun">,</span><span class="pln"> H</span><span class="pun">);</span></pre>

<p>
	На сайте проекта имеются ссылки на приложения под разные платформы. Я использую Android и для примера взял два разных виджета. Выглядит это следующим образом.
</p>

<blockquote class="ipsStyle_spoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			<a class="ipsAttachLink ipsAttachLink_image" data-fileid="69" href="https://it4it.club/uploads/monthly_2015_09/2015-09-27_11.25.39.png.2572b685bcdfd5380d5f892f6cb72041.png" rel=""><img alt="2015-09-27 11.25.39.png" class="ipsImage ipsImage_thumbnailed" data-fileid="69" src="https://it4it.club/uploads/monthly_2015_09/2015-09-27_11.25.39.thumb.png.a376142ffafcea413288848c257fdd4c.png"></a>
		</p>
	</div>
</blockquote>

<p>
	В дальнейшем планирую:
</p>

<ol>
<li>
		Увеличить разнообразие датчиков
	</li>
	<li>
		Объединить обе части метеостанции и вынести все на улицу
	</li>
	<li>
		Уйти от ENC28J60 в пользу W5100 или W5500
	</li>
	<li>
		Использовать POE для питания всей кухни
	</li>
</ol>
<p>
	<strong>PS:</strong> пока все доволен. Посмотрим как конструкция переживет зиму и сделаем дополнительные выводы.
</p>

<p>
	<a class="ipsAttachLink" data-fileid="68" href="https://it4it.club/applications/core/interface/file/attachment.php?id=68" rel="">bmp085.zip</a>
</p>
]]></description><guid isPermaLink="false">17</guid><pubDate>Sun, 27 Sep 2015 08:55:49 +0000</pubDate></item><item><title>&#x417;&#x430;&#x43C;&#x43E;&#x43A; &#x441; &#x440;&#x430;&#x434;&#x438;&#x43E;&#x447;&#x430;&#x441;&#x442;&#x43E;&#x442;&#x43D;&#x43E;&#x439; &#x438;&#x434;&#x435;&#x43D;&#x442;&#x438;&#x444;&#x438;&#x43A;&#x430;&#x446;&#x438;&#x435;&#x439;</title><link>https://it4it.club/topic/24-zamok-s-radiochastotnoy-identifikaciey/</link><description><![CDATA[
<p>
	 
</p>
<iframe data-embedcontent="" frameborder="0" src="https://it4it.club/topic/60-zamok-s-radiochastotnoy-identifikaciey-na-baze-nfc-kontrollera-pn532/?do=embed"></iframe>

<p>
	<strong>Обновление по просьбе Alex13 <a href="https://it4it.club/topic/24-zamok-s-radiochastotnoy-identifikatsiey/?do=findComment&amp;comment=112" rel="">находится тут</a></strong>
</p>

<ol>
<li>
		Открытие/Закрытие разнесены на разные пины микроконтроллера (для управление соленоидом)
	</li>
</ol>
<div class="ipsSpoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<div class="ipsEmbeddedVideo" contenteditable="false">
			<div>
				<iframe allowfullscreen="true" frameborder="0" height="270" src="https://www.youtube.com/embed/nh6kXqP5pWg?feature=oembed" width="480"></iframe>
			</div>
		</div>

		<p>
			 
		</p>
	</div>
</div>

<p>
	<strong>Обновление по просьбе Alex13 <a href="https://it4it.club/topic/24-zamok-s-radiochastotnoy-identifikatsiey/?do=findComment&amp;comment=56" rel="">находится тут</a></strong>
</p>

<ol>
<li>
		Добавлен выбор режима закрытия замка (автоматический или по карте)
	</li>
	<li>
		Добавлена сигнализация оповещающая о попытках подбора ключа
	</li>
</ol>
<p>
	<strong>Обновление по просьбе svchekalin <a href="https://it4it.club/topic/24-zamok-s-radiochastotnoy-identifikatsiey/?page=2#comment-79" rel="">находится тут</a></strong>
</p>

<ol>
<li>
		Добавлен Ethernet Shield на чипе W5100
	</li>
	<li>
		Ключи теперь хранятся не в EEPROM контроллера, а в MySQL базе на удаленном сервере
	</li>
	<li>
		...
	</li>
</ol>
<p style="text-align:center;">
	<img alt="nrf_z9.jpg.38a9bbdeb71babfdc66653a8d099b" class="ipsImage ipsImage_thumbnailed" data-fileid="151" data-unique="zgf3xr0y8" src="https://it4it.club/uploads/monthly_2015_11/nrf_z9.jpg.38a9bbdeb71babfdc66653a8d099b670.jpg"></p>

<p>
	<span style="color:#FF0000;"><strong>Внимание: Очень много фотографий в статье!</strong></span>
</p>

<p>
	<strong>Начнем с предыстории.</strong>
</p>

<p>
	В один обыденный рабочий день ко мне обратились мои друзья и по совместительству коллеги по работе с идеей сделать замок с радиочастотной идентификацией. Электронный замок должен обслуживать дверь в рабочее помещение. Все бы хорошо, но дверь далеко не домашняя, сделана из метала и стоит в металлической коробки. Собрать электронную начинку замка и написать программу для микроконтроллера - решаемая задача, но как механически удержать такого монстра в зафиксированном состоянии?
</p>

<p>
	Но то, что для меня казалось проблемой, было воспринято моими друзьями с ухмылкой, и мне показали здоровый электромагнит. Точно такие же электромагниты используются в домофонах. Даже не хочу знать, откуда они его достали, но меня увиденное воодушевило.
</p>

<div class="ipsSpoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p style="text-align:center;">
			<img alt="nrf_z14.jpg.c2ea95d8d6a6215b1930ae5083c5" class="ipsImage ipsImage_thumbnailed" data-fileid="156" data-unique="djh3yg2fx" src="https://it4it.club/uploads/monthly_2015_11/nrf_z14.jpg.c2ea95d8d6a6215b1930ae5083c58122.jpg"><img alt="nrf_z15.jpg.abd99b3ce7edb35efdf99b83b19d" class="ipsImage ipsImage_thumbnailed" data-fileid="157" data-unique="vnvlbybje" src="https://it4it.club/uploads/monthly_2015_11/nrf_z15.jpg.abd99b3ce7edb35efdf99b83b19dc43d.jpg"></p>
	</div>
</div>

<p>
	Задача поставлена, приступаем к реализации!
</p>

<p>
	<strong>Техническое задание</strong>
</p>

<ol>
<li>
		Замок должен аутентифицировать хозяев без физического контакта пользователя с устройством
	</li>
	<li>
		Память должна вмещать не менее двух десятков ключей
	</li>
	<li>
		Устройство должно иметь возможность добавлять в память новые ключи
	</li>
	<li>
		Добавлять новые ключи можно только, используя специальный, мастер ключ
	</li>
	<li>
		Мастер ключ должен также иметь возможность открывать замок
	</li>
	<li>
		Должна быть реализована возможность обнуления списка используемых ключей, в том числе и удаление мастер ключа
	</li>
	<li>
		Замок должен иметь возможность открываться изнутри по нажатию на кнопку (как в домофоне)
	</li>
	<li>
		Все описанные пункты должны быть просты в использовании и не требовать знания программирования
	</li>
</ol>
<p>
	<strong>Реализация</strong>
</p>

<p>
	За основу было решено взять клон <strong>Arduino UNO</strong> с <strong>ATmega328p</strong> на борту в паре с <strong>RFID (NRF)</strong> сканером <strong>RC522</strong>. Сам сканер является очень удачным выбором т.к работает на частоте <strong>13.56 МГц</strong> и поддерживает чипы:
</p>

<ol>
<li>
		MIFARE S50
	</li>
	<li>
		MIFARE S70
	</li>
	<li>
		MIFARE UltraLight
	</li>
	<li>
		MIFARE Pro
	</li>
	<li>
		MIFARE DESfire
	</li>
	<li>
		...
	</li>
</ol>
<p style="text-align:center;">
	<img alt="nrf_z2.jpg.8508ffa5ad9a4870a2cb66b7d1a97" class="ipsImage ipsImage_thumbnailed" data-fileid="144" data-unique="29jmg735w" src="https://it4it.club/uploads/monthly_2015_11/nrf_z2.jpg.8508ffa5ad9a4870a2cb66b7d1a976c1.jpg"></p>

<div class="ipsSpoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p style="text-align:center;">
			<img alt="nrf_z3.jpg.867d059e0990bd6b1275223d13791" class="ipsImage ipsImage_thumbnailed" data-fileid="145" data-unique="jmh26cpr7" src="https://it4it.club/uploads/monthly_2015_11/nrf_z3.jpg.867d059e0990bd6b1275223d13791b58.jpg"></p>
	</div>
</div>

<p>
	Данные чипы используются в различных карточках метро и прочего общественного транспорта, ключах современных домофонов, различных умных браслетах и носимой электроники. У братьев Китайцев можно купить даже кольца с RFID (NRF) меткой. Некоторые чипы имеют энергонезависимую память небольшого объема.
</p>

<p>
	<strong>Прокручиваем решение в голове</strong>
</p>

<p>
	Хранить все ключи будем в энергонезависимой памяти микроконтроллера (<strong>EEPROM</strong>). Хорошее и как мне кажется единственное решение. <strong>ATmega328p</strong> имеет <strong>1kB</strong> памяти, <strong>RFID (NRF)</strong> ключи содержат уникальный номер размером от 4 до N байт. Если уровнять все типы ключей, то читать мы будем только первый четыре байта любого ключа. Делаем вывод, что <span style="color:#008000;"><strong>1024/4=256</strong></span> ключей.
</p>

<p>
	Но необходимо знать точное их количество чтобы не читать пустую память, иначе можно взломать замок так, как это делается с некоторыми домофонами, а именно - передать ключ, состоящий из одних 0 или 255 и Вуаля!
</p>

<p>
	Выделим один и по совместительству первый байт в <strong>EEPROM</strong> под число с количеством ключей и получаем <span style="color:#008000;"><strong>(1024-1)/4=255,75</strong></span>, а это 255 полноценных четырехбайтных ключей! Это более чем достаточно, хоть домофон делай.
</p>

<p>
	Добавлять ключи будем путем записи его первых четырех байт, в свободную память микроконтроллера, начиная с N+1 занятого байта памяти Arduino. Но делать это необходимо только с использованием мастер ключа. И тут встают два вопроса, какой из ключей должен быть мастером и как его найти среди кучи всех остальных? 
</p>

<p>
	А пусть мастер ключ хранится в строго определенных "ячейках" памяти микроконтроллера, мы ведь делаем это с количеством ключей! Пусть первый байт <strong>EEPROM</strong> отвечает за количество известных нам ключей, а следующие четыре байта будут отведены мастер ключу. Оставшуюся память отдаем под все остальное.
</p>

<p>
	Открытие дверей. Как понять, что поднесенный к сканеру ключ является тем самым или наоборот. Давайте опять отталкиваться от идеи четырехбайтного ключа. Пройдя все предыдущие этапы записи памяти микроконтроллера, мы с 100% точностью можем сказать, сколько ключей и как они расположены в памяти Arduino. Следовательно, для быстрого сравнения логичнее искать совпадение по первому байту каждого ключа в памяти, и только если оно найдено переходить к сравнению следующего байта. Если какой либо из 4 байт не совпал, то останавливаем проверку и переходить к следующему ключу в памяти микроконтроллера. Если найдено совпадение всех четырех байт ключа, то прекращаем проверку и устанавливаем замок в состояние открыто, иначе оставляем замок запертым.
</p>

<p>
	Пройдя эту не хитрую процедуру, мы можем точно сказать разрешен данному ключу доступ или нет, а заодно является ли он мастер ключом. Ведь мы будем знать номер совпавшего ключа в памяти Arduino следовательно, если он первый (на самом деле нулевой), то это волшебный ключ.
</p>

<p>
	Чтобы добавить новый ключ в память замка необходимо поднести и удерживать у <strong>RFID (NRF)</strong> сканера мастер ключ. Для начала будет открыта дверь, чтобы впустить владыку в обитель. Но если мастер ключ удерживается в течение 5 секунд (по умолчанию), то замок переводится в постоянно открытое состояние и система распознавания ключей, описанная ранее, начинает работать как проверка наличия ключа в памяти. Ключа нет, тогда записываем его. Ключ найден, значит, ругаемся, плюемся и топаем ногами.
</p>

<p>
	Таким образом, можно добавлять ключи пачками. Для выхода из режима программирования необходимо поднести ключ владыки и удерживает его 5 секунд.
</p>

<p>
	Для очистки памяти решено ввести красную кнопку с защитой от ложного нажатия. Если удерживать её в течение 5 секунд, то контроллер начинает перезапись <strong>EEPROM</strong> одними нулями. По окончанию операции производится перезапуск программы микроконтроллера. Но теперь нет ни единого ключа, следовательно, и мастера тоже. Непорядок! В этом безмятежном состоянии замок стоит держать постоянно открытым иначе "Се Ля Ви", что в переводе с древнегреческого "не повезло"!
</p>

<p>
	Первый поднесенный к сканеру ключ будет записан в память Arduino и станет мастером т.к его порядковый номер - 0. Следом за этим замок перестанет бездельничать и перейдет в состояние закрыто. С этого момента помещение считается святым, и проникнуть в него может только обладатель единственного записанного в память ключа. Для всех остальных нужно начать процедуру добавления ключей, но её мы уже придумали.
</p>

<p>
	Открытие двери изнутри по нажатию на волшебную кнопку поначалу показалось мне тривиальной задачей, и я добавил этот механизм простым способом (как и кнопку очистки памяти) - ногу микроконтроллера посадил через резистор на землю, а сама кнопка коммутировала на эту же ногу +5V. Все дешево и сердито, но вся соль кроется в деталях! Кнопок открытия двери будет несколько. Все они должны сидеть параллельно и самая дальняя будет расположена как минимум в 15, а то и больше, метрах от контроллера (если мерить длинной кабеля)! Это расстояние смело можно умножать на 2 и получить нереальную для +5V цифру. <u>Необходимо пересадить ногу Arduino с GND на +5V (через резистор <strong>10k</strong>), предварительно задействовать встроенный подтягивающий резистор микроконтроллера, а сама кнопка станет прижимать ногу к земле. Резистор между ногой и питанием необходим для избегания короткого замыкания при использовании самой кнопки.</u>
</p>

<p>
	Управление электромагнитом, по понятным и так причинам, происходит через реле. Электромагнит подключен через постоянно замкнутую группу контактов и соответственно при открытии замка, на реле подается логическая единица. Это удобно т.к не приходится постоянно держать реле под напряжением, но есть и обратная сторона медали – если нет питания на контроллере, а на электромагните есть, ты открыть замок станет очень проблемной задачей. В общем, Вам самим выбирать какой из подводных камней оставить. Я свой выбор сделал.
</p>

<p>
	<strong>Схема подключения</strong>
</p>

<pre class="ipsCode">
 - РАСПИНОВКА ----------------------------------------------------------------------------
             MFRC522      Arduino       Arduino   Arduino    Arduino          Arduino
             Reader/PCD   Uno           Mega      Nano v3    Leonardo/Micro   Pro Micro
 Signal      Pin          Pin           Pin       Pin        Pin              Pin
 -----------------------------------------------------------------------------------------
 RST/Reset   RST          9             5         D9         RESET/ICSP-5     RST
 SPI SS      SDA(SS)      10            53        D10        10               10
 SPI MOSI    MOSI         11 / ICSP-4   51        D11        ICSP-4           16
 SPI MISO    MISO         12 / ICSP-1   50        D12        ICSP-1           14
 SPI SCK     SCK          13 / ICSP-3   52        D13        ICSP-3           15
 -----------------------------------------------------------------------------------------</pre>

<p style="text-align:center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="209" href="https://it4it.club/uploads/monthly_2016_01/nrf_z1.jpg.9ba0527051795bd358367553a038943e.jpg" rel=""><img alt="nrf_z1.thumb.jpg.6a5e883f690c1a98aa46f2d" class="ipsImage ipsImage_thumbnailed" data-fileid="209" data-unique="3fxsf7wsl" src="https://it4it.club/uploads/monthly_2016_01/nrf_z1.thumb.jpg.6a5e883f690c1a98aa46f2deb741dec0.jpg"></a>
</p>

<p>
	Оставлю дополнительные фото для наглядности. На самом деле, если вы будите внедрять подобное где-то в обиходе, а не просто собирать на столе, то обязательно все документируйте и перепроверяйте по несколько раз.
</p>

<p style="text-align:center;">
	<img alt="nrf_z4.jpg.e10319f0e151b93b373b5d3264020" class="ipsImage ipsImage_thumbnailed" data-fileid="146" data-unique="aebigrxhv" src="https://it4it.club/uploads/monthly_2015_11/nrf_z4.jpg.e10319f0e151b93b373b5d3264020b3d.jpg"></p>

<div class="ipsSpoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p style="text-align:center;">
			<img alt="nrf_z5.jpg.dd7d824f048ea9148f581fcd6105e" class="ipsImage ipsImage_thumbnailed" data-fileid="147" data-unique="fyk3xurtt" src="https://it4it.club/uploads/monthly_2015_11/nrf_z5.jpg.dd7d824f048ea9148f581fcd6105ef30.jpg"></p>
	</div>
</div>

<div class="ipsSpoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p style="text-align:center;">
			<img alt="nrf_z7.jpg.61ff1243230db1abec9937cf07f2a" class="ipsImage ipsImage_thumbnailed" data-fileid="149" data-unique="m89heiph5" src="https://it4it.club/uploads/monthly_2015_11/nrf_z7.jpg.61ff1243230db1abec9937cf07f2a686.jpg"></p>
	</div>
</div>

<div class="ipsSpoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p style="text-align:center;">
			<a class="ipsAttachLink ipsAttachLink_image" data-fileid="148" href="https://it4it.club/uploads/monthly_2015_11/nrf_z6.jpg.83bb54531d15d7af08fdcfdad765578f.jpg" rel=""><img alt="nrf_z6.thumb.jpg.788a389d2296b0a92e0d42f" class="ipsImage ipsImage_thumbnailed" data-fileid="148" data-unique="777tqyxv9" src="https://it4it.club/uploads/monthly_2015_11/nrf_z6.thumb.jpg.788a389d2296b0a92e0d42ffd192cc70.jpg"></a>
		</p>
	</div>
</div>

<p>
	Для быстрого монтажа я использовал плату для прототипирования. Цена на неё довольно завышена у братьев Китайцев, но я не пожалел.
</p>

<p style="text-align:center;">
	<img alt="nrf_z8.jpg.8c1bb165a20a93c05bd7256c238d7" class="ipsImage ipsImage_thumbnailed" data-fileid="150" data-unique="e1ex1kr7n" src="https://it4it.club/uploads/monthly_2015_11/nrf_z8.jpg.8c1bb165a20a93c05bd7256c238d740a.jpg"><img alt="nrf_z10.jpg.cbf31932e4320128c2b2b1e67e15" class="ipsImage ipsImage_thumbnailed" data-fileid="152" data-unique="1b2w8pfwv" src="https://it4it.club/uploads/monthly_2015_11/nrf_z10.jpg.cbf31932e4320128c2b2b1e67e158162.jpg"></p>

<p>
	Перед установкой всего это добра на заслуженное рабочее место проводились испытания различных кабелей для выноса рабочей части (RFID сканера) за стену. В итоге выбор остановился на медной, многожильной витой паре используемой для прокладки Ethernet. Если использовать одножильную (моно) витую пару, то потери могут быть довольно высоки, как и с использованием различных Китайских (якобы медных) шлейфов. Гарантию работы, а соответственно и Вашего попадания в помещение, сможет гарантировать лишь страховой полис.
</p>

<p style="text-align:center;">
	<img alt="nrf_z13.jpg.eb0b0efa7831f41b99f63376859f" class="ipsImage ipsImage_thumbnailed" data-fileid="155" data-unique="723i93g3f" src="https://it4it.club/uploads/monthly_2015_11/nrf_z13.jpg.eb0b0efa7831f41b99f63376859fa873.jpg"></p>

<p>
	Сам сканер был помещен в крышку от металлической коробки и закрыт стеклотекстолитом, естественно НЕ фольгированным!
</p>

<p style="text-align:center;">
	<img alt="nrf_z12.jpg.103e183dadc201d69b086c47622e" class="ipsImage ipsImage_thumbnailed" data-fileid="154" data-unique="cwwkt3tsf" src="https://it4it.club/uploads/monthly_2015_11/nrf_z12.jpg.103e183dadc201d69b086c47622ea80a.jpg"></p>

<p>
	Полученный результат показался мне довольно сносным и был передан заказчику для установки. Для питания был задействован компьютерный блок питания, с которого, через стабилизатор напряжения 12v в 8v для запитки Arduino UNO через стандартный 5,5мм разъем.
</p>

<p>
	<strong>Фото монтажа</strong>
</p>

<div class="ipsSpoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p style="text-align:center;">
			<img alt="nrf_z16.jpg.4e7d7872ac17c73691753db10fbe" class="ipsImage ipsImage_thumbnailed" data-fileid="158" data-unique="q72o87prk" src="https://it4it.club/uploads/monthly_2015_11/nrf_z16.jpg.4e7d7872ac17c73691753db10fbeebd1.jpg"><img alt="nrf_z17.jpg.56ede63219cf7012460ac4109997" class="ipsImage ipsImage_thumbnailed" data-fileid="159" data-unique="3qt98u4tf" src="https://it4it.club/uploads/monthly_2015_11/nrf_z17.jpg.56ede63219cf7012460ac4109997620b.jpg"><img alt="nrf_z19.jpg.b772512ca803a8c3a546ce98d7b8" class="ipsImage ipsImage_thumbnailed" data-fileid="160" data-unique="nyt2fqcu9" src="https://it4it.club/uploads/monthly_2015_11/nrf_z19.jpg.b772512ca803a8c3a546ce98d7b87df9.jpg"><img alt="nrf_z21.jpg.87b2f63077553a11f86c4ade8f73" class="ipsImage ipsImage_thumbnailed" data-fileid="162" data-unique="c6ddpqaas" src="https://it4it.club/uploads/monthly_2015_11/nrf_z21.jpg.87b2f63077553a11f86c4ade8f7309f6.jpg"><img alt="nrf_z20.jpg.6594bc4a5c74275e7ba1a82714fa" class="ipsImage ipsImage_thumbnailed" data-fileid="161" data-unique="ofpitjz0x" src="https://it4it.club/uploads/monthly_2015_11/nrf_z20.jpg.6594bc4a5c74275e7ba1a82714fa63ce.jpg"></p>
	</div>
</div>

<p>
	За дверью все выглядит очень скромно. Т.к. сканер находится в просторном корпусе, то на него была прикреплена кнопка для электронного звонка. Довольно эстетически приятный вид, для промышленного помещения.
</p>

<div class="ipsSpoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p style="text-align:center;">
			<a class="ipsAttachLink ipsAttachLink_image" data-fileid="163" href="https://it4it.club/uploads/monthly_2015_11/nrf_z22.jpg.b0eccc35bcfeee0242fc6d102abb70ee.jpg" rel=""><img alt="nrf_z22.thumb.jpg.94a403aacbcf0e1f56b871" class="ipsImage ipsImage_thumbnailed" data-fileid="163" data-unique="mkdwegdbc" src="https://it4it.club/uploads/monthly_2015_11/nrf_z22.thumb.jpg.94a403aacbcf0e1f56b87142395cc4a4.jpg"></a><a class="ipsAttachLink ipsAttachLink_image" data-fileid="164" href="https://it4it.club/uploads/monthly_2015_11/nrf_z23.jpg.a6167332999122677d0041a0fed1da18.jpg" rel=""><img alt="nrf_z23.thumb.jpg.133042d2c51c011c6df531" class="ipsImage ipsImage_thumbnailed" data-fileid="164" data-unique="g3udy0kpl" src="https://it4it.club/uploads/monthly_2015_11/nrf_z23.thumb.jpg.133042d2c51c011c6df5319ef737fdfb.jpg"></a>
		</p>
	</div>
</div>

<p>
	<strong>Программная часть</strong>
</p>

<p>
	Вам понадобятся следующие библиотеки:
</p>

<ol>
<li>
		<a href="https://github.com/miguelbalboa/rfid" rel="external nofollow">RFID-RC522 (NRF)</a>
	</li>
	<li>
		<a href="https://github.com/thomasfredericks/Bounce2" rel="external nofollow">Bounce2 (избавляет от дребезга контактов при нажатии кнопок)</a>
	</li>
</ol>
<p>
	<strong style="color:#353c41; font-size:14px; text-align:start">Хотите помочь проект?</strong>
</p>

<ul style="background-color:#ffffff; color:#353c41; font-size:14px; text-align:start">
<li>
		<strong><span style="font-size:20px"><a href="https://money.yandex.ru/to/410014941215337" rel="external nofollow" style="background-color:transparent; color:#3d6594" target="_blank">Yandex.Money</a></span></strong>
	</li>
	<li>
		<span style="font-size:20px"><strong><a href="https://www.paypal.me/kitsum" rel="external nofollow" style="background-color:transparent; color:#3d6594" target="_blank">PayPal.me</a></strong></span>
	</li>
</ul>
<p>
	<strong>Сам скетч</strong>
</p>

<div class="ipsSpoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8846_8">

<span class="com">/*
 * Программа управления нагрузкой с помощью RFID-RC522 13.56 мГц
 *  
 * - РАСПИНОВКА ----------------------------------------------------------------------------
 *             MFRC522      Arduino       Arduino   Arduino    Arduino          Arduino
 *             Reader/PCD   Uno           Mega      Nano v3    Leonardo/Micro   Pro Micro
 * Signal      Pin          Pin           Pin       Pin        Pin              Pin
 * -----------------------------------------------------------------------------------------
 * RST/Reset   RST          9             5         D9         RESET/ICSP-5     RST
 * SPI SS      SDA(SS)      10            53        D10        10               10
 * SPI MOSI    MOSI         11 / ICSP-4   51        D11        ICSP-4           16
 * SPI MISO    MISO         12 / ICSP-1   50        D12        ICSP-1           14
 * SPI SCK     SCK          13 / ICSP-3   52        D13        ICSP-3           15
 * -----------------------------------------------------------------------------------------
 *
 */</span><span class="pln">

</span><span class="com">// Необходимые библиотеки</span><span class="pln">
</span><span class="com">#include</span><span class="pln"> </span><span class="str">&lt;avr/wdt.h&gt;</span><span class="pln">
</span><span class="com">#include</span><span class="pln"> </span><span class="str">&lt;EEPROM.h&gt;</span><span class="pln">
</span><span class="com">#include</span><span class="pln"> </span><span class="str">&lt;SPI.h&gt;</span><span class="pln">
</span><span class="com">#include</span><span class="pln"> </span><span class="str">&lt;MFRC522.h&gt;</span><span class="pln">
</span><span class="com">#include</span><span class="pln"> </span><span class="str">&lt;Bounce2.h&gt;</span><span class="pln">

</span><span class="com">// Необходимые пины</span><span class="pln">
</span><span class="com">#define</span><span class="pln"> PIN_RESET         </span><span class="lit">4</span><span class="pln">        </span><span class="com">// RESER MEMORY</span><span class="pln">
</span><span class="com">#define</span><span class="pln"> PIN_OPEN          </span><span class="lit">2</span><span class="pln">        </span><span class="com">// OPEN</span><span class="pln">

</span><span class="com">#define</span><span class="pln"> PIN_RELAY         </span><span class="lit">7</span><span class="pln">        </span><span class="com">// RELAY</span><span class="pln">
</span><span class="com">#define</span><span class="pln"> PIN_TONE          </span><span class="lit">3</span><span class="pln">        </span><span class="com">// TONE</span><span class="pln">

</span><span class="com">#define</span><span class="pln"> PIN_RST	          </span><span class="lit">9</span><span class="pln">        </span><span class="com">// RFID</span><span class="pln">
</span><span class="com">#define</span><span class="pln"> PIN_SS	          </span><span class="lit">10</span><span class="pln">       </span><span class="com">// RFID</span><span class="pln">

</span><span class="com">// Инициализация RFID ридера</span><span class="pln">
MFRC522 mfrc522</span><span class="pun">(</span><span class="pln">PIN_SS</span><span class="pun">,</span><span class="pln"> PIN_RST</span><span class="pun">);</span><span class="pln">

</span><span class="com">// Переменные необходимые для работы со списком ключей</span><span class="pln">
byte </span><span class="pun">**</span><span class="pln">keys</span><span class="pun">;</span><span class="pln">
byte keys_count </span><span class="pun">=</span><span class="pln"> EEPROM</span><span class="pun">.</span><span class="pln">read</span><span class="pun">(</span><span class="lit">0</span><span class="pun">);</span><span class="pln">

</span><span class="com">// Переменные необходимые для режима программирования</span><span class="pln">
byte modeProgTime         </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span><span class="pln">       </span><span class="com">// Количество секунд удержания мастер ключа для входа\выхода в\из режим\а программирования</span><span class="pln">
</span><span class="kwd">bool</span><span class="pln"> mode                 </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">   </span><span class="com">// НЕ МЕНЯТЬ!</span><span class="pln">
byte modeClean            </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">       </span><span class="com">// НЕ МЕНЯТЬ!</span><span class="pln">
</span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">long</span><span class="pln"> modeTimer   </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">       </span><span class="com">// НЕ МЕНЯТЬ!</span><span class="pln">
</span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">long</span><span class="pln"> resetTimer  </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">       </span><span class="com">// НЕ МЕНЯТЬ!</span><span class="pln">

</span><span class="com">// Управление замком</span><span class="pln">
</span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">long</span><span class="pln"> openTimer </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">

</span><span class="com">// Защита кнопок от дребезга</span><span class="pln">
</span><span class="typ">Bounce</span><span class="pln"> key_reset </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Bounce</span><span class="pun">();</span><span class="pln">
</span><span class="typ">Bounce</span><span class="pln"> key_open  </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Bounce</span><span class="pun">();</span><span class="pln">
</span><span class="com">/*
  Якобы программный reset, но мы с Вами знаем, что это не так ;)
*/</span><span class="pln">
</span><span class="kwd">void</span><span class="pun">(*</span><span class="pln"> resetFunc</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">void</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="com">/*
  Функция звукового оповещения.
  Принимает параметры: количество звуковых сигналов, частота в герцах, продолжительность звука, пауза в милесекундах (не обязательно)
*/</span><span class="pln">
</span><span class="kwd">void</span><span class="pln"> squeaker</span><span class="pun">(</span><span class="pln">byte count</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">unsigned</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> </span><span class="typ">Hz</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">unsigned</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> duration</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">unsigned</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> sleep </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> 
</span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">for</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="pln">count</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    tone</span><span class="pun">(</span><span class="pln">PIN_TONE</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Hz</span><span class="pun">,</span><span class="pln"> duration</span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">sleep </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> delay</span><span class="pun">(</span><span class="pln">sleep</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">/*
  Функция читает EEPROM и составляет список активных ключей
  Первый байт в памяти содержит количество ключей
  UID ключа содержит 4 байта
  Общая память 1 + количество ключей * 4
  Максимум можно записать 255 ключей
*/</span><span class="pln">
</span><span class="kwd">void</span><span class="pln"> keysRead</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// Выводим количество ключей</span><span class="pln">
  </span><span class="typ">Serial</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln">F</span><span class="pun">(</span><span class="str">"KEYS COUNT: "</span><span class="pun">));</span><span class="pln">
  </span><span class="typ">Serial</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">keys_count</span><span class="pun">);</span><span class="pln">
  </span><span class="typ">int</span><span class="pln"> eb </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  keys </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">byte</span><span class="pun">**)</span><span class="pln">malloc</span><span class="pun">(</span><span class="kwd">sizeof</span><span class="pun">(</span><span class="pln">byte</span><span class="pun">*)*</span><span class="pln">keys_count</span><span class="pun">);</span><span class="pln">
  </span><span class="com">// Читаем список ключей из EPROM</span><span class="pln">
  </span><span class="typ">Serial</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">F</span><span class="pun">(</span><span class="str">"------------------------------"</span><span class="pun">));</span><span class="pln">
  </span><span class="kwd">for</span><span class="pun">(</span><span class="pln">byte i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="pln">keys_count</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">Serial</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln">F</span><span class="pun">(</span><span class="str">"KEY: "</span><span class="pun">));</span><span class="typ">Serial</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln">i</span><span class="pun">);</span><span class="typ">Serial</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">" | "</span><span class="pun">);</span><span class="pln">
    keys</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">byte</span><span class="pun">*)</span><span class="pln">malloc</span><span class="pun">(</span><span class="kwd">sizeof</span><span class="pun">(</span><span class="pln">byte</span><span class="pun">)*</span><span class="lit">4</span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">for</span><span class="pun">(</span><span class="pln">byte b</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> b</span><span class="pun">&lt;</span><span class="lit">4</span><span class="pun">;</span><span class="pln"> b</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      keys</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">b</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> EEPROM</span><span class="pun">.</span><span class="pln">read</span><span class="pun">(++</span><span class="pln">eb</span><span class="pun">);</span><span class="pln">
      </span><span class="typ">Serial</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln">keys</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">b</span><span class="pun">]);</span><span class="pln">
      </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">b </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">3</span><span class="pun">)</span><span class="pln"> </span><span class="typ">Serial</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln">F</span><span class="pun">(</span><span class="str">" "</span><span class="pun">));</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    </span><span class="typ">Serial</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="typ">Serial</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">F</span><span class="pun">(</span><span class="str">"------------------------------"</span><span class="pun">));</span><span class="pln">
  </span><span class="typ">Serial</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">/*
  Функция выводит UID ключа и, при необходимости, сопроводительное сообщение
*/</span><span class="pln">
</span><span class="kwd">void</span><span class="pln"> uidPrint</span><span class="pun">(</span><span class="typ">String</span><span class="pln"> text </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="typ">Serial</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln">F</span><span class="pun">(</span><span class="str">"UID: "</span><span class="pun">));</span><span class="pln">
  </span><span class="kwd">for</span><span class="pun">(</span><span class="pln">byte i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="pln">mfrc522</span><span class="pun">.</span><span class="pln">uid</span><span class="pun">.</span><span class="pln">size</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">Serial</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln">mfrc522</span><span class="pun">.</span><span class="pln">uid</span><span class="pun">.</span><span class="pln">uidByte</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]);</span><span class="pln">
    </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">i </span><span class="pun">&lt;</span><span class="pln"> mfrc522</span><span class="pun">.</span><span class="pln">uid</span><span class="pun">.</span><span class="pln">size </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="typ">Serial</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln">F</span><span class="pun">(</span><span class="str">" "</span><span class="pun">));</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="typ">Serial</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">
  </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">text</span><span class="pun">.</span><span class="pln">length</span><span class="pun">()</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="typ">Serial</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">text </span><span class="pun">+</span><span class="pln"> </span><span class="str">"\r\n"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">/*
  Инициализация программы
*/</span><span class="pln">
</span><span class="kwd">void</span><span class="pln"> setup</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// Настраиваем сторожевой таймер</span><span class="pln">
  wdt_disable</span><span class="pun">();</span><span class="pln">
  delay</span><span class="pun">(</span><span class="lit">8000</span><span class="pun">);</span><span class="pln"> </span><span class="com">// &lt;- ЗАКОМЕНТИРУЙТЕ ЭТУ СТРОКУ, ЕСЛИ ЗНАЕТЕ, ЧТО ТАКОЕ wdt_enable(WDTO_8S);</span><span class="pln">
  wdt_enable</span><span class="pun">(</span><span class="pln">WDTO_8S</span><span class="pun">);</span><span class="pln">
    
  </span><span class="com">// Инициализация используемых пинов</span><span class="pln">
  </span><span class="com">// Реле</span><span class="pln">
  pinMode</span><span class="pun">(</span><span class="pln">PIN_RELAY</span><span class="pun">,</span><span class="pln"> OUTPUT</span><span class="pun">);</span><span class="pln">
  digitalWrite</span><span class="pun">(</span><span class="pln">PIN_RELAY</span><span class="pun">,</span><span class="pln"> HIGH</span><span class="pun">);</span><span class="pln">
  
  </span><span class="com">// Кнопка сброса памяти</span><span class="pln">
  pinMode</span><span class="pun">(</span><span class="pln">PIN_RESET</span><span class="pun">,</span><span class="pln">INPUT_PULLUP</span><span class="pun">);</span><span class="pln">
  key_reset</span><span class="pun">.</span><span class="pln">attach</span><span class="pun">(</span><span class="pln">PIN_RESET</span><span class="pun">);</span><span class="pln">
  key_reset</span><span class="pun">.</span><span class="pln">interval</span><span class="pun">(</span><span class="lit">5</span><span class="pun">);</span><span class="pln">
  
  </span><span class="com">// Кнопка открытия двери</span><span class="pln">
  pinMode</span><span class="pun">(</span><span class="pln">PIN_OPEN</span><span class="pun">,</span><span class="pln">INPUT_PULLUP</span><span class="pun">);</span><span class="pln">
  key_open</span><span class="pun">.</span><span class="pln">attach</span><span class="pun">(</span><span class="pln">PIN_OPEN</span><span class="pun">);</span><span class="pln">
  key_open</span><span class="pun">.</span><span class="pln">interval</span><span class="pun">(</span><span class="lit">5</span><span class="pun">);</span><span class="pln">   
  
  </span><span class="com">// Инициализация консоли</span><span class="pln">
  </span><span class="typ">Serial</span><span class="pun">.</span><span class="pln">begin</span><span class="pun">(</span><span class="lit">9600</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(!</span><span class="typ">Serial</span><span class="pun">);</span><span class="pln">
  </span><span class="com">// Приглашаем в гости</span><span class="pln">
  </span><span class="typ">Serial</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">F</span><span class="pun">(</span><span class="str">"iT4iT CLUB (C) 2015\r\nhttps://it4it.club\r\n"</span><span class="pun">));</span><span class="pln">
  
  </span><span class="com">// Инициализация ридера</span><span class="pln">
  SPI</span><span class="pun">.</span><span class="pln">begin</span><span class="pun">();</span><span class="pln">
  mfrc522</span><span class="pun">.</span><span class="pln">PCD_Init</span><span class="pun">();</span><span class="pln">

  </span><span class="com">// Читаем количество ключей</span><span class="pln">
  </span><span class="com">// Значение должно быть равным или больше 1 т.к первый ключ это мастер</span><span class="pln">
  </span><span class="com">// В случае утери мастер ключа, мы можем сбросить EEPROM и прикрутить новый мастер ключ</span><span class="pln">
  </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">keys_count </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> and keys_count </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">255</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    keysRead</span><span class="pun">();</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    keys_count </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
    </span><span class="typ">Serial</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">F</span><span class="pun">(</span><span class="str">"The master key is not in memory. The first presentation to the key will be the master!\r\n"</span><span class="pun">));</span><span class="pln">
    digitalWrite</span><span class="pun">(</span><span class="pln">PIN_RELAY</span><span class="pun">,</span><span class="pln"> LOW</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">/*
  Лупаем, что происходит
*/</span><span class="pln">
</span><span class="kwd">void</span><span class="pln"> loop</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// Сбрасываем сторожевой таймер микроконтроллера</span><span class="pln">
  wdt_reset</span><span class="pun">();</span><span class="pln">

  </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">resetTimer </span><span class="pun">&gt;</span><span class="pln"> millis</span><span class="pun">()+</span><span class="lit">10000</span><span class="pun">)</span><span class="pln"> resetTimer </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">openTimer </span><span class="pun">&gt;</span><span class="pln"> millis</span><span class="pun">()+</span><span class="lit">10000</span><span class="pun">)</span><span class="pln"> openTimer </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  
  </span><span class="com">// Очистка памяти</span><span class="pln">
  key_reset</span><span class="pun">.</span><span class="pln">update</span><span class="pun">();</span><span class="pln">
  </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">key_reset</span><span class="pun">.</span><span class="pln">read</span><span class="pun">()</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> HIGH</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">resetTimer </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> resetTimer </span><span class="pun">=</span><span class="pln"> millis</span><span class="pun">();</span><span class="pln">
    </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">if</span><span class="pun">((</span><span class="pln">millis</span><span class="pun">()-</span><span class="pln">resetTimer</span><span class="pun">)/</span><span class="lit">1000</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">5</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">Serial</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">F</span><span class="pun">(</span><span class="str">"Launched memory cleaning"</span><span class="pun">));</span><span class="pln">
        squeaker</span><span class="pun">(</span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1600</span><span class="pun">,</span><span class="pln"> </span><span class="lit">300</span><span class="pun">,</span><span class="pln"> </span><span class="lit">200</span><span class="pun">);</span><span class="pln">
        wdt_disable</span><span class="pun">();</span><span class="pln">
        </span><span class="kwd">for</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">1</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;=</span><span class="pln">EEPROM</span><span class="pun">.</span><span class="pln">length</span><span class="pun">();</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          EEPROM</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">i</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">);</span><span class="pln">
          </span><span class="kwd">if</span><span class="pun">(!(</span><span class="pln">i</span><span class="pun">%</span><span class="lit">50</span><span class="pun">))</span><span class="pln"> </span><span class="typ">Serial</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">F</span><span class="pun">(</span><span class="str">"#"</span><span class="pun">));</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="typ">Serial</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln">F</span><span class="pun">(</span><span class="str">"#"</span><span class="pun">));</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        </span><span class="typ">Serial</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">F</span><span class="pun">(</span><span class="str">"\r\nMemory cleaning is completed\r\n"</span><span class="pun">));</span><span class="pln">
        delay</span><span class="pun">(</span><span class="lit">1000</span><span class="pun">);</span><span class="pln">
        resetFunc</span><span class="pun">();</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">resetTimer </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> resetTimer </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  </span><span class="com">// Открытие двери с кнопки</span><span class="pln">
  key_open</span><span class="pun">.</span><span class="pln">update</span><span class="pun">();</span><span class="pln">
  </span><span class="com">//Serial.println(key_open.read());</span><span class="pln">
  </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">key_open</span><span class="pun">.</span><span class="pln">read</span><span class="pun">()</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> LOW and openTimer </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">keys_count </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      openTimer </span><span class="pun">=</span><span class="pln"> millis</span><span class="pun">()/</span><span class="lit">1000</span><span class="pun">;</span><span class="pln">
      digitalWrite</span><span class="pun">(</span><span class="pln">PIN_RELAY</span><span class="pun">,</span><span class="pln"> LOW</span><span class="pun">);</span><span class="pln">
      </span><span class="typ">Serial</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">F</span><span class="pun">(</span><span class="str">"The door opened from the inside"</span><span class="pun">));</span><span class="pln">
      squeaker</span><span class="pun">(</span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3200</span><span class="pun">,</span><span class="pln"> </span><span class="lit">100</span><span class="pun">,</span><span class="pln"> </span><span class="lit">300</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    </span><span class="kwd">else</span><span class="pln"> </span><span class="typ">Serial</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">F</span><span class="pun">(</span><span class="str">"\nAttempting to open the lock from the inside.\nAccess denied. The master key is unknown. The castle is always open.\n"</span><span class="pun">));</span><span class="pln">
    delay</span><span class="pun">(</span><span class="lit">2000</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">  
  </span><span class="com">// Автоматическое закрытие двери</span><span class="pln">
  </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">openTimer </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">millis</span><span class="pun">()/</span><span class="lit">1000</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> openTimer </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">5</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      openTimer </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
      digitalWrite</span><span class="pun">(</span><span class="pln">PIN_RELAY</span><span class="pun">,</span><span class="pln"> HIGH</span><span class="pun">);</span><span class="pln">
      </span><span class="typ">Serial</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"* closed lock\r\n"</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="com">// Если ключ отсутствует или не читается, не выполняем дальнейший код</span><span class="pln">
  </span><span class="kwd">if</span><span class="pun">(!</span><span class="pln">mfrc522</span><span class="pun">.</span><span class="pln">PICC_IsNewCardPresent</span><span class="pun">())</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// Очистка таймера входа в режим программирования, в случае если ридер свободен</span><span class="pln">
    </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">modeTimer </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">if</span><span class="pun">(++</span><span class="pln">modeClean </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">5</span><span class="pun">)</span><span class="pln"> modeTimer </span><span class="pun">=</span><span class="pln"> modeClean </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">if</span><span class="pun">(!</span><span class="pln">mfrc522</span><span class="pun">.</span><span class="pln">PICC_ReadCardSerial</span><span class="pun">())</span><span class="pln"> </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
  </span><span class="com">// Останавливаем режим очистки</span><span class="pln">
  modeClean </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  
  </span><span class="com">// Кривое создание мастер ключа</span><span class="pln">
  </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">keys_count </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">for</span><span class="pun">(</span><span class="pln">byte i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="lit">4</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> EEPROM</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">i</span><span class="pun">+</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> mfrc522</span><span class="pun">.</span><span class="pln">uid</span><span class="pun">.</span><span class="pln">uidByte</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]);</span><span class="pln">
    EEPROM</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> keys_count </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">
    uidPrint</span><span class="pun">(</span><span class="pln">F</span><span class="pun">(</span><span class="str">"master key is created"</span><span class="pun">));</span><span class="pln">
    digitalWrite</span><span class="pun">(</span><span class="pln">PIN_RELAY</span><span class="pun">,</span><span class="pln"> HIGH</span><span class="pun">);</span><span class="pln">
    keysRead</span><span class="pun">();</span><span class="pln">
    squeaker</span><span class="pun">(</span><span class="lit">8</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1200</span><span class="pun">,</span><span class="pln"> </span><span class="lit">100</span><span class="pun">,</span><span class="pln"> </span><span class="lit">100</span><span class="pun">);</span><span class="pln">
    delay</span><span class="pun">(</span><span class="lit">2000</span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  
  </span><span class="com">// Проверка ключа на соответствие</span><span class="pln">
  </span><span class="kwd">bool</span><span class="pln"> access </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">bool</span><span class="pln"> master </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">for</span><span class="pun">(</span><span class="pln">byte i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="pln">keys_count</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">for</span><span class="pun">(</span><span class="pln">byte b</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> b</span><span class="pun">&lt;</span><span class="lit">4</span><span class="pun">;</span><span class="pln"> b</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">keys</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">b</span><span class="pun">]</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> mfrc522</span><span class="pun">.</span><span class="pln">uid</span><span class="pun">.</span><span class="pln">uidByte</span><span class="pun">[</span><span class="pln">b</span><span class="pun">])</span><span class="pln"> </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
      </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">b </span><span class="pun">==</span><span class="pln"> </span><span class="lit">3</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        access </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">i </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> master </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
        </span><span class="com">// Останавливаем проверку костылем т.к "break 2;" не работает</span><span class="pln">
        i </span><span class="pun">=</span><span class="pln"> keys_count</span><span class="pun">;</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="com">// ========================================================================================</span><span class="pln">
  </span><span class="com">// Следующая секция имеет двойное назначение:</span><span class="pln">
  </span><span class="com">//  1. В обычном режиме - контроль доступа</span><span class="pln">
  </span><span class="com">//  2. В режиме программирования - запись ключа при его отсутствие в EEPROM</span><span class="pln">
  </span><span class="com">// ========================================================================================</span><span class="pln">
  </span><span class="com">// ОБЫЧНЫЙ РЕЖИМ</span><span class="pln">
  </span><span class="com">// ========================================================================================</span><span class="pln">
  </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">access and </span><span class="pun">!</span><span class="pln">mode and </span><span class="pun">!</span><span class="pln">master</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// Доступ разрешен</span><span class="pln">
    openTimer </span><span class="pun">=</span><span class="pln"> millis</span><span class="pun">()/</span><span class="lit">1000</span><span class="pun">;</span><span class="pln">
    digitalWrite</span><span class="pun">(</span><span class="pln">PIN_RELAY</span><span class="pun">,</span><span class="pln"> LOW</span><span class="pun">);</span><span class="pln">
    uidPrint</span><span class="pun">(</span><span class="pln">F</span><span class="pun">(</span><span class="str">"access allow"</span><span class="pun">));</span><span class="pln">
    squeaker</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2200</span><span class="pun">,</span><span class="pln"> </span><span class="lit">200</span><span class="pun">,</span><span class="pln"> </span><span class="lit">200</span><span class="pun">);</span><span class="pln">
	delay</span><span class="pun">(</span><span class="lit">2000</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pun">(!</span><span class="pln">access and </span><span class="pun">!</span><span class="pln">mode and </span><span class="pun">!</span><span class="pln">master</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// Доступ запрещен</span><span class="pln">
    uidPrint</span><span class="pun">(</span><span class="pln">F</span><span class="pun">(</span><span class="str">"access dany"</span><span class="pun">));</span><span class="pln">
    squeaker</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">500</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">);</span><span class="pln">
    delay</span><span class="pun">(</span><span class="lit">2000</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="com">// ========================================================================================</span><span class="pln">
  </span><span class="com">// РЕЖИМ ПРОГРАММИРОВАНИЯ</span><span class="pln">
  </span><span class="com">// ========================================================================================</span><span class="pln">
  </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">access and mode and </span><span class="pun">!</span><span class="pln">master</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// Попытка записи существующего ключа</span><span class="pln">
    uidPrint</span><span class="pun">(</span><span class="pln">F</span><span class="pun">(</span><span class="str">"error: key elrady exists in eeprom"</span><span class="pun">));</span><span class="pln">
    squeaker</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">500</span><span class="pun">,</span><span class="pln"> </span><span class="lit">300</span><span class="pun">);</span><span class="pln">
    delay</span><span class="pun">(</span><span class="lit">2000</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pun">(!</span><span class="pln">access and mode and </span><span class="pun">!</span><span class="pln">master</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// Записываем новый ключ</span><span class="pln">
    </span><span class="com">// Максимум 255 ключей (с учетом первого байта) для 328 камня</span><span class="pln">
    </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">keys_count </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">255</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">for</span><span class="pun">(</span><span class="pln">byte i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="lit">4</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> EEPROM</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="lit">1</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> keys_count</span><span class="pun">*</span><span class="lit">4</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> i</span><span class="pun">,</span><span class="pln"> mfrc522</span><span class="pun">.</span><span class="pln">uid</span><span class="pun">.</span><span class="pln">uidByte</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]);</span><span class="pln">
      EEPROM</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="pun">++</span><span class="pln">keys_count</span><span class="pun">);</span><span class="pln">
      uidPrint</span><span class="pun">(</span><span class="pln">F</span><span class="pun">(</span><span class="str">"add key in eeprom"</span><span class="pun">));</span><span class="pln">
      keysRead</span><span class="pun">();</span><span class="pln">
      squeaker</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2200</span><span class="pun">,</span><span class="pln"> </span><span class="lit">200</span><span class="pun">,</span><span class="pln"> </span><span class="lit">200</span><span class="pun">);</span><span class="pln">      
    </span><span class="pun">}</span><span class="pln">
    </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      uidPrint</span><span class="pun">(</span><span class="pln">F</span><span class="pun">(</span><span class="str">"error: not enough memory for recording key!"</span><span class="pun">));</span><span class="pln">
      squeaker</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">500</span><span class="pun">,</span><span class="pln"> </span><span class="lit">300</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    delay</span><span class="pun">(</span><span class="lit">2000</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="com">// ========================================================================================</span><span class="pln">
  </span><span class="com">// РАБОТА С МАСТЕР КЛЮЧОМ</span><span class="pln">
  </span><span class="com">// ========================================================================================</span><span class="pln">
  </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">access and master</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// Мастер ключ в обычном режиме</span><span class="pln">
    </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">modeTimer </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      modeTimer </span><span class="pun">=</span><span class="pln"> millis</span><span class="pun">()/</span><span class="lit">1000</span><span class="pun">;</span><span class="pln">
      </span><span class="kwd">if</span><span class="pun">(!</span><span class="pln">mode</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        openTimer </span><span class="pun">=</span><span class="pln"> millis</span><span class="pun">()/</span><span class="lit">1000</span><span class="pun">;</span><span class="pln">
        digitalWrite</span><span class="pun">(</span><span class="pln">PIN_RELAY</span><span class="pun">,</span><span class="pln"> LOW</span><span class="pun">);</span><span class="pln">
        </span><span class="com">// Сигнал о наличии мастер ключа в обычном режиме</span><span class="pln">
        uidPrint</span><span class="pun">(</span><span class="pln">F</span><span class="pun">(</span><span class="str">"MASTER KEY"</span><span class="pun">));</span><span class="pln">
        squeaker</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2200</span><span class="pun">,</span><span class="pln"> </span><span class="lit">200</span><span class="pun">,</span><span class="pln"> </span><span class="lit">200</span><span class="pun">);</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">millis</span><span class="pun">()/</span><span class="lit">1000</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> modeTimer </span><span class="pun">&gt;</span><span class="pln"> modeProgTime and modeTimer </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        modeTimer </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">if</span><span class="pun">((</span><span class="pln">mode </span><span class="pun">=</span><span class="pln"> </span><span class="pun">!</span><span class="pln">mode</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          </span><span class="com">// Вход в режим программирования</span><span class="pln">
          digitalWrite</span><span class="pun">(</span><span class="pln">PIN_RELAY</span><span class="pun">,</span><span class="pln"> LOW</span><span class="pun">);</span><span class="pln">
          uidPrint</span><span class="pun">(</span><span class="pln">F</span><span class="pun">(</span><span class="str">"MASTER PROGRAMMING MODE ON"</span><span class="pun">));</span><span class="pln">
          squeaker</span><span class="pun">(</span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1200</span><span class="pun">,</span><span class="pln"> </span><span class="lit">200</span><span class="pun">,</span><span class="pln"> </span><span class="lit">200</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          </span><span class="com">// Выход из режима программирования</span><span class="pln">
          digitalWrite</span><span class="pun">(</span><span class="pln">PIN_RELAY</span><span class="pun">,</span><span class="pln"> HIGH</span><span class="pun">);</span><span class="pln">
          uidPrint</span><span class="pun">(</span><span class="pln">F</span><span class="pun">(</span><span class="str">"MASTER PROGRAMMING MODE OFF"</span><span class="pun">));</span><span class="pln">
          squeaker</span><span class="pun">(</span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2200</span><span class="pun">,</span><span class="pln"> </span><span class="lit">200</span><span class="pun">,</span><span class="pln"> </span><span class="lit">200</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
      delay</span><span class="pun">(</span><span class="lit">2000</span><span class="pun">);</span><span class="pln">
      </span><span class="com">// Дополнительные действия по таймеру modeProgTime</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    </span><span class="com">// Мастер ключ удерживается у ридера</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

		<p>
			 
		</p>
	</div>
</div>

<p>
	Все довольно плотно закомментировано, но есть большой фронт для доработки. Надеюсь, Вы дополните это создание своими идеями и нужным функционалом, а я в свою очередь уже присмотрел идеи для будущего обновления и заказал новый модуль RC522 для теста.
</p>

<p>
	<strong>PS:</strong> Желаю Вам приятного и надеюсь полезного использования.
</p>
]]></description><guid isPermaLink="false">24</guid><pubDate>Tue, 24 Nov 2015 20:58:37 +0000</pubDate></item><item><title>&#x417;&#x430;&#x43C;&#x43E;&#x43A; &#x441; &#x440;&#x430;&#x434;&#x438;&#x43E;&#x447;&#x430;&#x441;&#x442;&#x43E;&#x442;&#x43D;&#x43E;&#x439; &#x438;&#x434;&#x435;&#x43D;&#x442;&#x438;&#x444;&#x438;&#x43A;&#x430;&#x446;&#x438;&#x435;&#x439; &#x43D;&#x430; &#x431;&#x430;&#x437;&#x435; NFC &#x43A;&#x43E;&#x43D;&#x442;&#x440;&#x43E;&#x43B;&#x43B;&#x435;&#x440;&#x430; PN532</title><link>https://it4it.club/topic/60-zamok-s-radiochastotnoy-identifikaciey-na-baze-nfc-kontrollera-pn532/</link><description><![CDATA[
<p>
	Доброе время суток.
</p>

<p>
	Сегодня мы будем собирать бесконтактный замок с использованием NFC контроллера <a data-fileid="454" href="https://it4it.club/applications/core/interface/file/attachment.php?id=454" rel="">PN532</a>. Опираясь на опыт прошлого варианта (на контроллере MFRC522) и на отзывы тех, кто пытался повторить схему, были сделаны определенные выводы. Постараемся избавиться от старых подводных камней и поищем новые <img alt=":)" data-emoticon="1" height="20" src="https://it4it.club/uploads/emoticons/smile.png" srcset="https://it4it.club/uploads/emoticons/smile@2x.png 2x" title=":)" width="20"></p>

<p>
	<img alt="PN532.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="447" data-unique="0v7v22t9g" src="https://it4it.club/uploads/monthly_2017_02/PN532.jpg.9c73887fff4029d72340d01faf1033b4.jpg"></p>

<div class="ipsSpoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			<a class="ipsAttachLink ipsAttachLink_image" data-fileid="453" href="https://it4it.club/uploads/monthly_2017_02/rfid___nfc_pn532_16.png.fef22034f88a4a5d1edd82717cea66fa.png" rel=""><img alt="rfid___nfc_pn532_16.png" class="ipsImage ipsImage_thumbnailed" data-fileid="453" data-unique="8c2t30sj0" src="https://it4it.club/uploads/monthly_2017_02/rfid___nfc_pn532_16.thumb.png.9b2a61b78de7d809d86b7df16f46e562.png"></a>
		</p>
	</div>
</div>

<p>
	И так, что мы знаем о PN532:
</p>

<ul>
<li>
		Очень компактный размер 42.7 x 40.4 мм
	</li>
	<li>
		Поддерживает работу по SPI, i2C и HSU (высокоскоростной UART)
	</li>
	<li>
		Читение/Запись RFID меток, может общаться с другими контроллерами PN532, и вроде как общаться с Android телефонами
	</li>
	<li>
		Рабочая дистанция 5-7 см
	</li>
</ul>
<p>
	Поддерживаемые чипы
</p>

<ul>
<li>
		ISO 14443 Type A  - NXP Mifare 1k, 4k, Ultralight, Desfire
	</li>
	<li>
		ISO 14443 Type B
	</li>
	<li>
		ISO/IEC 14443-4-совместимые чипы
	</li>
	<li>
		FeliCa
	</li>
	<li>
		Jewel
	</li>
	<li>
		TopaZ
	</li>
</ul>
<p>
	Чтение / Запись RFID меток
</p>

<div class="ipsSpoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			<img alt="PN532-4.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="449" data-unique="0drw5847n" src="https://it4it.club/uploads/monthly_2017_02/PN532-4.jpg.d92b0078512d3d760890a62abf7b31b2.jpg"></p>
	</div>
</div>

<p>
	Обмен данными P2P
</p>

<div class="ipsSpoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			<img alt="PN532-5.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="450" data-unique="q7ipf80hc" src="https://it4it.club/uploads/monthly_2017_02/PN532-5.jpg.2a32ff70ef1d8410f3406b3a0a82a933.jpg"></p>
	</div>
</div>

<p>
	Передача данных смартфону
</p>

<div class="ipsSpoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			<img alt="PN532-6.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="451" data-unique="iv4a0ywii" src="https://it4it.club/uploads/monthly_2017_02/PN532-6.jpg.f8aaffafbe29bf65dbcb4b7eb95f4b2b.jpg"></p>
	</div>
</div>

<p>
	Кстати, вроде как начиная с Androik 4.4 KitKat операционная система умеет эмулировать NFC метки программным способом. Это подразумевает, что мы можем на телефоне сделать копию проездного билета (БСК, Тройка) или просто обычной метки, и использовать смартфон в качестве ключа для замка. К сожалению, у меня пока нет под рукой аппарата с поддержкой NFC, а значит и проверить это мне не под силам. Оставляю эту задачу Вам! 
</p>

<p>
	Для сборки замка нам понадобятся:
</p>

<ol>
<li>
		Arduino UNO или любой аналог с контроллером ATmega328
	</li>
	<li>
		Сам модуль сканера с контроллером PN532
	</li>
	<li>
		Китайский модуль реле с опторазвязкой (в программе предусмотрена инверсия управляющего сигнала на случай управления реле напрямую или замены его на транзисторный ключ / мосфет)
	</li>
	<li>
		Две кнопки для, одна для разблокировки замка изнутри помещения, а другая для сброса памяти микроконтроллера
	</li>
	<li>
		Два резистора 10kOm и 4.7kOm
	</li>
	<li>
		Танталовый конденсатор на 1uF
	</li>
	<li>
		Светодиод для индикации о попытках взлома замка с помощью брутфорса ключа
	</li>
	<li>
		Транзистор KT315 или его аналог для управления питанием PN532. Говорят, что война между Десептиконами и Автоботами началась именно из-за этих Советских транзисторов!
	</li>
</ol>
<p>
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="464" href="https://it4it.club/uploads/monthly_2017_02/pn532.png.bcbca451d112345d37cbba43dbaa14e0.png" rel=""><img alt="pn532.png" class="ipsImage ipsImage_thumbnailed" data-fileid="464" data-unique="9kkbtg98e" src="https://it4it.club/uploads/monthly_2017_02/pn532.thumb.png.1f3943a504554c583fdcb8776e6d2d16.png"></a>
</p>

<p>
	Зачем нужен транзистор? Он используется для управления питанием сканера, если по какой-либо причине Arduino пойдет на перезагрузку, то она потянет за собой и сканер. Таким образом мы лишний раз подстрахуем себя. Конденсатор в обвязке транзистора необходим для сглаживания пульсаций, у меня они были явно заметны при питании от USB. Конечно это все можно выкинуть из схемы и пустить на ножку VCC контроллера PN532 питание напрямую с 5V платы Arduino. Это уже на Ваш страх и риск.
</p>

<p>
	Критически важно обратить внимание на питание! Не поленитесь и возьмите отдельный блок питания, USB используйте только в качестве Serial монитора. На реле желательно подавать отдельное питание, на Китайских модулях для этого есть соответствующие пины (GND, VCC, JD-VCC). На схеме я это не отражено т.к каждый волен самостоятельно выбирать как управлять силовой частью замка. Может вы замените реле мосфетом.
</p>

<p>
	На просторах мирового интернета нашел пару изображений схем показывающий, как реализовано питание и управление китайскими релейными модулями.
</p>

<p>
	Так показано на схеме и так делает большинство. Все будет работать. 
</p>

<p>
	<img alt="HL-52S-Relay-Module-Circuit-Schematics.png" class="ipsImage ipsImage_thumbnailed" data-fileid="455" data-unique="cbug32bri" src="https://it4it.club/uploads/monthly_2017_02/HL-52S-Relay-Module-Circuit-Schematics.png.6e3b67798f913d500f8c0e021bab3455.png"></p>

<p>
	А так будет правильно, но необходим отдельный источник питания для релейного модуля
</p>

<p>
	<img alt="Relay-Module-Circuit-Schematics.png" class="ipsImage ipsImage_thumbnailed" data-fileid="456" data-unique="19dhpid1s" src="https://it4it.club/uploads/monthly_2017_02/Relay-Module-Circuit-Schematics.png.cd41489c8d9166143158db4e0f1e7b48.png"></p>

<p>
	Выбор за Вами.
</p>

<p>
	Вернемся к сканеру. Уже упоминалось, что он имеет возможность общаться по одному из нескольких интерфейсов на выбор. Сам выбор интерфейса реализован на физическом уровне и представляет из себя сдвоенный переключатель. На изображении ниже выбран HSU (UART). В таком варианте модули приходят к нам из поднебесной.
</p>

<p>
	<img alt="PN532-NFC-RFID-Module-V3.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="452" data-unique="52rx2vras" src="https://it4it.club/uploads/monthly_2017_02/PN532-NFC-RFID-Module-V3.jpg.d762f7a9f24fed34d0e234e2f45edd61.jpg"></p>

<p>
	Мы будем использовать i2C интерфейс. Возможно стоило бы SPI?
</p>

<p>
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="459" href="https://it4it.club/uploads/monthly_2017_02/PN532_i2C.JPG.aa978195780808e04c39c28516388dbb.JPG" rel=""><img alt="PN532_i2C.JPG" class="ipsImage ipsImage_thumbnailed" data-fileid="459" data-unique="9h15l722y" src="https://it4it.club/uploads/monthly_2017_02/PN532_i2C.thumb.JPG.7341819a8916bd2972069d41c9aaef26.JPG" style="width: 300px; height: auto;"></a><a class="ipsAttachLink ipsAttachLink_image" data-fileid="460" href="https://it4it.club/uploads/monthly_2017_02/PN532_i2C_2.JPG.6e8d0b47c0eb5b6e09d849d7170987a6.JPG" rel=""><img alt="PN532_i2C_2.JPG" class="ipsImage ipsImage_thumbnailed" data-fileid="460" data-unique="33zftn709" src="https://it4it.club/uploads/monthly_2017_02/PN532_i2C_2.thumb.JPG.462b8c494ba9a63533031207a3e7b0f8.JPG" style="width: 300px; height: auto;"></a>
</p>

<p>
	Все подключения можно свести к одной таблицы
</p>

<p>
	<img alt="PN532-Atmega328p - Arduino 1-6-12.png" class="ipsImage ipsImage_thumbnailed" data-fileid="461" data-unique="4q12gpczl" src="https://it4it.club/uploads/monthly_2017_02/58a9b1f17229b_PN532-Atmega328p-Arduino1-6-12.png.08898b2051cba1955065e452a9c7cf69.png"></p>

<p>
	Как все устроено
</p>

<p>
	Часть функционала было позаимствовано из предыдущего варианта о котором говорилось в самом начале данного поста. При первом запуске Вам будет предложено создать мастер ключ, но не спешите это делать. Я советую Вам очистить EEPROM, для этого нажмите и удерживайте кнопку RESET до тех пор, пока не услышите звуковой сигнал. После очистки памяти контроллер будет перезапущен, замок разблокируется в ожидании первого поднесенного ключа (метки), может быть даже смартфона (ищите эмуляторы RFID меток и проверяйте).
</p>

<p>
	Первый поднесенный ключ станет мастером, советую его надежно спрятать дома т.к только с его помощью можно записывать новые ключи в память микроконтроллера. Кстати о памяти, вот схема как она используется, всего занято 1kB.
</p>

<p>
	<img alt="PN532-Atmega328p - Arduino 1-6-12-2.png" class="ipsImage ipsImage_thumbnailed" data-fileid="462" data-unique="el97x17g1" src="https://it4it.club/uploads/monthly_2017_02/58a9b1f1af555_PN532-Atmega328p-Arduino1-6-12-2.png.bd3f0473a3e151d5207aa31691ca0fe8.png"></p>

<p>
	Первые 8 байт используются для хранения системной информации. Пока заняты только первые 2 байта, а остальные 6 зарезервированы под будущие улучшения. Возможно Вы что-то захотите добавить свое. Начиная с 9 байта идут ключи. Ключи бывают разного размера, но мы будем использовать только первые его 4 байта. Первый ключ всегда идет мастер, все последующие обычные. Всего можно иметь 1 мастер и 253 обычных ключа. То есть мы израсходуем весь объем EEPROM контроллера ATmega328. Вы конечно можете воспользоваться другим контроллером, с большим количеством памяти, но программа не даст Вам создать более 254 ключей. Оставшаяся память останется свободной.
</p>

<p>
	И так после создания мастер ключа замок перейдет в дежурный режим, разблокировать его можно кратковременным нажатием на кнопку OPEN или самим мастер ключом. Для добавления новых ключей необходимо поднести мастер ключ к сканеру и удерживать более 5 секунд. Замок перейдет в режим программирования оповестив Вас об этом звуковым сигналом. В этом состоянии замок будет в разблокированном состоянии и все поднесенные новые ключи будет записаны в память. Для выхода из режима программирования необходимо опять поднести мастер ключ к сканеру и удерживать более 5 секунд. Звуковой сигнал оповестит об этом и замок вернется в дежурный режим.
</p>

<p>
	После открытия двери ключом или кнопкой запускается таймер, который закроет замок через 5 секунд. Можно удерживать замок в открытом состоянии при удержании кнопки OPEN, но при её отпускании замок сразу закроется.
</p>

<p>
	Теперь немного про защиту
</p>

<p>
	В программе имеется счетчик ложных срабатываний. Если в течении минуты будут зарегистрированы 5 попыток подбора ключа, замок будет заблокирован на 1 минуту. Открыть дверь можно будет только с кнопки OPEN. Поднесения действующего ключа, даже мастера, будет проигнорировано замком. По истечению минуты доступ будет открыт, но на этом еще не конец. Счетчик даст только одну попытку разблокировать замок, если она потерпит неудачу, блокировка повторится. Замок будет давать по одной дополнительной попытки за каждую минуту ожидания, но не более 5 попыток. Таким образом скорость подбора ключа сводится к 1 ключу в минуту, а учитывая длину ключа даже в 4 байта, тот кто захочет этим заняться должен быть бессмертным. Проще ключ украсть или сделать копию, но от этого не застрахованы даже обычные замки, но в следующем варианте программы мы позаботимся и об этом.
</p>

<p>
	Если кто-то пытался подобрать ключ и замок его поймал на этом, то светодиод начнет периодически мигать. И даже если отключить питания, контроллер не забудет об этом инциденте и при его восстановлении продолжит оповещать о случившемся. Интенсивность мигания будет напрямую зависеть от количества блокировок.
</p>

<ul>
<li>
		1 раз в секунду если была выявлена хотя бы одна блокировка
	</li>
	<li>
		2 раза в секунду если было выявлено более 5 блокировок
	</li>
	<li>
		3 раза в секунду если более 10 блокировок
	</li>
	<li>
		4 раза в секунду если выявлено более 20 попыток
	</li>
	<li>
		Горит постоянно при более 50 попытках
	</li>
</ul>
<p>
	Есть два способа сбросить счетчик. Воспользоваться мастер ключом и перевести замок в режим программирования, после вернуть обратно в дежурный режим. Или удерживая активный ключ у сканера PN532 зажать кнопку OPEN на 5 секунд.
</p>

<p>
	В принципе на этом пока все. Для реализации Вам понадобятся следующие библиотеки:
</p>

<ol>
<li>
		<a href="https://github.com/thomasfredericks/Bounce2" rel="external nofollow">Bounce2 для программной защиты от дребезга</a>
	</li>
	<li>
		<a href="http://playground.arduino.cc/Code/Timer1" rel="external nofollow">Timer1 для удобной реализации прерываний</a>
	</li>
	<li>
		<a href="https://github.com/adafruit/Adafruit-PN532" rel="external nofollow">Adafruit PN532 для связи с самим сканером</a>
	</li>
</ol>
<p style="background-color:#ffffff; color:#353c41; font-size:14px; text-align:start">
	<strong>Хотите помочь проект?</strong>
</p>

<ul style="background-color:#ffffff; color:#353c41; font-size:14px; text-align:start">
<li>
		<strong><span style="font-size:20px"><a href="https://money.yandex.ru/to/410014941215337" rel="external nofollow" style="background-color:transparent; color:#3d6594" target="_blank">Yandex.Money</a></span></strong>
	</li>
	<li>
		<span style="font-size:20px"><strong><a href="https://www.paypal.me/kitsum" rel="external nofollow" style="background-color:transparent; color:#3d6594" target="_blank">PayPal.me</a></strong></span>
	</li>
</ul>
<p>
	Сама программа замка: <a class="ipsAttachLink" data-fileid="463" href="https://it4it.club/applications/core/interface/file/attachment.php?id=463" rel="">PN532_lock_iT4iT.CLUB.7z</a>
</p>

<ul style="background-color:#ffffff; color:#353c41; font-size:14px; text-align:start"></ul>
<p>
	 
</p>
]]></description><guid isPermaLink="false">60</guid><pubDate>Sat, 18 Feb 2017 15:45:05 +0000</pubDate></item><item><title>&#x41D;&#x443;&#x436;&#x43D;&#x430; &#x43F;&#x43E;&#x43C;&#x43E;&#x449;&#x44C; &#x413;&#x423;&#x420;&#x423;: &#x43F;&#x440;&#x43E;&#x431;&#x43B;&#x435;&#x43C;&#x430; &#x438;&#x43D;&#x438;&#x446;&#x438;&#x430;&#x43B;&#x438;&#x437;&#x430;&#x446;&#x438;&#x438; &#x441;&#x43E;&#x441;&#x442;&#x43E;&#x44F;&#x43D;&#x438;&#x44F; &#x434;&#x430;&#x442;&#x447;&#x438;&#x43A;&#x43E;&#x432; &#x445;&#x43E;&#x43B;&#x43B;&#x430;</title><link>https://it4it.club/topic/101-nuzhna-pomosch-guru-problema-inicializacii-sostoyaniya-datchikov-holla/</link><description><![CDATA[
<p style="background-color:#ffffff;color:#555555;font-size:12px;">
	Дано: модуль датчика холла A3144 подключенный через I2C расширитель PCF8575 к UNO R3
</p>

<p style="background-color:#ffffff;color:#555555;font-size:12px;">
	Необходимо контролировать наличие магнита и передавать информацию на сервер по mqtt-протоколу
</p>

<p style="background-color:#ffffff;color:#555555;font-size:12px;">
	При инициализации устройства магниты УЖЕ поднесены к датчику Холла. 
</p>

<p style="background-color:#ffffff;color:#555555;font-size:12px;">
	<strong>Проблема: при старте устройства с поднесенными магнитом, скетчу "сносит" башню и Ардуино не понимает состояние датчика и не может отслеживать их переключение.</strong>
</p>

<p style="background-color:#ffffff;color:#555555;font-size:12px;">
	Если изначально при старте магниты не поднесены, всё прекрасно работает.
</p>

<p style="background-color:#ffffff;color:#555555;font-size:12px;">
	Код (часть связанную с сетью и передачей по mqtt-протоколу на брокер исключил):
</p>

<div style="border:0px;color:#555555;font-size:12px;padding:0px;text-align:left;vertical-align:baseline;">
	<pre class="ipsCode prettyprint lang-c prettyprinted">
<span class="lit">01</span><span class="pln">  </span><span class="com">#include</span><span class="pln"> </span><span class="str">&lt;SPI.h&gt;</span><span class="pln">
</span><span class="lit">02</span><span class="pln">	</span><span class="com">#include</span><span class="pln"> </span><span class="str">&lt;Wire.h&gt;</span><span class="pln">
</span><span class="lit">03</span><span class="pln">	</span><span class="com">#include</span><span class="pln"> </span><span class="str">&lt;PCF8575.h&gt;</span><span class="pln">
</span><span class="lit">04</span><span class="pln">	
</span><span class="lit">05</span><span class="pln">	</span><span class="com">#define</span><span class="pln"> PUB_DELAY </span><span class="lit">3000</span><span class="pln"> </span><span class="com">// Частота передачи данных ото всех ключей</span><span class="pln">
</span><span class="lit">06</span><span class="pln">	</span><span class="com">#define</span><span class="pln"> CHK_DELAY </span><span class="lit">500</span><span class="pln"> </span><span class="com">// Частота проверки ключей</span><span class="pln">
</span><span class="lit">07</span><span class="pln">	</span><span class="com">#define</span><span class="pln"> KEYS </span><span class="lit">3</span><span class="pln"> </span><span class="com">// Кол-во ключей</span><span class="pln">
</span><span class="lit">08</span><span class="pln">	</span><span class="com">#define</span><span class="pln"> ACT LOW </span><span class="com">// Состояние входа при активации</span><span class="pln">
</span><span class="lit">09</span><span class="pln">	</span><span class="com">#define</span><span class="pln"> DIS </span><span class="pun">!</span><span class="pln">ACT
</span><span class="lit">10</span><span class="pln">	
</span><span class="lit">11</span><span class="pln">	PCF8575 ex1</span><span class="pun">;</span><span class="pln">
</span><span class="lit">12</span><span class="pln">	  
</span><span class="lit">13</span><span class="pln">	</span><span class="kwd">long</span><span class="pln"> previousMillis</span><span class="pun">,</span><span class="pln"> checkMillis</span><span class="pun">;</span><span class="pln">
</span><span class="lit">14</span><span class="pln">	boolean kst</span><span class="pun">[</span><span class="pln">KEYS</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="lit">0</span><span class="pun">};</span><span class="pln">
</span><span class="lit">15</span><span class="pln">	  
</span><span class="lit">16</span><span class="pln">	</span><span class="kwd">void</span><span class="pln"> setup </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="lit">17</span><span class="pln">	  </span><span class="com">// setup serial communication</span><span class="pln">
</span><span class="lit">18</span><span class="pln">	  </span><span class="typ">Serial</span><span class="pun">.</span><span class="pln">begin</span><span class="pun">(</span><span class="lit">9600</span><span class="pun">);</span><span class="pln">
</span><span class="lit">19</span><span class="pln">	  
</span><span class="lit">20</span><span class="pln">	  
</span><span class="lit">21</span><span class="pln">	  </span><span class="com">// Адрес i2c расширителя pcf8575</span><span class="pln">
</span><span class="lit">22</span><span class="pln">	  ex1</span><span class="pun">.</span><span class="pln">begin</span><span class="pun">(</span><span class="lit">0x20</span><span class="pun">);</span><span class="pln">
</span><span class="lit">23</span><span class="pln">	   
</span><span class="lit">24</span><span class="pln">	  </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">3</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> ex1</span><span class="pun">.</span><span class="pln">pinMode</span><span class="pun">(</span><span class="pln">i</span><span class="pun">,</span><span class="pln"> INPUT</span><span class="pun">);</span><span class="pln">
</span><span class="lit">25</span><span class="pln">	  </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> KEYS</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> kst </span><span class="pun">=</span><span class="pln"> DIS</span><span class="pun">;</span><span class="pln"> </span><span class="com">// состояние датчика задается константой </span><span class="pln">
</span><span class="lit">26</span><span class="pln">   
</span><span class="lit">27</span><span class="pln">   delay</span><span class="pun">(</span><span class="lit">1500</span><span class="pun">);</span><span class="pln"> </span><span class="com">// Allow hardware to stabilize</span><span class="pln">
</span><span class="lit">28</span><span class="pln">   
</span><span class="lit">29</span><span class="pln">   previousMillis </span><span class="pun">=</span><span class="pln"> millis</span><span class="pun">();</span><span class="pln">
</span><span class="lit">30</span><span class="pln">   checkMillis </span><span class="pun">=</span><span class="pln"> millis</span><span class="pun">();</span><span class="pln">
</span><span class="lit">31</span><span class="pln">    
</span><span class="lit">32</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="lit">33</span><span class="pln">   
</span><span class="lit">34</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> loop </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="lit">35</span><span class="pln">   </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">millis</span><span class="pun">()</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> checkMillis </span><span class="pun">&gt;</span><span class="pln"> CHK_DELAY</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// проверка ключей</span><span class="pln">
</span><span class="lit">36</span><span class="pln">     </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">3</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> kst </span><span class="pun">=</span><span class="pln"> ex1</span><span class="pun">.</span><span class="pln">digitalRead</span><span class="pun">(</span><span class="pln">i</span><span class="pun">);</span><span class="pln">
</span><span class="lit">37</span><span class="pln">     </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">3</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++){</span><span class="pln">
</span><span class="lit">38</span><span class="pln">       </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">kst</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> ACT</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// если хотя бы 1 ключ активен</span><span class="pln">
</span><span class="lit">39</span><span class="pln">         </span><span class="typ">String</span><span class="pln"> state </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Active"</span><span class="pun">;</span><span class="pln">
</span><span class="lit">40</span><span class="pln">         </span><span class="typ">Serial</span><span class="pun">.</span><span class="pln">println </span><span class="pun">(</span><span class="pln">state</span><span class="pun">);</span><span class="pln">
</span><span class="lit">41</span><span class="pln">       </span><span class="pun">}</span><span class="pln">
</span><span class="lit">42</span><span class="pln">     </span><span class="pun">}</span><span class="pln">
</span><span class="lit">43</span><span class="pln">     checkMillis </span><span class="pun">=</span><span class="pln"> millis</span><span class="pun">();</span><span class="pln">
</span><span class="lit">44</span><span class="pln">   </span><span class="pun">}</span><span class="pln">
</span><span class="lit">45</span><span class="pln">   </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">millis</span><span class="pun">()</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> previousMillis </span><span class="pun">&gt;</span><span class="pln"> PUB_DELAY</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// передача данных о ключах</span><span class="pln">
</span><span class="lit">46</span><span class="pln">     </span><span class="typ">String</span><span class="pln"> request</span><span class="pun">;</span><span class="pln">
</span><span class="lit">47</span><span class="pln">     </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">3</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="lit">48</span><span class="pln">        </span><span class="typ">Serial</span><span class="pun">.</span><span class="pln">println </span><span class="pun">(</span><span class="pln">request</span><span class="pun">);</span><span class="pln">
</span><span class="lit">49</span><span class="pln">     </span><span class="pun">}</span><span class="pln">
</span><span class="lit">50</span><span class="pln">     previousMillis </span><span class="pun">=</span><span class="pln"> millis</span><span class="pun">();</span><span class="pln">
</span><span class="lit">51</span><span class="pln">   </span><span class="pun">}</span><span class="pln">
</span><span class="lit">52</span><span class="pln">     </span><span class="com">// mqttClient.loop();</span><span class="pln">
</span><span class="lit">53</span><span class="pln"> </span><span class="pun">}</span></pre>

	<p>
		 
	</p>
</div>
]]></description><guid isPermaLink="false">101</guid><pubDate>Wed, 10 Apr 2019 12:33:02 +0000</pubDate></item><item><title>&#x41C;&#x435;&#x442;&#x435;&#x43E;&#x441;&#x442;&#x430;&#x43D;&#x446;&#x438;&#x44F; &#x43D;&#x430; ESP8266 &#x438; &#x434;&#x432;&#x443;&#x445; &#x434;&#x430;&#x442;&#x447;&#x438;&#x43A;&#x430;&#x445; BME280 &#x434;&#x43B;&#x44F; &#x434;&#x432;&#x443;&#x445; &#x442;&#x43E;&#x447;&#x435;&#x43A; &#x438;&#x437;&#x43C;&#x435;&#x440;&#x435;&#x43D;&#x438;&#x44F;</title><link>https://it4it.club/topic/75-meteostanciya-na-esp8266-i-dvuh-datchikah-bme280-dlya-dvuh-tochek-izmereniya/</link><description><![CDATA[
<p>
	Метеостанция для измерения параметров в двух точках одинаковыми датчиками, например, дома и на улице. Собственно, пока что просто пример, как подключаются одинаковые датчики на одну шину I2C.
</p>

<p>
	Детали: Nodemcu v3, два датчика BME280, подключенные на один I2C.
</p>

<p>
	Для первого датчика с адресом 0х76 использовалась библиотека <a href="https://github.com/Seeed-Studio/Grove_BME280" rel="external nofollow">https://github.com/Seeed-Studio/Grove_BME280</a>  и эта же библиотека отредактирована для второго датчика с адресом 0х77 (в прикрепленном файле). Как поменять адрес второго датчика например тут - <a href="http://arduino.ru/forum/apparatnye-voprosy/pomenyat-adres-i2c-na-bme280" rel="external nofollow">http://arduino.ru/forum/apparatnye-voprosy/pomenyat-adres-i2c-na-bme280</a>  Установить обе библиотеки.
</p>

<p>
	Метеостанция умеет выводить данные в UART. Также создает WEB-сервер, по WIFI соединяется с домашней сетью, данные с метеостанции можно посмотреть в браузере, перейдя по адресу, который дал роутер. В скетч вставить имя/пароль своей сети, а также указать к каким пинам подключены датчики. В моем случае это D1 и D2.
</p>

<p>
	В дальнейшем предполагается добавить в метеостанцию возможность регулировать температуру и влажность по домашнему датчику, включая обогреватель/кондиционер и ультразвуковой увлажнитель/вентилятор для проветривания. И возможно добавить датчик освещения и включать на ночь уличный свет/ прикрутить датчик влажности почвы и сделать автоматический полив/ добавить управление по WEB-интерфейсу уличным освещением и сливным бачком в тубзике
</p>

<p>
	Ну и скетч:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted">
<span class="com">#include</span><span class="pln"> </span><span class="str">"Seeed_BME280.h"</span><span class="pln">
</span><span class="com">#include</span><span class="pln"> </span><span class="str">"Seeed_BME280_77.h"</span><span class="pln">
</span><span class="com">#include</span><span class="pln"> </span><span class="str">&lt;Wire.h&gt;</span><span class="pln">
</span><span class="com">#include</span><span class="pln"> </span><span class="str">&lt;ESP8266WiFi.h&gt;</span><span class="pln">

BME280 bme280</span><span class="pun">;</span><span class="pln">
BME280_77 bme280_77</span><span class="pun">;</span><span class="pln">

</span><span class="com">#define</span><span class="pln"> pin_sda </span><span class="lit">5</span><span class="pln"> </span><span class="com">// default sda pin //вставить свое значение</span><span class="pln">
</span><span class="com">#define</span><span class="pln"> pin_scl </span><span class="lit">4</span><span class="pln"> </span><span class="com">// default scl pin //вставить свое значение</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">char</span><span class="pun">*</span><span class="pln"> ssid </span><span class="pun">=</span><span class="pln"> </span><span class="str">"ssid"</span><span class="pun">;</span><span class="pln"> </span><span class="com">//вставить свое значение</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">char</span><span class="pun">*</span><span class="pln"> password </span><span class="pun">=</span><span class="pln"> </span><span class="str">"password"</span><span class="pun">;</span><span class="pln"> </span><span class="com">//вставить свое значение</span><span class="pln">


</span><span>WiFiServer</span><span class="pln"> server</span><span class="pun">(</span><span class="lit">80</span><span class="pun">);</span><span class="pln">

</span><span class="kwd">void</span><span class="pln"> setup</span><span class="pun">()</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
  </span><span>Serial</span><span class="pun">.</span><span class="pln">begin</span><span class="pun">(</span><span class="lit">115200</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">if</span><span class="pun">(!</span><span class="pln">bme280</span><span class="pun">.</span><span class="pln">init</span><span class="pun">()){</span><span class="pln">
    </span><span>Serial</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Device error!"</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
    </span><span class="kwd">if</span><span class="pun">(!</span><span class="pln">bme280_77</span><span class="pun">.</span><span class="pln">init</span><span class="pun">()){</span><span class="pln">
    </span><span>Serial</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Device error!"</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
    delay</span><span class="pun">(</span><span class="lit">10</span><span class="pun">);</span><span class="pln">
      </span><span class="com">// Connect to WiFi network</span><span class="pln">
  </span><span>Serial</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">
  </span><span>Serial</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">
  </span><span>Serial</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"Connecting to "</span><span class="pun">);</span><span class="pln">
  </span><span>Serial</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">ssid</span><span class="pun">);</span><span class="pln">
  
  </span><span>WiFi</span><span class="pun">.</span><span class="pln">mode</span><span class="pun">(</span><span class="pln">WIFI_STA</span><span class="pun">);</span><span class="pln">
  </span><span>WiFi</span><span class="pun">.</span><span class="pln">begin</span><span class="pun">(</span><span class="pln">ssid</span><span class="pun">,</span><span class="pln"> password</span><span class="pun">);</span><span class="pln">
  
  </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span>WiFi</span><span class="pun">.</span><span class="pln">status</span><span class="pun">()</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> WL_CONNECTED</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    delay</span><span class="pun">(</span><span class="lit">500</span><span class="pun">);</span><span class="pln">
    </span><span>Serial</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"."</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span>Serial</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">""</span><span class="pun">);</span><span class="pln">
  </span><span>Serial</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"WiFi connected"</span><span class="pun">);</span><span class="pln">
  

  server</span><span class="pun">.</span><span class="pln">begin</span><span class="pun">();</span><span class="pln">
  </span><span>Serial</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Server started"</span><span class="pun">);</span><span class="pln">

  
  </span><span>Serial</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span>WiFi</span><span class="pun">.</span><span class="pln">localIP</span><span class="pun">());</span><span class="pln">
    
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">void</span><span class="pln"> loop</span><span class="pun">()</span><span class="pln">
</span><span class="pun">{</span><span class="pln">

  </span><span>float</span><span class="pln"> t </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">bme280</span><span class="pun">.</span><span class="pln">getTemperature</span><span class="pun">());</span><span class="pln">
  </span><span>float</span><span class="pln"> p </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">bme280</span><span class="pun">.</span><span class="pln">getPressure</span><span class="pun">()*</span><span class="lit">0.00750063</span><span class="pun">);</span><span class="pln">
  </span><span>float</span><span class="pln"> h </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">bme280</span><span class="pun">.</span><span class="pln">getHumidity</span><span class="pun">());</span><span class="pln">


  </span><span>float</span><span class="pln"> t_77 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">bme280_77</span><span class="pun">.</span><span class="pln">getTemperature</span><span class="pun">());</span><span class="pln">
  </span><span>float</span><span class="pln"> p_77 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">bme280_77</span><span class="pun">.</span><span class="pln">getPressure</span><span class="pun">()*</span><span class="lit">0.00750063</span><span class="pun">);</span><span class="pln">
  </span><span>float</span><span class="pln"> h_77 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">bme280_77</span><span class="pun">.</span><span class="pln">getHumidity</span><span class="pun">());</span><span class="pln">
  
    </span><span class="com">//get and print temperatures</span><span class="pln">
  </span><span>Serial</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"Temp: "</span><span class="pun">);</span><span class="pln">
  </span><span>Serial</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln">t</span><span class="pun">);</span><span class="pln">
  </span><span>Serial</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">" C"</span><span class="pun">);</span><span class="com">//The unit for  Celsius because original arduino don't support speical symbols</span><span class="pln">

    </span><span class="com">//get and print temperatures_77</span><span class="pln">
  </span><span>Serial</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"Temp_77: "</span><span class="pun">);</span><span class="pln">
  </span><span>Serial</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln">t_77</span><span class="pun">);</span><span class="pln">
  </span><span>Serial</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">" C"</span><span class="pun">);</span><span class="com">//The unit for  Celsius because original arduino don't support speical symbols</span><span class="pln">
  
  </span><span class="com">//get and print atmospheric pressure data</span><span class="pln">
  </span><span>Serial</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"Pressure: "</span><span class="pun">);</span><span class="pln">
  </span><span>Serial</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln">p</span><span class="pun">);</span><span class="pln">
  </span><span>Serial</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">" mm.Hg"</span><span class="pun">);</span><span class="pln">

    </span><span class="com">//get and print atmospheric pressure data_77</span><span class="pln">
  </span><span>Serial</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"Pressure_77: "</span><span class="pun">);</span><span class="pln">
  </span><span>Serial</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln">p_77</span><span class="pun">);</span><span class="pln">
  </span><span>Serial</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">" mm.Hg"</span><span class="pun">);</span><span class="pln">

  </span><span class="com">//get and print humidity data</span><span class="pln">
  </span><span>Serial</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"Humidity: "</span><span class="pun">);</span><span class="pln">
  </span><span>Serial</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln">h</span><span class="pun">);</span><span class="pln">
  </span><span>Serial</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">" %"</span><span class="pun">);</span><span class="pln">

    </span><span class="com">//get and print humidity data_77</span><span class="pln">
  </span><span>Serial</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"Humidity_77: "</span><span class="pun">);</span><span class="pln">
  </span><span>Serial</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln">h_77</span><span class="pun">);</span><span class="pln">
  </span><span>Serial</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">" %"</span><span class="pun">);</span><span class="pln">

  delay</span><span class="pun">(</span><span class="lit">1000</span><span class="pun">);</span><span class="pln">

</span><span>WiFiClient</span><span class="pln"> client </span><span class="pun">=</span><span class="pln"> server</span><span class="pun">.</span><span class="pln">available</span><span class="pun">();</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">client</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">while</span><span class="pun">(!</span><span class="pln">client</span><span class="pun">.</span><span class="pln">available</span><span class="pun">()){</span><span class="pln">
delay</span><span class="pun">(</span><span class="lit">1</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span>String</span><span class="pln"> req </span><span class="pun">=</span><span class="pln"> client</span><span class="pun">.</span><span class="pln">readStringUntil</span><span class="pun">(</span><span class="str">'\r'</span><span class="pun">);</span><span class="pln">
client</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"HTTP/1.1 200 OK"</span><span class="pun">);</span><span class="pln">
client</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Content-Type: text/html"</span><span class="pun">);</span><span class="pln">
client</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Connection: close"</span><span class="pun">);</span><span class="pln">
client</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">""</span><span class="pun">);</span><span class="pln">
client</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"&lt;!DOCTYPE HTML&gt;"</span><span class="pun">);</span><span class="pln">
client</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"&lt;html&gt;"</span><span class="pun">);</span><span class="pln">
client</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"&lt;head&gt;&lt;/head&gt;&lt;body&gt;"</span><span class="pun">);</span><span class="pln">
client</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"Temperatures_in: "</span><span class="pun">);</span><span class="pln">
client</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln">t</span><span class="pun">);</span><span class="pln">
client</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">" &amp;#8451"</span><span class="pun">);</span><span class="pln">
client</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"&lt;br&gt;"</span><span class="pun">);</span><span class="pln">
client</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"Pressure_in: "</span><span class="pun">);</span><span class="pln">
client</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln">p</span><span class="pun">);</span><span class="pln">
client</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">" mm.Hg."</span><span class="pun">);</span><span class="pln">
client</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"&lt;br&gt;"</span><span class="pun">);</span><span class="pln">
client</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"Humidity_in: "</span><span class="pun">);</span><span class="pln">
client</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln">h</span><span class="pun">);</span><span class="pln">
client</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">" %"</span><span class="pun">);</span><span class="pln">
client</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"&lt;br&gt;&lt;br&gt;"</span><span class="pun">);</span><span class="pln">
client</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"Temperatures_out: "</span><span class="pun">);</span><span class="pln">
client</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln">t_77</span><span class="pun">);</span><span class="pln">
client</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">" &amp;#8451"</span><span class="pun">);</span><span class="pln">
client</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"&lt;br&gt;"</span><span class="pun">);</span><span class="pln">
client</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"Pressure_out: "</span><span class="pun">);</span><span class="pln">
client</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln">p_77</span><span class="pun">);</span><span class="pln">
client</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">" mm.Hg."</span><span class="pun">);</span><span class="pln">
client</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"&lt;br&gt;"</span><span class="pun">);</span><span class="pln">
client</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"Humidity_out: "</span><span class="pun">);</span><span class="pln">
client</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln">h_77</span><span class="pun">);</span><span class="pln">
client</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">" %"</span><span class="pun">);</span><span class="pln">
client</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"&lt;/body&gt;&lt;/html&gt;"</span><span class="pun">);</span><span class="pln">
delay</span><span class="pun">(</span><span class="lit">1</span><span class="pun">);</span><span class="pln">
client</span><span class="pun">.</span><span class="pln">stop</span><span class="pun">();</span><span class="pln">
  
</span><span class="pun">}</span></pre>

<p>
	 
</p>

<p>
	<a class="ipsAttachLink" href="https://it4it.club/applications/core/interface/file/attachment.php?id=931" data-fileid="931" rel="">Grove_BME280_77-master.zip</a>
</p>
]]></description><guid isPermaLink="false">75</guid><pubDate>Tue, 20 Feb 2018 21:38:29 +0000</pubDate></item><item><title>&#x41A;&#x43E;&#x43D;&#x444;&#x438;&#x433;&#x443;&#x440;&#x430;&#x446;&#x438;&#x44F; &#x43C;&#x438;&#x43A;&#x440;&#x43E;&#x43A;&#x43E;&#x43D;&#x442;&#x440;&#x43E;&#x43B;&#x43B;&#x435;&#x440;&#x430; &#x447;&#x435;&#x440;&#x435;&#x437; uart &#x438; &#x445;&#x440;&#x430;&#x43D;&#x435;&#x43D;&#x438;&#x435; &#x43D;&#x430;&#x441;&#x442;&#x440;&#x43E;&#x435;&#x43A; &#x432; eeprom &#x43D;&#x430; &#x43F;&#x440;&#x438;&#x43C;&#x435;&#x440;&#x435; mqtt &#x43B;&#x43E;&#x433;&#x433;&#x435;&#x440;&#x430;</title><link>https://it4it.club/topic/71-konfiguraciya-mikrokontrollera-cherez-uart-i-hranenie-nastroek-v-eeprom-na-primere-mqtt-loggera/</link><description><![CDATA[
<p>
	Привет друзья.
</p>

<p>
	В данной теме пойдет речь о конфигурации микроконтроллера через <strong>UART</strong> (<a href="https://ru.wikipedia.org/wiki/%D0%A3%D0%BD%D0%B8%D0%B2%D0%B5%D1%80%D1%81%D0%B0%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D1%81%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%BD%D1%8B%D0%B9_%D0%BF%D1%80%D0%B8%D1%91%D0%BC%D0%BE%D0%BF%D0%B5%D1%80%D0%B5%D0%B4%D0%B0%D1%82%D1%87%D0%B8%D0%BA" rel="external nofollow">Universal Asynchronous Receiver-Transmitter</a>) интерфейс. А рассмотрим мы это на примере <strong>MQTT</strong> логгера. В данном случае, это будет логгер температуры. Мне это устройство потребовалось на работе, даже не мне, а моим коллегам, и оно действительно работает и приносит огромную пользу т.к контроль температуры производится совместно с отличной, на мой взгляд, системой мониторинга Zabbix с оперативными оповещениями, построением графиков, блэк-джеком и... Подробнее о дружбе <strong>Arduino</strong> и <strong>Zabbix</strong> можно почитать тут
</p>
<iframe allowfullscreen="" class="ipsEmbed_finishedLoading" data-controller="core.front.core.autosizeiframe" data-embedcontent="" data-embedid="embed7980465405" scrolling="no" src="https://it4it.club/topic/62-obuchaem-zabbix-rabotat-s-mqtt-protokolom/?do=embed" style="overflow: hidden; height: 327px; max-width: 502px;"></iframe>

<p>
	Но как всегда, есть нюансы. А заключаются они в том, что в будущем, обслуживать армию мелких контроллеров придется людям, которые заняты своими задачами и им попросту некогда изучать Arduino, не говоря уже о серьезных альтернативах, разбираться в том, как прописать нужные значения переменных в программу и загрузить её в микроконтроллер. Все настройки необходимо производить быстро, с явным указанием изменяемого параметра и его значения. Ровно также, как это делается с любым промышленным оборудованием.
</p>

<p>
	<strong>И тут на помощь приходит UART</strong>
</p>

<p>
	Микросхема <strong>UART to USB</strong> имеется в большинстве плат семейства Arduino, а там, где её нет, обычно выведены соответствующие "пины". И все это очень облегчает жизнь т.к позволяет общаться с контроллером, просто подключив его к компьютеру напрямую или через переходник, благо их везде навалом, да и стоят они как пачка семечек. Остается только запустить любой терминал, который умеет доставлять в конец строки символ "перевод строки", что известен в народе как "<strong>\n</strong>", а в ASCII таблице имеет номер <strong>0A</strong>.
</p>

<p>
	Кстати, в Serial мониторе Arduino IDE выставить символ конца строки можно так
</p>

<p>
	<img alt="uart-to-usb-nl.png" class="ipsImage ipsImage_thumbnailed" data-fileid="657" data-unique="di1cre6wz" src="https://it4it.club/uploads/monthly_2017_10/uart-to-usb-nl.png.90a3d098b3189f24d332a3b632cc34cf.png"></p>

<p>
	Ну а дальше только, что и остается, как общаться с устройством на той стороне. И тут мы переходим к основному алгоритму программы. Но перед этим хочу отметить, и это ВАЖНО, что за любое упрощение жизни, всякие красивости и прочее, приходиться платить, и цена довольно высока! В данном случае, это ОЗУ микроконтроллера. Поэтому не раскатываем губы, а если очень хочется, то берем следующий по характеристикам микроконтроллер. А начинать мы будем с ATmega328P, что известен в народе как Arduino UNO, Arduino Nano, IBoard v1.1 и т.д по списку. Заканчивать Вы можете чем угодно, хоть ATmega2560, ESP8266 или ESP32. В противном случае, производим оптимизацию кода, отказываемся от громоздких библиотек, или вообще, от Arduino IDE.
</p>

<p>
	<strong>Что мы хотим получить</strong>
</p>

<ol>
<li>
		Вся конфигурация микроконтроллера должна храниться в энергонезависимой памяти (ПЗУ) известной нам как EEPROMM.
	</li>
	<li>
		Если в ПЗУ конфигурация отсутствует, необходимо иметь резервный план. И им станет сброс конфигурации на настройки по умолчанию. Это поведение знакомо всем, особенно по домашним дешевым маршрутизаторам, а значит, интуитивно понятно.
	</li>
	<li>
		Выводить справку при начале общения пользователя и устройства, на мой взгляд, как манеры высшего общества. Контроллер должен представляться и сообщать всю необходимую информацию о себе и о том, как с ним вести диалог.
	</li>
	<li>
		Все команды должны быть просты и иметь не двусмысленное значение.
	</li>
	<li>
		И конечно, мы должны иметь возможность просмотра текущего состояния датчиков или процессов, которыми занимается устройство в свободное от общения с нами время.
	</li>
</ol>
<p>
	<strong>Как сохранять конфигурацию в EEPROM</strong>
</p>

<p>
	Пожалуй, стоит начать с того, как сохранить конфигурацию микроконтроллера в энергонезависимую память. Для этих целей, в стандартный набор инструментов Arduino IDE входит библиотека для работы с EEPROM.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5553_47" style="">
<span class="com">#include</span><span class="pln"> </span><span class="str">&lt;EEPROM.h&gt;</span></pre>

<p>
	На данный момент нас интересуют две функции, это чтение и запись
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5553_55" style="">
<span class="pln">EEPROM</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="pln">address</span><span class="pun">,</span><span class="pln"> variable</span><span class="pun">);</span><span class="pln">
EEPROM</span><span class="pun">.</span><span class="pln">put</span><span class="pun">(</span><span class="pln">address</span><span class="pun">,</span><span class="pln"> variable</span><span class="pun">);</span></pre>

<p>
	Обе принимают два параметра:
</p>

<ol>
<li>
		Адрес, начиная с которого будет произведено чтение или запись данных в память
	</li>
	<li>
		Переменная чье содержимое надо сохранить или в которую нужно из памяти прочитать
	</li>
</ol>
<p>
	Особенность работы этих функция заключается в том, что в зависимости от типа переданной им переменной во втором параметре, будет произведено чтение или запись ровно того количества данных которое соответствует размеру типа этой самой переменной. На простом языке это означает, что если переменная variable будет иметь типа byte, то и работать мы будем с объемом памяти в 1 байт. И тоже самое произойдет с абсолютно любым типом данных пока мы не упремся в размеры самого EEPROM или ОЗУ микроконтролера. Из этого всего следует, что мы можем создать свой собственный тип данных, разместить в нем необходимую нам информацию и всего лишь двумя функциями помещать его в память и извлекать обратно.
</p>

<p>
	И в этом нам поможет пользовательский составной тип - структура (struct). Данный тип позволяет объединить в себе различные типы данных, упорядочить их и присвоить им понятные имена.
</p>

<div class="ipsSpoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5553_68" style="">

<span class="com">// Описываем структуру</span><span class="pln">
</span><span class="kwd">struct</span><span class="pln"> user </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">char</span><span class="pln"> name</span><span class="pun">[</span><span class="lit">40</span><span class="pun">];</span><span class="pln">
  byte age</span><span class="pun">;</span><span class="pln">
</span><span class="pun">};</span><span class="pln">
</span><span class="com">// Объявляем новую переменную с нашим типом и помещаем в неё нужные нам значения</span><span class="pln">
user anna</span><span class="pun">;</span><span class="pln">
anna</span><span class="pun">.</span><span class="pln">name </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Smirnova Anna"</span><span class="pun">;</span><span class="pln">
anna</span><span class="pun">.</span><span class="pln">age  </span><span class="pun">=</span><span class="pln"> </span><span class="lit">15</span><span class="pun">;</span><span class="pln">
</span><span class="com">// Записываем данные в EEPROM</span><span class="pln">
EEPROM</span><span class="pun">.</span><span class="pln">put</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> anna</span><span class="pun">);</span><span class="pln">
</span><span class="com">// Объявляем еще одну переменную с нашим типом</span><span class="pln">
user human</span><span class="pun">;</span><span class="pln">
</span><span class="com">// Читаем данные из EEPROM</span><span class="pln">
EEPROM</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> human</span><span class="pun">);</span><span class="pln">
</span><span class="com">// Выводим содержимое</span><span class="pln">
</span><span class="typ">Serial</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">human</span><span class="pun">.</span><span class="pln">name</span><span class="pun">);</span><span class="pln"> </span><span class="com">// Smirnova Anna </span><span class="pln">
</span><span class="typ">Serial</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">human</span><span class="pun">.</span><span class="pln">age</span><span class="pun">);</span><span class="pln">  </span><span class="com">// 15</span></pre>

		<p>
			 
		</p>
	</div>
</div>

<p>
	Это общий пример для большего понимания, как объединить несколько типов данных в одной структуре, получить к ним доступ, записать и прочитать их из EEPROM.
</p>

<p>
	Наша структура будет немного сложнее, но суть остается той же самой.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5553_72" style="">
<span class="com">// Дополнительная структура описывающая IPv4 адреса</span><span class="pln">
</span><span class="kwd">struct</span><span class="pln"> addres </span><span class="pun">{</span><span class="pln">
  byte a</span><span class="pun">;</span><span class="pln">
  byte b</span><span class="pun">;</span><span class="pln">
  byte c</span><span class="pun">;</span><span class="pln">
  byte d</span><span class="pun">;</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="com">// Структура объекта конфига для хранения в EEPROM</span><span class="pln">
</span><span class="kwd">struct</span><span class="pln"> configObj </span><span class="pun">{</span><span class="pln">
  addres ip</span><span class="pun">;</span><span class="pln">
  addres subnet</span><span class="pun">;</span><span class="pln">
  addres gateway</span><span class="pun">;</span><span class="pln">
  addres dns</span><span class="pun">;</span><span class="pln">
  byte mac</span><span class="pun">[</span><span class="lit">6</span><span class="pun">];</span><span class="pln">
  byte hex</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">char</span><span class="pln"> server</span><span class="pun">[</span><span class="lit">40</span><span class="pun">];</span><span class="pln">
  </span><span class="kwd">char</span><span class="pln"> topic</span><span class="pun">[</span><span class="lit">40</span><span class="pun">];</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> config</span><span class="pun">;</span></pre>

<p>
	Данная структура хранит сетевые настройки для работы с Ethernet модулем (w5100 и выше) Arduino, базовые настройки для связи с MQTT брокером. Сразу при описании структуры мы объявили новую переменную с именем config с типом нашей структуры.
</p>

<p>
	<span style="color:#e74c3c;"><strong>ВАЖНО:</strong></span> кроме наших данных в структуре имеется дополнительная переменная с именем hex. Её задача, это контроль наличия наших данных в EEPROM. Она всегда должна содержать одно и тоже значение. Представьте ситуацию, что вы взяли контроллер в EEPROM которого находится какая-либо информация (может там чисто, но мы этого не знаем наверняка) и мы прочитаем данные и поместим их в нашу переменную. В итоге мы получим данные которым нельзя доверять, а что еще хуже, это если эти самые данные нарушат работу внешнего оборудования.
</p>

<p>
	Более правильным, на мой взгляд, будет проверка значений по конкретно определенным адресам. Например, мы знаем, что в 16 байте должно быть значение 0xAA и если оно действительно там, то мы убеждаемся, что это наша информация. Естественно, что контрольных точек может быть несколько и разумеется с разными значениями, это увеличит гарантию того, что данные являются нашими, но 100% гарантии не даст. Для более серьезных проектов есть более серьезные методы, например, подсчет контрольной суммы всего набора данных.
</p>

<p>
	Также структура может иметь вложенные структуры, у нас ими являются: ip, subnet, gateway, dns. Вы можете отказаться от такого варианта и записывать данные просто в массив байт, как это было сделано с MAC адресом. Естественно, что обращаться к этим полям нужно по-разному.
</p>

<p>
	Запись данных в поле subnet
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5553_74" style="">
<span class="pln">config</span><span class="pun">.</span><span class="pln">subnet </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="lit">255</span><span class="pun">,</span><span class="pln"> </span><span class="lit">255</span><span class="pun">,</span><span class="pln"> </span><span class="lit">255</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">};</span></pre>

<p>
	Запись данных в поле mac
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5553_76" style="">
<span class="pln">byte mac</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="lit">0x00</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0xAA</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0xBB</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0xCC</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0xDE</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0x02</span><span class="pun">};</span><span class="pln">
memcpy</span><span class="pun">(</span><span class="pln">config</span><span class="pun">.</span><span class="pln">mac</span><span class="pun">,</span><span class="pln"> mac</span><span class="pun">,</span><span class="pln"> </span><span class="lit">6</span><span class="pun">);</span></pre>

<p>
	С записью данных в поле server все еще проще
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5553_79" style="">
<span class="pln">config</span><span class="pun">.</span><span class="pln">server </span><span class="pun">=</span><span class="pln"> </span><span class="str">"mqtt.it4it.club"</span><span class="pun">;</span></pre>

<p>
	Функция, которая возвращает нашу структуру данных с полностью заполненными полями.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5553_83" style="">
<span class="com">// Начальный конфиг</span><span class="pln">
configObj defaultConfig</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  configObj config </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="pun">{</span><span class="lit">192</span><span class="pun">,</span><span class="pln"> </span><span class="lit">168</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">200</span><span class="pun">},</span><span class="pln">
    </span><span class="pun">{</span><span class="lit">255</span><span class="pun">,</span><span class="pln"> </span><span class="lit">255</span><span class="pun">,</span><span class="pln"> </span><span class="lit">255</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">},</span><span class="pln">
    </span><span class="pun">{</span><span class="lit">192</span><span class="pun">,</span><span class="pln"> </span><span class="lit">168</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">},</span><span class="pln">
    </span><span class="pun">{</span><span class="lit">192</span><span class="pun">,</span><span class="pln"> </span><span class="lit">168</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">},</span><span class="pln">
    </span><span class="pun">{</span><span class="lit">0x00</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0xAA</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0xBB</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0xCC</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0xDE</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0x02</span><span class="pun">},</span><span class="pln">
    </span><span class="lit">0xAA</span><span class="pun">,</span><span class="pln"> </span><span class="com">// Не трогать! Используется для проверки конфигурации в EEPROM</span><span class="pln">
    F</span><span class="pun">(</span><span class="str">"mqtt.it4it.club"</span><span class="pun">),</span><span class="pln">
    F</span><span class="pun">(</span><span class="str">"arduino/serial/config"</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> config</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	К примеру, два последних значения записывать не обязательно, тогда эти поля останутся пусты если использовать данную функцию для возврата к "заводским" настройкам.
</p>

<p>
	Вот пример того, как используя описанную нами структуру, мы проверяем целостность настроек в EEPROM и в случае не совпадения hex значений, загружаем настройки по умолчанию.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5553_85" style="">
<span class="kwd">const</span><span class="pln"> byte startingAddress </span><span class="pun">=</span><span class="pln"> </span><span class="lit">9</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">bool</span><span class="pln"> configured </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">void</span><span class="pln"> loadConfig</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  EEPROM</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="pln">startingAddress</span><span class="pun">,</span><span class="pln"> config</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">config</span><span class="pun">.</span><span class="pln">hex </span><span class="pun">==</span><span class="pln"> </span><span class="lit">170</span><span class="pun">)</span><span class="pln"> configured </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">else</span><span class="pln"> config </span><span class="pun">=</span><span class="pln"> defaultConfig</span><span class="pun">();</span><span class="pln">
  configEthernet</span><span class="pun">();</span><span class="pln"> </span><span class="com">// Функция производящая настройку сети</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	<strong>Как контроллеру начать понимать, что от него хотят</strong>
</p>

<p>
	В Arduino имеется функция, вызываемая каждый раз, когда в передаваемый буфер данных попадает знакомый нам символ перевода строки.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5553_7" style="">
<span class="kwd">void</span><span class="pln"> serialEvent</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// Вызывается каждый раз, когда что-то прилетает по UART</span><span class="pln">
    </span><span class="com">// Данные передаются посимвольно. Если в строке 100 символов, то функция будет вызвана 100 раз</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	И в контексте обсуждаемой нами программы, мы можем представить ее в следующем виде
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5553_9" style="">
<span class="kwd">void</span><span class="pln"> serialEvent</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  serialEventTime </span><span class="pun">=</span><span class="pln"> millis</span><span class="pun">();</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">console</span><span class="pun">.</span><span class="pln">available</span><span class="pun">())</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">char</span><span class="pln"> c </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">char</span><span class="pun">)</span><span class="pln">console</span><span class="pun">.</span><span class="pln">read</span><span class="pun">();</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">inputCommands</span><span class="pun">.</span><span class="pln">length</span><span class="pun">()</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> inputCommandsLength</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">c </span><span class="pun">!=</span><span class="pln"> </span><span class="str">'\n'</span><span class="pun">)</span><span class="pln"> inputCommands </span><span class="pun">+=</span><span class="pln"> c</span><span class="pun">;</span><span class="pln">
      </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">inputCommands</span><span class="pun">.</span><span class="pln">length</span><span class="pun">())</span><span class="pln"> inputCommandsComplete </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span></pre>

<p>
	Её задача, символ за символом, собрать в кучу все переданные нами данные и при получении заветного символа перевода строки (именно он даст нам понять, что передача сообщения завершена) сообщить, что команда получена и передать накопленный буфер данных своей напарнице по цеху.
</p>

<p>
	Но перед тем как это сделать стоит рассмотреть альтернативную ветку развития событий, а именно тот факт, что нам попросту могут прислать огромную, кучу шлака без волшебного символа, а раз могут, значит рано или поздно пришлют. И мы бесполезно потратим ценные ресурсы микроконтроллера, что может привести к непредсказуемым результатам в дальнейшем. Поэтому, в логику функции, мы добавим дополнительное ограничение на количество переданных символов, если оно достигнуто, то попросту перестаем воспринимать последующие данные.
</p>

<p>
	Останется только избавиться от них, и самым удобным моментом будет, когда этот поток шлака прекратиться. Чтобы об этом узнать мы будем запоминать время, когда пришел каждый из символов переданной строки перезаписывая соответствующую временную переменную данными о следующем символе и т.д пока поток не иссякнет. И как только расхождение текущего времени CPU и времени, когда поступил последний символ превысит некоторое значение, пусть это будет 1 секунда, мы очистим нашу память. Этот простой механизм напоминающий амнезию позволит избавить нас от лишних проблем.
</p>

<p>
	Переменная отвечающая за размер принимаемого буфера
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5553_11" style="">
<span class="kwd">const</span><span class="pln"> byte inputCommandsLength </span><span class="pun">=</span><span class="pln"> </span><span class="lit">60</span><span class="pun">;</span></pre>

<p>
	Теперь можно переходить к напарнице предыдущей героини и, по совместительству, основной рабочей лошадки - функции обрабатывающей адекватно полученные данные.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5553_13" style="">
<span class="kwd">void</span><span class="pln"> serialEventHandler</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// вызывается в loop и проверяет взведена ли переменная inputCommandsComplete</span><span class="pln">
    </span><span class="com">// в полученных данных пытается распознать команды</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	По началу я хотел описать данную функцию в упрощенном варианте, но в процессе понял, что ничего хорошего из этого не выйдет, и я решил описать только ключевые моменты, но их будет достаточно, на мой взгляд.
</p>

<p>
	<strong>Разбор serialEventHandler</strong>
</p>

<p>
	Полученные данные будут переданы нам в переменной inputCommands с типом String
</p>

<p>
	В первую очередь стоит почистить ее от лишних пробельных символов. Они часто встречаются в начале и в конце строки если пользователь копирует текст, а не набирает его самостоятельно. Это распространенная ситуация, приводящая к отказу принятия команды и бороться с ней очень просто.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5553_15" style="">
<span class="pln">inputCommands</span><span class="pun">.</span><span class="pln">trim</span><span class="pun">();</span></pre>

<p>
	Далее стоит отсеять команды, не несущие никакой динамической информации, например, help, restart, reset и т.п это предписывающие команды которые заставляют контроллер выполнять строго описанные функции без вмешательства в их работу.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5553_18" style="">
<span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">inputCommands </span><span class="pun">==</span><span class="pln"> F</span><span class="pun">(</span><span class="str">"help"</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    consoleHelp</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">inputCommands </span><span class="pun">==</span><span class="pln"> F</span><span class="pun">(</span><span class="str">"restart"</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    resetFunc</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// Все сложные команды обрабатываются в этом блоке</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	Как Вы видите, все очень просто и скучно. Но не в том случае если команда динамическая, то есть содержит не только саму команду (заголовок) но и полезную нагрузку (параметр) которая может меняться раз от раза. Простой пример это команда изменения ip адреса и её варианты:
</p>

<ul>
<li>
		<em>ip 37.140.198.90</em>
	</li>
	<li>
		<em>ip 192.168.0.244</em>
	</li>
	<li>
		<em>ip 10.10.10.88</em>
	</li>
</ul>
<p>
	В данном случае, нам стоит понять, относится ли данная команда именно к ip адресу. Для этого в наборе String имеется отличный метод, позволяющий производить сравнение переданного ему параметра с началом строки.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5553_22" style="">
<span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">inputCommands</span><span class="pun">.</span><span class="pln">startsWith</span><span class="pun">(</span><span class="pln">F</span><span class="pun">(</span><span class="str">"ip"</span><span class="pun">)))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// Строка inputCommands начинается с пары символов "ip"</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	Если все идет так, как мы задумали, то нам стоит отделить динамическую часть - наш параметр, от заголовка и получить полезную нагрузку. В этом нам поможет, опять же из набора String, метод substring позволяющий получать часть строки с указанием начального и конечного символа подстроки. Последний параметр указывать не обязательно и в таком случае мы получим всю строку начиная с указанного символа.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5553_116" style="">
<span class="pln">inputCommands</span><span class="pun">.</span><span class="pln">substring</span><span class="pun">(</span><span class="lit">4</span><span class="pun">)</span></pre>

<p>
	В данном случае начиная с 4-его и заканчивая последним. И как Вы успели заметить, отсчет мы начинаем не с третьего символа, что соответствует нашей строке без вступительного "ip", а на один больше т.к между заголовком и параметром имеется разделяющий символ в виде пробела.
</p>

<p>
	Далее, полученную строку мы передадим в функцию, занимающуюся разбором на компоненты и принимающую следующие параметры:
</p>

<ol>
<li>
		Указатель на переменную с типом char, для этого нам потребуется преобразовать наш тип String
	</li>
	<li>
		Символ разделителя, что для IPv4 является точка "."
	</li>
	<li>
		Указатель на массив типа byte, которому будет присвоен результат разбора
	</li>
	<li>
		Количество искомых элементов в строке
	</li>
	<li>
		И система счисления, подразумеваемая в качестве исходной для записи элементов подстроки
	</li>
</ol>
<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5553_26" style="">
<span class="com">/*
    Парсинг
    https://stackoverflow.com/questions/35227449/convert-ip-or-mac-address-from-string-to-byte-array-arduino-or-c
*/</span><span class="pln">
</span><span class="kwd">void</span><span class="pln"> parseBytes</span><span class="pun">(</span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">char</span><span class="pun">*</span><span class="pln"> str</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">char</span><span class="pln"> sep</span><span class="pun">,</span><span class="pln"> byte</span><span class="pun">*</span><span class="pln"> bytes</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> maxBytes</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> base</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> maxBytes</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        bytes</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> strtoul</span><span class="pun">(</span><span class="pln">str</span><span class="pun">,</span><span class="pln"> NULL</span><span class="pun">,</span><span class="pln"> base</span><span class="pun">);</span><span class="pln">
        str </span><span class="pun">=</span><span class="pln"> strchr</span><span class="pun">(</span><span class="pln">str</span><span class="pun">,</span><span class="pln"> sep</span><span class="pun">);</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">str </span><span class="pun">==</span><span class="pln"> NULL </span><span class="pun">||</span><span class="pln"> </span><span class="pun">*</span><span class="pln">str </span><span class="pun">==</span><span class="pln"> </span><span class="str">'\0'</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
        str</span><span class="pun">++;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	В нашем случае выглядеть это будет следующим образом
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5553_118" style="">
<span class="pln">byte ip</span><span class="pun">[</span><span class="lit">4</span><span class="pun">];</span><span class="pln">
parseBytes</span><span class="pun">(</span><span class="pln">inputCommands</span><span class="pun">.</span><span class="pln">substring</span><span class="pun">(</span><span class="lit">4</span><span class="pun">).</span><span class="pln">c_str</span><span class="pun">(),</span><span class="pln"> </span><span class="str">'.'</span><span class="pun">,</span><span class="pln"> ip</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">);</span></pre>

<p>
	А дале все становится еще проще, попросту проверить попадает ли наш ip адрес, в список правильных адресов. И самой простой проверкой послужит проверка первого байта адреса на несоответствие не угодным нам сетям (0, 127, 255)
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5553_97" style="">
<span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">ip</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">127</span><span class="pln"> and ip</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">255</span><span class="pln"> and ip</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// Производим необходимые нам действия с ip адресом, например, запись в конфиг</span><span class="pln">
    config</span><span class="pun">.</span><span class="pln">ip </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">ip</span><span class="pun">[</span><span class="lit">0</span><span class="pun">],</span><span class="pln"> ip</span><span class="pun">[</span><span class="lit">1</span><span class="pun">],</span><span class="pln"> ip</span><span class="pun">[</span><span class="lit">2</span><span class="pun">],</span><span class="pln"> ip</span><span class="pun">[</span><span class="lit">3</span><span class="pun">]};</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	Вы в праве реализовать собственные проверки, какие только душе угодны.
</p>

<p>
	Также хотелось бы отметить, что обрабатывать некоторые параметры проще и быстрее через их короткие записи. К таким можно отнести маску подсети устройства. Например, привычный дня нас адрес 192.168.0.1 с маской подсети 255.255.255.0 можно записать в виде 192.168.0.1/24, где цифра 24 указывает нашу подсеть в краткой форме. А, следовательно, мы можем записать несколько кратких форм масок подсети в следующем виде:
</p>

<ol>
<li>
		<em>subnet 255.255.255.0 или subnet 24</em>
	</li>
	<li>
		<em>subnet 255.255.0.0 или subnet 16</em>
	</li>
	<li>
		<em>subnet 255.0.0.0 или subnet 8</em>
	</li>
</ol>
<p>
	Это основные маски, и я не описывал все существующие т.к в этом нет нужды, но если Вам интересно, то почитать про них можно в <a href="https://ru.wikipedia.org/wiki/%D0%9C%D0%B0%D1%81%D0%BA%D0%B0_%D0%BF%D0%BE%D0%B4%D1%81%D0%B5%D1%82%D0%B8" rel="external nofollow">wikipedia</a>.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5553_120" style="">
<span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">inputCommands</span><span class="pun">.</span><span class="pln">startsWith</span><span class="pun">(</span><span class="pln">F</span><span class="pun">(</span><span class="str">"subnet"</span><span class="pun">)))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">String</span><span class="pln"> input </span><span class="pun">=</span><span class="pln"> inputCommands</span><span class="pun">.</span><span class="pln">substring</span><span class="pun">(</span><span class="lit">8</span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">input </span><span class="pun">==</span><span class="pln"> F</span><span class="pun">(</span><span class="str">"24"</span><span class="pun">))</span><span class="pln">      config</span><span class="pun">.</span><span class="pln">subnet </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="lit">255</span><span class="pun">,</span><span class="pln"> </span><span class="lit">255</span><span class="pun">,</span><span class="pln"> </span><span class="lit">255</span><span class="pun">,</span><span class="pln">   </span><span class="lit">0</span><span class="pun">};</span><span class="pln">
    </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">input </span><span class="pun">==</span><span class="pln"> F</span><span class="pun">(</span><span class="str">"16"</span><span class="pun">))</span><span class="pln"> config</span><span class="pun">.</span><span class="pln">subnet </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="lit">255</span><span class="pun">,</span><span class="pln"> </span><span class="lit">255</span><span class="pun">,</span><span class="pln">   </span><span class="lit">0</span><span class="pun">,</span><span class="pln">   </span><span class="lit">0</span><span class="pun">};</span><span class="pln">
    </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">input </span><span class="pun">==</span><span class="pln"> F</span><span class="pun">(</span><span class="str">"8"</span><span class="pun">))</span><span class="pln">  config</span><span class="pun">.</span><span class="pln">subnet </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="lit">255</span><span class="pun">,</span><span class="pln">   </span><span class="lit">0</span><span class="pun">,</span><span class="pln">   </span><span class="lit">0</span><span class="pun">,</span><span class="pln">   </span><span class="lit">0</span><span class="pun">};</span><span class="pln">
    </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="com">// Все остальные маски попадают в этот блок</span><span class="pln">
        byte subnet</span><span class="pun">[</span><span class="lit">4</span><span class="pun">];</span><span class="pln">
        parseBytes</span><span class="pun">(</span><span class="pln">input</span><span class="pun">.</span><span class="pln">c_str</span><span class="pun">(),</span><span class="pln"> </span><span class="str">'.'</span><span class="pun">,</span><span class="pln"> subnet</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">);</span><span class="pln">
        config</span><span class="pun">.</span><span class="pln">subnet </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">subnet</span><span class="pun">[</span><span class="lit">0</span><span class="pun">],</span><span class="pln"> subnet</span><span class="pun">[</span><span class="lit">1</span><span class="pun">],</span><span class="pln"> subnet</span><span class="pun">[</span><span class="lit">2</span><span class="pun">],</span><span class="pln"> subnet</span><span class="pun">[</span><span class="lit">3</span><span class="pun">]};</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	MAC адрес хранится у нас в виде массива байт. Его перезапись другим массивом производится с помощью функции memcpy
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5553_91" style="">
<span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">inputCommands</span><span class="pun">.</span><span class="pln">startsWith</span><span class="pun">(</span><span class="pln">F</span><span class="pun">(</span><span class="str">"mac"</span><span class="pun">)))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    byte mac</span><span class="pun">[</span><span class="lit">6</span><span class="pun">];</span><span class="pln">
    parseBytes</span><span class="pun">(</span><span class="pln">inputCommands</span><span class="pun">.</span><span class="pln">substring</span><span class="pun">(</span><span class="lit">4</span><span class="pun">).</span><span class="pln">c_str</span><span class="pun">(),</span><span class="pln"> </span><span class="str">':'</span><span class="pun">,</span><span class="pln"> mac</span><span class="pun">,</span><span class="pln"> </span><span class="lit">6</span><span class="pun">,</span><span class="pln"> </span><span class="lit">16</span><span class="pun">);</span><span class="pln">
    memcpy</span><span class="pun">(</span><span class="pln">config</span><span class="pun">.</span><span class="pln">mac</span><span class="pun">,</span><span class="pln"> mac</span><span class="pun">,</span><span class="pln"> </span><span class="lit">6</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	Изменение адреса MQTT сервера
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5553_122" style="">
<span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">inputCommands</span><span class="pun">.</span><span class="pln">startsWith</span><span class="pun">(</span><span class="pln">F</span><span class="pun">(</span><span class="str">"server"</span><span class="pun">)))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">String</span><span class="pln"> server </span><span class="pun">=</span><span class="pln"> inputCommands</span><span class="pun">.</span><span class="pln">substring</span><span class="pun">(</span><span class="lit">8</span><span class="pun">);</span><span class="pln">
    server</span><span class="pun">.</span><span class="pln">trim</span><span class="pun">();</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">server</span><span class="pun">.</span><span class="pln">length</span><span class="pun">()</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">40</span><span class="pun">)</span><span class="pln"> server</span><span class="pun">.</span><span class="pln">toCharArray</span><span class="pun">(</span><span class="pln">config</span><span class="pun">.</span><span class="pln">server</span><span class="pun">,</span><span class="pln"> </span><span class="lit">40</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	В принципе теперь понятно, как производить получение, разбор и сохранение конфигурации в EEPROM микроконтроллера.
</p>

<p>
	<strong>Как это выглядит на практике</strong>
</p>

<p>
	Заливаем программу в микроконтроллер и подключаемся к Arduino по usb или через переходник. Открываем терминал и нас приветствуют краткой справкой с описанием доступных команд.
</p>

<pre class="ipsCode" id="ips_uid_2950_5">
- ---------------------------------------------------------------------------------------
# Sensor with data sending to mqtt server (c) it4it.club
# Use the "config" command to view the current configuration
# To change the configuration, specify the parameter name and its new value with a space,
# for example "ip 192.168.0.200", "subnet 255.255.255.0" or "mac AA:BB:CC:DD:EE:FF"
# You can also specify a subnet using the mask 24, 16 or 8
# Additional commands:
# sensors - view current data from sensors
# config - view current configuration
# save - saves the current configuration
# reset - resets all settings
# restart - restarts the device
# eeprom clear - removes all contents of eeprom
# help - view this help
- ---------------------------------------------------------------------------------------</pre>

<p>
	Т.к. в EEPROM микроконтроллера не была обнаружена конфигурация (волшебный hex байт нам подсказал), то были задействованы стандартные настройки. Просмотреть текущую конфигурацию можно командой config
</p>

<pre class="ipsCode" id="ips_uid_5553_101">
config
# ip: 192.168.0.200
# subnet: 255.255.255.0
# gateway: 192.168.0.1
# dns: 192.168.0.1
# mac: 00:AA:BB:CC:DE:02
# server: mqtt.it4it.club
# topic: arduino/serial/config</pre>

<p>
	чтобы изменить значение любого из этих параметров необходимо передать имя параметра и его новое значение, разделенные между собой пробелом.
</p>

<pre class="ipsCode" id="ips_uid_5553_103">
ip 10.10.10.99
# ok
gateway 10.10.10.1
# ok
dns 10.10.10.1
# ok</pre>

<p>
	После окончания конфигурации необходимо сохранить настройки и если были затронуты критические параметры, например, сеть, то перезапустить Arduino соответствующей командой.
</p>

<pre class="ipsCode" id="ips_uid_5553_111">
save
# ok
restart
# ok
# restarting device...</pre>

<p>
	Если параметр был успешно принят, то контроллер ответит нам "ok", а в противном случае ругнется.
</p>

<pre class="ipsCode" id="ips_uid_5553_107">
ip 127.0.0.1
# bad ip</pre>

<p>
	Также мы получим негативный ответ если команда не была распознана.
</p>

<pre class="ipsCode" id="ips_uid_5553_109">
qwerqwer1243
# bad command</pre>

<p>
	С остальными командами Вы разберетесь самостоятельно.
</p>

<p>
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="659" href="https://it4it.club/uploads/monthly_2017_10/arduino-zabbix-mqtt2.JPG.7b89238411a71ff3da872028ceecb4f9.JPG" rel=""><img alt="arduino-zabbix-mqtt2.JPG" class="ipsImage ipsImage_thumbnailed" data-fileid="659" data-unique="clmovgz28" src="https://it4it.club/uploads/monthly_2017_10/arduino-zabbix-mqtt2.thumb.JPG.2344558561cd4e6b5bd75c08599aaeab.JPG" style="width: 471px; height: auto;"></a><a class="ipsAttachLink ipsAttachLink_image" data-fileid="658" href="https://it4it.club/uploads/monthly_2017_10/arduino-zabbix-mqtt1.JPG.c37f787ae3782206ec543b65babb15fe.JPG" rel=""><img alt="arduino-zabbix-mqtt1.JPG" class="ipsImage ipsImage_thumbnailed" data-fileid="658" data-unique="ugrek44gb" src="https://it4it.club/uploads/monthly_2017_10/arduino-zabbix-mqtt1.thumb.JPG.20461370e3cf3052273c13a615dd2b9e.JPG" style="width: 471px; height: auto;"></a>
</p>

<p>
	<img alt="arduino-zabbix-mqtt3.png" class="ipsImage ipsImage_thumbnailed" data-fileid="661" data-unique="kbe2h7dci" src="https://it4it.club/uploads/monthly_2017_10/arduino-zabbix-mqtt3.png.e52fe5f17d7d19220b74117331105be2.png"></p>

<p>
	Исходник: <a class="ipsAttachLink" data-fileid="663" href="https://it4it.club/applications/core/interface/file/attachment.php?id=663" rel="">MQTT_CLIENT_328_SERIAL_CONFIG.zip</a>
</p>

<p>
	PS: в общем то это статья родилась только для того, чтобы в соседнем форуме с системой мониторинга Zabbix появилась ссылка на устройство, но я надеюсь, что она также станет полезна любителям домашней автоматизации и не только.
</p>
]]></description><guid isPermaLink="false">71</guid><pubDate>Tue, 31 Oct 2017 12:26:52 +0000</pubDate></item><item><title>Arduino &#x432; &#x430;&#x432;&#x442;&#x43E;&#x43C;&#x43E;&#x431;&#x438;&#x43B;&#x435;</title><link>https://it4it.club/topic/38-arduino-v-avtomobile/</link><description><![CDATA[<p>
	Предлогаю в данной теме обсуждать возможность применения Arduino в автомобиле для его улучшения.
</p>]]></description><guid isPermaLink="false">38</guid><pubDate>Sun, 24 Apr 2016 19:00:48 +0000</pubDate></item><item><title>pn532</title><link>https://it4it.club/topic/37-pn532/</link><description><![CDATA[
<p>
	Прикупил ридер <a href="http://ru.aliexpress.com/item/PN532-NFC-RFID-Module-V3-Reader-Writer-Breakout-Board-For-Arduino-Android/32649945085.html?spm=2114.30010708.3.29.KzC3G9&amp;ws_ab_test=searchweb201556_10,searchweb201602_4_10034_507_508_10020_10017_10005_10006_10021_10022_10009_10008_10018_10019,searchweb201603_9&amp;btsid=10d3136e-a659-4216-8f06-ebc8d5a2302b" style="margin:0px;padding:0px;border:0px;font-style:inherit;font-variant:inherit;font-weight:inherit;font-size:14px;line-height:inherit;font-family:inherit;vertical-align:baseline;color:rgb(255,153,0);text-decoration:underline;" title="Pn532 NFC модуль RFID V3 карт писатель прорыв плата для Arduino android-автомобильный" rel="external nofollow">Pn532</a> . RFID модуль поддерживает технологию NFC (<span style="color:rgb(51,51,51);font-family:'Trebuchet MS', Trebuchet, tahoma, serif;font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:21.28px;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;background-color:rgb(221,221,221);">NFC это часть RFID стандарта ISO 14443</span>) и может взаимодействовать с девайсами поддерживающими данную возможность(в большинстве современных смартфонов имеется) Модуль стоит ощутимо дороже rc522 я взял за 800р но так как давно имею задумку соорудить IT замок в квартиру, покупку считаю оправданной. Покурив тему не нашел примеров реализации замка в рунете так что обращаю внимание на данную тему уважаемого KITSUM. Так вот немного подробнее: 
</p>

<p>
	 
</p>

<p>
	<span style="color:rgb(33,33,33);font-family:arial, sans-serif;font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:24px;text-align:left;text-indent:0px;text-transform:none;white-space:pre-wrap;word-spacing:0px;float:none;background-color:rgb(255,255,255);">ридер имеет размер . </span>
</p>

<p>
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="316" src="https://it4it.club/uploads/monthly_2016_04/PN532.jpg.b399c910e2ad06026bc9735bba0b909a.jpg" alt="PN532.jpg" /></p>

<p>
	<span style="color:rgb(33,33,33);font-family:arial, sans-serif;font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:24px;text-align:left;text-indent:0px;text-transform:none;white-space:pre-wrap;word-spacing:0px;float:none;background-color:rgb(255,255,255);">Поддержка I2C , SPI и HSU (High Speed UART )</span>
</p>

<p>
	прошу прощения за кривой гугл перевод данных производителя
</p>

<p>
	<span lang="ru" xml:lang="ru">чтения и запись , P2P общение с коллегами, NFC с Android телефон RFID- устройство считывания / записи поддерживает следующие функции: Mifare 1k , 4k , Ultralight , и DESFire карт ISO / IEC 14443-4 карты, такие как CD97BX , CD свет, DESFire , P5CN072 ( SMX ) Innovision Jewel карты, такие как карты IRT5001 FeliCa карты, такие как RCS_860 и RCS_854 До 5 см - 7см расстояние чтения На борту сдвига уровня , Стандартный 5V TTL для I2C и UART , SPI 3.3V TTL</span>
</p>

<p>
	 
</p>

<p>
	<span lang="ru" xml:lang="ru">В качестве основной функции , этот модуль может считывать и записывать RFID- карты . Различные карты могут быть поддержаны .</span>
</p>

<div class="ipsSpoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			<img class="ipsImage ipsImage_thumbnailed" data-fileid="317" src="https://it4it.club/uploads/monthly_2016_04/PN5321.jpg.f31a40e2c3e703bf7d578af728b30367.jpg" alt="PN5321.jpg" /></p>
	</div>
</div>

<p>
	 
</p>

<p>
	Два модуля PN532 могли бы общаться друг с другом .
</p>

<div class="ipsSpoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			<img class="ipsImage ipsImage_thumbnailed" data-fileid="318" src="https://it4it.club/uploads/monthly_2016_04/PN5322.jpg.a085844621762aea1e1006e8ea19849e.jpg" alt="PN5322.jpg" /></p>
	</div>
</div>

<p>
	в качестве ключа можно использовать телефон с NFC и если допустим в базе пользователь не зарегистрирован то телефон автоматически переходит на страничку с инструкцией по получению ключа а в случае авторизированного пользователя можно получить страничку с кнопками для дальнейших действий и все это использует в качестве связи технологию NFC никаких WIFi или GSM
</p>

<p>
	ссылка на английский мануал от производителя <a href="http://www.elechouse.com/elechouse/images/product/PN532_module_V3/PN532_%20Manual_V3.pdf" rel="external nofollow">http://www.elechouse.com/elechouse/images/product/PN532_module_V3/PN532_%20Manual_V3.pdf</a> 
</p>

<p>
	библеотечка <a class="ipsAttachLink" href="//it4it.club/applications/core/interface/file/attachment.php?id=320" data-fileid="320" rel="">nfc-pn532-master.zip</a> <a class="ipsAttachLink" href="//it4it.club/applications/core/interface/file/attachment.php?id=321" data-fileid="321" rel="">PN532-PN532_HSU.zip</a>
</p>

<p>
	На данный момент занят собственными изысканиями на эту тему буду рад любой информации и идеям.
</p>
]]></description><guid isPermaLink="false">37</guid><pubDate>Thu, 21 Apr 2016 13:20:00 +0000</pubDate></item><item><title>[&#x440;&#x435;&#x448;&#x435;&#x43D;&#x43E;] &#x414;&#x43E;&#x440;&#x430;&#x431;&#x43E;&#x442;&#x43A;&#x430; &#x43A;&#x43E;&#x434;&#x43E;&#x432;&#x43E;&#x433;&#x43E; &#x437;&#x430;&#x43C;&#x43A;&#x430;</title><link>https://it4it.club/topic/43-resheno-dorabotka-kodovogo-zamka/</link><description><![CDATA[
<p>
	Доброго времени суток! Прошу помощи с доработкой кодового замка, замок работает на ура, но при вводе правильного пароля реле срабатывает и отключается а если нажать еще рас * тогда реле так же сработает. Каким способом можно организовать программный сброс который включиться после нажатия любой кнопки клавиатуры и сбросит arduino по истечению 10 сек. За ранее благодарю.
</p>

<p>
	<a class="ipsAttachLink ipsAttachLink_image" href="https://it4it.club/uploads/monthly_2016_06/DbrlVas01lo.jpg.097e8c6caba3ba19e672e417cd0d94e1.jpg" data-fileid="346" rel="external"><img alt="DbrlVas01lo.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="346" src="https://it4it.club/uploads/monthly_2016_06/DbrlVas01lo.jpg.097e8c6caba3ba19e672e417cd0d94e1.jpg" /></a>
</p>

<p>
	<a class="ipsAttachLink" href="//it4it.club/applications/core/interface/file/attachment.php?id=347" data-fileid="347" rel="">скетч.7z</a>
</p>
]]></description><guid isPermaLink="false">43</guid><pubDate>Fri, 24 Jun 2016 21:54:05 +0000</pubDate></item><item><title>&#x410;&#x432;&#x442;&#x43E;&#x43C;&#x430;&#x442;&#x438;&#x437;&#x438;&#x440;&#x443;&#x435;&#x43C; &#x440;&#x430;&#x431;&#x43E;&#x442;&#x443; &#x441; &#x416;&#x430;&#x43B;&#x44E;&#x437;&#x438;</title><link>https://it4it.club/topic/22-%D0%B0%D0%B2%D1%82%D0%BE%D0%BC%D0%B0%D1%82%D0%B8%D0%B7%D0%B8%D1%80%D1%83%D0%B5%D0%BC-%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%83-%D1%81-%D0%B6%D0%B0%D0%BB%D1%8E%D0%B7%D0%B8/</link><description><![CDATA[
<p>
	Доброе время суток.
</p>

<p>
	Хочу поделиться опытом автоматизации изобретения Джона Уэбстера - Жалюзи, что в переводе с Французского звучит как Ревность! Скажу честно, что мой опыт обуздать это не хитрое устройство имеет как положительный, так и отрицательный результат. И я буду очень рад поделиться им с Вами, дабы Вы не совершали моих ошибок, и результат Вашей работы вызывал настоящую Ревность у всех, кто её видит!
</p>

<p style="text-align:center;">
	<img alt="zh_17.jpg.7f5ea4843e3c45fdab8e4526b94104" class="ipsImage ipsImage_thumbnailed" data-fileid="134" src="https://it4it.club/uploads/monthly_2015_11/zh_17.jpg.7f5ea4843e3c45fdab8e4526b9410470.jpg"></p>

<p>
	Первое с чего стоит начать это изучить конструкцию механизма Ваших жалюзи. У меня дома внедрен и плотно эксплуатируется в спальне механизм с вертикальным расположением ламелей. Сам механизм прост как две копейки. Веревка с расположенными на ней пластиковыми шариками вращает вал, который производит поворот всех секций с ламелями. Ничего лишнего, устройство работает как часы.
</p>

<p>
	Второе, и самое главное (на чем я прокололся), это выбор привода для управления механизмом. Я правильно подумал, что для поворота всех секций необходимо довольно большой крутящий момент и дать его мне может сервопривод. Решено было взять серву <strong>MG995</strong> с металлическими шестернями, крутящим моментом 13 кг. на сантиметр и переделать её в сервопривод постоянного вращения.
</p>

<p>
	Сама процедура модернизация "мускул" проекта очень проста.
</p>

<ol><li>
		Аккуратно разбираем привод (внутри много смазки) и запоминаем его устройство.
	</li>
	<li>
		На основной шестерни расположен ограничитель хода (простой цилиндр из другого метала, отличается цветом от шестерней), удаляем его (без усилия вытягивается плоскогубцами).
	</li>
	<li>
		Вынимаем всю электронику и запоминаем расположения контактов переменного резистора необходимого для позиционирования устройства.
	</li>
	<li>
		Удаляем переменный резистор и заменяем его двумя обычными и равными половине номинала удаленного <s>органа</s> (в моем случае это два резистора по 2.5 кОм). Полагаю, что можно воспользоваться любыми резисторами одинакового номинала до 10 кОм. Но это стоит перепроверить!
	</li>
	<li>
		Собираем все обратно.
	</li>
</ol><p>
	К сожалению, у меня не сохранились фотографии всего процесса извращения над сервоприводом. Запечатленным остался лишь момент замены не нужного переменка на делитель из постоянных резисторов.
</p>

<p style="text-align:center;">
	<img alt="zh_1.jpg.a8fcf84d807d100728736702be98531" class="ipsImage ipsImage_thumbnailed" data-fileid="117" src="https://it4it.club/uploads/monthly_2015_11/zh_1.jpg.a8fcf84d807d100728736702be98531f.jpg"></p>

<p>
	Далее идет примерка сервы к поворотному шкиву Жалюзи и соответственно попытки приколхозить привод к нему. Ничего сложного в этой операции нет. Можно использовать один из рычагов идущих в комплекте с сервоприводом. Но я решил заменить подходящий пластиковый рычаг, на железный, купленный отдельно. 
</p>

<p>
	Пара минут манипуляций и союз между шкивом и рычагом (хотя второй тоже выглядит как шкив, тфу... масло масляное...) заключен.
</p>

<div class="ipsSpoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			 
		</p>

		<p style="text-align:center;">
			<img alt="zh_2.jpg.ca1a35ac686ce25c7f02e91815c8a54" class="ipsImage ipsImage_thumbnailed" data-fileid="118" src="https://it4it.club/uploads/monthly_2015_11/zh_2.jpg.ca1a35ac686ce25c7f02e91815c8a542.jpg"></p>

		<p style="text-align:center;">
			<img alt="zh_3.jpg.6a0feb163bc798b7ddea043c5f5fd53" class="ipsImage ipsImage_thumbnailed" data-fileid="119" src="https://it4it.club/uploads/monthly_2015_11/zh_3.jpg.6a0feb163bc798b7ddea043c5f5fd533.jpg"></p>

		<p style="text-align:center;">
			<img alt="zh_4.jpg.300fb1160e84b5d8e72651701e3cabd" class="ipsImage ipsImage_thumbnailed" data-fileid="120" src="https://it4it.club/uploads/monthly_2015_11/zh_4.jpg.300fb1160e84b5d8e72651701e3cabd0.jpg"></p>

		<p>
			 
		</p>
	</div>
</div>

<p>
	Позже, было принято решение перевернуть крепежные болты дабы сохранить возможность установки фиксирующей крышки от Жалюзи.
</p>

<p>
	На самом деле позже было принято очень много решений. После теста возможностей сервопривода был выявлен один крошечный недостаток, но он убивал на корню всю возможность автоматизации. Это был дребезг (другого слова я подобрать не могу) который заставлял привод совершать еле заметные и слышимые дерганья в произвольном направлении, но иногда постоянно в одном, что могло привести к натяжению поворотного вала Жалюзи в одном из крайних положений.
</p>

<p>
	Причина крылась в неидеальности нашего мира. Создать идеальный резистор не подверженный окружающей среде способна только задача из учебника по физике. А в результате, как только в комнате изменялась температура, даже на короткий миг, один из резисторов менял свои свойства. Вот тут и проявлялись те самые 1%, 5%, 10% погрешностей которые обещал производитель. Мириться с этим я не мог!
</p>

<p>
	Решений было два:
</p>

<ol><li>
		Разобраться в устройстве мозгов сервопривода и заложить эту погрешность в программу микроконтроллера сервы.
	</li>
	<li>
		Купить заводскую серву постоянного вращения.
	</li>
</ol><p>
	И как Вы угадали, я сделал единственно верный выбор! Заказал новую серву и ею стало произведения Китайского искуства - модель DS04-NFC. Пластиковые шестерни, крутящий момент 5,5 кг. на сантиметр. Взяв её в руки, и сравнив с предшественницей, я отчетливо испытал чувство со столь красивым названием Жалюзи! Да это была Ревность! Как можно променять <strong>MG995</strong> на <strong>DS04-NFC</strong>, <s>каааакккк! Каарррлл скажииии, каааааккк</s>!
</p>

<p>
	Ладно, боль стихла, выбор сделан. Необходимо проверить её в деле. И забегая вперед, я обязан сказать, что новая серва была подвержена той же болезни, что и переделанная <strong>MG995</strong>. Фокус не удался, но исправить проблему получилось программно в самом скетче!
</p>

<p style="text-align:center;">
	 
</p>

<div class="ipsSpoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			 
		</p>

		<p style="text-align:center;">
			<a class="ipsAttachLink ipsAttachLink_image" href="https://it4it.club/uploads/monthly_2015_11/zh_5.jpg.6638cace0191eac918ddbb2329c6075f.jpg"><img alt="zh_5.thumb.jpg.c8d71e5e595293debd40961c2" class="ipsImage ipsImage_thumbnailed" data-fileid="121" src="https://it4it.club/uploads/monthly_2015_11/zh_5.thumb.jpg.c8d71e5e595293debd40961c2654f516.jpg"></a><a class="ipsAttachLink ipsAttachLink_image" href="https://it4it.club/uploads/monthly_2015_11/zh_6.jpg.e4dc32dc5e5cd7fdebabf22f7157ff40.jpg"><img alt="zh_6.thumb.jpg.e7f2828416ea66b1a6206b472" class="ipsImage ipsImage_thumbnailed" data-fileid="123" src="https://it4it.club/uploads/monthly_2015_11/zh_6.thumb.jpg.e7f2828416ea66b1a6206b472a9c6509.jpg"></a>
		</p>

		<p style="text-align:center;">
			<img alt="zh_7.jpg.8189388ee6c31cd42b2e5dcde5aec1a" class="ipsImage ipsImage_thumbnailed" data-fileid="122" src="https://it4it.club/uploads/monthly_2015_11/zh_7.jpg.8189388ee6c31cd42b2e5dcde5aec1a6.jpg"></p>

		<p>
			 
		</p>
	</div>
</div>

<p>
	Тут стоит сделать небольшой отступ и для Новичков вроде меня дать пояснение. Питать сервопривод от самого контроллера невозможно т.к привод высасывает все соки из питающей линии. Контроллер начнет задыхаться и уйдет в ребут. 
</p>

<p>
	Для исправления данного недостатка я посадил параллельно нестабилизированного входа Arduino преобразователь AMS-1117-5.0 (Китайский клон LM-1117-5.0). Таким образом, я могу подавать питание (рекомендую 7-9V) на вход платы c контроллером и иметь раздельное стабилизированное питание, как самого контроллера, так и сервопривода. Фокус удался...
</p>

<p>
	Думаю, что схему параллельного соединения приводить нет смысла. Добавлю лишь обвязку преобразователя (два танталовых конденсатора по 10mF).
</p>

<p style="text-align:center;">
	<img alt="zh_8.jpg.5dd0dc619df32029a768bdadf45cf09" class="ipsImage ipsImage_thumbnailed" data-fileid="124" src="https://it4it.club/uploads/monthly_2015_11/zh_8.jpg.5dd0dc619df32029a768bdadf45cf094.jpg"></p>

<p>
	Для первого раза было решено использовать управление от старого пульта TV-тюнера. Ну, раз пошла такая пляска, то в довесок выдернуть из TV-тюнера IR приемник и гнездо для него. Если быть честным, то я не собирался потрошить тюнер, но один из моих Китайских поставщиков  электроники решил меня <s>обмануть</s> кинуть (скажу по секрету, это был не его день!).
</p>

<p>
	Пару тройку минут с паяльником и в руках красуется изделие способное произвести неимоверное впечатление на средневекового человека, но не на нас. Выглядит этот колхоз следующим образом.
</p>

<div class="ipsSpoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			 
		</p>

		<p style="text-align:center;">
			<img alt="zh_9.jpg.5cce44fd1ad5bc811af27ca570597c7" class="ipsImage ipsImage_thumbnailed" data-fileid="125" src="https://it4it.club/uploads/monthly_2015_11/zh_9.jpg.5cce44fd1ad5bc811af27ca570597c71.jpg"></p>

		<p style="text-align:center;">
			<img alt="zh_10.jpg.0f14205d09f7e9e174705b60679741" class="ipsImage ipsImage_thumbnailed" data-fileid="126" src="https://it4it.club/uploads/monthly_2015_11/zh_10.jpg.0f14205d09f7e9e174705b60679741bb.jpg"></p>

		<p style="text-align:center;">
			<img alt="zh_11.jpg.f41c4bc41e14f71fa94e42394225d2" class="ipsImage ipsImage_thumbnailed" data-fileid="127" src="https://it4it.club/uploads/monthly_2015_11/zh_11.jpg.f41c4bc41e14f71fa94e42394225d288.jpg"> 
		</p>

		<p>
			 
		</p>
	</div>
</div>

<p>
	Согласен, не очень красиво но, что я могу поделать. Исправлю в следующей версии.
</p>

<p>
	<strong>Переходим к программной части</strong>
</p>

<p>
	По началу стоит определиться с командами, на которые будет реагировать контроллер. Это зависит только от используемого Вами пульта дистанционного управления. За основу я взял библиотеку <a class="ipsAttachLink" href="//it4it.club/applications/core/interface/file/attachment.php?id=128">Arduino-IRremote-master.zip</a> В комплекте куча примеров чтобы научиться с ней дружить.
</p>

<p>
	Ну а итоговый скетч будет выглядеть следующим образом
</p>

<pre class="ipsCode prettyprint">
#include &lt;IRremote.h&gt;
#include &lt;Servo.h&gt; 

byte PIN_IR     = 8;
byte PIN_SERVO  = 9;

IRrecv irrecv(PIN_IR);
decode_results ir;

Servo myservo;

unsigned long timer = 0;

unsigned long lSpeed = 0;
unsigned long rSpeed = 0;

byte Speed;
int  fullSpeedTime = 3000;  // Время в миллисекундах, за которое серва выходит на полную скорость

void setup()
{
  Serial.begin(9600); 
  irrecv.enableIRIn();
}

void loop() {
  if (irrecv.decode(&amp;ir)) {   
    //Serial.println(ir.value);
    
    // Поворот направо
    if(ir.value == 117192113) {
      timer = millis();

      if(rSpeed == 0) rSpeed = millis();
      Speed = map(millis()-rSpeed&lt;fullSpeedTime?millis()-rSpeed:fullSpeedTime, 0, fullSpeedTime, 100, 180);
      Serial.println("Servo turns to the right. Speed " + String(Speed));
      
      myservo.attach(PIN_SERVO);
      myservo.write(Speed);
    }
    // Поворот налево
    else if(ir.value == 1819890863) {
      timer = millis();

      if(lSpeed == 0) lSpeed = millis();
      Speed = map(millis()-lSpeed&lt;fullSpeedTime?millis()-lSpeed:fullSpeedTime, 0, fullSpeedTime, 100, 0);
      Serial.println("Servo turns to the left. Speed " + String(Speed));
      
      myservo.attach(PIN_SERVO);
      myservo.write(Speed);
    }

    irrecv.resume();
  }
  else {
    // Обнуляем все задействованные таймеры и отключаем серву
    if(timer != 0 and millis() - timer &gt; 200) {
      rSpeed = lSpeed = timer = 0;
      myservo.detach(); // &lt;- Именно этот костыль заставляет серву молчать
      Serial.println(F("Servo stop\n"));
    }
  }
}</pre>

<p>
	В программе используется плавный разгон сервопривода до максимальных скоростей. За это отвечает переменная <strong>fullSpeedTime</strong>, принимающая значения в миллисекундах. Думаю, что трех секунд достаточно, чтобы плавно регулировать разгон и тем самым позволить, в случае необходимости, управлять поворотом ламелей на очень малый угол, используя кратковременные нажатия на кнопку пульта дистанционного управления.
</p>

<p>
	Углы поворота влияют на скорость:
</p>

<ol><li>
		от 0 до 100
	</li>
	<li>
		от 100 до 180
	</li>
</ol><p>
	Это те значения, что получились у меня на двух сервах, и которые я использовал в скетче.
</p>

<p>
	Чтобы заставить сервопривод не дергаться во время простоя я произвожу его отключение с использованием метода
</p>

<pre class="ipsCode prettyprint prettyprinted">
<span>myservo</span><span>.</span><span>detach</span><span>();</span></pre>

<p>
	Все прекрасно отработало. Серва крутит, а в простоях молчит и даже не думает дернуться.
</p>

<p>
	Привожу еще немного снимков всей получившейся конструкции
</p>

<div class="ipsSpoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			<img alt="zh_12.jpg.01382d1ebab231cf53ef5d1d2c44d3" class="ipsImage ipsImage_thumbnailed" data-fileid="129" src="https://it4it.club/uploads/monthly_2015_11/zh_12.jpg.01382d1ebab231cf53ef5d1d2c44d35f.jpg"><img alt="zh_13.jpg.530ad14f8ef2b21132959cf5a90ec3" class="ipsImage ipsImage_thumbnailed" data-fileid="130" src="https://it4it.club/uploads/monthly_2015_11/zh_13.jpg.530ad14f8ef2b21132959cf5a90ec30e.jpg"><img alt="zh_14.jpg.903b59243274dad36df3cfbfed628b" class="ipsImage ipsImage_thumbnailed" data-fileid="131" src="https://it4it.club/uploads/monthly_2015_11/zh_14.jpg.903b59243274dad36df3cfbfed628b68.jpg"><img alt="zh_15.jpg.1a069862217d291cbc04f8cfc9ef0b" class="ipsImage ipsImage_thumbnailed" data-fileid="132" src="https://it4it.club/uploads/monthly_2015_11/zh_15.jpg.1a069862217d291cbc04f8cfc9ef0bfb.jpg"><a class="ipsAttachLink ipsAttachLink_image" href="https://it4it.club/uploads/monthly_2015_11/zh_16.jpg.f0f8c791ceaf167505609de951c49f70.jpg"><img alt="zh_16.thumb.jpg.51da77fc4abecde7973fcc7a" class="ipsImage ipsImage_thumbnailed" data-fileid="133" src="https://it4it.club/uploads/monthly_2015_11/zh_16.thumb.jpg.51da77fc4abecde7973fcc7ad529fb61.jpg"></a>
		</p>
	</div>
</div>

<p>
	<span style="color:#FF0000;"><strong>Самый главный вывод - стоит подобрать очень тихий привод</strong></span>. <span style="color:#FF0000;"><strong>Серва жутко шумит, и если днем это терпимо, то вечером или ночью... это будет ужасно.</strong></span>
</p>

<p>
	<strong>PS:</strong> В общем первая версия была проверена и зарекомендовала себя хорошо, правда выглядит ужасно. Планирую добавить пару датчиков освещенности и автоматически менять угол поворота ламелей в зависимости от освещенности в течении дня. И заменить серву на тихий шаговый двигатель c редуктором.
</p>
]]></description><guid isPermaLink="false">22</guid><pubDate>Mon, 09 Nov 2015 21:33:29 +0000</pubDate></item><item><title>&#x410;&#x432;&#x442;&#x43E;&#x440;&#x438;&#x437;&#x430;&#x446;&#x438;&#x44F; &#x43D;&#x430; Web &#x441;&#x435;&#x440;&#x432;&#x435;&#x440;&#x435; &#x43C;&#x438;&#x43A;&#x440;&#x43E;&#x43A;&#x43E;&#x43D;&#x442;&#x440;&#x43E;&#x43B;&#x43B;&#x435;&#x440;&#x430;</title><link>https://it4it.club/topic/13-%D0%B0%D0%B2%D1%82%D0%BE%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F-%D0%BD%D0%B0-web-%D1%81%D0%B5%D1%80%D0%B2%D0%B5%D1%80%D0%B5-%D0%BC%D0%B8%D0%BA%D1%80%D0%BE%D0%BA%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D0%BB%D0%B5%D1%80%D0%B0/</link><description><![CDATA[
<p>Управление микроконтроллером <strong>Arduino</strong> через <strong>Ethernet</strong> получает все большую популярность. Я сам активно использую микроконтроллеры в сети для сбора различной информации на удаленных объектах. И в один прекрасный день натолкнулся на мысль, что изменять настройки моих поделок можно только перезаписывая микропрограмму, что не совсем удобно. Намного приятнее производить конфигурацию и менять поведение контроллера через Web интерфейс. Но последовала мысль, что любой может набрать в браузере адрес моей железки и оказаться там, где его не ждут, со всеми вытекающими последствиями! Нужно сделать хотя бы картонную дверь.</p><p><a class="ipsAttachLink ipsAttachLink_image" href="https://it4it.club/uploads/monthly_2015_08/DSC_0328.jpg.a1309832855977f06f34ef4678720754.jpg"><img data-fileid="39" class="ipsImage ipsImage_thumbnailed" alt="DSC_0328.thumb.jpg.88049c3a98a4fe772b689" src="https://it4it.club/uploads/monthly_2015_08/DSC_0328.thumb.jpg.88049c3a98a4fe772b689b9bfd815e3d.jpg"></a><a class="ipsAttachLink ipsAttachLink_image" href="https://it4it.club/uploads/monthly_2015_08/DSC_0331.jpg.7635fb08d5dbb035a23bf98afdc472a4.jpg"><img data-fileid="40" class="ipsImage ipsImage_thumbnailed" alt="DSC_0331.thumb.jpg.7136e9efea18a8646db13" src="https://it4it.club/uploads/monthly_2015_08/DSC_0331.thumb.jpg.7136e9efea18a8646db13c4b13bbb4b0.jpg"></a></p><p>Идея есть, приступаем к реализации. </p><p>Т.к работа с моими игрушками происходит через Web браузер, то логично воспользоваться стандартными средствами авторизации заложенными в большинство браузеров. Забегая вперед скажу, что у меня все заработало в браузерах: <span style="line-height:22.3999996185303px;">chrome, </span>firefox и opera. Через ишака не завелось, но он живет своей жизнью и меня не интересует (даже разбираться не стал). В остальных не проверял, но думаю, что все будет работать.</p><p><strong>Механизм выглядит следующим образом</strong></p><p>При запросе страницы, браузер (например Opera) отправляет множество различной информации на Web сервер. </p><pre class="ipsCode prettyprint">GET / HTTP/1.1
User-Agent: Opera/9.80 (Windows NT 6.1; U; ru) Presto/2.10.229 Version/11.60
Host: 10.10.10.2
Accept: text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/webp, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1
Accept-Language: ru-RU,ru;q=0.9,en;q=0.8
Accept-Encoding: gzip, deflate
Connection: keep-alive</pre><p>В свою очередь мы ожидаем во всем этом шлаке увидеть заголовок <span style="color:#008000;"><strong>Authorization: Basic <u>&lt;encoded-key&gt;</u></strong></span> и естественно его не видим. Делаем правильный вывод - клиент не авторизован. Отправляем пользователю заголовок который заставит его браузер отобразить форму авторизации.</p><pre class="ipsCode prettyprint">HTTP/1.0 401 Unauthorized
WWW-Authenticate: Basic realm="Arduino - iT4iT.CLUB"</pre><p><a class="ipsAttachLink ipsAttachLink_image" href="https://it4it.club/uploads/monthly_2015_08/arduino_web_auth.png.25ad2fb28205e699851cf51ee9a762f7.png"><img data-fileid="42" class="ipsImage ipsImage_thumbnailed" alt="arduino_web_auth.thumb.png.af90cb0fe91e3" src="https://it4it.club/uploads/monthly_2015_08/arduino_web_auth.thumb.png.af90cb0fe91e3daec85770e2297c0377.png"></a></p><p>После заполнения пользователем соответствующих форм и отправки данных на сервер, мы получаем тот же шлак, но в нем присутствует интересующий нас заголовок.</p><pre class="ipsCode prettyprint">GET / HTTP/1.1
User-Agent: Opera/9.80 (Windows NT 6.1; U; ru) Presto/2.10.229 Version/11.60
Host: 10.10.10.2
Accept: text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/webp, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1
Accept-Language: ru-RU,ru;q=0.9,en;q=0.8
Accept-Encoding: gzip, deflate
<strong>Authorization: Basic bG9naW46cGFzc3dvcmQ=</strong>
Connection: keep-alive</pre><p>При дальнейшем изучении вопроса, выясняется, что уникальный ключ <span style="color:#008000;"><strong>bG9naW46cGFzc3dvcmQ=</strong></span> является ничем иным как строкой закодированной в Base64. И при её преобразовании в читаемый вид получаем <span style="color:#008000;"><strong>login:password</strong></span>. Это и есть наши данные разделенные спец. символом "<strong>:</strong>".</p><p>Для работы с Base64, для Arduino имеется сторонняя библиотека с одноименным названием и забрать ей можно тут: <a rel="external nofollow" href="https://github.com/adamvr/arduino-base64">https://github.com/adamvr/arduino-base64</a></p><p>У меня в наличие имеются <strong>Ethernet</strong> модули на чипах <strong>W5100</strong> и <span style="line-height:22.3999996185303px;"><strong>ENC28J60</strong> для Arduino <strong>Uno</strong> и <strong>Nano</strong> соответственно. Они имеют серьезные отличия и требуют для работы различные библиотеки. К примеру <strong>W5100</strong> , в отличие от </span><strong style="line-height:22.3999996185303px;">ENC28J60</strong><span style="line-height:22.3999996185303px;">, имеет аппаратную поддержку </span><span style="color:#008000;"><strong>TCP/IP: TCP, UDP, IPv4, ICMP, ARP, IGMP, MAC</strong></span><span style="line-height:22.3999996185303px;">. Следовательно в </span><strong style="line-height:22.3999996185303px;">ENC28J60</strong><span style="line-height:22.3999996185303px;"> вся эта кухня должна быть реализована программно, что отразится на свободной памяти микроконтроллера.</span></p><p><strong>W5100</strong></p><p><a class="ipsAttachLink ipsAttachLink_image" href="https://it4it.club/uploads/monthly_2015_08/DSC_0332.jpg.1ee6f5836240d54b604a26355383b849.jpg"><img data-fileid="41" class="ipsImage ipsImage_thumbnailed" alt="DSC_0332.thumb.jpg.3760124f669f5a65753db" src="https://it4it.club/uploads/monthly_2015_08/DSC_0332.thumb.jpg.3760124f669f5a65753db913f2539118.jpg"></a></p><p>Для работы требуются библиотеки <span style="color:#008000;"><strong>Ethernet.h</strong></span> и <span style="color:#008000;"><strong>SPI.h</strong></span>. Поставляется совместно со средой разработки Arduino. Скетч для микроконтроллера будет выглядеть следующим образом:</p><blockquote class="ipsStyle_spoiler" data-ipsspoiler=""><pre class="ipsCode prettyprint">/*
  sign in (authentication) to the Web server Arduino
  (с) <a href="http://it4it.club" rel="external nofollow">http://it4it.club</a>
*/
#include &lt;SPI.h&gt;
#include &lt;Ethernet.h&gt; // Used for Ethernet
#include &lt;Base64.h&gt;
/*
  Настройки сети
*/
byte mac[] = { 0x54, 0x34, 0x41, 0x30, 0x30, 0x32 };
IPAddress ip(10, 10, 10, 11);                        

EthernetServer server(80);
/*
  Переменные для авторизации через web
*/
String readString;                // Буфер для данных от пользователя Web сервера
String auth_hash;                 // Тут храним полноценную строку авторизации, которую ожидаем от браузера в таком виде "Authorization: Basic bG9naW46cGFzc3dvcmQ="
char login[] = "login";           // Логин по дефолту. В дальнейшем необходимо измененные данные авторизации в Web морде хранить в EPROM
char password[] = "password";     // Пароль по умолчанию. -/-
/*
  SETUP
*/
void setup() {
  Serial.begin(9600);
  // Подготавливаем строку авторизации
  auth_hash = auth_update(login, password);
  // Поднимаем сеть  
  Ethernet.begin(mac, ip);
  server.begin();
  Serial.println(Ethernet.localIP());
}
/*
  LOOP
*/
void loop() {
  EthernetClient client = server.available();
  if (client) {  
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        readString += c;
        if (c == '\n' &amp;&amp; currentLineIsBlank) {
          if (readString.lastIndexOf(auth_hash)&gt;-1) {
            if (readString.lastIndexOf("GET /favicon.ico")&gt;-1) {
              client.println(F("HTTP/1.0 404 Not Found"));
            }
            else {
              client.println(F("HTTP/1.0 200 OK"));
              client.println(F("Content-Type: text/html"));
              client.println(F("Pragma: no-cache\r\nRefresh: 30\r\n"));
              client.println(F("&lt;html&gt;&lt;head&gt;&lt;meta charset=UTF-8\"&gt;&lt;title&gt;Arduino - iT4iT.CLUB&lt;/title&gt;"));
              client.println(F("&lt;style&gt;body,table,tr,td{font-style:normal;font-family:verdana;font-size:11px;}body{background-color:#FFEBD5;}&lt;/style&gt;&lt;/head&gt;&lt;body&gt;"));
              client.print(F("Arduino on &lt;a href=\"<a href="https://it4it.club" rel="external nofollow">https://it4it.club</a>\"&gt;iT4iT.CLUB&lt;/a&gt;"));
              client.println(F("&lt;/body&gt;&lt;/html&gt;"));
            }
          }
          else {
            client.println(F("HTTP/1.0 401 Unauthorized"));
            client.println(F("WWW-Authenticate: Basic realm=\"Arduino - iT4iT.CLUB\""));
          }
          break;
        }

        if (c == '\n') {
          currentLineIsBlank = true;
        }
        else if (c != '\r') {
          currentLineIsBlank = false;
        }
      } 
    }
    delay(30);

    readString = "";
    client.stop();
  }
}
/*
  Функция подготавливает строку авторизации с хэшем учетных данных, для сравнения её с данными в HEADER браузера которые мы получим
*/
String auth_update(char login[], char password[]) {
  // Строка для будущего хэша
  String hash = strcat(strcat(login, ":"),password);
  int buf_size = hash.length()+1;
  char buf_char[buf_size];
  // Переводим строку в char для дальнейшей обработки base64
  hash.toCharArray(buf_char, buf_size);
  char encoded[base64_enc_len(buf_size-1)];
  // Получаем хэш для авторизации
  base64_encode(encoded, buf_char, buf_size-1);
  // Формируем полную строку поиска "Authorization: Basic &lt;BASE64-HASH&gt;" чтобы не могли подсунуть хэш в GET или POST
  return "Authorization: Basic " + String(encoded);
}</pre><p> </p></blockquote><p><strong>ENC28J60</strong></p><p>Для данного чипа требуется сторонняя библиотека. Я выбрал <span style="color:#008000;"><strong>UIPEthernet.h</strong></span>, забрать можно тут: <a rel="external nofollow" href="https://github.com/ntruchsess/arduino_uip">https://github.com/ntruchsess/arduino_uip</a><span style="line-height:22.3999996185303px;"> </span></p><p>Для работы подойдет предыдущий скетч, необходимо лишь изменить подключаемые библиотеки:</p><pre class="ipsCode prettyprint">/*
  sign in (authentication) to the Web server Arduino
  (с) http://it4it.club
*/
#include &lt;UIPEthernet.h&gt; // Used for Ethernet
#include &lt;Base64.h&gt;</pre><p>На этом пока все, всем удачи с экспериментами!</p><p><strong>PS:</strong> Не забывайте изменить IP в скетче.</p>
]]></description><guid isPermaLink="false">13</guid><pubDate>Fri, 21 Aug 2015 11:05:59 +0000</pubDate></item><item><title>&#x41F;&#x435;&#x440;&#x435;&#x43F;&#x440;&#x43E;&#x448;&#x438;&#x432;&#x43A;&#x430; bootloader (&#x437;&#x430;&#x433;&#x440;&#x443;&#x437;&#x447;&#x438;&#x43A;&#x430;)</title><link>https://it4it.club/topic/19-pereproshivka-bootloader-zagruzchika/</link><description><![CDATA[
<p>
	<strong>Update 02.12.2015</strong>
</p>

<ul>
<li>
		Статья переработана и перепроверена
	</li>
	<li>
		Актуально для <strong>Optiboot 6.2</strong> и <strong>Arduino IDE 1.6.6</strong> или выше.
	</li>
</ul>
<p>
	Рано или поздно приходится столкнуться с необходимостью замены <strong>bootloader</strong> (загрузчика) микроконтроллера. В моём случае остро потребовался функционал загрузчика <a href="https://github.com/Optiboot/optiboot" rel="external nofollow">Optiboot</a>, из-за реализованного в нем сторожевого таймера (<strong>watchdog</strong>). Плюс ко всему, он весит в четыре раза меньше стандартного и освобождает дополнительно <strong>1.5kb</strong> памяти для скетча!
</p>

<p>
	Сразу хочу отметить, что <strong>Optiboot</strong> залит по умолчанию на <strong>Arduino UNO</strong> и <span style="color:rgb(67,67,67);font-family:Tahoma, 'Helvetica Neue', Arial, Helvetica, sans-serif;line-height:22.4px;"><strong>Mega 2560</strong>.</span>
</p>

<p>
	У меня в наличии имелись: <strong>Arduino Nano</strong> и <strong>Arduino Pro Mini</strong> на чипах <strong>ATmega328P-AU</strong>, и просто пачка "голых" <strong>ATmega328P-PU</strong>. Есть несколько простых способов перезаписать загрузчик которыми я воспользовался (это далеко не все возможные варианты).
</p>

<p>
	<span style="color:#008000;"><span style="font-size:18px;"><strong>Использование программатора USBasp</strong></span></span>
</p>

<p>
	Как по мне, это самый простой способ не требующий никакой магии. Сам программатор можно приобрести у братьев Китайцев за $2. Он представляет из себя плату с ATmega8 или ATmega128, USB на входе и 10Pin ICSP интерфейс на выходе. От стандартного 6Pin интерфейса он отличается лишь тремя дополнительными пинами GND и одним не использующимся NC. Чтобы упростить себе жизнь, советую сразу брать переходник с <strong>USBasp 10pin to 6pin</strong> за $0.5
</p>

<p>
	<em>Выглядит это следующим образом</em>
</p>

<p>
	<a class="ipsAttachLink ipsAttachLink_image" href="https://it4it.club/uploads/monthly_2015_10/USBasp_1.jpg.08e0082ca75c57f3c7ba922e03d96131.jpg" data-fileid="80" rel="external"><img alt="USBasp_1.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="80" data-unique="kf8tqbh2c" src="https://it4it.club/uploads/monthly_2015_10/USBasp_1.thumb.jpg.8d0c1a12529220afea0d84bcf76c0b6f.jpg"></a>
</p>

<p>
	<a class="ipsAttachLink ipsAttachLink_image" href="https://it4it.club/uploads/monthly_2015_10/USBasp_2.jpg.82a7a947ad28b71bc35e3a1803b5c550.jpg" data-fileid="81" rel="external"><img alt="USBasp_2.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="81" data-unique="l5l7nf9w8" src="https://it4it.club/uploads/monthly_2015_10/USBasp_2.thumb.jpg.bf9ed94fec6fb570aada4022a1d620db.jpg"></a>
</p>

<p>
	<em>Сама распиновка программатора и разъемов (позаимствована у братьев наших)</em>
</p>

<p>
	<a class="ipsAttachLink ipsAttachLink_image" href="https://it4it.club/uploads/monthly_2015_10/USBasp_PinoutVisual.jpg.63e32fd24f0b4aad7b1998a17220ce7b.jpg" data-fileid="82" rel="external"><img alt="USBasp_PinoutVisual.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="82" src="https://it4it.club/uploads/monthly_2015_10/USBasp_PinoutVisual.thumb.jpg.6c12ea0c22fdd2aedd77c2705c531706.jpg"></a>
</p>

<p>
	Если на плате Arduino распаян <strong>6pin</strong> разъем <strong>ICSP</strong>, то подключение до безобразия простое. Совмещаем одноименные контакты программатора с платой Arduino. Если готового разъема нет, то используем соответствующие ноги на плате Arduino или на самом микроконтроллере.
</p>

<p>
	Необходимые ноги:
</p>

<ol>
<li>
		<em>GND</em>
	</li>
	<li>
		<em>VCC</em>
	</li>
	<li>
		<em>MOSI</em>
	</li>
	<li>
		<em>MISO</em>
	</li>
	<li>
		<em>RST</em>
	</li>
</ol>
<p>
	Распиновка некоторых плат Arduino и микроконтроллеров находится в <a href="https://it4it.club/topic/18-%D1%80%D0%B0%D1%81%D0%BF%D0%B8%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0-%D0%BC%D0%B8%D0%BA%D1%80%D0%BE%D0%BA%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D0%BB%D0%B5%D1%80%D0%BE%D0%B2-%D0%B8-%D0%BF%D0%BB%D0%B0%D1%82-%D0%BD%D0%B0-%D0%B8%D1%85-%D0%BE%D1%81%D0%BD%D0%BE%D0%B2%D0%B5/" rel="">соседней теме</a>
</p>

<div class="ipsSpoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			<a class="ipsAttachLink ipsAttachLink_image" href="https://it4it.club/uploads/monthly_2015_10/USBasp_3.jpg.79a4432d4511afabbfae28b58c0f72c7.jpg" data-fileid="83" rel="external"><img alt="USBasp_3.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="83" src="https://it4it.club/uploads/monthly_2015_10/USBasp_3.thumb.jpg.5390bff3b514b1ec9ab4b297f45cf6a1.jpg"></a><a class="ipsAttachLink ipsAttachLink_image" href="https://it4it.club/uploads/monthly_2015_10/USBasp_4.jpg.dc3b605a7841c8896aefb5cad9f637ef.jpg" data-fileid="84" rel="external"><img alt="USBasp_4.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="84" src="https://it4it.club/uploads/monthly_2015_10/USBasp_4.thumb.jpg.333e2a7209d3824219742281e4014ef8.jpg"></a>
		</p>
	</div>
</div>

<p>
	Пример подключения <strong>USBasp</strong> к <strong>Arduino Pro Mini</strong> и к <strong>ATmega328P-PU</strong>. В случае с последним, конденсаторы можно выкинуть из схемы.
</p>

<div class="ipsSpoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			<a class="ipsAttachLink ipsAttachLink_image" href="https://it4it.club/uploads/monthly_2015_10/USBasp_pro_mini.png.3a262179967a6e8b7ad3367e11325537.png" data-fileid="85" rel="external"><img alt="USBasp_pro_mini.png" class="ipsImage ipsImage_thumbnailed" data-fileid="85" data-unique="2rcyx30bb" src="https://it4it.club/uploads/monthly_2015_10/USBasp_pro_mini.thumb.png.3f38eb346b40cb97f905c5711db148d2.png"></a>
		</p>

		<p>
			<a class="ipsAttachLink ipsAttachLink_image" href="https://it4it.club/uploads/monthly_2015_10/USBasp_atmega328p-pu.png.76e8752aff21601a1fdadd8d69688f9e.png" data-fileid="86" rel="external"><img alt="USBasp_atmega328p-pu.png" class="ipsImage ipsImage_thumbnailed" data-fileid="86" data-unique="be5nnqmrf" src="https://it4it.club/uploads/monthly_2015_10/USBasp_atmega328p-pu.thumb.png.304cf86e3aae53d94acb328fb2b59556.png"></a>
		</p>
	</div>
</div>

<div class="ipsSpoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			<a class="ipsAttachLink ipsAttachLink_image" href="https://it4it.club/uploads/monthly_2015_10/USBasp_6.jpg.27ff9490fafccea59eb9c057b86ee1f7.jpg" data-fileid="88" rel="external"><img alt="USBasp_6.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="88" data-unique="xcepr03un" src="https://it4it.club/uploads/monthly_2015_10/USBasp_6.thumb.jpg.38a994b57f77ae2c0c870ddafc32af2a.jpg"></a><a class="ipsAttachLink ipsAttachLink_image" href="https://it4it.club/uploads/monthly_2015_10/USBasp_5.jpg.9b84534d6e4da141b21b7f6b9cb0eaf6.jpg" data-fileid="87" rel="external"><img alt="USBasp_5.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="87" data-unique="yyeeupqol" src="https://it4it.club/uploads/monthly_2015_10/USBasp_5.thumb.jpg.26cf87397533ca8dd73bf01bb939e310.jpg"></a>
		</p>
	</div>
</div>

<p>
	Теперь самое интересное
</p>

<ol>
<li>
		Переходим на <strong>GitHub</strong> проекта <strong>Optiboot</strong> (ссылка имеется в начале поста) и скачиваем архив со всем необходимым.
	</li>
	<li>
		Переходим в каталог где хранятся созданные вами скетчи (в Windows это "<strong>\Мои документы\Arduino\</strong>") и создаем в нем ветку каталогов <span style="color:#008000;"><strong>\hardware\optiboot\avr\</strong></span>
	</li>
	<li>
		В скачанном архиве находим каталог <strong>optiboot</strong> и переносим все его содержимое в каталог созданный в предыдущем пункте.
	</li>
	<li>
		Среди всех перенесенных файлов находим <span style="color:#008000;"><strong>boards.txt</strong></span> удаляем его. <span style="color:#FF0000;">Он является устаревшим и более нас не интересует!</span>
	</li>
	<li>
		Находим файл <span style="color:#008000;"><strong>boards-1.6.txt</strong></span> и переименовываем в <span style="color:#008000;"><strong>boards.txt</strong></span>, в итоге должно получится как на изображении ниже
		<div class="ipsSpoiler" data-ipsspoiler="">
			<div class="ipsSpoiler_header">
				<span>Скрытый текст</span>
			</div>

			<div class="ipsSpoiler_contents">
				<p>
					<img alt="Arduino_optiboot_1.png" class="ipsImage ipsImage_thumbnailed" data-fileid="170" data-unique="e1ja01o7q" src="https://it4it.club/uploads/monthly_2015_12/Arduino_optiboot_1.png.5a3bdbee15e8e102b32f687560e5844a.png"></p>
			</div>
		</div>

		<p>
			 
		</p>
	</li>
	<li>
		Перезапускаем срезу <strong>Arduino IDE</strong>
	</li>
	<li>
		Проверяем список плат во вкладке "Инструменты" и наслаждаемся результатом
	</li>
</ol>
<div class="ipsSpoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			<a class="ipsAttachLink ipsAttachLink_image" href="https://it4it.club/uploads/monthly_2015_12/optiboot_1.png.0db465f315383552d096c77efa3e67b6.png" data-fileid="171" rel="external"><img alt="optiboot_1.png" class="ipsImage ipsImage_thumbnailed" data-fileid="171" data-unique="3yy7e6alm" src="https://it4it.club/uploads/monthly_2015_12/optiboot_1.thumb.png.79cc31cde547460bb5af9f75c16a2d99.png"></a>
		</p>

		<p>
			<a class="ipsAttachLink ipsAttachLink_image" href="https://it4it.club/uploads/monthly_2015_12/optiboot_2.png.7cdc7ab4a3f2d1181d4612ed821161a4.png" data-fileid="172" rel="external"><img alt="optiboot_2.png" class="ipsImage ipsImage_thumbnailed" data-fileid="172" data-unique="pkecp5zq7" src="https://it4it.club/uploads/monthly_2015_12/optiboot_2.thumb.png.ef8407fb4b023bab45a59ad7a4ab657c.png"></a>
		</p>

		<p>
			<a class="ipsAttachLink ipsAttachLink_image" href="https://it4it.club/uploads/monthly_2015_12/optiboot_3.png.dc6d70bb76be258a2d7b28d8ab04fdd2.png" data-fileid="173" rel="external"><img alt="optiboot_3.png" class="ipsImage ipsImage_thumbnailed" data-fileid="173" data-unique="h71wvw9mu" src="https://it4it.club/uploads/monthly_2015_12/optiboot_3.thumb.png.62c612a4f5d1bf1fc1b7c35ad661ebdb.png"></a>
		</p>

		<p>
			 
		</p>
	</div>
</div>

<p>
	При хранении всех необходимых файлов вне среды разработки <strong>Arduino IDE</strong> последующее обновление самой среды не позволит Вам потерять настройки и файлы загрузчика <strong>Optiboot</strong> в отличие от прямого вмешательства в оригинальный <strong>boards.txt</strong>
</p>

<p>
	Ленивые могут забрать готовый архив со всеми изменениями и распаковать его содержимое в папку со скетчами. В данном случае все достаточно только перезапустить среду разработки. Сам архив прикреплен к посту.
</p>

<p>
	Выбираем программатор <strong>USBasp</strong>
</p>

<p>
	<a class="ipsAttachLink ipsAttachLink_image" href="https://it4it.club/uploads/monthly_2015_12/optiboot_4.png.471ccfbedbac9488719011ff6a566ec5.png" data-fileid="174" rel="external"><img alt="optiboot_4.png" class="ipsImage ipsImage_thumbnailed" data-fileid="174" data-unique="fbkr6ridy" src="https://it4it.club/uploads/monthly_2015_12/optiboot_4.thumb.png.377d611784860037e2bc4a702d0800ea.png"></a>
</p>

<p>
	И жмем "Записать загрузчик".
</p>

<p>
	<span style="color:#FF0000;"><strong>ВАЖНО:</strong></span> Если желаете залить скетч через <strong>USBasp</strong>, то необходимо нажимать "<strong>Записать\Вгрузить</strong>" при зажатой клавиши <strong>SHIFT</strong>. Только в этом случае будет выбран <u>программатор</u> для заливки, а соответствующая подсказка изменится за "<strong>Загрузить через программатор</strong>".
</p>

<p>
	<a class="ipsAttachLink ipsAttachLink_image" href="https://it4it.club/uploads/monthly_2015_10/Arduino_optiboot_4.png.1e2e584b94c1645b8670fee1a3d12894.png" data-fileid="91" rel="external"><img alt="Arduino_optiboot_4.png" class="ipsImage ipsImage_thumbnailed" data-fileid="91" data-unique="s09ftf3vx" src="https://it4it.club/uploads/monthly_2015_10/Arduino_optiboot_4.thumb.png.53904dfbaba9665af60ee0748942aa98.png"></a>
</p>

<p>
	В ходе данной операции могут сыпаться ошибки указывающие на проблемы с <strong>USBasp</strong>.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		Цитата
	</div>

	<div class="ipsQuote_contents">
		<p>
			avrdude: warning: cannot set sck period. please check for usbasp firmware update.
		</p>
	</div>
</blockquote>

<p>
	Попросту игнорируем их!
</p>

<p>
	<span style="color:#008000;"><span style="font-size:18px;"><strong>Использование Arduino в качестве программатора</strong></span></span>
</p>

<p>
	Нам понадобится вторая плата Arduino. Прошиваем её скетчем <strong>ArduinoISP</strong>, идущим по умолчанию со средой разработки. После этого Arduino становится полноценным программатором.
</p>

<pre class="ipsCode prettyprint prettyprinted">
<span>// pin name:    not-mega:         mega(1280 and 2560)</span><span>
</span><span>// slave reset: 10:               53</span><span>
</span><span>// MOSI:        11:               51</span><span>
</span><span>// MISO:        12:               50</span><span>
</span><span>// SCK:         13:               52</span></pre>

<p>
	В скетче имеется подсказка с способом подключения.
</p>

<div class="ipsSpoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			<a class="ipsAttachLink ipsAttachLink_image" href="https://it4it.club/uploads/monthly_2015_10/Arduino_isp_1.png.29e3f3a8cdf25e440a07a42a2f256a53.png" data-fileid="92" rel="external"><img alt="Arduino_isp_1.png" class="ipsImage ipsImage_thumbnailed" data-fileid="92" data-unique="mpzy21pbm" src="https://it4it.club/uploads/monthly_2015_10/Arduino_isp_1.thumb.png.dce98f2285e51eb409e08022e7886e40.png"></a>
		</p>
	</div>
</div>

<div class="ipsSpoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			<a class="ipsAttachLink ipsAttachLink_image" href="https://it4it.club/uploads/monthly_2015_10/Arduino_isp_2.jpg.4f045946c7dc6c423da7f1be11c0aafb.jpg" data-fileid="93" rel="external"><img alt="Arduino_isp_2.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="93" data-unique="3fuuce0bq" src="https://it4it.club/uploads/monthly_2015_10/Arduino_isp_2.thumb.jpg.d077eb75dcaddf7bded701176ec8deb0.jpg"></a>
		</p>
	</div>
</div>

<p>
	Изменяем в Arduino IDE программатор на  <strong>Arduino as ISP</strong>, выбираем необходимую плату, к которой подключен наш вновь испеченный программатор и "прожигаем" загрузчик.
</p>

<p>
	<a class="ipsAttachLink ipsAttachLink_image" href="https://it4it.club/uploads/monthly_2015_10/Arduino_isp_3.png.c50f7691be16c764bab20f137df0ac4c.png" data-fileid="94" rel="external"><img alt="Arduino_isp_3.png" class="ipsImage ipsImage_thumbnailed" data-fileid="94" data-unique="83jgiqr2s" src="https://it4it.club/uploads/monthly_2015_10/Arduino_isp_3.thumb.png.52f6630a545baf1ad8082295b0223f17.png"></a>
</p>

<p>
	Если необходимо записать какой либо скетч, то делаем это также при зажатой клавиши <strong>SHIFT</strong> (как и в первом варианте).
</p>

<p>
	<strong>PS:</strong> По умолчанию в среде разработки имеются файлы загрузчика <strong>optiboot</strong> и скачивать ничего не нужно. Достаточно выбрать плату <strong>Arduino UNO</strong> и перезаписать загрузчик. Но в этом случае Ваше детище станет определяться именно как <strong>UNO</strong>, даже если на самом деле это <strong>NANO</strong>, <strong>Pro Mini</strong> или еще что-то.
</p>

<p>
	<a class="ipsAttachLink" href="https://it4it.club/applications/core/interface/file/attachment.php?id=175" data-fileid="175" rel="">hardware.zip</a>
</p>
]]></description><guid isPermaLink="false">19</guid><pubDate>Sun, 11 Oct 2015 20:05:34 +0000</pubDate></item><item><title>&#x420;&#x430;&#x441;&#x43F;&#x438;&#x43D;&#x43E;&#x432;&#x43A;&#x430; &#x43C;&#x438;&#x43A;&#x440;&#x43E;&#x43A;&#x43E;&#x43D;&#x442;&#x440;&#x43E;&#x43B;&#x43B;&#x435;&#x440;&#x43E;&#x432; &#x438; &#x43F;&#x43B;&#x430;&#x442; &#x43D;&#x430; &#x438;&#x445; &#x43E;&#x441;&#x43D;&#x43E;&#x432;&#x435;</title><link>https://it4it.club/topic/18-raspinovka-mikrokontrollerov-i-plat-na-ih-osnove/</link><description><![CDATA[
<p>
	Данный пост является шпаргалкой из собранных в сети различных материалов связанных с распиновкой (pinout) распространенных микроконтроллеров и плат на их основе.
</p>

<p>
	<span style="color:#008000;"><span style="font-size:18px;"><strong>Микроконтроллеры</strong></span></span>
</p>

<p>
	<strong>ATmega328p-pu</strong>
</p>

<blockquote class="ipsStyle_spoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			<a class="ipsAttachLink ipsAttachLink_image" href="https://it4it.club/uploads/monthly_2015_10/Atmega328P-PU.png.c60c88059fd605bec042e9cae025cc08.png"><img alt="Atmega328P-PU.thumb.png.1701da0396de316c" class="ipsImage ipsImage_thumbnailed" data-fileid="70" src="https://it4it.club/uploads/monthly_2015_10/Atmega328P-PU.thumb.png.1701da0396de316c8d5a3f034267dbf7.png"></a>
		</p>
	</div>
</blockquote>

<p>
	<strong><span style="line-height:22.4px;">ATmega328p-au</span></strong>
</p>

<blockquote class="ipsStyle_spoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			<a class="ipsAttachLink ipsAttachLink_image" href="https://it4it.club/uploads/monthly_2015_10/Atmega328P-AU.png.586d20b9b1c24ae595477930b3463353.png"><img alt="Atmega328P-AU.thumb.png.db7299316d0d61c1" class="ipsImage ipsImage_thumbnailed" data-fileid="71" src="https://it4it.club/uploads/monthly_2015_10/Atmega328P-AU.thumb.png.db7299316d0d61c1b34ebc4f1f3128a0.png"></a>
		</p>
	</div>
</blockquote>

<p>
	<strong>ATmega2560</strong>
</p>

<blockquote class="ipsStyle_spoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			<a class="ipsAttachLink ipsAttachLink_image" href="https://it4it.club/uploads/monthly_2015_10/ATMEGA2560U.png.0b1274424d5895a3dbbbc37c37e0cad1.png"><img alt="ATMEGA2560U.thumb.png.348d460cf61b1c2181" class="ipsImage ipsImage_thumbnailed" data-fileid="72" src="https://it4it.club/uploads/monthly_2015_10/ATMEGA2560U.thumb.png.348d460cf61b1c2181dfea6d869ebe57.png"></a>
		</p>
	</div>
</blockquote>

<p>
	<strong>ATmega32u4-au</strong>
</p>

<div class="ipsSpoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			<a class="ipsAttachLink ipsAttachLink_image" href="https://it4it.club/uploads/monthly_2016_01/atmega32u4-au.png.9684aece65bd61b3c68375d11a67173a.png"><img alt="atmega32u4-au.thumb.png.079db8ccff4b3877" class="ipsImage ipsImage_thumbnailed" data-fileid="184" data-unique="1fbf9k44p" src="https://it4it.club/uploads/monthly_2016_01/atmega32u4-au.thumb.png.079db8ccff4b38772293b47940d36455.png"></a>
		</p>
	</div>
</div>

<p>
	<strong>Attiny</strong>
</p>

<div class="ipsSpoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			<img class="ipsImage ipsImage_thumbnailed" data-fileid="188" data-unique="5hdzs8a6x" src="https://it4it.club/uploads/monthly_2016_01/attiny.png.1aab35cee53c1501804720212f72294b.png" alt="attiny.png.1aab35cee53c1501804720212f722"></p>
	</div>
</div>

<p>
	<span style="color:#008000;"><span style="font-size:18px;"><strong>Платы</strong></span></span>
</p>

<p>
	<strong>Arduino UNO</strong>
</p>

<blockquote class="ipsStyle_spoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			<a class="ipsAttachLink ipsAttachLink_image" href="https://it4it.club/uploads/monthly_2015_10/arduino_uno.jpg.461be96a61710639aaf7c1b1ca95faa4.jpg"><img alt="arduino_uno.thumb.jpg.ff036c92479856679c" class="ipsImage ipsImage_thumbnailed" data-fileid="73" src="https://it4it.club/uploads/monthly_2015_10/arduino_uno.thumb.jpg.ff036c92479856679c8397f616075180.jpg"></a>
		</p>
	</div>
</blockquote>

<p>
	<strong>Arduino NANO</strong>
</p>

<blockquote class="ipsStyle_spoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			<a class="ipsAttachLink ipsAttachLink_image" href="https://it4it.club/uploads/monthly_2015_10/arduono-nano.png.a3f5ec24c4b434f2b0a9e2e12ca1747a.png"><img alt="arduono-nano.thumb.png.60210eb9259fe6eaf" class="ipsImage ipsImage_thumbnailed" data-fileid="74" src="https://it4it.club/uploads/monthly_2015_10/arduono-nano.thumb.png.60210eb9259fe6eaf730d69f5905715b.png"></a>
		</p>
	</div>
</blockquote>

<p>
	<strong><span style="line-height:22.4px;">Arduino PRO-</span><span style="line-height:22.4px;">MINI</span></strong>
</p>

<blockquote class="ipsStyle_spoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			<span style="line-height:22.4px;"><a class="ipsAttachLink ipsAttachLink_image" href="https://it4it.club/uploads/monthly_2015_10/pro_mini.png.84ca40ca73a3c7cec5dda33728cf34f7.png"><img alt="pro_mini.thumb.png.f5ddc4081b0ab088412f3" class="ipsImage ipsImage_thumbnailed" data-fileid="75" src="https://it4it.club/uploads/monthly_2015_10/pro_mini.thumb.png.f5ddc4081b0ab088412f3d1d34f405aa.png"></a></span>
		</p>
	</div>
</blockquote>

<p>
	<strong>Arduino MICRO</strong>
</p>

<blockquote class="ipsStyle_spoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			<a class="ipsAttachLink ipsAttachLink_image" href="https://it4it.club/uploads/monthly_2015_10/arduino_micro.png.124b5917f17cb1468878d92048a30120.png"><img alt="arduino_micro.thumb.png.20eb4270b8971d50" class="ipsImage ipsImage_thumbnailed" data-fileid="76" src="https://it4it.club/uploads/monthly_2015_10/arduino_micro.thumb.png.20eb4270b8971d50f105d0d452aad7d9.png"></a>
		</p>
	</div>
</blockquote>

<p>
	<strong>Arduino MEGA</strong>
</p>

<blockquote class="ipsStyle_spoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			<a class="ipsAttachLink ipsAttachLink_image" href="https://it4it.club/uploads/monthly_2015_10/arduino_mega.png.b4b0dd657aea018ab8c654f2904d5026.png"><img alt="arduino_mega.thumb.png.b3efe3fb39fb4f531" class="ipsImage ipsImage_thumbnailed" data-fileid="77" src="https://it4it.club/uploads/monthly_2015_10/arduino_mega.thumb.png.b3efe3fb39fb4f53137584b22e904efe.png"></a>
		</p>
	</div>
</blockquote>

<p>
	<strong>Arduino LEONARDO</strong>
</p>

<blockquote class="ipsStyle_spoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			<a class="ipsAttachLink ipsAttachLink_image" href="https://it4it.club/uploads/monthly_2015_10/arduino_leonardo.png.096b1e0d4496ce72028439085c5d751d.png"><img alt="arduino_leonardo.thumb.png.16302e7fe7b72" class="ipsImage ipsImage_thumbnailed" data-fileid="79" src="https://it4it.club/uploads/monthly_2015_10/arduino_leonardo.thumb.png.16302e7fe7b726f83111e0c679cea1de.png"></a> 
		</p>
	</div>
</blockquote>

<p>
	<strong>Arduino Yun</strong>
</p>

<div class="ipsSpoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			<img alt="Arduino-Yun.png.3f9ce62fcdeb0db2ecd9dea5" class="ipsImage ipsImage_thumbnailed" data-fileid="185" data-unique="iilfzs50e" src="https://it4it.club/uploads/monthly_2016_01/Arduino-Yun.png.3f9ce62fcdeb0db2ecd9dea5d39cc471.png"></p>
	</div>
</div>

<p>
	<strong>Arduino Esplora</strong>
</p>

<div class="ipsSpoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			<a class="ipsAttachLink ipsAttachLink_image" href="https://it4it.club/uploads/monthly_2016_01/arduino-esplora.png.c40f4c12b3ee92fbfd5f06fbb359cb9f.png"><img alt="arduino-esplora.thumb.png.e719a3cccd0e06" class="ipsImage ipsImage_thumbnailed" data-fileid="186" data-unique="zai50mpj7" src="https://it4it.club/uploads/monthly_2016_01/arduino-esplora.thumb.png.e719a3cccd0e06a3cbc5426c7cc68b06.png"></a>
		</p>
	</div>
</div>

<p>
	<strong>Arduino Fio</strong>
</p>

<div class="ipsSpoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			<a class="ipsAttachLink ipsAttachLink_image" href="https://it4it.club/uploads/monthly_2016_01/arduino-fio.png.66d08f4a872799da0c3961f01bafdf6a.png"><img alt="arduino-fio.thumb.png.f97c06db6113012eb0" class="ipsImage ipsImage_thumbnailed" data-fileid="187" data-unique="p6480dt6s" src="https://it4it.club/uploads/monthly_2016_01/arduino-fio.thumb.png.f97c06db6113012eb0c77413aa79f62d.png"></a>
		</p>
	</div>
</div>

<p>
	 
</p>
]]></description><guid isPermaLink="false">18</guid><pubDate>Sat, 10 Oct 2015 09:01:08 +0000</pubDate></item></channel></rss>
