<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Электроника для всех</title>
	
	<link>http://easyelectronics.ru</link>
	<description>Блог о электронике</description>
	<pubDate>Wed, 28 Jul 2010 04:35:41 +0000</pubDate>
	
	<language>en</language>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/easyelectronics" /><feedburner:info uri="easyelectronics" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:emailServiceId>easyelectronics</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><item>
		<title>Пример виртуальной машины</title>
		<link>http://feedproxy.google.com/~r/easyelectronics/~3/JRHhtbO74Zc/primer-virtualnoj-mashiny.html</link>
		<comments>http://easyelectronics.ru/primer-virtualnoj-mashiny.html#comments</comments>
		<pubDate>Tue, 27 Jul 2010 20:13:00 +0000</pubDate>
		<dc:creator>DI HALT</dc:creator>
		
		<category><![CDATA[AVR. Учебный курс]]></category>

		<category><![CDATA[Робототехника]]></category>

		<category><![CDATA[RTOS]]></category>

		<category><![CDATA[Программирование]]></category>

		<category><![CDATA[Трюки]]></category>

		<guid isPermaLink="false">http://easyelectronics.ru/?p=332</guid>
		<description><![CDATA[ Как то раз я описывал концепцию создания языка программирования для устройства. Который бы позволил запихать сложнейший алгоритм или последовательность действий в виде компактного скрипта.  
Простой пример для чего это нужно &#8212; фрезерный станок с ЧПУ.  И надо на нем выточить голову Сократа из цельного куска металла. Задача, на самом деле, не шибко [...]]]></description>
			<content:encoded><![CDATA[<p> Как то раз я описывал <a href="http://easyelectronics.ru/virtualnaya-mashina-i-bajt-kod.html" >концепцию создания языка программирования для устройства</a>. Который бы позволил запихать сложнейший алгоритм или последовательность действий в виде компактного скрипта.  </p>
<p>Простой пример для чего это нужно &#8212; фрезерный станок с ЧПУ.  И надо на нем выточить голову Сократа из цельного куска металла. Задача, на самом деле, не шибко сложная.</p>
<p> Но попробуйте написать прошивку, двигающую резцом, в виде классического конечного автомата &#8212; двигающую резцом в зависимости от условий или состояний. Да вы сдохнете раньше чем это сможете сделать.</p>
<p>  Другое дело если разбить программу на элементарные операции, вроде &#8220;Резец вверх&#8221;, &#8220;резец вниз&#8221;, &#8220;шаг на n мм&#8221;, а прошивке скормить последовательность этих микроопераций в виде байт-кода или текстового скрипта. Как все серьезно упрощается. Да и попутно можно нашинковать Платона с Гераклом, было бы желание, да образец для копирования.   </p>
<p> Т.е. у нас появился свой язык устройства, полностью отвязанный от аппаратной реализации и оперирующий только органами устройства. И вот тут, главное, не впасть в высокоуровневую прелесть и не начать изобретать универсального интерпретируемого языка аля JAVA для микроконтроллеров. В условиях ограниченных ресурсов это полный бред. </p>
<p> Наоборот, этот язык нужно максимально упрощать за счет усложнения процедур машины, затачивая их строго под текущую задачу, а не делая нечто универсальное. Тогда можно выжать максимум из контроллера. </p>
<p>Ну, хватит воды, приведу пример того, что у меня получилось за вечерок курения в код. Код рабочий, но я там ничего не оптимизировал. Так, накидал чтоб работало, до ума доведете сами. Сделано все на базе ядра диспетчера. Я его <a href="http://easyelectronics.ru/avr-uchebnyj-kurs-arxitektura-programm-chast-2.html" ><b>уже описывал</b></a>, поэтому работу его функций пояснять не буду<br />
<span id="more-332"></span><br />
Итак, начну разматывать с самого верха. Есть у нас программа:</p>
<ul>
<li> FWD	</li>
<li> DLY,T(1000) </li>
<li> STP </li>
<li> DLY,T(1000) </li>
<li> BCK </li>
<li> DLY,T(2000) </li>
<li> STP    </li>
<li> OFF </li>
</ul>
<p>Очень похожа на ассемблер, да она по сути дела им и является &#8212; это ассемблер устройства. В данном случае некой самобеглой тележки. Все на примитивнейшем уровне, только чтобы показать идею. </p>
<ul>
<li> FWD - ехать вперед.  </li>
<li> DLY - задержка, в скобочках время в мс </li>
<li> STP - стоп </li>
<li> BCK - назад </li>
<li> OFF - выключение. </li>
</ul>
<p>Простенькая такая программка истинного партийца &#8212; шаг вперед, два шага назад. =)))</p>
<p>Программку я оформил в файле <a href="http://easyelectronics.ru/repository.php?act=view&#038;id=11" ><b>VM_PROG.h</b></a>, чтобы не путаться где у нас что я буду звать этот скрипт <b>надпрограммой</b></p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td class="code"><pre class="c c" style="font-family:monospace;"><span style="color: #339933;">#define OFF 0</span>
<span style="color: #339933;">#define BCK 1</span>
<span style="color: #339933;">#define FWD 2</span>
<span style="color: #339933;">#define DLY 3</span>
<span style="color: #339933;">#define STP 4</span>
<span style="color: #339933;">#define T(X) ((X)&amp; 0xFF),((X)&gt;&gt;8)</span>
&nbsp;
<span style="color: #993333;">static</span> u08 VM_PGM<span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span>
&nbsp;
<span style="color: #009900;">&#123;</span>
FWD<span style="color: #339933;">,</span>            <span style="color: #666666; font-style: italic;">//0</span>
DLY<span style="color: #339933;">,</span>T<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1000</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>    <span style="color: #666666; font-style: italic;">//1,2,3</span>
STP<span style="color: #339933;">,</span>            <span style="color: #666666; font-style: italic;">//4</span>
DLY<span style="color: #339933;">,</span>T<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1000</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>    <span style="color: #666666; font-style: italic;">//5,6,7</span>
BCK<span style="color: #339933;">,</span>            <span style="color: #666666; font-style: italic;">//8</span>
DLY<span style="color: #339933;">,</span>T<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">2000</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>    <span style="color: #666666; font-style: italic;">//9,10,11</span>
STP<span style="color: #339933;">,</span>            <span style="color: #666666; font-style: italic;">//12</span>
OFF             <span style="color: #666666; font-style: italic;">//13</span>
<span style="color: #009900;">&#125;</span>;</pre></td></tr></table></div>

<p>Тут все просто. Вначале через дефайны мы каждой мнемонике нашего ассемблера присваиваем номер команды (это важно!). А потом забиваем их в стандартный массив во флеше.  Массив занял у нас 13 байт. Обрати внимание на то, что команды переменной длины. Т.е. есть простые - однобайтные, а есть двубайтные, например, задержка. Там байт на команду и два байта на выдержку. </p>
<p>Каждой команде присвоена своя процедура, содержимое процедур не важно особо, они для примера. Тут у меня &#8220;вперед&#8221; это зажигание одного светодиода на <a href="http://shop.easyelectronics.ru/index.php?productID=147" >Pinboard</a>, а &#8220;назад&#8221; другого.  Команды эти лежат в файле <a href="http://easyelectronics.ru/repository.php?act=view&#038;id=9" ><b>VM.c</b></a>, а хидеры в <a href="http://easyelectronics.ru/repository.php?act=view&#038;id=10" ><b>VM.h</b></a> :</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
</pre></td><td class="code"><pre class="c c" style="font-family:monospace;"><span style="color: #993333;">void</span> VM_Back<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
LED_PORT  <span style="color: #339933;">^=</span><span style="color: #0000dd;">1</span><span style="color: #339933;">&lt;&lt;</span>LED3; 		<span style="color: #666666; font-style: italic;">// Зажигаем диод</span>
VM_PC<span style="color: #009900;">&#91;</span><span style="color:#800080;">0</span><span style="color: #009900;">&#93;</span>++;			<span style="color: #666666; font-style: italic;">// Выбор следующей задачи VM</span>
&nbsp;
SetTask<span style="color: #009900;">&#40;</span>VM<span style="color: #009900;">&#41;</span>;			<span style="color: #666666; font-style: italic;">// Вброс диспетчера виртуальной </span>
				<span style="color: #666666; font-style: italic;">// машины на конвейер диспетчера RTOS</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

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

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
</pre></td><td class="code"><pre class="c c" style="font-family:monospace;"><span style="color: #993333;">void</span> VM_Stop<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
LED_PORT  <span style="color: #339933;">^=</span><span style="color: #0000dd;">1</span><span style="color: #339933;">&lt;&lt;</span>LED3;
VM_PC<span style="color: #009900;">&#91;</span><span style="color:#800080;">0</span><span style="color: #009900;">&#93;</span>++;
&nbsp;
SetTask<span style="color: #009900;">&#40;</span>VM<span style="color: #009900;">&#41;</span>;
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="code"><pre class="c c" style="font-family:monospace;"><span style="color: #993333;">void</span> VM_Delay<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
u16 delay;				<span style="color: #666666; font-style: italic;">// Двубайтная переменная</span>
u08 <span style="color: #339933;">*</span>OneByte;				<span style="color: #666666; font-style: italic;">// Указатель на один байт</span>
&nbsp;
OneByte <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>u08 <span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">&amp;</span>delay;		<span style="color: #666666; font-style: italic;">// Берем адрес переменной</span>
&nbsp;
<span style="color: #339933;">*</span>OneByte <span style="color: #339933;">=</span> VM_PGM<span style="color: #009900;">&#91;</span><span style="color: #339933;">++</span>VM_PC<span style="color: #009900;">&#91;</span><span style="color:#800080;">0</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#93;</span>;	<span style="color: #666666; font-style: italic;">// По байтикам собираем слово</span>
OneByte++;
<span style="color: #339933;">*</span>OneByte <span style="color: #339933;">=</span> VM_PGM<span style="color: #009900;">&#91;</span><span style="color: #339933;">++</span>VM_PC<span style="color: #009900;">&#91;</span><span style="color:#800080;">0</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#93;</span>;
&nbsp;
VM_PC<span style="color: #009900;">&#91;</span><span style="color:#800080;">0</span><span style="color: #009900;">&#93;</span>++;				<span style="color: #666666; font-style: italic;">// Прощелкиваем счетчиком надпрограммы</span>
&nbsp;
SetTimerTask<span style="color: #009900;">&#40;</span>VM<span style="color: #339933;">,</span>delay<span style="color: #009900;">&#41;</span>;		<span style="color: #666666; font-style: italic;">// Запуск задачи VM через диспетчер таймеров.</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

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

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
</pre></td><td class="code"><pre class="c c" style="font-family:monospace;"><span style="color: #993333;">void</span> VM_OFF<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
InitVM<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

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

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
</pre></td><td class="code"><pre class="c c" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">//VM Task Table </span>
<span style="color: #993333;">static</span> TPTR VM_FUNC<span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> PROGMEM <span style="color: #339933;">=</span>
   <span style="color: #009900;">&#123;</span>
   <span style="color: #339933;">&amp;</span>VM_OFF<span style="color: #339933;">,</span>		<span style="color: #666666; font-style: italic;">//0</span>
   <span style="color: #339933;">&amp;</span>VM_Back<span style="color: #339933;">,</span>		<span style="color: #666666; font-style: italic;">//1</span>
   <span style="color: #339933;">&amp;</span>VM_Forward<span style="color: #339933;">,</span>      	<span style="color: #666666; font-style: italic;">//2</span>
   <span style="color: #339933;">&amp;</span>VM_Delay<span style="color: #339933;">,</span>		<span style="color: #666666; font-style: italic;">//3</span>
   <span style="color: #339933;">&amp;</span>VM_Stop		<span style="color: #666666; font-style: italic;">//4</span>
   <span style="color: #009900;">&#125;</span>;</pre></td></tr></table></div>

<p>И вот тут важная деталь! Расположение адресов в таблице переходов ТОЧНО соответствует коду операции. Т.е. по нашей надпрограммной системе команд у команды OFF код 0, и ее адрес находится в нулевой ячейке массива VM_FUNC[].  </p>
<p>И дальше все получается очень и очень просто! Мы тупо берем байты из которых состоит надпрограмма и по таблице переходов перебрасываемся на нужный обработчик.  Переброску осуществляет диспетчер RTOS. Поэтому процедура обработки диспетчера виртуальной машины всего из одной строчки:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
</pre></td><td class="code"><pre class="c c" style="font-family:monospace;"><span style="color: #993333;">void</span> VM<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #009900;">&#41;</span>    <span style="color: #666666; font-style: italic;">// Виртуальная машина</span>
<span style="color: #009900;">&#123;</span>
SetTask<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span>pgm_read_word_near<span style="color: #009900;">&#40;</span>VM_FUNC<span style="color: #339933;">+</span>VM_PGM<span style="color: #009900;">&#91;</span>VM_PC<span style="color: #009900;">&#91;</span><span style="color:#800080;">0</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>;
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>То есть тут только вызов <strong>SetTask</strong>. Куда мы считываем ему адрес из памяти программ, из массива VM_FUNC, по смещению из массива VM_PGM, а само смещение берем из массива VM_PC. Вот такая вот Кащеева смерть <i>(Кащей, кстати, знаю что читаешь &#8212; заходи бухать. Давно тебя не видел)</i>.  </p>
<p>А что за массив VM_PC? А это программный счетчик нашей виртуальной машины. Переменная в нем дает значение смещения по массиву с надпрограммой. Для выборки следующей выполняемой команды надпрограммы. Т.е. исходя из значения в VM_PC мы берем значение следующей команды. Поэтому то мы в каждой задаче и увеличивали его значение на 1, а если шли данные, то на 1+величину этих данных (в нашем случае на 1+2). Заботу о программном счетчике приходится решать нам, в обработчиках операторов надпрограммы. А как ты хотел? Реальный процессор работает точно также :)))) А мы сделали процессор в процессоре.  </p>
<p> Меняя значение в VM_PC мы можем делать переходы на нужный оператор, а добавив в операнды обработчик условия получим в нашей надпрограмме ветвления и циклы. Если нужно, конечно. Главное правильно вычислять адрес, ведь у нас команды могут быть и многобайтными, а значит легко выполнить данные вместо кода.  </p>
<p>Остается один только вопрос, а нафига VM_PC массив? Ведь хватит и одного байта. Хватит, ага, но кто сказал, что у нас может выполняться только одна надпрограмма? ;))))</p>
<p> Почему бы не запустить несколько параллельных процессов, каждая со своим VM_PC?</p>
<p> Надо только в обработчики операторов надпрограммы передавать номер обрабатываемой ветви, да следить чтобы конвейер ядра RTOS не сорвало. Плюс придумать что то с очередью таймеров. Т.к. сейчас DELAY прописывается в единственном числе под каждую задачу. Так что у нас не может быть в очереди таймеров, скажем, два FWD на ожидании. Также надо будет решить over 9000 проблем связанных с блокировками общих ресурсов и прочим загоном многозадачных систем. Но все эти проблемы давно уже описаны и известны, так что курить книжки <a href="http://easyelectronics.ru/endryu-tanenbaum-operacionnye-sistemy-razrabotka-i-realizaciya.html" >Таненбаума</a> и дорогу осилит идущий.</p>
<p>Запускается же виртуальная машина просто:</p>
<p>Вначале инициализация программных счетчиков, чтобы поехать точно с начала</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
</pre></td><td class="code"><pre class="c c" style="font-family:monospace;"><span style="color: #993333;">void</span> InitVM<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
u08 i;
&nbsp;
<span style="color: #b1b100;">for</span><span style="color: #009900;">&#40;</span>i<span style="color: #339933;">=</span><span style="color:#800080;">0</span>;i<span style="color: #339933;">!=</span><span style="color: #0000dd;">10</span>;i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
   <span style="color: #009900;">&#123;</span>
   VM_PC<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span><span style="color:#800080;">0</span>;
   <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>А дальше запускаем ее как обычную задачу из под диспетчера:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
</pre></td><td class="code"><pre class="c c" style="font-family:monospace;"><span style="color: #993333;">int</span> main<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
InitAll<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;		<span style="color: #666666; font-style: italic;">// Инициализируем периферию</span>
InitRTOS<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;		<span style="color: #666666; font-style: italic;">// Инициализируем ядро</span>
InitVM<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
RunRTOS<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;		<span style="color: #666666; font-style: italic;">// Старт ядра.</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// Запуск фоновых задач.</span>
SetTask<span style="color: #009900;">&#40;</span>VM<span style="color: #009900;">&#41;</span>;
&nbsp;
<span style="color: #b1b100;">while</span><span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span>		<span style="color: #666666; font-style: italic;">// Главный цикл диспетчера</span>
<span style="color: #009900;">&#123;</span>
wdt_reset<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;		<span style="color: #666666; font-style: italic;">// Сброс собачьего таймера</span>
TaskManager<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;		<span style="color: #666666; font-style: italic;">// Вызов диспетчера</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #b1b100;">return</span> <span style="color:#800080;">0</span>;
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>Ну и, напоследок, как обычно, собранный проект для WinAVR+AVRStudio с этим примером</p>
<p><a href="http://easyelectronics.ru/files/Robot/WM-GCC-RTOS.ZIP" ><b>WM-GCC-RTOS.ZIP</b></a> </p>
<p><b>З.Ы.</b><br />
На сайт теперь прикручена кодопомойка с подсветкой синтаксиса. Цветами я еще поиграюсь, но уже работает. Теперь не будет проблемы с публикацией длинных кусков кода в комментарии. Достаточно разместить ее в кодопомойке, а в коммент вставить ссылку. Ссылка на кодопомойку встроена теперь в поле ответа на коммент (открывается в новом окне). </p>
<p><a href="http://easyelectronics.ru/repository.php" ><strong>Кодопомойка</strong></a></p>
<p>Работает только для зарегистрированных участников. </p>
<p><b>З.З.Ы.</b><br />
В <a href="http://easyelectronics.ru/united.php" ><b>Карте Сообщества</b></a> был добит зверский баг из-за которого многие точки теряли координаты и топились в Атлантическом Океане, где то в районе Африки. Глюк мы подчистили, а также зачистили базу с битыми точками. Битых точек было вагон, поэтому если кто ставил свои отметки &#8212; проверьте их наличие, возможно их уже там нет. Надо переставить. Ну и народу там понадобавлялось порядочно. Сама же карта теперь торчит в виде баннера в виде&#8230; хм, карты. </p>
<p><b>З.З.З.Ы.</b><br />
У меня тут, ВНЕЗАПНО, родственники, ТЫСЯЧИ ИХ! Плюс еще дела мелкие, но по тому же сценарию. Так что не теряйте. Я не забил, просто очень занят :(</p>
<img src="http://feeds.feedburner.com/~r/easyelectronics/~4/JRHhtbO74Zc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://easyelectronics.ru/primer-virtualnoj-mashiny.html/feed</wfw:commentRss>
		<feedburner:origLink>http://easyelectronics.ru/primer-virtualnoj-mashiny.html</feedburner:origLink></item>
		<item>
		<title>Колеса… колеса… Ноги! Во!</title>
		<link>http://feedproxy.google.com/~r/easyelectronics/~3/u9l2dpdfHUY/kolesa-kolesa-nogi-vo.html</link>
		<comments>http://easyelectronics.ru/kolesa-kolesa-nogi-vo.html#comments</comments>
		<pubDate>Sun, 11 Jul 2010 18:40:21 +0000</pubDate>
		<dc:creator>DI HALT</dc:creator>
		
		<category><![CDATA[Робототехника]]></category>

		<category><![CDATA[Видео]]></category>

		<category><![CDATA[Робот]]></category>

		<guid isPermaLink="false">http://easyelectronics.ru/?p=327</guid>
		<description><![CDATA[
Главное его не красить в зеленый цвет, а то монтировками загасят.  
]]></description>
			<content:encoded><![CDATA[<p><object width="640" height="385"><param name="movie" value="http://www.youtube.com/v/nUQsRPJ1dYw&#038;color1=0xb1b1b1&#038;color2=0xd0d0d0&#038;hl=ru_RU&#038;feature=player_embedded&#038;fs=1"></param><param name="allowFullScreen" value="true"></param><param name="allowScriptAccess" value="always"></param><embed src="http://www.youtube.com/v/nUQsRPJ1dYw&#038;color1=0xb1b1b1&#038;color2=0xd0d0d0&#038;hl=ru_RU&#038;feature=player_embedded&#038;fs=1" type="application/x-shockwave-flash" allowfullscreen="true" allowScriptAccess="always" width="640" height="385"></embed></object></p>
<p>Главное его не красить в зеленый цвет, а то монтировками загасят.  </p>
<img src="http://feeds.feedburner.com/~r/easyelectronics/~4/u9l2dpdfHUY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://easyelectronics.ru/kolesa-kolesa-nogi-vo.html/feed</wfw:commentRss>
		<feedburner:origLink>http://easyelectronics.ru/kolesa-kolesa-nogi-vo.html</feedburner:origLink></item>
		<item>
		<title>AVR. Учебный курс. Конечный автомат</title>
		<link>http://feedproxy.google.com/~r/easyelectronics/~3/svOS0PtyAQA/avr-uchebnyj-kurs-konechnyj-avtomat.html</link>
		<comments>http://easyelectronics.ru/avr-uchebnyj-kurs-konechnyj-avtomat.html#comments</comments>
		<pubDate>Thu, 08 Jul 2010 20:15:31 +0000</pubDate>
		<dc:creator>DI HALT</dc:creator>
		
		<category><![CDATA[AVR. Учебный курс]]></category>

		<category><![CDATA[Алгоритм]]></category>

		<category><![CDATA[Программирование]]></category>

		<category><![CDATA[Трюки]]></category>

		<guid isPermaLink="false">http://easyelectronics.ru/?p=326</guid>
		<description><![CDATA[Каждый кто пытался разбираться с конечными автоматами наверняка натыкался на всякие замудреные графы, какие то графики. Многие посчитав это слишком сложным плюнули и забили. А Зря! 
С простейшим конечным автоматом каждый из нас сталкивался с самого детства &#8212; это механическая авторучка. Объект с единственной функцией &#8220;Нажатие кнопки&#8221;, но в зависимости от очередности результат разный. Стержень [...]]]></description>
			<content:encoded><![CDATA[<p>Каждый кто пытался разбираться с конечными автоматами наверняка натыкался на всякие замудреные графы, какие то графики. Многие посчитав это слишком сложным плюнули и забили. А Зря! </p>
<p>С простейшим конечным автоматом каждый из нас сталкивался с самого детства &#8212; это механическая авторучка. Объект с единственной функцией &#8220;Нажатие кнопки&#8221;, но в зависимости от очередности результат разный. Стержень то прячется, то вылазит. </p>
<p>Так и в нашем случае &#8212; конечный автомат это функция которая запоминает свое состояние и при следующем вызове делает свое черное дело исходя из прошлого опыта. Простой пример &#8212; мигалка (псевдокод):</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
</pre></td><td class="code"><pre class="c c" style="font-family:monospace;">; Глобальные переменные
u08 Blink_State;
&nbsp;
<span style="color: #993333;">void</span> Blink<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>Blink_State <span style="color: #339933;">==</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span>
	<span style="color: #009900;">&#123;</span>
	Led_On<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
	Blink_State <span style="color: #339933;">=</span> <span style="color:#800080;">0</span>;
	<span style="color: #b1b100;">Return</span>;
	<span style="color: #009900;">&#125;</span>
<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>Blink_State <span style="color: #339933;">==</span> <span style="color:#800080;">0</span><span style="color: #009900;">&#41;</span>
	<span style="color: #009900;">&#123;</span>
	Led_Off<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
	Blink_State <span style="color: #339933;">=</span> <span style="color: #0000dd;">1</span>;
	<span style="color: #b1b100;">Return</span>;
	<span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>Вызывая эту функцию подряд мы заставим диодик менять свое состояние при каждом вызове.<br />
<span id="more-326"></span><br />
Но никто не мешает взять и сделать автомат куда сложней, на несколько десятков состояний. Никто не запрещает использовать вложенные конечные автоматы, никто не запрещает менять состояние автомата извне. В общем, мощнейший инструмент для построения быстрых и очень компактных алгоритмов. </p>
<p>Приведу другой, более сложный пример. Генерацию сигнала сложной формы. </p>
<p>Пусть у нас есть сигнал:</p>
<table border="0" cellspacing="0" cellpadding="0" align=center>
<tr>
<td><img src="http://easyelectronics.ru/img/AVR_kurs/switch/sw-sig.gif" alt=""></td>
</tr>
</table>
<p>Цифрами указана задержка, в каких нибудь величинах. Это не суть важно. </p>
<p>Обычно народ не парится и лепит его по быдлокодерски, через delay:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
</pre></td><td class="code"><pre class="c c" style="font-family:monospace;">Set_Pin<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;	<span style="color: #666666; font-style: italic;">// Вывод в 1</span>
Delay<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">10</span><span style="color: #009900;">&#41;</span>;	<span style="color: #666666; font-style: italic;">// Задержка 10</span>
&nbsp;
Clr_Pin<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;	<span style="color: #666666; font-style: italic;">// Вывод в 0</span>
Delay<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">100</span><span style="color: #009900;">&#41;</span>;	<span style="color: #666666; font-style: italic;">// Задержка в 100</span>
&nbsp;
Set_Pin<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
Delay<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span>;
&nbsp;
Clr_Pin<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
Delay<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">5</span><span style="color: #009900;">&#41;</span>;
&nbsp;
Set_Pin<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
Delay<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#41;</span>;
&nbsp;
Clr_Pin<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
Delay<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">3</span><span style="color: #009900;">&#41;</span>;
&nbsp;
Set_Pin;
Delay<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">4</span><span style="color: #009900;">&#41;</span>;
&nbsp;
Clr_Pin<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;</pre></td></tr></table></div>

<p>Это дает минимальный код, но затыкает работу контроллера на весь период посылки. А если слать надо постоянно? Да еще дофига всего попутно делать? Экран обновлять, данные обрабатывать, в память писать&#8230;<br />
В таком случае у нас рулит RTOS, где на Delay происходит передача управления диспетчеру. Но если ОС нету? Вот тут то и идет в ход конечный автомат. </p>
<p>Проще всего тут применить таймер и его прерывание по переполнению. Таймер сам, в своем прерывании, будет загружать себя новыми значениями выдержки и щелкать дальше.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
</pre></td><td class="code"><pre class="c c" style="font-family:monospace;">Timer_Overflow_Interrupt<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
<span style="color: #b1b100;">switch</span><span style="color: #009900;">&#40;</span>TMR_State<span style="color: #009900;">&#41;</span>			<span style="color: #666666; font-style: italic;">// Обработчик прерывания по переполнению</span>
	<span style="color: #009900;">&#123;</span>
	<span style="color: #b1b100;">case</span> <span style="color:#800080;">0</span><span style="color: #339933;">:</span>	
		<span style="color: #009900;">&#123;</span> 
		Clr_Pin<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;		<span style="color: #666666; font-style: italic;">// Вывод в 0</span>
		TCNT <span style="color: #339933;">=</span> <span style="color: #0000dd;">255</span><span style="color: #339933;">-</span><span style="color: #0000dd;">100</span>; 	<span style="color: #666666; font-style: italic;">// Задержка в 100 (до переполнения)</span>
		TMR_State <span style="color: #339933;">=</span> <span style="color: #0000dd;">1</span>; 		<span style="color: #666666; font-style: italic;">// Следующая стадия 1</span>
		<span style="color: #000000; font-weight: bold;">Break</span>;			<span style="color: #666666; font-style: italic;">// Выход</span>
		<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #b1b100;">case</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">:</span>	
		<span style="color: #009900;">&#123;</span> 
		Set_Pin<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
		TCNT <span style="color: #339933;">=</span> <span style="color: #0000dd;">255</span><span style="color: #339933;">-</span><span style="color: #0000dd;">1</span>; 
		TMR_State <span style="color: #339933;">=</span> <span style="color: #0000dd;">2</span>; 
		<span style="color: #000000; font-weight: bold;">Break</span>;
		<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #b1b100;">case</span> <span style="color: #0000dd;">2</span><span style="color: #339933;">:</span>	
		<span style="color: #009900;">&#123;</span> 
		Clr_Pin<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
		TCNT <span style="color: #339933;">=</span> <span style="color: #0000dd;">255</span><span style="color: #339933;">-</span><span style="color: #0000dd;">5</span>; 
		TMR_State <span style="color: #339933;">=</span> <span style="color: #0000dd;">3</span>; 
		<span style="color: #000000; font-weight: bold;">Break</span>;
		<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #b1b100;">case</span> <span style="color: #0000dd;">3</span><span style="color: #339933;">:</span>	
		<span style="color: #009900;">&#123;</span> 
		Set_Pin<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
		TCNT <span style="color: #339933;">=</span> <span style="color: #0000dd;">255</span><span style="color: #339933;">-</span><span style="color: #0000dd;">2</span>; 
		TMR_State <span style="color: #339933;">=</span> <span style="color: #0000dd;">4</span>; 
		<span style="color: #000000; font-weight: bold;">Break</span>;
		<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #b1b100;">case</span> <span style="color: #0000dd;">4</span><span style="color: #339933;">:</span>	
		<span style="color: #009900;">&#123;</span> 
		Clr_Pin<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
		TCNT <span style="color: #339933;">=</span> <span style="color: #0000dd;">255</span><span style="color: #339933;">-</span><span style="color: #0000dd;">3</span>; 
		TMR_State <span style="color: #339933;">=</span> <span style="color: #0000dd;">5</span>; 
		<span style="color: #000000; font-weight: bold;">Break</span>;
		<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #b1b100;">case</span> <span style="color: #0000dd;">5</span><span style="color: #339933;">:</span>	
		<span style="color: #009900;">&#123;</span> 
		Set_Pin<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
		TCNT <span style="color: #339933;">=</span> <span style="color: #0000dd;">255</span><span style="color: #339933;">-</span><span style="color: #0000dd;">4</span>; 
		TMR_State <span style="color: #339933;">=</span> <span style="color: #0000dd;">6</span>; 
		<span style="color: #000000; font-weight: bold;">Break</span>;
		<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #b1b100;">case</span> <span style="color: #0000dd;">6</span><span style="color: #339933;">:</span>
		<span style="color: #009900;">&#123;</span> 
		Clr_Pin<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
		Timer_OFF<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>; 		<span style="color: #666666; font-style: italic;">// Выключаем таймер. Работа окончена</span>
		TMR_State <span style="color: #339933;">=</span> <span style="color:#800080;">0</span>; 		<span style="color: #666666; font-style: italic;">// Обнуляем состояние</span>
		<span style="color: #000000; font-weight: bold;">Break</span>;			
		<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #b1b100;">default</span><span style="color: #339933;">:</span> 	<span style="color: #000000; font-weight: bold;">break</span>;		
	<span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>А запускается эта байда простым пинком:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
</pre></td><td class="code"><pre class="c c" style="font-family:monospace;">Set_Pin<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
TCNT<span style="color: #339933;">=</span><span style="color: #0000dd;">255</span><span style="color: #339933;">-</span><span style="color: #0000dd;">10</span>;		<span style="color: #666666; font-style: italic;">// Грузим таймер на выдержку 10 тиков</span>
TMR_State <span style="color: #339933;">=</span> <span style="color:#800080;">0</span>;		<span style="color: #666666; font-style: italic;">// Устанавливаем начальное положение</span>
Timer_ON<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;		<span style="color: #666666; font-style: italic;">// Поехали!</span>
&nbsp;
... <span style="color: #666666; font-style: italic;">// После чего можно заниматься чем угодно.</span></pre></td></tr></table></div>

<p>Когда автомат отработает - сама себя выключит. Можно еще какоенить событие сгенерировать, дабы основная программа поняла, что все уже готово. Хотя основная программа спокойно может палить переменную состояния автомата и все оттуда узнать сама. </p>
<p>Конечный автомат можно зациклить &#8212; скажем на стадии 6 сделать перенаправление на стадию 0, то получим генератор сигнала сложной формы. Причем он будет занимать минимум процессорного времени. </p>
<p>Если мы, например, захотим сделать десяток ШИМ сигналов? То что нам мешает повесить их на ОДИН таймер, главное отсортировать все скважности по возростанию, причем сортировать их вместе с ногами которыми нужно дрыгать. А потом прогнать по прерыванию таймера конечный автомат, да так чтобы он по стадиям передергивал ножки. Правда при изменении скважности любого из этих софтверных ШИМ каналов придется делать повторную сортировку всего массива. Разумеется больших скоростей мы на этом не получим. Таймер не может щелкать так быстро, да и математики там хватит. Но для многих задач, например, одновременное управление десятком сервомашинок этого более чем достаточно. </p>
<p>А если в том же прерывании таймера сделать выбор следующей стадии исходя не из тупой последовательности, а, скажем, на основе обрабатываемого байта, то мы получим программно-аппаратный генератор, к примеру, 1-Wire кода. Достаточно анализировать входной буфер и если там 1 - перебрасывать автомат  в состояние соответствующее отработки генерации сигнала 1, а если 0, то в состояние генерящее выдержку нуля. </p>
<p>Более того, на автоматах можно полностью построить логику работы программы. От и до. Получается весьма торчково, пока не въедешь в это всей душой мозг сломать можно, но зато работает просто зверски и очень проста в отладке. </p>
<p>Не буду описывать это так как есть замечательный цикл статей Владимира Татарчевского, опубликованный в журнале Компоненты и Технологии. Настоятельно рекомендую к прочтению. Чтобы вам не шерстить по инету, я все части этой замечательной статьи выложил в <a href="http://easyelectronics.ru/img/AVR_kurs/switch/switch_tech.zip" onclick="javascript:pageTracker._trackPageview('/downloads/img/AVR_kurs/switch/switch_tech.zip');"><b>архив</b></a>. Качайте и вкуривайте.</p>
<p>Особенно автоматный метод доставляет тем, что готовые автоматы вписываются как родные в ЛЮБУЮ почти архитектуру. У меня они и во флаговых автоматах работают на ура, и из диспетчера RTOS я их гоняю как родные. Красота! </p>
<img src="http://feeds.feedburner.com/~r/easyelectronics/~4/svOS0PtyAQA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://easyelectronics.ru/avr-uchebnyj-kurs-konechnyj-avtomat.html/feed</wfw:commentRss>
		<feedburner:origLink>http://easyelectronics.ru/avr-uchebnyj-kurs-konechnyj-avtomat.html</feedburner:origLink></item>
		<item>
		<title>Кибергусеница</title>
		<link>http://feedproxy.google.com/~r/easyelectronics/~3/Y1VBPUxKHzM/kibergusenica.html</link>
		<comments>http://easyelectronics.ru/kibergusenica.html#comments</comments>
		<pubDate>Sat, 03 Jul 2010 13:29:48 +0000</pubDate>
		<dc:creator>Serafim</dc:creator>
		
		<category><![CDATA[Робототехника]]></category>

		<guid isPermaLink="false">http://easyelectronics.ru/?p=325</guid>
		<description><![CDATA[Дабы отдать дань уважения сайту решил написать данную статью о своем роботе-самоделке. Это была моя магистерская и инженерная работа и теперь хочется поделиться ею со всем просвященным миром)
Итак, несколько слов об устройстве. Ниже приведена 3d моделька девайсины.





В основе робота сервомашинки Futaba S3003 - самые простые и дешевые, что удалось раздобыть на нашей кафедре (кафедра ТМ [...]]]></description>
			<content:encoded><![CDATA[<p>Дабы отдать дань уважения сайту решил написать данную статью о своем роботе-самоделке. Это была моя магистерская и инженерная работа и теперь хочется поделиться ею со всем просвященным миром)</p>
<p>Итак, несколько слов об устройстве. Ниже приведена 3d моделька девайсины.</p>
<table border="0" cellspacing="0" cellpadding="0" align=center>
<tr>
<td><img src="http://easyelectronics.ru/img/Robot/worm/3D.jpeg" alt=""></td>
</tr>
</table>
<p>В основе робота сервомашинки Futaba S3003 - самые простые и дешевые, что удалось раздобыть на нашей кафедре (кафедра ТМ и М ЮЗГУ(КурскГТУ)).  О том, что такое сервомашинка и как она работает у Вас есть <a href="http://easyelectronics.ru/servomashinka-hs-311.html" ><strong>отдельная статья</strong></a> на данном сайте, поэтому останавливаться на этом я не буду.<br />
<span id="more-325"></span><br />
<b>Конструктив</b><br />
 Всего в конструкции 8 сервомашинок, управляющихся от одной 16ой атмеги. Соединенные металлическими уголками</p>
<table border="1" cellspacing="1" cellpadding="1" align=center style="margin:10px;" >
<tr>
<td><img src="http://easyelectronics.ru/img/Robot/worm/DSC03331.JPG" alt=""></td>
</tr>
</table>
<p>Вначале для реализации управления я использовал тупые задержки, но потом перешел на таймер и потом уже 16ую атмегу заменил на 8ую (и схемка получилась меньше и выглядеть робот начал получше). </p>
<p> Под мою задачу возникла необходимость уменьшения скорости поворота серв (при максимальной скорости поворота, т.к. робот делался на коленках, он переворачивался). Сделано это было так: посылалось не начальное и конечное значение на привод, а задавалось несколько промежуточных положений + количество импульсов на отработку одного положения. Таким образом, можно получить самые разные скорости и характеристики поворота от очень плавного и медленного до очень корявого. Для дополнительного трения с нижней стороны модулей были добавлены резиновые контактные площадки из обычных ластиков)). </p>
<p><b>О движении</b><br />
 Робот движется по прямой за счет продольных волн деформации. Чем выше скорость пробега волны по роботу, тем выше скорость движения. При этом, как ни странно, амплитуда поворота не играет большой роли. Я рассматривал 2 варианта - 1 волна из двух соседних звеньев и 2 волны также с двумя звеньями в волне.</p>
<table border="0" cellspacing="0" cellpadding="0" align=center>
<tr>
<td><img src="http://easyelectronics.ru/img/Robot/worm/algoitm.jpeg" alt=""></td>
</tr>
</table>
<p>И вот, что из всего этого получилось</p>
<table border="1" cellspacing="1" cellpadding="1" align=center style="margin:10px;" >
<tr>
<td><img src="http://easyelectronics.ru/img/Robot/worm/zmei2.jpeg" alt=""></td>
</tr>
</table>
<p>При отладке проги внчале я делал симуляцию в протеусе. Надо сказать, что при правильной настройке модели сервы в протеусе, он симулирует ее очень правдиво. Вот симуляция в протеусе</p>
<div style="text-align: center;"><object width="480" height="385"><param name="movie" value="http://www.youtube.com/v/5fmfgz0dnOs&amp;hl=ru_RU&amp;fs=1"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/5fmfgz0dnOs&amp;hl=ru_RU&amp;fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="480" height="385"></embed></object></div>
<p>А вот как это все в движении:</p>
<div style="text-align: center;"><object width="480" height="385"><param name="movie" value="http://www.youtube.com/v/7widewRBuXI&amp;hl=ru_RU&amp;fs=1"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/7widewRBuXI&amp;hl=ru_RU&amp;fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="480" height="385"></embed></object></div>
<p>Когда переделал схемку под 8ую мегу и сделал красивую шкурку получилось очень даже мило внешне :)</p>
<table border="1" cellspacing="1" cellpadding="1" align=center style="margin:10px;" >
<tr>
<td><img src="http://easyelectronics.ru/img/Robot/worm/zmei1.jpg" alt=""></td>
</tr>
</table>
<table border="1" cellspacing="1" cellpadding="1" align=center style="margin:10px;" >
<tr>
<td><img src="http://easyelectronics.ru/img/Robot/worm/DSC05948.JPG" alt=""></td>
</tr>
</table>
<p>Вопросы можете задавать в комментариях.</p>
<img src="http://feeds.feedburner.com/~r/easyelectronics/~4/Y1VBPUxKHzM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://easyelectronics.ru/kibergusenica.html/feed</wfw:commentRss>
		<feedburner:origLink>http://easyelectronics.ru/kibergusenica.html</feedburner:origLink></item>
		<item>
		<title>Робоконструктор Velleman Robotic Arm KSR10</title>
		<link>http://feedproxy.google.com/~r/easyelectronics/~3/x6_nIEt3nFA/robokonstruktor-velleman-robotic-arm-ksr10.html</link>
		<comments>http://easyelectronics.ru/robokonstruktor-velleman-robotic-arm-ksr10.html#comments</comments>
		<pubDate>Tue, 22 Jun 2010 11:29:06 +0000</pubDate>
		<dc:creator>DI HALT</dc:creator>
		
		<category><![CDATA[Робототехника]]></category>

		<category><![CDATA[Манипулятор]]></category>

		<category><![CDATA[Механика]]></category>

		<category><![CDATA[Робот]]></category>

		<guid isPermaLink="false">http://easyelectronics.ru/?p=323</guid>
		<description><![CDATA[Наши дружеские посиделки, хоть и малым составом, но состоялись. Кроме обсуждения ряда технических задач и возможного сотрудничества просто классно и плодотворно пообщались. Андрей натащил кучу разных прикольных штуковин одну из которых я вам сейчас и покажу. 





Это очередной робоконструктор &#8212; механическая рука с пятью степенями свободы. Velleman Robotic Arm KSR10
Штука довольно редко встречающася, т.к. на [...]]]></description>
			<content:encoded><![CDATA[<p>Наши дружеские посиделки, хоть и малым составом, но состоялись. Кроме обсуждения ряда технических задач и возможного сотрудничества просто классно и плодотворно пообщались. Андрей натащил кучу разных прикольных штуковин одну из которых я вам сейчас и покажу. </p>
<table border="0" cellspacing="0" cellpadding="0" align=center>
<tr>
<td><img src="http://easyelectronics.ru/img/Robot/Robotic_arm_ksr10/roboarm.gif" alt=""></td>
</tr>
</table>
<p>Это очередной робоконструктор &#8212; механическая рука с пятью степенями свободы. Velleman Robotic Arm KSR10<br />
Штука довольно редко встречающася, т.к. на Ebay я нашел всего одного продавца и в exUSSR эта редиска слать не желает. Встречается в нескольких буржуйских магазинах и вроде бы была в ЧиД, но оттуда была выкуплена нами :)  Цена вопроса от 60&#8230;100 баксов. </p>
<p>Сам агрегат это очередная продвинутая игрушка, но для баловства и отработки алгоритмов нам больше и не требуется. <span id="more-323"></span></p>
<table border="0" cellspacing="0" cellpadding="0" align=center>
<tr>
<td><img src="http://easyelectronics.ru/img/Robot/Robotic_arm_ksr10/80-7360.JPG" alt=""></td>
</tr>
</table>
<p>Итак, это механика и только механика. Тут нет никакой электронной начинки. Вообще. Т.е. пять движков и простейшая тумблерная система управления вперед-назад. </p>
<table border="0" cellspacing="0" cellpadding="0" align=center>
<tr>
<td><img src="http://easyelectronics.ru/img/Robot/Robotic_arm_ksr10/roboarm_sx.gif" alt=""></td>
</tr>
</table>
<p> Работает от батареек и имеет пульт с пятью рычажками. </p>
<table border="1" cellspacing="1" cellpadding="1" align=center style="margin:10px;" >
<tr>
<td><img src="http://easyelectronics.ru/img/Robot/Robotic_arm_ksr10/pult.jpg" alt=""></td>
</tr>
</table>
<p>По каждой степени свободы манипулятор вращается через редуктор с весьма большим передаточным числом. На глазок - не меньше чем 1:300. Редуктор червячно-цилиндрический, многоступенчатый. С трещеткой ограничителя момента. </p>
<table border="0" cellspacing="0" cellpadding="0" align=center>
<tr>
<td><img src="http://easyelectronics.ru/img/Robot/Robotic_arm_ksr10/roboarm_gears.gif" alt=""></td>
</tr>
</table>
<table border="0" cellspacing="0" cellpadding="0" align=center>
<tr>
<td><img src="http://easyelectronics.ru/img/Robot/Robotic_arm_ksr10/roboarm_motors.gif" alt=""></td>
</tr>
</table>
<p>Пластик качественный, не хрупкий, конструкции мощные. Откровенно слабых мест я на первый взгляд не нашел. Довольно жесткий, люфты небольшие, ничего не болтается. Много элементов всяких декоративных украшалок на корпусах редукторов. Оно и понятно &#8212; игрушка же. Но все провода можно убрать за спец крючочки, так что ничего не будет болтаться. У меня на фотках это все торчит во все стороны, т.к. крючочки по неосторожности были сломаны. </p>
<p>А теперь подробней о содержимом. В большой красочной коробке лежат несколько литников с деталями редукторов.</p>
<table border="1" cellspacing="1" cellpadding="1" align=center style="margin:10px;" >
<tr>
<td><img src="http://easyelectronics.ru/img/Robot/Robotic_arm_ksr10/litnik.jpg" alt=""></td>
</tr>
</table>
<p>Пакетики с винтами и шестернями</p>
<table border="1" cellspacing="1" cellpadding="1" align=center style="margin:10px;">
<tr>
<td><img src="http://easyelectronics.ru/img/Robot/Robotic_arm_ksr10/gears.jpg" alt=""></td>
</tr>
</table>
<p>Пять движков с червяками на валу. Двигло &#8212; китайское барахло, но благо имеют стандартный типоразмер и можно их заменить на что нибудь более породистое от той же Mabuchi motor с угольными щетками. </p>
<table border="1" cellspacing="1" cellpadding="1" align=center style="margin:10px;" >
<tr>
<td><img src="http://easyelectronics.ru/img/Robot/Robotic_arm_ksr10/motors.jpg" alt=""></td>
</tr>
</table>
<p>Под дружное веселье нашей  компании, я снял небольшую видяшку о том как Андрей этой клешней пытался захватить за хвост нашу пивную закусь. В ходе пятиминутного грозного елозения клешней под дружные &#8220;Ать!   Ыть! Ну же!&#8221; ему таки удалось, ага:</p>
<table border="1" cellspacing="1" cellpadding="1" align=center style="margin:10px;" >
<tr>
<td><img src="http://easyelectronics.ru/img/Robot/Robotic_arm_ksr10/roboarm_foto.jpg " alt=""></td>
</tr>
</table>
<p>Но увы, качество и скорость моего интернета не позволяет мне залить видео отсюда. Как приеду домой, обязательно добавлю. Пока же я выдавил из Тюбика ряд роликов про эту клешню.</p>
<div style="text-align: center;"><object width="640" height="385"><param name="movie" value="http://www.youtube.com/v/EXN_PYLg2Wg&#038;hl=ru_RU&#038;fs=1&#038;"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/EXN_PYLg2Wg&#038;hl=ru_RU&#038;fs=1&#038;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="385"></embed></object></div>
<div style="text-align: center;"><object width="640" height="385"><param name="movie" value="http://www.youtube.com/v/7wh4HV5umgg&#038;hl=ru_RU&#038;fs=1&#038;"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/7wh4HV5umgg&#038;hl=ru_RU&#038;fs=1&#038;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="480" height="385"></embed></object></div>
<p>Очень нехватает одной степени свободы &#8212; поворот клешни вокруг своей оси. Это затрудняет возможность схватить что-либо. А так сделано все приятно и смотрится как готовый узел для развлекухи и добавить электронное управление и микроконтроллер было бы несложно, но существует тут одна большая проблема &#8212; отсутствие какой-либо обратной связи по положению. Т.е. манипулятор полностью слеп. Мы не можем определить ни его текущее положение, ни насколько он переместился под нашим воздействием. А значит управлять им в автоматическом режиме будет весьма сложно. Впрочем, на глазок, полости редуктора при наличии прямых рук позволяют запихать туда хотя бы оптический датчик на базе диска с прорезями. Или прикрутить хотя бы переменный резистор к валу &#8212; он является несущим и не вращается, а по диаметру соразмерен с валом резистора RS09. Так что сколхозить можно и выглядеть будет не сильно страшно. Тем более, что углы вращения составляют не более 300 градусов по самой подвижной оси.</p>
<table border="0" cellspacing="0" cellpadding="0" align=center>
<tr>
<td><img src="http://easyelectronics.ru/img/Robot/Robotic_arm_ksr10/angle.jpg" alt=""></td>
</tr>
</table>
<p> Так что может быть я себе эту игрушку даже прикуплю, если найду по адекватной цене. </p>
<p>Также существует апгрейд-кит для этой штуки, подключащий ее к USB. Но дается мне это не более чем виртуальный пульт, как полная замена железному &#8212; обратной связи то нет. Т.е. полная фигня направленная на дополнительное выбивание бабла. </p>
<p><b>З.Ы.</b><br />
Плюс там была куча разных шасси причем некоторые от раритетных советских игрушек, а еще мне задарили убойную ОЗУ на магнитных доменах (радиационностойкую). Попробую ее раскачать и заюзать по приезду.<br />
 Следующая наша тусовка в Евпатории планируется в районе 25 числа.</p>
<img src="http://feeds.feedburner.com/~r/easyelectronics/~4/x6_nIEt3nFA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://easyelectronics.ru/robokonstruktor-velleman-robotic-arm-ksr10.html/feed</wfw:commentRss>
		<feedburner:origLink>http://easyelectronics.ru/robokonstruktor-velleman-robotic-arm-ksr10.html</feedburner:origLink></item>
		<item>
		<title>Точка сбора</title>
		<link>http://feedproxy.google.com/~r/easyelectronics/~3/h1qYeLP_VqE/tochka-sbora.html</link>
		<comments>http://easyelectronics.ru/tochka-sbora.html#comments</comments>
		<pubDate>Wed, 16 Jun 2010 19:51:06 +0000</pubDate>
		<dc:creator>DI HALT</dc:creator>
		
		<category><![CDATA[Новости]]></category>

		<category><![CDATA[От Автора]]></category>

		<guid isPermaLink="false">http://easyelectronics.ru/?p=322</guid>
		<description><![CDATA[В общем, я в Евпатории, уже второй день. Сергей с Андреем встретили меня аки министра какого, аж не ожидал. Спасибо огромное :)  Пять дней отдохну (пока Сергей с вахты не вернется), а там надо замутить тусовочку.
 Где нибудь цивильно посидеть, пообщаться. Предположительно в Евпатории, но с Симферополя и ближайших окрестностей Андрей может народ на [...]]]></description>
			<content:encoded><![CDATA[<p>В общем, я в Евпатории, уже второй день. Сергей с Андреем встретили меня аки министра какого, аж не ожидал. Спасибо огромное :)  Пять дней отдохну (пока Сергей с вахты не вернется), а там надо замутить тусовочку.</p>
<p> Где нибудь цивильно посидеть, пообщаться. Предположительно в Евпатории, но с Симферополя и ближайших окрестностей Андрей может народ на машине вывезти, а при большом количестве народу, думаю не составит проблемы зафрахтовать какую-нибудь газельку или что тут у вас в ходу. </p>
<p>Так что желающие познакомиться, пообщаться, встретить местных единомышленников отписывайтесь, организуйтесь. Пока еще четко ничего не решено, сроки и место не определены, так что время для маневра есть. По ходу, когда все желающие отзовутся, тогда и решим все точно, с учетом интересов каждого.</p>
<img src="http://feeds.feedburner.com/~r/easyelectronics/~4/h1qYeLP_VqE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://easyelectronics.ru/tochka-sbora.html/feed</wfw:commentRss>
		<feedburner:origLink>http://easyelectronics.ru/tochka-sbora.html</feedburner:origLink></item>
		<item>
		<title>Автоэлектрика и автоэлектроника. Курс молодого бойца.</title>
		<link>http://feedproxy.google.com/~r/easyelectronics/~3/fh4tpEiJOfk/avtoelektrika-i-avtoelektronika-kurs-molodogo-bojca.html</link>
		<comments>http://easyelectronics.ru/avtoelektrika-i-avtoelektronika-kurs-molodogo-bojca.html#comments</comments>
		<pubDate>Fri, 11 Jun 2010 20:22:09 +0000</pubDate>
		<dc:creator>kry-love</dc:creator>
		
		<category><![CDATA[Автоэлектроника]]></category>

		<category><![CDATA[Авто]]></category>

		<category><![CDATA[От Автора]]></category>

		<guid isPermaLink="false">http://easyelectronics.ru/?p=320</guid>
		<description><![CDATA[
DI HALT
Надумал тут замутить еще одну рубрику - Автоэлектроника
Ну и есть ряд мыслей по поводу поковырять свою Нексию на предмет разных улучшений и прочего самопала. Я правда больше по всякой автоматике прусь, а кто то может и прошивки ЭБУ меняет. Прорвы материала не обещаю, но что будет то выложу. Ну и можете свои наработки присылать. [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p>
<b>DI HALT</b><br />
Надумал тут замутить еще одну рубрику - Автоэлектроника</p>
<p>Ну и есть ряд мыслей по поводу поковырять свою Нексию на предмет разных улучшений и прочего самопала. Я правда больше по всякой автоматике прусь, а кто то может и прошивки ЭБУ меняет. Прорвы материала не обещаю, но что будет то выложу. Ну и можете свои наработки присылать. </p>
<p>Пока выложу пробным камнем статью Владимира Крылова о работе инжекторных движков, дабы было общее впечатление о их работе.</p></blockquote>
<p><b>Часть первая, обзорная. Общий принцип работы бензинового двигателя внутреннего сгорания</b></p>
<p>Для удобства разделим мотор на три концептуальные части:</p>
<ul>
<li> Железки (ШПГ, КШМ, ГРМ) </li>
<li> Система питания </li>
<li> Система зажигания </li>
</ul>
<p><span id="more-320"></span><br />
<b>Железки</b><br />
Если в школе(и/или вузе) тебе было глубоко положить на термодинамику, циклы Карно и Отто, тепловые процессы и иже с ними, если капот ты открывал только с целью долить масла или другой жижи – просто набери в Википедии «поршневой двигатель». Там есть анимированные картинки, которые дадут общее представление о кинематике ДВС. Сразу оговоримся, мы будем говорить о четырехтактном бензиновом моторе -– двухтактники это архаично и неэкологично, а дизель – это гораздо сложнее для неспециалиста. Итак, железки – они в сборе выполняют функции:</p>
<p>- преобразование энергии горящего топлива в механическую(поступательную)-поршень с уплотнительными кольцами, цилиндр. Здесь рулить особо нечем.</p>
<p>-преобразование возвратно-поступательного движения поршня во вращательное - шатун, коленчатый вал. Тут тоже все сугубо железно.</p>
<p>-организация процесса – газораспределительный механизм. В простейшем случае это кулачковый вал, связанный с коленчатым цепной или зубчатоременной передачей, открывающий и закрывающий в нужный момент впускные и выпускные клапана. Тут бывают электронные системы изменения фаз газораспределения, это интересно, но об этом гораздо позже.</p>
<p>-всякая вспомогательная фигня – смазка трущихся поверхностей, поддержание температурного режима мотора, выработка электричества, пуск мотора – в этих железках есть чуть-чуть электроники, но самый минимум, упомянем их позже по мере надобности.</p>
<p>Вот такая вот абстракция из железок сложилась, теперь собственно наша цель – как всем этим управлять. В основном управлением занимаются вышеупомянутые системы питания и зажигания. Сейчас трудно рассматривать их не в связи друг с другом, а во времена, когда «копейки» были новыми эти две системы жили каждая абсолютно своей жизнью.</p>
<p>Итак, что же нам нужно, чтобы запустить систему, которая так весело крутится на Википедии? Достаточно немного – раскрутить железки электромотором от аккумулятора, подать на впуск ПРАВИЛЬНУЮ горючую смесь, и в ПРАВИЛЬНЫЙ момент её, сжатую, поджечь. Поехали? Просто? Вроде бы да, да закавыка в том, что ПРАВИЛЬНЫЕ состав смеси и момент искрообразования для каждой комбинации «обороты-нагрузка-тепература-положение педали газа-еще куча параметров» - величины совершенно разные. А сильно отклоняться от ПРАВИЛЬНЫХ нельзя: тут тебе и мощность, и экономичность с экологичностью логарифмически быстро ухудшаются.</p>
<p> Вот где простор для современной вычислительной техники! Однако, когда компьютеры были большими, рулила аналоговая техника. Применительно к авто они назывались «карбюратор» и «контактная система зажигания». Я сравниваю эти два автоархаизма с арифмометром «Феликс» - железно, надежно при качественном изготовлении, но уж очень медленно, инерционно, и поэтому неточно. </p>
<p>В век дешевого бензина, дорогих микросхем и попустительского отношения к экологии прокатывало -– но инженерная мысль не стояла на месте. </p>
<p>Углубляться в прошлое и рассказывать про карбюраторы и контактное зажигание не буду – любопытный сам найдет, а мы представим что их никогда и не было, забудем как страшный сон, и перейдем к более современным Электронным Системам Управления Двигателем – для своих просто ЭСУД или для буржуев Engine Management System.</p>
<p>Все гениальное просто – механическая часть систем питания и зажигания современных ДВС, оборудованных ЭСУД, действительно проста. Как мы договорились выше, нам нужно дать мотору правильную смесь и в нужный момент поджечь.</p>
<p> Для этого мы засовываем в бензобак топливный насос который, в отличие от своего карбюраторного собрата, способен давать некислое давление (на моём Опеле до 6 очков, как-то мерял), и врезаем в топливопровод регулятор давления. Эта фигня жутко похожа на стабилизатор LM78xx – она пропускает нужные мотору 2-3 атмосферы в топливную рейку, а остальное отправляет обратно в бак.<br />
 Топливная рейка(она же рампа), чтоб ты знал – это такая трубка из нержавейки квадратная в сечении обычно, по одной из граней которой прорезаны отверстия под форсунки. Собственно форсунка – это маленький электромагнитный клапан с распылителем. Подали напругу - Соленоид втягивает подпружиненную иглу, которая выходит из своего конического седла, и открывает форсунку. А она, как ты помнишь вставлена одним концом в рейку, в которой, как ты надеюсь тоже не забыл, строго определенное давление. Соответственно из крошечных отверстий распылителя форсунки изрыгается факел тончайше распыленного топлива. И самое интересное –- не абы сколько этого топлива, а до микрограмма определенное. Давление-то постоянное, и расход топлива через форсунку за единицу времени мы знаем… Какой вывод? Замечательный –- этой темой могут рулить твои и мои любимые электронные «жучки»</p>
<p>Т.е. подавая на форсунку импульсы определенной ширины мы получаем впрыснутую дозу топлива, строго пропорциональную ширине поданного импульса. Таким образом мы с тобой познакомились с первым исполнительным устройством системы управления двигателем.<br />
 Но, как известно, чтобы получить что-то на выходе, надо иметь что-то и на входе. В самом деле-впрыснуть топлива мы теперь можем сколько захотим, а вот сколько надо захотеть? Тут самое время сделать еще одно физическое-лирическое отступление: о составе горючей смеси. Как ты уже понял, оная состоит из воздуха и топлива(в нашем случае бензина), причем топливо подразумевается в испаренном состоянии. Фишка здесь в том, что наибольшая теплота сгорания развивается при сжигании смеси с определенным составом – на одну массовую долю топлива надо 14.7 массовых долей воздуха.<br />
 При отклонениях туда-сюда в 10 процентов тоже горит, но не всегда оптимально, при дальнейших отклонениях начинает переставать воспламеняться. Выходит, для того, чтобы впрыснуть сколько надо топлива, надо знать сколько мы засосали воздуха. Карбюратор не знал, он оперировал непосредственно законом Бернулли, за что был списан на задворки истории, а вот нам непременно надо. Для этого познакомимся с первым датчиком – массового расхода воздуха (ДМРВ). Раньше для замера массы входящего воздуха во впускном канале устанавливалась подпружиненная заслонка, ось которой была связана с потенциометрическим датчиком. Недостатки долго объяснять не надо – много механики, инерционная тяжелая заслонка, стирающееся покрытие дорожки потенциометра(ужас любого электронщика и аудиофила) – в общем у меня на машине такой, но ей уже 18 лет.</p>
<p>Современная конструкция –  два волоска из платины, нагреваемых от источника тока, один из которых обдувает входящий поток воздуха, второй - контрольный. Чем плотнее поток – тем сильнее остывает обдуваемый волосок, по изменению сопротивления вычисляется масса воздуха. На выходе уже удобоваримый сигнал для контроллера.</p>
<p>Ну вот, элементарные исходные данные чтобы приготовить нужную смесь у нас есть, теперь надо придумать как поджечь это дело. Тут особо сложного ничего также нет. Непосредственно поджигом занимается свеча зажигания – обычный высоковольтный искровой разрядник. А нужные ему 10-20 кВ выдает катушка зажигания – по сути трансформатор.</p>
<p> Подали на первичку 12 вольт постоянки – накопили энергию. Потом разрываем первичную цепь – великая и ужасная электромагнитная индукция наводит на вторичке требуемое высокое напряжение. Оно пробивает воздушный зазор на свече – и смесь нужной консистенции, которую мы с тобой засосали в цилиндр и сжали на первом «туда-сюда» рабочего цикла, благополучно воспламеняется. </p>
<blockquote><p>Тут лирическое отступление. Я как человек, вкуривший-таки (хоть и в достаточно зрелом возрастеJ) в термодинамику, не люблю, когда говорят, что смесь в цилиндре «взрывается». Взрываться – слишком общее слово, взрывы могут происходить с участием не только процесса горения, но всяких там цепных ядерных реакций, термоядерных синтезов, гидроударов  т.п. И лексика слова «взрыв» - оно однокоренное слову «рвать». И действительно – то, что взывается, обычно имеет оболочку, которая и рвется, у нас же в ее роли стенки цилиндров, которые остаются целыми и невредимыми. Так что я и книжки предпочитаем говорить, что смесь сгорает. И это действительно так – сгорая, нагревает теплотой сгорания газы, которые при сгорании образуются (а там безвредные CO2 и H2O, а также ужасные CO, CH, Nox, с которыми нужно бороться).</p></blockquote>
<p> Газы, как им положено, при этом расширяются и давят на поршень, который на втором «чих-пых» рабочего цикла отдает механическую энергию вращающейся системе (там еще есть на одном конце коленвала круглая фигня, похожая на блин от штанги с зубчатым венцом по краю – маховик – он запасает энергию на рабочем ходу и отдает на прочих ходях поршня – получаем плавный ход).<br />
 Ну и напоследок еще одним ходом вверх при открытом выпускном клапане поршень выбрасывает газы наружу (в современных авто через специальный очиститель), загрязняя нашу многострадальную атмосферу. Цикл повторяется раз за разом, и оно крутится!<br />
 Но крутится пока только у нас в уме – поджечь-то мы подожгли, а вот в нужный ли момент? Фишка в том, что время сгорания определенной порции смеси – величина условно постоянная, а вот при разных оборотах мотора время цикла, разумеется, меняется. А еще, в идеальном случае сила давления на поршень должна появляться в момент, когда он пройдет свою верхнюю точку и только-только начнет движение вниз. Но если мы подадим искру в этот самый момент – пока смесь будет разгораться, пока начнет отдавать свое тепло газам – поршень уже уйдет чуть вниз, а когда дойдет до низа, у нас еще вовсю будет гореть смесь, которая уже должна быть отработанными газами.<br />
 Короче часть энергии – просто на ветер, а еще температура выпускного тракта поднимается, и еще есть негативные последствия. Стало быть, поджигать надо чуть раньше. Вот мы и подобрались к еще одной важнейшей количественной мере теории ДВС – углу опережения зажигания. Это угол по коленвалу между его положением в верхней мертвой точке и положением в момент подачи искры. Чем выше обороты, тем раньше надо поджечь, чтобы успело разгореться, тем больше соответственно угол. Выходит, нам с тобой надо знать положение коленвала в каждый момент времени.<br />
 И тут снова приходит на помощь наша любимая электроника. Вешаем на коленвал диск с зубчиками по краям, неподвижно у края диска закрепляем датчик (может быть датчиком Холла, индуктивным, да хоть оптическим). В простом случае хватает 60 зубчиков. При вращении коленвала датчик будет вырабатывать электрический сигнал (прямоугольный, синус, зависит от типа датчика). И самая главная хитрость – в одном или нескольких местах по окружности нашего диска убираем один зуб – теперь мы можем засечь КОНКРЕТНОЕ положение коленвала а дальше отсчитывать угол по импульсам датчика. Теперь мы поджигаем смесь не когда попало, а с нужным углом опережения. Больше оборотов – раньше генерим искру, меньше – позже. А что же происходит, когда давишь на газ? Элементарно – даешь мотору больше воздуха.<br />
 Мы не зря пошли плясать именно от воздуха – цепочка начинается с него. Больше воздуха измерили – больше впрыснули топлива – больше энергии выделилось – обороты увеличились(либо при тех же оборотах работаем на бОльшую нагрузку). Для регулирования потока воздуха поставим на его пути канал круглого сечения (называется дроссельный патрубок)и перекроем его круглым диском, надетым на ось, совпадающую с линией его диаметра так, что на этой оси он может поворачиваться. Поворачивая диск на оси регулируем поток воздуха – вуаля! Называется этот диск дроссельной заслонкой, управляется механически от педали газа, либо электронно (датчик на педали, исполнительный шаговик с датчиком положения на заслонке).<br />
 Вот так, в первом приближении оно все и работает. Знакомиться плотнее с системой управления, датчиками и исполнительными устройствами будем далее. Ждите новых материалов, задавайте вопросы, буду стараться отвечать.</p>
<img src="http://feeds.feedburner.com/~r/easyelectronics/~4/fh4tpEiJOfk" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://easyelectronics.ru/avtoelektrika-i-avtoelektronika-kurs-molodogo-bojca.html/feed</wfw:commentRss>
		<feedburner:origLink>http://easyelectronics.ru/avtoelektrika-i-avtoelektronika-kurs-molodogo-bojca.html</feedburner:origLink></item>
		<item>
		<title>Пульт дистанционного управления для фотоаппаратов Canon и Nikon</title>
		<link>http://feedproxy.google.com/~r/easyelectronics/~3/p9vdwZJi734/pult-distancionnogo-upravleniya-dlya-fotoapparatov-canon-i-nikon.html</link>
		<comments>http://easyelectronics.ru/pult-distancionnogo-upravleniya-dlya-fotoapparatov-canon-i-nikon.html#comments</comments>
		<pubDate>Tue, 08 Jun 2010 12:25:06 +0000</pubDate>
		<dc:creator>Maksoff</dc:creator>
		
		<category><![CDATA[Готовые устройства]]></category>

		<category><![CDATA[AVR]]></category>

		<category><![CDATA[Интерфейс]]></category>

		<category><![CDATA[Корпус]]></category>

		<guid isPermaLink="false">http://easyelectronics.ru/?p=319</guid>
		<description><![CDATA[Сильмаллирион
Случилось так, что примерно в одно и то же время у одних знакомых появился фотоаппарат Nikon, у другой знакомой - Canon, а в интернете я наткнулся на замечательную статью про пульт ДУ к ним.
Паять я люблю, а ещё больше я люблю делать подарки людям, а что может быть лучше действительно полезного подарка?
Но, поскольку с PIC-ами [...]]]></description>
			<content:encoded><![CDATA[<p><b>Сильмаллирион</b><br />
Случилось так, что примерно в одно и то же время у одних знакомых появился фотоаппарат Nikon, у другой знакомой - Canon, а в интернете я <a href="http://sappa.livejournal.com/13006.html" onclick="javascript:pageTracker._trackPageview('/outbound/article/sappa.livejournal.com');">наткнулся на замечательную статью</a> про пульт ДУ к ним.</p>
<p>Паять я люблю, а ещё больше я люблю делать подарки людям, а что может быть лучше действительно полезного подарка?<br />
Но, поскольку с PIC-ами я не дружу, то пульт я переделал под маленькую tiny2313, благо их везде навалом, и они весьма недорогие. Плюс, хотелось поставить рекорд скорости по сборке устройства.</p>
<p><b>Братство Кольца</b><br />
Немного теории, найденной на просторах интернета:<br />
для фотоаппаратов марки Canon собирается пульт RC-1 (RC-5 это такой же пульт, только без &#8220;моментального спуска&#8221;)</p>
<blockquote><p>-Несущая частота 33 кГц:<br />
-команда &#8220;Спуск&#8221;: посылка 480 мкс, пауза 7324 мкс, посылка 480 мкс<br />
-команда &#8220;Спуск с 2 сек. задержкой&#8221;: посылка 480 мкс, пауза 5371 мкс, посылка 480 мкс</p>
<p><b>Важно!</b><br />
Не у всех фотоаппаратов Canon есть ИК приёмник (обычно расположен на ручке, под спусковой кнопкой). Смотрите инструкцию к своему фотоаппарату!</p></blockquote>
<p>Nikon выбрал себе алгоритм похитрее, но всё равно мы и его скопируем:</p>
<blockquote><p>-Несущая частота 40 кГц:<br />
-команда &#8220;Спуск&#8221;: посылка 2250 мкс, пауза 27600 мкс, посылка 650 мкс, пауза 1375 мкс, посылка 575 мкс, пауза 3350 мкс, посылка 650 мкс. Потом пауза в 63 мс (милли- не микро-!!!) и повтор всей последовательности еще один раз</p></blockquote>
<p><span id="more-319"></span><br />
Интернет-народ утверждает, что лучше всего выбирать светодиоды с длиной волны 940 нм, я поверил им на слово.<br />
Самые дешевые светодиоды оказались SFH415-U, на 1.3-1.5 вольта и 100 мА, поэтому была выбрана таблеточная трёхвольтовая батарейка и последовательное соединение светодиодов.<br />
Для тактирования тини2313 я, естественно, использовал внутренний RC осциллятор на 1 Мгц.</p>
<p>Для экономии батарейки питание на микроконтроллер подается только при нажатии на кнопку спуска, после чего пульт отрабатывает посылку и отправляется в sleep (на случай если в сумке что-нибудь надавит на кнопку, батарейка не сдохла до съемки).</p>
<p><b>Две твердыни</b><br />
Ну что же, время составить схемку и написать программку.</p>
<p>Схемка для Никона:</p>
<table border="0" cellspacing="0" cellpadding="0" align=center>
<tr>
<td><img src="http://easyelectronics.ru/img/readydev/fotoIRpult/nikon_scheme.jpg" alt=""></td>
</tr>
</table>
<p>не отличается чем-либо особым. Конденсатор С2 выбран танталовым потому, что у него оооочень маленький ток утечки, поэтому батарейке ничего не должно грозить (кстати, этот пульт используется уже в течении года).</p>
<p>Схемка для Кэнона:</p>
<table border="0" cellspacing="0" cellpadding="0" align=center>
<tr>
<td><img src="http://easyelectronics.ru/img/readydev/fotoIRpult/canon_scheme.jpg" alt=""></td>
</tr>
</table>
<p>Тут уже повеселее. Я решил выбрать переключатель на три позиции, тем самым у меня появилось три &#8220;режима&#8221;:</p>
<ul>
<li>Выключен, чтобы при случайном нажатии на кнопку не садить батарейку. </li>
<li>Спуск с 2сек задержкой - чтобы при фотографировании себя успеть убрать пульт из кадра. </li>
<li>Немедленный спуск - отлично использовать для фотоохоты. Или фотографирования ночных пейзажей. Или для режима Bulb. </li>
</ul>
<p>Естественно, при желании можно выкинуть переключатель, и использовать просто две кнопки, например так:</p>
<table border="0" cellspacing="0" cellpadding="0" align=center>
<tr>
<td><img src="http://easyelectronics.ru/img/readydev/fotoIRpult/canon_2.jpg" alt=""></td>
</tr>
</table>
<p>Или вообще оставить одну только функцию, и взять схемку как для Никона, контроллер ведь один, поэтому прошивка там заливается любая. </p>
<p>Варьируя количество и ток светодиодов можно регулировать и дальнобойность устройства. В данном исполнении фотоаппарат уверенно принимал на расстоянии 5-6 метров, а также хорошо ловил отраженный сигнал. Правда, при увеличении количества светодиодов надо не забыть увеличить емкость танталового конденсатора.</p>
<p>Программа написана на С (для ускорения времени разработки и простоты вычисления задержек)<br />
Код для Никона:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
</pre></td><td class="code"><pre class="c c" style="font-family:monospace;"><span style="color: #339933;">#include &lt;avr/io.h&gt;</span>
<span style="color: #339933;">#include &lt;avr/sleep.h&gt;</span>
<span style="color: #339933;">#include &lt;util/delay.h&gt;</span>
&nbsp;
<span style="color: #339933;">#define led_port PORTD</span>
<span style="color: #339933;">#define led_ddr DDRD</span>
<span style="color: #339933;">#define led_pin (1&lt;&lt;6);</span>
&nbsp;
<span style="color: #339933;">#define nop() asm(&quot;nop&quot;)</span>
<span style="color: #666666; font-style: italic;">//Посылка двух импульсов, количество нопов выверено в симуляторе</span>
<span style="color: #339933;">#define two_pulses {led_port |= led_pin; nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop();</span>
nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>; nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>; nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>; led_port <span style="color: #339933;">&amp;=</span> ~led_pin; nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>; nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>; nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>; nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>; nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>; nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>; nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>; 
nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>; nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>; nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>; led_port |= led_pin; nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>; nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>; nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>; nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>; nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>; nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>; nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>; nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>; nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>; nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>; led_port <span style="color: #339933;">&amp;=</span> ~led_pin; nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>; nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>; nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>; nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>; nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>; nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>; <span style="color: #009900;">&#125;</span> <span style="color: #666666; font-style: italic;">//50 us</span>
&nbsp;
<span style="color: #666666; font-style: italic;">//Весь алгоритм передачи команды, ничего сверхъестественного</span>
<span style="color: #993333;">void</span> program <span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
	<span style="color: #993333;">unsigned</span> <span style="color: #993333;">char</span> i;
	<span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span>i <span style="color: #339933;">=</span> <span style="color:#800080;">0</span>; i <span style="color: #339933;">&lt;</span> <span style="color: #009900;">&#40;</span><span style="color: #0000dd;">2250</span><span style="color: #339933;">/</span><span style="color: #0000dd;">50</span><span style="color: #009900;">&#41;</span>; i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
		two_pulses;
	_delay_ms<span style="color: #009900;">&#40;</span><span style="color:#800080;">27.6</span><span style="color: #009900;">&#41;</span>;
	<span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span>i <span style="color: #339933;">=</span> <span style="color:#800080;">0</span>; i <span style="color: #339933;">&lt;</span> <span style="color: #009900;">&#40;</span><span style="color: #0000dd;">650</span><span style="color: #339933;">/</span><span style="color: #0000dd;">50</span><span style="color: #009900;">&#41;</span>; i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
		two_pulses;
	_delay_ms<span style="color: #009900;">&#40;</span><span style="color:#800080;">1.35</span><span style="color: #009900;">&#41;</span>;
	<span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span>i <span style="color: #339933;">=</span> <span style="color:#800080;">0</span>; i <span style="color: #339933;">&lt;</span> <span style="color: #009900;">&#40;</span><span style="color: #0000dd;">600</span><span style="color: #339933;">/</span><span style="color: #0000dd;">50</span><span style="color: #009900;">&#41;</span>; i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
		two_pulses;
	_delay_ms<span style="color: #009900;">&#40;</span><span style="color:#800080;">3.35</span><span style="color: #009900;">&#41;</span>;
	<span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span>i <span style="color: #339933;">=</span> <span style="color:#800080;">0</span>; i <span style="color: #339933;">&lt;</span> <span style="color: #009900;">&#40;</span><span style="color: #0000dd;">650</span><span style="color: #339933;">/</span><span style="color: #0000dd;">50</span><span style="color: #009900;">&#41;</span>; i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
		two_pulses;
&nbsp;
	_delay_ms<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">63</span><span style="color: #009900;">&#41;</span>;
&nbsp;
	<span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span>i <span style="color: #339933;">=</span> <span style="color:#800080;">0</span>; i <span style="color: #339933;">&lt;</span> <span style="color: #009900;">&#40;</span><span style="color: #0000dd;">2250</span><span style="color: #339933;">/</span><span style="color: #0000dd;">50</span><span style="color: #009900;">&#41;</span>; i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
		two_pulses;
	_delay_ms<span style="color: #009900;">&#40;</span><span style="color:#800080;">27.6</span><span style="color: #009900;">&#41;</span>;
	<span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span>i <span style="color: #339933;">=</span> <span style="color:#800080;">0</span>; i <span style="color: #339933;">&lt;</span> <span style="color: #009900;">&#40;</span><span style="color: #0000dd;">650</span><span style="color: #339933;">/</span><span style="color: #0000dd;">50</span><span style="color: #009900;">&#41;</span>; i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
		two_pulses;
	_delay_ms<span style="color: #009900;">&#40;</span><span style="color:#800080;">1.35</span><span style="color: #009900;">&#41;</span>;
	<span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span>i <span style="color: #339933;">=</span> <span style="color:#800080;">0</span>; i <span style="color: #339933;">&lt;</span> <span style="color: #009900;">&#40;</span><span style="color: #0000dd;">600</span><span style="color: #339933;">/</span><span style="color: #0000dd;">50</span><span style="color: #009900;">&#41;</span>; i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
		two_pulses;
	_delay_ms<span style="color: #009900;">&#40;</span><span style="color:#800080;">3.35</span><span style="color: #009900;">&#41;</span>;
	<span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span>i <span style="color: #339933;">=</span> <span style="color:#800080;">0</span>; i <span style="color: #339933;">&lt;</span> <span style="color: #009900;">&#40;</span><span style="color: #0000dd;">650</span><span style="color: #339933;">/</span><span style="color: #0000dd;">50</span><span style="color: #009900;">&#41;</span>; i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
		two_pulses;
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #993333;">int</span> main <span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
	MCUCR |= <span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">&lt;&lt;</span>SM0<span style="color: #009900;">&#41;</span>; <span style="color: #666666; font-style: italic;">//PowerDown</span>
	ACSR |= <span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">&lt;&lt;</span>ACD<span style="color: #009900;">&#41;</span>; <span style="color: #666666; font-style: italic;">//AnaComp Disable</span>
	led_ddr |= led_pin;
	_delay_ms<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">8</span><span style="color: #009900;">&#41;</span>;
	program<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
	sleep_enable<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
	sleep_cpu<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;	<span style="color: #666666; font-style: italic;">//Усыпляем до следующего включения питания	</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>А это для Кэнона:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
</pre></td><td class="code"><pre class="c c" style="font-family:monospace;"><span style="color: #339933;">#include &lt;avr/io.h&gt;</span>
<span style="color: #339933;">#include &lt;avr/sleep.h&gt;</span>
<span style="color: #339933;">#include &lt;util/delay.h&gt;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">//Leds port:</span>
<span style="color: #339933;">#define led_port PORTD</span>
<span style="color: #339933;">#define led_ddr DDRD</span>
<span style="color: #339933;">#define led_pin 6</span>
<span style="color: #339933;">#define led_one (1&lt;&lt;led_pin)</span>
<span style="color: #339933;">#define led_all (1&lt;&lt;led_pin)</span>
&nbsp;
<span style="color: #666666; font-style: italic;">//Delay 2 sec</span>
<span style="color: #339933;">#define pin_delay (1&lt;&lt;0) //PortB pin0 //for delay</span>
<span style="color: #339933;">#define all_button_pins pin_delay</span>
&nbsp;
<span style="color: #339933;">#define nop() asm(&quot;nop&quot;)</span>
&nbsp;
<span style="color: #666666; font-style: italic;">//Функция, которая отправляет одну посылку</span>
<span style="color: #993333;">void</span> Post <span style="color: #009900;">&#40;</span><span style="color: #993333;">char</span> bits_to_set<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
	<span style="color: #993333;">unsigned</span> <span style="color: #993333;">char</span> i;
	<span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span>i <span style="color: #339933;">=</span> <span style="color:#800080;">0</span>; i <span style="color: #339933;">&lt;</span> <span style="color: #0000dd;">16</span>; i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
	<span style="color: #009900;">&#123;</span>
		led_port |= bits_to_set;
		nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>; 
		nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
		nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
		nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
		nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
		nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
		nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
		nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
		nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
		nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
		nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
		nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
&nbsp;
		led_port <span style="color: #339933;">&amp;=</span> ~bits_to_set;
		nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
		nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
		nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
		nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
		nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
		nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
		nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
		nop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>; <span style="color: #666666; font-style: italic;">//Количество нопов высчитано в симуляторе</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">//Немедленный спуск</span>
<span style="color: #993333;">void</span> Shutter <span style="color: #009900;">&#40;</span><span style="color: #993333;">char</span> led<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
	Post<span style="color: #009900;">&#40;</span>led<span style="color: #009900;">&#41;</span>;
	_delay_ms<span style="color: #009900;">&#40;</span><span style="color:#800080;">7.324</span><span style="color: #009900;">&#41;</span>;
	Post<span style="color: #009900;">&#40;</span>led<span style="color: #009900;">&#41;</span>;
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">//Спуск с двух секундной задержкой</span>
<span style="color: #993333;">void</span> Shutter2 <span style="color: #009900;">&#40;</span><span style="color: #993333;">char</span> led<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
	Post<span style="color: #009900;">&#40;</span>led<span style="color: #009900;">&#41;</span>;
	_delay_ms<span style="color: #009900;">&#40;</span><span style="color:#800080;">5.371</span><span style="color: #009900;">&#41;</span>;
	Post<span style="color: #009900;">&#40;</span>led<span style="color: #009900;">&#41;</span>;
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #993333;">int</span> main <span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
	PORTB |= all_button_pins; <span style="color: #666666; font-style: italic;">//PullUp</span>
	led_ddr |= led_all; <span style="color: #666666; font-style: italic;">// DDR out</span>
	MCUCR |= <span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">&lt;&lt;</span>SM0<span style="color: #009900;">&#41;</span>; <span style="color: #666666; font-style: italic;">//PowerDown</span>
	ACSR |= <span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">&lt;&lt;</span>ACD<span style="color: #009900;">&#41;</span>; <span style="color: #666666; font-style: italic;">//AnaComp Disable</span>
	<span style="color: #b1b100;">for</span><span style="color: #009900;">&#40;</span>;;<span style="color: #009900;">&#41;</span>
	<span style="color: #009900;">&#123;</span>
		_delay_ms<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">8</span><span style="color: #009900;">&#41;</span>; <span style="color: #666666; font-style: italic;">//Debounce</span>
		<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>PINB<span style="color: #339933;">&amp;</span>pin_delay<span style="color: #009900;">&#41;</span><span style="color: #666666; font-style: italic;">//Проверяем состоние пина</span>
		<span style="color: #009900;">&#123;</span>
			Shutter2<span style="color: #009900;">&#40;</span>led_one<span style="color: #009900;">&#41;</span>;
		<span style="color: #009900;">&#125;</span>
		<span style="color: #b1b100;">else</span>
		<span style="color: #009900;">&#123;</span>
			Shutter<span style="color: #009900;">&#40;</span>led_one<span style="color: #009900;">&#41;</span>;
		<span style="color: #009900;">&#125;</span>
&nbsp;
		sleep_enable<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
		sleep_cpu<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>; <span style="color: #666666; font-style: italic;">//Усыпляем до следующего включения питания</span>
	<span style="color: #009900;">&#125;</span>	
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>Всё очень просто, никаких оптимизаций, просто следование алгоритму.<br />
Памяти занимает немного, можно без проблем перенести на какую-нибудь более мелкую Тини.</p>
<p><b>Возращение государя</b><br />
Конечно же, самое интересное &#8212; это корпус.</p>
<p>Для Никона, с его единственной кнопкой, подошел вот такой:</p>
<table border="1" cellspacing="1" cellpadding="1" align=center>
<tr>
<td><img src="http://easyelectronics.ru/img/readydev/fotoIRpult/nikon_box.jpg" alt=""></td>
</tr>
</table>
<p>К сожалению, его внутренностей не могу показать, далеко он от меня&#8230;</p>
<p>А вот для Кэнона корпус я делал недавно, поэтому парочка фоток есть :)</p>
<p>Рассыпуха деталек для будущего пульта:</p>
<table border="1" cellspacing="1" cellpadding="1" align=center>
<tr>
<td><img src="http://easyelectronics.ru/img/readydev/fotoIRpult/canon_box_1.jpg" alt=""></td>
</tr>
</table>
<p>С платой замарачиваться не стал, тем более корпус всего-то 50х30х20 мм, поэтому микрушку и всякие транзюки понапаял на макетку, дрелью да напильником сделал необходимые отверстия, переключатель посадил на клей, распаял паутинку проводов:</p>
<table border="1" cellspacing="1" cellpadding="1" align=center>
<tr>
<td><img src="http://easyelectronics.ru/img/readydev/fotoIRpult/canon_box_2.jpg" alt=""></td>
</tr>
</table>
<p>Корпус оказался ооочень маленький, так что влезло всё впритык. Прижав коленкой закрутил винтики, и вот что получилось:</p>
<table border="1" cellspacing="1" cellpadding="1" align=center>
<tr>
<td><img src="http://easyelectronics.ru/img/readydev/fotoIRpult/canon_box_3.jpg" alt=""></td>
</tr>
</table>
<p>Результатом доволен и я, и те кому достался пультик. А на написание этой статьи ушло примерно столько же времени, сколько на изготовление одного пультика :)</p>
<p><a href="http://easyelectronics.ru/img/readydev/fotoIRpult/studio%20files.zip" onclick="javascript:pageTracker._trackPageview('/downloads/img/readydev/fotoIRpult/studio%20files.zip');">Проект в AVR Studio</a></p>
<p>Если у вас какой-либо другой фотоаппарат, то <a href="http://sappa.livejournal.com/13006.html" onclick="javascript:pageTracker._trackPageview('/outbound/article/sappa.livejournal.com');"><b>то в статье от sappa</b></a> есть алгоритмы и для них. Дерзайте, творческих (в пайке и в фотографии) успехов вам!</p>
<p><strong>Bonus:</strong><br />
Ну и вот вам, бонусом, идея для корпуса кухонных часов. Со стратегическим запасом гречки на черный день.</p>
<table border="1" cellspacing="1" cellpadding="1" align=center>
<tr>
<td><img src="http://easyelectronics.ru/img/readydev/fotoIRpult/clock.jpg" alt=""></td>
</tr>
</table>
<img src="http://feeds.feedburner.com/~r/easyelectronics/~4/p9vdwZJi734" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://easyelectronics.ru/pult-distancionnogo-upravleniya-dlya-fotoapparatov-canon-i-nikon.html/feed</wfw:commentRss>
		<feedburner:origLink>http://easyelectronics.ru/pult-distancionnogo-upravleniya-dlya-fotoapparatov-canon-i-nikon.html</feedburner:origLink></item>
		<item>
		<title>AVR. Учебный Курс. Отладка программ. Часть 3</title>
		<link>http://feedproxy.google.com/~r/easyelectronics/~3/ZWzYNK-R29I/avr-uchebnyj-kurs-otladka-programm-chast-3.html</link>
		<comments>http://easyelectronics.ru/avr-uchebnyj-kurs-otladka-programm-chast-3.html#comments</comments>
		<pubDate>Sat, 29 May 2010 20:29:31 +0000</pubDate>
		<dc:creator>DI HALT</dc:creator>
		
		<category><![CDATA[AVR. Учебный курс]]></category>

		<category><![CDATA[Assembler]]></category>

		<category><![CDATA[AVR]]></category>

		<category><![CDATA[Отладка]]></category>

		<category><![CDATA[Трюки]]></category>

		<guid isPermaLink="false">http://easyelectronics.ru/?p=317</guid>
		<description><![CDATA[Метод 3. USART (Работа с последовательными интерфейсами)
Пожалуй самым популярным отладочным интерфейсом является все же USART. Во-первых, он поддерживается аппаратно почти всеми микроконтроллерами. Во-вторых, он прост в использовании и требует всего один/два сигнальных провода, а в третьих, для связи с компом не надо городить никаких специфичных девайсов. В худшем случае UART-USB или UART-RS232 конвертер на FT232RL [...]]]></description>
			<content:encoded><![CDATA[<p><font size="+1"><b>Метод 3. USART (Работа с последовательными интерфейсами)</b></font><br />
Пожалуй самым популярным отладочным интерфейсом является все же USART. Во-первых, он поддерживается аппаратно почти всеми микроконтроллерами. Во-вторых, он прост в использовании и требует всего один/два сигнальных провода, а в третьих, для связи с компом не надо городить никаких специфичных девайсов. В худшем случае UART-USB или UART-RS232 конвертер на FT232RL или MAX232. </p>
<p>Пользоваться им проще простого &#8212; в любой момент, когда нам это захочется, мы берем и отправляем нужный байт по этому интерфейсу. При этом достаточно заранее его настроить &#8212; стандартная инициализация UART:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="code"><pre class="avr avr" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">; Usart INIT</span>
		<span style="color: #339933;">.</span>equ 	XTAL = <span style="color: #0000ff;">8000000</span> 	
		<span style="color: #339933;">.</span>equ 	baudrate = <span style="color: #0000ff;">9600</span>  
		<span style="color: #339933;">.</span>equ 	bauddivider = XTAL<span style="color: #339933;">/</span><span style="color: #009900; font-weight: bold;">&#40;</span><span style="color: #0000ff;">16</span><span style="color: #339933;">*</span>baudrate<span style="color: #009900; font-weight: bold;">&#41;</span><span style="color: #339933;">-</span><span style="color: #0000ff;">1</span>
&nbsp;
uart_init<span style="color: #339933;">:</span>	<span style="color: #00007f; font-weight: bold;">LDI</span> 	<span style="color: #00007f;">R16</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">low</span><span style="color: #009900; font-weight: bold;">&#40;</span>bauddivider<span style="color: #009900; font-weight: bold;">&#41;</span>
		<span style="color: #00007f; font-weight: bold;">OUT</span> 	UBRRL<span style="color: #339933;">,</span><span style="color: #00007f;">R16</span>
		<span style="color: #00007f; font-weight: bold;">LDI</span> 	<span style="color: #00007f;">R16</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">high</span><span style="color: #009900; font-weight: bold;">&#40;</span>bauddivider<span style="color: #009900; font-weight: bold;">&#41;</span>
		<span style="color: #00007f; font-weight: bold;">OUT</span> 	UBRRH<span style="color: #339933;">,</span><span style="color: #00007f;">R16</span>
&nbsp;
		<span style="color: #00007f; font-weight: bold;">LDI</span> 	<span style="color: #00007f;">R16</span><span style="color: #339933;">,</span><span style="color: #0000ff;">0</span>
		<span style="color: #00007f; font-weight: bold;">OUT</span> 	UCSRA<span style="color: #339933;">,</span> <span style="color: #00007f;">R16</span></pre></td></tr></table></div>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
</pre></td><td class="code"><pre class="avr avr" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">; Прерывания запрещены, прием-передача разрешен.</span>
	<span style="color: #00007f; font-weight: bold;">LDI</span> 	<span style="color: #00007f;">R16</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">&#40;</span><span style="color: #0000ff;">1</span>&lt;&lt;RXEN<span style="color: #009900; font-weight: bold;">&#41;</span>|<span style="color: #009900; font-weight: bold;">&#40;</span><span style="color: #0000ff;">1</span>&lt;&lt;TXEN<span style="color: #009900; font-weight: bold;">&#41;</span>|<span style="color: #009900; font-weight: bold;">&#40;</span><span style="color: #0000ff;">0</span>&lt;&lt;RXCIE<span style="color: #009900; font-weight: bold;">&#41;</span>|<span style="color: #009900; font-weight: bold;">&#40;</span><span style="color: #0000ff;">0</span>&lt;&lt;TXCIE<span style="color: #009900; font-weight: bold;">&#41;</span>|<span style="color: #009900; font-weight: bold;">&#40;</span><span style="color: #0000ff;">0</span>&lt;&lt;UDRIE<span style="color: #009900; font-weight: bold;">&#41;</span>
	<span style="color: #00007f; font-weight: bold;">OUT</span> 	UCSRB<span style="color: #339933;">,</span> <span style="color: #00007f;">R16</span></pre></td></tr></table></div>

<p><b>Маркеры</b><br />
Всегда полезно знать где наша программа шляется в данный момент. Конечно, можно зажигать светодиодики, как в прошлом методе. Но когда точек много, то выводов не напасешься на эту затею. Или затрахаешься перекомпилировать. Проще всего натыкать в код маркеров, наступая на которые наш МК будет отрыгивать в терминал свое местоположение. Терминальный клиент будет писать лог и ничего не проморгаешь.<br />
 <span id="more-317"></span><br />
Для отправки надо записать наше маркерное число в регистр UDR, пусть это будет код буквы &#8220;А&#8221;.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
</pre></td><td class="code"><pre class="avr avr" style="font-family:monospace;">	<span style="color: #00007f; font-weight: bold;">LDI</span>	<span style="color: #00007f;">R16</span><span style="color: #339933;">,</span><span style="color: #7f007f;">'A'</span>
	<span style="color: #00007f; font-weight: bold;">OUT</span>	UDR<span style="color: #339933;">,</span><span style="color: #00007f;">R16</span></pre></td></tr></table></div>

<p>Я даже проверку на занятость UDR не делаю. Для одиночного байта, если у нас отправки по UART нет и участок не зациклен, этого вполне достаточно &#8212; регистр будет свободен. Разумеется в реальной программе такого делать не следует, но для отладочной затычки вполне сойдет. </p>
<p>Можно нафаршировать весь код такими вот затычками, но с разными буквами и смотреть в терминалке в каком порядке программа выполняется по выдаваемому слову. Правда учитывайте тот момент, что если данные будут сыпаться в терминалку быстрей чем она ее может прожевать, то регистр UDR захлебнется и у нас будет полная лажа. В этом случае можно сделать затычку чуть сложней, с ожиданием освобождения UDR</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
</pre></td><td class="code"><pre class="avr avr" style="font-family:monospace;">	<span style="color: #00007f; font-weight: bold;">LDI</span>	<span style="color: #00007f;">R16</span><span style="color: #339933;">,</span><span style="color: #7f007f;">'A'</span>
	<span style="color: #00007f; font-weight: bold;">SBIS</span> 	UCSRA<span style="color: #339933;">,</span>UDRE		<span style="color: #666666; font-style: italic;">; Пропуск если нет флага готовности</span>
	<span style="color: #00007f; font-weight: bold;">RJMP</span>	PC<span style="color: #339933;">-</span><span style="color: #0000ff;">1</span> 			<span style="color: #666666; font-style: italic;">; ждем готовности - флага UDRE</span>
 	<span style="color: #00007f; font-weight: bold;">OUT</span>	UDR<span style="color: #339933;">,</span> <span style="color: #00007f;">R16</span>		<span style="color: #666666; font-style: italic;">; шлем байт</span></pre></td></tr></table></div>

<p>Можно в макрос это запихать:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
</pre></td><td class="code"><pre class="avr avr" style="font-family:monospace;">	<span style="color: #339933;">.</span><span style="color: #000000; font-weight: bold;">MACRO</span>	DEB_SEND
	<span style="color: #00007f; font-weight: bold;">PUSH</span>	<span style="color: #00007f;">R16</span>
	<span style="color: #00007f; font-weight: bold;">LDI</span>	<span style="color: #00007f;">R16</span><span style="color: #339933;">,</span>@<span style="color: #0000ff;">0</span>
	<span style="color: #00007f; font-weight: bold;">SBIS</span>	UCSRA<span style="color: #339933;">,</span>UDRE
	<span style="color: #00007f; font-weight: bold;">RJMP</span>	PC<span style="color: #339933;">-</span><span style="color: #0000ff;">1</span>
	<span style="color: #00007f; font-weight: bold;">OUT</span>	UDR<span style="color: #339933;">,</span><span style="color: #00007f;">R16</span>
	<span style="color: #00007f; font-weight: bold;">POP</span>	<span style="color: #00007f;">R16</span>
	<span style="color: #339933;">.</span><span style="color: #000000; font-weight: bold;">ENDM</span></pre></td></tr></table></div>

<p>Заодно R16 в стеке спрячем, так что макрос можно юзать где угодно, словно команду:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="avr avr" style="font-family:monospace;">	DEB_SEND <span style="color: #7f007f;">'A'</span></pre></td></tr></table></div>

<p>Но это затормозит выполнение программы, могут полететь тайминги. Так что если у вас есть какие то участки жестко зависимые от времени (скажем тайминги протокола 1-wire), то данная затычка даст сбой. </p>
<p>Выводить можно любую инфу. Например содержание нужных регистров, содержание переменных, ячеек памяти, состояния битов регистров периферии. Что хотим поглядеть &#8212; то и тащим. Надо только загрузить это в UDR. А поскольку там могут быть произвольные значения, то глядеть их лучше через терминалку способную показывать в хексах. Например, моя любимая Terminal v1.9b.</p>
<p>Также полезно выбрасывать в терминал маркеры прохождения кода. Чтобы оценить правильность переходов и логики работы.</p>
<p> Еще настоятельно рекомендую заиметь спец литеру отправляемую в терминал сразу же после инициализации USART, еще до перехода к основной программе. У меня это обычно буква &#8220;R&#8221;. От &#8220;Reset&#8221;.  Это позволяет поймать момент перезагрузки контроллера.  </p>
<blockquote><p>Например, глючила у меня программа. Все работало нормально, но при попытке принять байт все начинало странно глючить. Все облазил, код весь до дыр проглядел. По коду все должно работать&#8230; Наконец воткнул в код OUTI UDR,&#8217;R&#8217; еще до вхождения в main. Опаньки &#8212; а контроллер то сбрасывается! </p>
<p> А почему контроллер может сбрасываться? Сбой по питанию я исключил сразу &#8212; не было там ничего такого, что бы могло дергаться. RESET был подтянут через 10кОм и особо тоже не вихлялся. Что еще?</p>
<p> Срыв стека, если произошел переход за конец кода, тоже похож на сброс &#8212; программа уходит за конец памяти и возвращается к нулевому адресу. Прошарил в отладчике и этот момент &#8212; нет срыва. Но может срыв не сразу, а спустя несколько итераций? Поставил .ORG на предпоследний адрес флеша и прописал туда маркер &#8212; не вылазит, значит срыва стека нет.<br />
 Да и код был прост как мычание, нечему там глючить.  Накидал отладочных маркеров по коду, засылающих байты в строго определенном порядке &#8212; в терминалке высветилась фраза &#8220;УБЕЙ СИБЯ АПСТОЛ&#8221; &#8212; значит прога работает четко по алгоритму. </p>
<p>Заглянул под панельку&#8230; Вот в чем засада &#8212; медная ворсинка от провода МГТФ попала между RXD и RST (На меге8 они совсем рядом) и при приходе байта в порт дрыганья на RXD сбрасывали контроллер. Соблюдайте чистоту на рабочем месте! Не допетри я тогда поставить на перезагрузку маркер, так я бы до утра ковырялся с кодом. А так я резко сузил круг возможных косяков и ушло не более десяти минут на отлов этого бага.</p></blockquote>
<p><b>Управление кодом, добыча произвольных данных</b><br />
Но не едиными маркерами сыт боец USART&#8217;овой  отладки. </p>
<p>Мы же можем не только слать, но и принимать! А принятое обрабатывать! Так что нам мешает делать полноценные брейкпоинты? </p>
<p>Скажем, такие:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
</pre></td><td class="code"><pre class="avr avr" style="font-family:monospace;">	<span style="color: #00007f; font-weight: bold;">PUSH</span>	<span style="color: #00007f;">R16</span>
	<span style="color: #00007f; font-weight: bold;">SBIS</span>	UCSRA<span style="color: #339933;">,</span>RXC
	<span style="color: #00007f; font-weight: bold;">RJMP</span>	PC<span style="color: #339933;">-</span><span style="color: #0000ff;">1</span>
	<span style="color: #00007f; font-weight: bold;">IN</span>	<span style="color: #00007f;">R16</span><span style="color: #339933;">,</span>UDR		<span style="color: #666666; font-style: italic;">; Читаем UDR, чтобы сбросить RXC флаг</span>
	<span style="color: #00007f; font-weight: bold;">POP</span>	<span style="color: #00007f;">R16</span></pre></td></tr></table></div>

<p>Данный код является банальным бряком, т.е. программа на ней встанет как вкопанная до тех пор, пока мы не зашлем ей байт в терминалку. Удобно, особенно когда осциллографа нет под рукой, можно, например, спокойно мультиметром уровни замерить на выводах, а потом пустить прогу до следующего чекпоинта. </p>
<p>В сочетании с маркерами дает еще и информацию о том, где мы встали. Но можно же и большее заиметь! </p>
<p>Что нам мешает сделать небольшой обработчик команд? Скажем, если мы послали R - выдаст значение нужного регистра, если М - ячейки памяти, I - байта из IO, а G - пойдет дальше:</p>
<p>Пример макроса может быть таким:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
</pre></td><td class="code"><pre class="avr avr" style="font-family:monospace;">	<span style="color: #339933;">.</span><span style="color: #000000; font-weight: bold;">MACRO</span>	DEB_CMD
	<span style="color: #00007f; font-weight: bold;">PUSH</span>	<span style="color: #00007f;">R16</span>		<span style="color: #666666; font-style: italic;">; Сохраняем регистр и флаги в стек</span>
	<span style="color: #00007f; font-weight: bold;">IN</span>	<span style="color: #00007f;">R16</span><span style="color: #339933;">,</span><span style="color: #00007f;">SREG</span>
	<span style="color: #00007f; font-weight: bold;">PUSH</span>	<span style="color: #00007f;">R16</span>
&nbsp;
	<span style="color: #00007f; font-weight: bold;">SBIS</span>	UCSRA<span style="color: #339933;">,</span>RXC
	<span style="color: #00007f; font-weight: bold;">RJMP</span>	PC<span style="color: #339933;">-</span><span style="color: #0000ff;">1</span>
	<span style="color: #00007f; font-weight: bold;">IN</span>	<span style="color: #00007f;">R16</span><span style="color: #339933;">,</span>UDR		<span style="color: #666666; font-style: italic;">; Читаем UDR, чтобы сбросить RXC флаг</span>
&nbsp;
				<span style="color: #666666; font-style: italic;">; Определяем что там пришло</span>
	<span style="color: #00007f; font-weight: bold;">CPI</span>	<span style="color: #00007f;">R16</span><span style="color: #339933;">,</span><span style="color: #7f007f;">'R'</span>
	<span style="color: #00007f; font-weight: bold;">BREQ</span>	PC<span style="color: #339933;">+</span><span style="color: #0000ff;">0x07</span>		<span style="color: #666666; font-style: italic;">; BREQ REGISTER</span>
&nbsp;
	<span style="color: #00007f; font-weight: bold;">CPI</span>	<span style="color: #00007f;">R16</span><span style="color: #339933;">,</span><span style="color: #7f007f;">'M'</span>
	<span style="color: #00007f; font-weight: bold;">BREQ</span>	PC<span style="color: #339933;">+</span><span style="color: #0000ff;">0x07</span>		<span style="color: #666666; font-style: italic;">; BREQ	MEMORY</span>
&nbsp;
	<span style="color: #00007f; font-weight: bold;">CPI</span>	<span style="color: #00007f;">R16</span><span style="color: #339933;">,</span><span style="color: #7f007f;">'I'</span>
	<span style="color: #00007f; font-weight: bold;">BREQ</span>	PC<span style="color: #339933;">+</span><span style="color: #0000ff;">0x09</span> 	<span style="color: #666666; font-style: italic;">; BREQ	IO</span>
&nbsp;
	<span style="color: #00007f; font-weight: bold;">CPI</span>	<span style="color: #00007f;">R16</span><span style="color: #339933;">,</span><span style="color: #7f007f;">'G'</span>
	<span style="color: #00007f; font-weight: bold;">BREQ</span>	PC<span style="color: #339933;">+</span><span style="color: #0000ff;">0x0A</span>		<span style="color: #666666; font-style: italic;">; BREQ GONEXT</span>
&nbsp;
&nbsp;
	<span style="color: #00007f; font-weight: bold;">OUT</span>	UDR<span style="color: #339933;">,</span>@<span style="color: #0000ff;">0</span>		<span style="color: #666666; font-style: italic;">; REGISTER - отправляем в UDR значение регистра</span>
	<span style="color: #00007f; font-weight: bold;">RJMP</span>	PC<span style="color: #339933;">+</span><span style="color: #0000ff;">0x0008</span>	<span style="color: #666666; font-style: italic;">; Проверка на пустоту UDR тут скорей всего не нужна.</span>
				<span style="color: #666666; font-style: italic;">; Т.к. пока впечатаешь ручкам в терминалку байт, наверняка </span>
				<span style="color: #666666; font-style: italic;">; все что хотело уйти уже уйдет и UDR опустошится.</span>
&nbsp;
	<span style="color: #00007f; font-weight: bold;">LDS</span>	<span style="color: #00007f;">R16</span><span style="color: #339933;">,</span>@<span style="color: #0000ff;">1</span>		<span style="color: #666666; font-style: italic;">; MEMORY - шлем значение из памяти</span>
	<span style="color: #00007f; font-weight: bold;">OUT</span>	UDR<span style="color: #339933;">,</span><span style="color: #00007f;">R16</span>
	<span style="color: #00007f; font-weight: bold;">RJMP</span>	PC<span style="color: #339933;">+</span><span style="color: #0000ff;">0x0004</span>
&nbsp;
	<span style="color: #00007f; font-weight: bold;">IN</span>	<span style="color: #00007f;">R16</span><span style="color: #339933;">,</span>@<span style="color: #0000ff;">2</span>		<span style="color: #666666; font-style: italic;">; IO - шлем значение из порта ввода-вывода.</span>
	<span style="color: #00007f; font-weight: bold;">OUT</span>	UDR<span style="color: #339933;">,</span><span style="color: #00007f;">R16</span>
&nbsp;
	<span style="color: #00007f; font-weight: bold;">POP</span>	<span style="color: #00007f;">R16</span>		<span style="color: #666666; font-style: italic;">; GONEXT - достаем все сохраненное из стека и идем дальше</span>
	<span style="color: #00007f; font-weight: bold;">OUT</span>	<span style="color: #00007f;">SREG</span><span style="color: #339933;">,</span><span style="color: #00007f;">R16</span>
	<span style="color: #00007f; font-weight: bold;">POP</span>	<span style="color: #00007f;">R16</span>
	<span style="color: #339933;">.</span><span style="color: #000000; font-weight: bold;">ENDM</span></pre></td></tr></table></div>

<p>Как видишь, макрос массово использует относительные переходы (иначе при вставке двух макросов метки будут дублироваться). Так что модифицировать его нужно очень осторожно. Высчитывая команды. Но есть спрособ проще - написать его вначале с обычными метками, скомпилить, запустить отладку, потом открыть дизассемблер (view->disassembler) и поглядеть там смещения. </p>
<p>Используется просто &#8212; вставляешь в код такую штуку:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="avr avr" style="font-family:monospace;">	DEB_CMD <span style="color: #00007f;">R15</span><span style="color: #339933;">,</span><span style="color: #0000ff;">0x0000</span><span style="color: #339933;">,</span><span style="color: #00007f;">PORTD</span></pre></td></tr></table></div>

<p>И при попадании в это место МК остановится и будет ждать приказа. По команде G - пойдет дальше. По команде R - даст содержание регистра R15, по команде M - содержание ячейки ОЗУ с адресом 0х0000, а по команде I - значение из порта PORTD. Порты, регистры, ячейки памяти вписываешь те которые хочешь посмотреть. Если нужно что то одно, то пишешь в ненужные поля любые подходящие значения. Ну или делаешь узкоспециализированные макросы под память, регистр и порт ВВ.</p>
<p> Можно еще прерывания запретить, чтобы стопор был полный, но не забывай, что всякие таймеры продолжают тикать самостоятельно вне зависимость от того работает МК или зациклен в ожидании команды. А еще, если включен WATCHDOG, то он может и за задницу укусить. Поэтому в макрос можно и команду WDR добавить, в цикл ожидания байта. </p>
<p>Более того, никто не запрещает написать простейший (или сложный) командный обработчик с шахматами и поэтессами, позволяющий указывать непосредственно в передаваемой команде какой ресурс надо забрать. Или что и в какой регистр записать, куда перейти&#8230; В общем, этакий микро SoftICE (если кто еще помнит этот легендарный отладчик).</p>
<p> А если дружишь с какими-нибудь Дельфями, то можешь снаружи и отладчик написать, который через этот супервизор будет выковыривать все нужные данные по USART и раскладывать их красивыми рядами на панельках, дабы было любо-дорого глядеть. <a href="http://avr.nikolaew.org/debug.htm" onclick="javascript:pageTracker._trackPageview('/outbound/article/avr.nikolaew.org');">Например Николев в своем отладочном модуле так и сделал, правда он через SPI работал, но не суть важно</a>.</p>
<p>Оставляю это на самостоятельное изучение :)</p>
<p>На Си все пишется примерно в том же ключе. Можешь функции забабахать под это дело. Можешь макросы, тут по желанию.</p>
<img src="http://feeds.feedburner.com/~r/easyelectronics/~4/ZWzYNK-R29I" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://easyelectronics.ru/avr-uchebnyj-kurs-otladka-programm-chast-3.html/feed</wfw:commentRss>
		<feedburner:origLink>http://easyelectronics.ru/avr-uchebnyj-kurs-otladka-programm-chast-3.html</feedburner:origLink></item>
		<item>
		<title>Организация древовидного меню</title>
		<link>http://feedproxy.google.com/~r/easyelectronics/~3/y2_CIHHdDoc/organizaciya-drevovidnogo-menyu.html</link>
		<comments>http://easyelectronics.ru/organizaciya-drevovidnogo-menyu.html#comments</comments>
		<pubDate>Sun, 16 May 2010 17:23:54 +0000</pubDate>
		<dc:creator>Steel.ne</dc:creator>
		
		<category><![CDATA[AVR. Учебный курс]]></category>

		<category><![CDATA[Алгоритм]]></category>

		<category><![CDATA[Программирование]]></category>

		<category><![CDATA[Язык Си]]></category>

		<guid isPermaLink="false">http://easyelectronics.ru/?p=316</guid>
		<description><![CDATA[Почти для всех проектов на микроконтроллере с экранчиком требуется система меню. Для каких-то  проектов одноуровневое, для других — многоуровневое древовидное. Памяти, как обычно, мало, поэтому хочется запихнуть все во флэш. 





Попутно, из проекта в проект, развивалась своя псевдоОС — таймеры, события, диспетчеры.
Я ее полностью писал на си, оптимизацией и вылизыванием еще не занимался. 
Перебирая [...]]]></description>
			<content:encoded><![CDATA[<p>Почти для всех проектов на микроконтроллере с экранчиком требуется система меню. Для каких-то  проектов одноуровневое, для других — многоуровневое древовидное. Памяти, как обычно, мало, поэтому хочется запихнуть все во флэш. </p>
<table border="0" cellspacing="0" cellpadding="0" align=center>
<tr>
<td><img src="http://easyelectronics.ru/img/AVR_kurs/C/menu/pic_menu1.gif" alt=""></td>
</tr>
</table>
<p>Попутно, из проекта в проект, развивалась своя псевдоОС — таймеры, события, диспетчеры.<br />
Я ее полностью писал на си, оптимизацией и вылизыванием еще не занимался. </p>
<p>Перебирая разные системы, наткнулся на <a href="http://www.avrfreaks.net/index.php?module=Freaks%20Files&#038;func=viewFile&#038;id=2178&#038;showinfo=1" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.avrfreaks.net');">MicroMenu</a>:</p>
<p>Попробуем разобрать ее на части и прикрутить к системе.<br />
<span id="more-316"></span><br />
<b>Структура данных:</b><br />
Меню организовано в виде четырехсвязного списка. Каждый элемент меню (пункт меню) ссылается на предыдущего и последующего элемента, также ссылается на своего родителя (пункт меню предыдущего уровня) и потомка (пункт подменю). Если это первый пункт, то предыдущего элемента у него нет, соответствующая ссылка пустая. </p>
<p>Изобразим это на рисунке:</p>
<table border="0" cellspacing="0" cellpadding="0" align=center>
<tr>
<td><img src="http://easyelectronics.ru/img/AVR_kurs/C/menu/pic_menu2.gif" alt=""></td>
</tr>
</table>
<p>Для чего такая избыточность? По сути,  с текущим пунктом меню можно сделать четыре вещи: </p>
<ul>
<li> Перейти вверх или вниз (предыдущий или следующий пункт) </li>
<li> Вернуться в родительское меню (если есть) </li>
<li> Выбрать текущий пункт. При этом мы или переходим в подменю (ели оно есть), или выполняется команда, прикрепленная к этому пункту меню. </li>
</ul>
<p>При наличии джойстика (или четырех кнопок «крестом») эти действия как раз вешаются на свою кнопку.</p>
<p>Соответственно, все эти действия отражают четыре указателя. В оригинальной системе указатель на потомка обозван SIBLING, но я считаю это идеологически неверным. Sibling – это родственник того же уровня. Брат или сестра. Но никак не потомок. Поэтому мы будем использовать идеологически выверенное CHILD.</p>
<p>Итак, описание структуры пункта меню:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
</pre></td><td class="code"><pre class="c c" style="font-family:monospace;"><span style="color: #993333;">typedef</span> <span style="color: #993333;">struct</span> PROGMEM<span style="color: #009900;">&#123;</span>
	<span style="color: #993333;">void</span>       <span style="color: #339933;">*</span>Next;
	<span style="color: #993333;">void</span>       <span style="color: #339933;">*</span>Previous;
	<span style="color: #993333;">void</span>       <span style="color: #339933;">*</span>Parent;
	<span style="color: #993333;">void</span>       <span style="color: #339933;">*</span>Child;
	uint8_t     Select;
	<span style="color: #993333;">const</span> <span style="color: #993333;">char</span>  Text<span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span>;
<span style="color: #009900;">&#125;</span> menuItem;</pre></td></tr></table></div>

<p>Добавлен байт Select – это код команды, привязанный к текущему пункту. Если у данного пункта есть подменю, код нулевой. Также есть поле Text. Капитан Очевидность подсказывает, что это, собственно, текст пункта меню. По расходам памяти — на каждый пункт меню расходуется 9 байт плюс длина текстовой части. И это все — кладется во флеш.</p>
<p>Самое полезное, почерпнутое у MicroMenu – набор дефайнов для быстрого и удобного определения меню.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
</pre></td><td class="code"><pre class="c c" style="font-family:monospace;"><span style="color: #339933;">#define MAKE_MENU(Name, Next, Previous, Parent, Child, Select, Text) \</span>
	<span style="color: #000000; font-weight: bold;">extern</span> menuItem Next;     \
	<span style="color: #000000; font-weight: bold;">extern</span> menuItem Previous; \
	<span style="color: #000000; font-weight: bold;">extern</span> menuItem Parent;   \
	<span style="color: #000000; font-weight: bold;">extern</span> menuItem Child;  \
	menuItem Name <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">&amp;</span>Next<span style="color: #339933;">,</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">&amp;</span>Previous<span style="color: #339933;">,</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">&amp;</span>Parent<span style="color: #339933;">,</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">&amp;</span>Child<span style="color: #339933;">,</span> <span style="color: #009900;">&#40;</span>uint8_t<span style="color: #009900;">&#41;</span>Select<span style="color: #339933;">,</span> <span style="color: #009900;">&#123;</span> Text <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

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

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
</pre></td><td class="code"><pre class="c c" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// для начала — пустой элемент. Который NULL на рисунке</span>
<span style="color: #339933;">#define NULL_ENTRY Null_Menu</span>
menuItem	Null_Menu <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span><span style="color:#800080;">0</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span><span style="color:#800080;">0</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span><span style="color:#800080;">0</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span><span style="color:#800080;">0</span><span style="color: #339933;">,</span> <span style="color:#800080;">0</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#123;</span><span style="color: #208080;">0x00</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#125;</span>;
&nbsp;
<span style="color: #000000; font-weight: bold;">enum</span> <span style="color: #009900;">&#123;</span>
    MENU_CANCEL<span style="color: #339933;">=</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span>
    MENU_RESET<span style="color: #339933;">,</span>
    MENU_MODE1<span style="color: #339933;">,</span>
    MENU_MODE2<span style="color: #339933;">,</span>
    MENU_MODE3<span style="color: #339933;">,</span>
    MENU_SENS1<span style="color: #339933;">,</span>
    MENU_SENS2<span style="color: #339933;">,</span>
<span style="color: #009900;">&#125;</span>;
&nbsp;
<span style="color: #666666; font-style: italic;">//                 NEXT,      PREVIOUS     PARENT,     CHILD</span>
MAKE_MENU<span style="color: #009900;">&#40;</span>m_s1i1<span style="color: #339933;">,</span>  m_s1i2<span style="color: #339933;">,</span>    NULL_ENTRY<span style="color: #339933;">,</span>  NULL_ENTRY<span style="color: #339933;">,</span> m_s2i1<span style="color: #339933;">,</span>       <span style="color:#800080;">0</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;Запуск&quot;</span><span style="color: #009900;">&#41;</span>;
MAKE_MENU<span style="color: #009900;">&#40;</span>m_s1i2<span style="color: #339933;">,</span>  m_s1i3<span style="color: #339933;">,</span>    m_s1i1<span style="color: #339933;">,</span>      NULL_ENTRY<span style="color: #339933;">,</span> m_s3i1<span style="color: #339933;">,</span>       <span style="color:#800080;">0</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;Настройка&quot;</span><span style="color: #009900;">&#41;</span>;
MAKE_MENU<span style="color: #009900;">&#40;</span>m_s1i3<span style="color: #339933;">,</span>  NULL_ENTRY<span style="color: #339933;">,</span>m_s1i2<span style="color: #339933;">,</span>      NULL_ENTRY<span style="color: #339933;">,</span> NULL_ENTRY<span style="color: #339933;">,</span>   MENU_RESET<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;Сброс&quot;</span><span style="color: #009900;">&#41;</span>;
&nbsp;
<span style="color: #666666; font-style: italic;">// подменю Запуск</span>
MAKE_MENU<span style="color: #009900;">&#40;</span>m_s2i1<span style="color: #339933;">,</span>  m_s2i2<span style="color: #339933;">,</span>    NULL_ENTRY<span style="color: #339933;">,</span>  m_s1i1<span style="color: #339933;">,</span>     NULL_ENTRY<span style="color: #339933;">,</span>   MENU_MODE1<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;Режим 1&quot;</span><span style="color: #009900;">&#41;</span>;
MAKE_MENU<span style="color: #009900;">&#40;</span>m_s2i2<span style="color: #339933;">,</span>  m_s2i3<span style="color: #339933;">,</span>    m_s2i1<span style="color: #339933;">,</span>      m_s1i1<span style="color: #339933;">,</span>     NULL_ENTRY<span style="color: #339933;">,</span>   MENU_MODE2<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;Режим 2&quot;</span><span style="color: #009900;">&#41;</span>;
MAKE_MENU<span style="color: #009900;">&#40;</span>m_s2i3<span style="color: #339933;">,</span>  NULL_ENTRY<span style="color: #339933;">,</span>m_s2i2<span style="color: #339933;">,</span>      m_s1i1<span style="color: #339933;">,</span>     NULL_ENTRY<span style="color: #339933;">,</span>   MENU_MODE3<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;Режим 3&quot;</span><span style="color: #009900;">&#41;</span>;
&nbsp;
<span style="color: #666666; font-style: italic;">// подменю Настройка</span>
MAKE_MENU<span style="color: #009900;">&#40;</span>m_s3i1<span style="color: #339933;">,</span>  m_s3i2<span style="color: #339933;">,</span>    NULL_ENTRY<span style="color: #339933;">,</span>  m_s1i2<span style="color: #339933;">,</span>     m_s4i1<span style="color: #339933;">,</span>       <span style="color:#800080;">0</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;Давление&quot;</span><span style="color: #009900;">&#41;</span>;
MAKE_MENU<span style="color: #009900;">&#40;</span>m_s3i2<span style="color: #339933;">,</span>  NULL_ENTRY<span style="color: #339933;">,</span>m_s3i1<span style="color: #339933;">,</span>      m_s1i2<span style="color: #339933;">,</span>     m_s5i1<span style="color: #339933;">,</span>       <span style="color:#800080;">0</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;Время&quot;</span><span style="color: #009900;">&#41;</span>;
&nbsp;
<span style="color: #666666; font-style: italic;">// подменю Давление</span>
MAKE_MENU<span style="color: #009900;">&#40;</span>m_s4i1<span style="color: #339933;">,</span>  m_s4i2<span style="color: #339933;">,</span>    NULL_ENTRY<span style="color: #339933;">,</span>  m_s3i1<span style="color: #339933;">,</span>     NULL_ENTRY<span style="color: #339933;">,</span>   MENU_SENS1<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;Датчик 1&quot;</span><span style="color: #009900;">&#41;</span>;
MAKE_MENU<span style="color: #009900;">&#40;</span>m_s4i2<span style="color: #339933;">,</span>  NULL_ENTRY<span style="color: #339933;">,</span>m_s4i1<span style="color: #339933;">,</span>      m_s3i1<span style="color: #339933;">,</span>     NULL_ENTRY<span style="color: #339933;">,</span>   MENU_SENS2<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;Датчик 2&quot;</span><span style="color: #009900;">&#41;</span>;
&nbsp;
<span style="color: #666666; font-style: italic;">// подменю Время</span>
MAKE_MENU<span style="color: #009900;">&#40;</span>m_s5i1<span style="color: #339933;">,</span>  m_s5i2<span style="color: #339933;">,</span>    NULL_ENTRY<span style="color: #339933;">,</span>  m_s3i2<span style="color: #339933;">,</span>     NULL_ENTRY<span style="color: #339933;">,</span>   MENU_WARM<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;Разогрев&quot;</span><span style="color: #009900;">&#41;</span>;
MAKE_MENU<span style="color: #009900;">&#40;</span>m_s5i2<span style="color: #339933;">,</span>  NULL_ENTRY<span style="color: #339933;">,</span>m_s5i1<span style="color: #339933;">,</span>      m_s3i2<span style="color: #339933;">,</span>     NULL_ENTRY<span style="color: #339933;">,</span>   MENU_PROCESS<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;Процесс&quot;</span><span style="color: #009900;">&#41;</span>;</pre></td></tr></table></div>

<p>Готово!</p>
<p>Естественно, пункты меню можно описывать и вперемешку, в порядке обхода дерева. Типа такого:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
</pre></td><td class="code"><pre class="c c" style="font-family:monospace;">MAKE_MENU<span style="color: #009900;">&#40;</span>m_s1i1<span style="color: #339933;">,</span>  m_s1i2<span style="color: #339933;">,</span>    NULL_ENTRY<span style="color: #339933;">,</span>  NULL_ENTRY<span style="color: #339933;">,</span> m_s2i1<span style="color: #339933;">,</span>       <span style="color:#800080;">0</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;Запуск&quot;</span><span style="color: #009900;">&#41;</span>;
    <span style="color: #666666; font-style: italic;">// подменю Запуск</span>
    MAKE_MENU<span style="color: #009900;">&#40;</span>m_s2i1<span style="color: #339933;">,</span>  m_s2i2<span style="color: #339933;">,</span>    NULL_ENTRY<span style="color: #339933;">,</span>  m_s1i1<span style="color: #339933;">,</span>     NULL_ENTRY<span style="color: #339933;">,</span>   MENU_MODE1<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;Режим 1&quot;</span><span style="color: #009900;">&#41;</span>;
    MAKE_MENU<span style="color: #009900;">&#40;</span>m_s2i2<span style="color: #339933;">,</span>  m_s2i3<span style="color: #339933;">,</span>    m_s2i1<span style="color: #339933;">,</span>      m_s1i1<span style="color: #339933;">,</span>     NULL_ENTRY<span style="color: #339933;">,</span>   MENU_MODE2<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;Режим 2&quot;</span><span style="color: #009900;">&#41;</span>;
    MAKE_MENU<span style="color: #009900;">&#40;</span>m_s2i3<span style="color: #339933;">,</span>  NULL_ENTRY<span style="color: #339933;">,</span>m_s2i2<span style="color: #339933;">,</span>      m_s1i1<span style="color: #339933;">,</span>     NULL_ENTRY<span style="color: #339933;">,</span>   MENU_MODE3<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;Режим 3&quot;</span><span style="color: #009900;">&#41;</span>;
MAKE_MENU<span style="color: #009900;">&#40;</span>m_s1i2<span style="color: #339933;">,</span>  m_s1i3<span style="color: #339933;">,</span>    m_s1i1<span style="color: #339933;">,</span>      NULL_ENTRY<span style="color: #339933;">,</span> m_s3i1<span style="color: #339933;">,</span>       <span style="color:#800080;">0</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;Настройка&quot;</span><span style="color: #009900;">&#41;</span>;</pre></td></tr></table></div>

<p>Можно даже пойти дальше — строить меню в какой-нибудь визуальной среде, а потом автоматически генерировать такой список. Но это на потом.</p>
<p>Плюсы и минусы такой организации. Минус — явная избыточность. Плюс — возможность быстро редактировать меню — вставить новый пункт, поменять местами, удалить. Изменяются только соседние элементы меню, без тотальной перенумерации. Мне этот плюс перевесил все остальные минусы.</p>
<p>Опять же бонус — можно организовать несколько не связанных друг с другом деревьев меню. Главное не потерять точку входа.</p>
<p>Дальше. Как ходить по меню. Автор предлагает несколько дефайнов. Я их сохранил, хотя можно и без них обойтись.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="code"><pre class="c c" style="font-family:monospace;"><span style="color: #339933;">#define PREVIOUS   ((menuItem*)pgm_read_word(&amp;selectedMenuItem-&gt;Previous))</span>
<span style="color: #339933;">#define NEXT       ((menuItem*)pgm_read_word(&amp;selectedMenuItem-&gt;Next))</span>
<span style="color: #339933;">#define PARENT     ((menuItem*)pgm_read_word(&amp;selectedMenuItem-&gt;Parent))</span>
<span style="color: #339933;">#define CHILD      ((menuItem*)pgm_read_word(&amp;selectedMenuItem-&gt;Child))</span>
<span style="color: #339933;">#define SELECT	    (pgm_read_byte(&amp;selectedMenuItem-&gt;Select))</span>
&nbsp;
menuItem<span style="color: #339933;">*</span> selectedMenuItem; <span style="color: #666666; font-style: italic;">// текущий пункт меню</span>
&nbsp;
<span style="color: #993333;">void</span> menuChange<span style="color: #009900;">&#40;</span>menuItem<span style="color: #339933;">*</span> NewMenu<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span>NewMenu <span style="color: #339933;">==</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">&amp;</span>NULL_ENTRY<span style="color: #009900;">&#41;</span>
	  <span style="color: #b1b100;">return</span>;
&nbsp;
	selectedMenuItem <span style="color: #339933;">=</span> NewMenu;
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

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

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="c c" style="font-family:monospace;">menuChange<span style="color: #009900;">&#40;</span>PREVIOUS<span style="color: #009900;">&#41;</span>;</pre></td></tr></table></div>

<p>Далее, процедура реакции на нажатие клавиш (в качестве параметра передается код нажатой клавиши):</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
</pre></td><td class="code"><pre class="c c" style="font-family:monospace;">uint8_t keyMenu<span style="color: #009900;">&#40;</span>msg_par par<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #b1b100;">switch</span> <span style="color: #009900;">&#40;</span>par<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #b1b100;">case</span> <span style="color:#800080;">0</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #b1b100;">return</span> <span style="color: #0000dd;">1</span>;
	<span style="color: #009900;">&#125;</span>
	<span style="color: #b1b100;">case</span> KEY_UP<span style="color: #339933;">:</span> <span style="color: #009900;">&#123;</span>
		menuChange<span style="color: #009900;">&#40;</span>PREVIOUS<span style="color: #009900;">&#41;</span>;
		<span style="color: #000000; font-weight: bold;">break</span>;
	<span style="color: #009900;">&#125;</span>
	<span style="color: #b1b100;">case</span> KEY_DOWN<span style="color: #339933;">:</span> <span style="color: #009900;">&#123;</span>
		menuChange<span style="color: #009900;">&#40;</span>NEXT<span style="color: #009900;">&#41;</span>;
		<span style="color: #000000; font-weight: bold;">break</span>;
	<span style="color: #009900;">&#125;</span>
	<span style="color: #b1b100;">case</span> KEY_RIGHT<span style="color: #339933;">:</span>
		;
	<span style="color: #b1b100;">case</span> KEY_OK<span style="color: #339933;">:</span>
		<span style="color: #009900;">&#123;</span> <span style="color: #666666; font-style: italic;">// выбор пункта</span>
			uint8_t sel;
			sel <span style="color: #339933;">=</span> SELECT;
			<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>sel <span style="color: #339933;">!=</span> <span style="color:#800080;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
				sendMessage<span style="color: #009900;">&#40;</span>MSG_MENU_SELECT<span style="color: #339933;">,</span> sel<span style="color: #009900;">&#41;</span>;
&nbsp;
				killHandler<span style="color: #009900;">&#40;</span>MSG_KEY_PRESS<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>keyMenu<span style="color: #009900;">&#41;</span>;
				killHandler<span style="color: #009900;">&#40;</span>MSG_DISP_REFRESH<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>dispMenu<span style="color: #009900;">&#41;</span>;
&nbsp;
				<span style="color: #b1b100;">return</span> <span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span>;
			<span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span>
				menuChange<span style="color: #009900;">&#40;</span>CHILD<span style="color: #009900;">&#41;</span>;
			<span style="color: #009900;">&#125;</span>
			<span style="color: #000000; font-weight: bold;">break</span>;
		<span style="color: #009900;">&#125;</span>
	<span style="color: #b1b100;">case</span> KEY_LEFT<span style="color: #339933;">:</span> <span style="color: #009900;">&#123;</span> <span style="color: #666666; font-style: italic;">// отмена выбора (возврат)</span>
		menuChange<span style="color: #009900;">&#40;</span>PARENT<span style="color: #009900;">&#41;</span>;
	<span style="color: #009900;">&#125;</span>
	<span style="color: #009900;">&#125;</span>
	dispMenu<span style="color: #009900;">&#40;</span><span style="color:#800080;">0</span><span style="color: #009900;">&#41;</span>;
	<span style="color: #b1b100;">return</span> <span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span>;
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>Процедура отрисовки меню. Зависит от выбранного экранчика, а также от используемой анимации при выборе. Например у меня экранчик 128х64 точки, текущий пункт меню всегда по середине экрана, сверху и снизу выводятся два предыдущих и два последующих элемента (если есть). Отрисовка вызывается после каждого нажатися на кнопку и по таймеру, два раза в секунду. Мало ли, может изменится что.<br />
В шапке можно выводить текст родителя, чтобы знать, где находимся. Можно двигать курсор по пунктам, а не пункты прокручивать. На вкус и цвет все фломастеры разные.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
</pre></td><td class="code"><pre class="c c" style="font-family:monospace;"><span style="color: #993333;">char</span><span style="color: #339933;">*</span> menuText<span style="color: #009900;">&#40;</span>int8_t menuShift<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
	int8_t i;
	menuItem<span style="color: #339933;">*</span> tempMenu;
&nbsp;
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span>selectedMenuItem <span style="color: #339933;">==</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">&amp;</span>NULL_ENTRY<span style="color: #009900;">&#41;</span>
	  <span style="color: #b1b100;">return</span> strNULL;
&nbsp;
	i <span style="color: #339933;">=</span> menuShift;
	tempMenu <span style="color: #339933;">=</span> selectedMenuItem;
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>i<span style="color: #339933;">&gt;</span><span style="color:#800080;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #b1b100;">while</span><span style="color: #009900;">&#40;</span> i<span style="color: #339933;">!=</span><span style="color:#800080;">0</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span>tempMenu <span style="color: #339933;">!=</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">&amp;</span>NULL_ENTRY<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
				tempMenu <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>menuItem<span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span>pgm_read_word<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>tempMenu<span style="color: #339933;">-&gt;</span>Next<span style="color: #009900;">&#41;</span>;
			<span style="color: #009900;">&#125;</span>
			i--;
		<span style="color: #009900;">&#125;</span>
	<span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #b1b100;">while</span><span style="color: #009900;">&#40;</span> i<span style="color: #339933;">!=</span><span style="color:#800080;">0</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span>tempMenu <span style="color: #339933;">!=</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">&amp;</span>NULL_ENTRY<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
				tempMenu <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>menuItem<span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span>pgm_read_word<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>tempMenu<span style="color: #339933;">-&gt;</span>Previous<span style="color: #009900;">&#41;</span>;
			<span style="color: #009900;">&#125;</span>
			i++;
		<span style="color: #009900;">&#125;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span>tempMenu <span style="color: #339933;">==</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">&amp;</span>NULL_ENTRY<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #b1b100;">return</span> strNULL;
	<span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #b1b100;">return</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">char</span> <span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span>tempMenu<span style="color: #339933;">-&gt;</span>Text<span style="color: #009900;">&#41;</span>;
	<span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #993333;">unsigned</span> <span style="color: #993333;">char</span> dispMenu<span style="color: #009900;">&#40;</span>msg_par par<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #993333;">char</span> buf<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">25</span><span style="color: #009900;">&#93;</span>;
&nbsp;
	LCD_clear<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
&nbsp;
	sprintf_P<span style="color: #009900;">&#40;</span>buf<span style="color: #339933;">,</span> PSTR<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;&gt;%-20S&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> menuText<span style="color: #009900;">&#40;</span><span style="color:#800080;">0</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>;
	LCD_putsXY<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">2</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">28</span><span style="color: #339933;">,</span> buf<span style="color: #009900;">&#41;</span>;
&nbsp;
	sprintf_P<span style="color: #009900;">&#40;</span>buf<span style="color: #339933;">,</span> PSTR<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%-20S&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> menuText<span style="color: #009900;">&#40;</span><span style="color: #339933;">-</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>;
	LCD_putsXY<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">2</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">8</span><span style="color: #339933;">,</span> buf<span style="color: #009900;">&#41;</span>;
&nbsp;
	sprintf_P<span style="color: #009900;">&#40;</span>buf<span style="color: #339933;">,</span> PSTR<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%-20S&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> menuText<span style="color: #009900;">&#40;</span><span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>;
	LCD_putsXY<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">5</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">17</span><span style="color: #339933;">,</span> buf<span style="color: #009900;">&#41;</span>;
&nbsp;
&nbsp;
	sprintf_P<span style="color: #009900;">&#40;</span>buf<span style="color: #339933;">,</span> PSTR<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%-20S&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> menuText<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>;
	LCD_putsXY<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">5</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">39</span><span style="color: #339933;">,</span> buf<span style="color: #009900;">&#41;</span>;
&nbsp;
	sprintf_P<span style="color: #009900;">&#40;</span>buf<span style="color: #339933;">,</span> PSTR<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%-20S&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> menuText<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>;
	LCD_putsXY<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">2</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">48</span><span style="color: #339933;">,</span> buf<span style="color: #009900;">&#41;</span>;
&nbsp;
	LCD_drawLine<span style="color: #009900;">&#40;</span><span style="color:#800080;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">26</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">127</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">26</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span>;
	LCD_drawLine<span style="color: #009900;">&#40;</span><span style="color:#800080;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">34</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">127</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">34</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span>;
&nbsp;
	<span style="color: #b1b100;">return</span> <span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span>;
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>И последний штрих — инициализация меню:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
</pre></td><td class="code"><pre class="c c" style="font-family:monospace;"><span style="color: #993333;">void</span> startMenu<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	selectedMenuItem <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>menuItem<span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">&amp;</span>m_l1i1;
&nbsp;
	dispMenu<span style="color: #009900;">&#40;</span><span style="color:#800080;">0</span><span style="color: #009900;">&#41;</span>;
	setHandler<span style="color: #009900;">&#40;</span>MSG_KEY_PRESS<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>keyMenu<span style="color: #009900;">&#41;</span>;
	setHandler<span style="color: #009900;">&#40;</span>MSG_DISP_REFRESH<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>dispMenu<span style="color: #009900;">&#41;</span>;
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>Для начала хватит. В продолжении — сделать несколько меню, сделать процедуру работы с меню реентерабельной, забабахать модель в протеусе.</p>
<p>Краткое описание того, что делает процедура setHandler - она привязывает обработчик к событию. В данном случае, при возникновении события MSG_KEY_PRESS вызовется функция keyMenu для обработки этого события.</p>
<p>Для демонстрации системы меню, описанной в предыдущем посте, собрал модель в протеусе. На базе двухстрочного LCD-индикатора, контроллераatmega32 и пяти кнопок (влево-вправо-вверх-вниз и выбор). В своих схемах использую джойстики от мобилок, они тоже пятипозиционные. Также воткнул три светодиода, чтобы хоть как-то реагировать на выбор пунктов меню.</p>
<p>Поскольку на экране у нас всего две строчки, решил отображение меню сделать горизонтальным. В верхней строчке отображается родительский пункт меню (или просто &#8220;Меню:&#8221;, если мы на верхнем уровне), во второй строчке - текущий пункт меню. Клавишами влево-вправо выбираем предыдущий-следующий. Клавишей вверх - возвращаемся в родительское меню, клавиша вниз (или ОК) - заходим в выбранный пункт.</p>
<p><strong>Обработка меню:</strong></p>
<ul>
<li>при выборе пунктов Start/Mode 1, Start/Mode 2, Start/Mode 3 загорается соответствующий светодиод </li>
<li>при выборе пункта Reset - все светодиоды гаснут </li>
<li>после выбора любого конечного пункта, возвращаемся обратно в корень меню. </li>
</ul>
<p><strong>Некоторые модификации, связанные с моделированием:</strong></p>
<ul>
<li>заменил весь текст на английский, потому что в оригинале модель экранчика не поддерживает русский язык. Да, я знаю, про замену dll, но не у всех она есть, а для просмотра - пойдет. </li>
<li>моя боевая библиотека работы с LCD почему-то отказалась работать с моделью. Поэтому взял какую-то первую попавшуюся из древнего проекта. </li>
<li>отключил автоповтор кнопок (на модели неудобно работать), но он есть </li>
</ul>
<p>Ну и, надеюсь, мне простят подключение светодиодов без балластного резистора? ;)</p>
<p><b>Файлы к статье</b><br />
<b>
<ul>
<li> <a href="http://easyelectronics.ru/img/AVR_kurs/C/menu/testmenusrc.zip" onclick="javascript:pageTracker._trackPageview('/downloads/img/AVR_kurs/C/menu/testmenusrc.zip');">Исходники</a>  </li>
<li> <a href="http://easyelectronics.ru/img/AVR_kurs/C/menu/testmenumod.zip" onclick="javascript:pageTracker._trackPageview('/downloads/img/AVR_kurs/C/menu/testmenumod.zip');">Файлы для Proteus</a> </li>
</ul>
<p></b></p>
<img src="http://feeds.feedburner.com/~r/easyelectronics/~4/y2_CIHHdDoc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://easyelectronics.ru/organizaciya-drevovidnogo-menyu.html/feed</wfw:commentRss>
		<feedburner:origLink>http://easyelectronics.ru/organizaciya-drevovidnogo-menyu.html</feedburner:origLink></item>
	</channel>
</rss>
