<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	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:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	
	xmlns:georss="http://www.georss.org/georss"
	xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#"
	>

<channel>
	<title>Topic atmega8 | Hey, ruX is here.</title>
	<atom:link href="https://rux.vc/tags/atmega8/feed/" rel="self" type="application/rss+xml" />
	<link>https://rux.vc</link>
	<description>Delivering things - from code to product</description>
	<lastBuildDate>Wed, 14 Apr 2010 10:47:03 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.4.8</generator>
<site xmlns="com-wordpress:feed-additions:1">162978439</site>	<item>
		<title>Cветодиодная линейка на MAX7219</title>
		<link>https://rux.vc/2010.04/led-line-based-on-max7219/</link>
					<comments>https://rux.vc/2010.04/led-line-based-on-max7219/#comments</comments>
		
		<dc:creator><![CDATA[ruX]]></dc:creator>
		<pubDate>Sat, 03 Apr 2010 21:32:44 +0000</pubDate>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[C/C++]]></category>
		<category><![CDATA[Coding]]></category>
		<category><![CDATA[Electronics]]></category>
		<category><![CDATA[atmega8]]></category>
		<category><![CDATA[avr]]></category>
		<category><![CDATA[driver]]></category>
		<category><![CDATA[led]]></category>
		<category><![CDATA[max7219]]></category>
		<category><![CDATA[pwm]]></category>
		<category><![CDATA[spi]]></category>
		<guid isPermaLink="false">http://rux.pp.ru/blog/?p=467</guid>

					<description><![CDATA[<p>Попалась мне в руки светодиодная линейка неизвестного происхождения из 52 двухцветных светодиодов - красный и зелёный. Которая управлялась двумя микросхемами maxim max7919(драйвер). У этой платки было 8 пинов для подпайки, один из которых ни к чему не подключался. Цель - разобраться что она из себя представляет, как работает и сделать что-нибудь с ней - погонять ... <a title="Cветодиодная линейка на MAX7219" class="read-more" href="https://rux.vc/2010.04/led-line-based-on-max7219/" aria-label="More on Cветодиодная линейка на MAX7219">Read more</a></p>
The post <a href="https://rux.vc/2010.04/led-line-based-on-max7219/">Cветодиодная линейка на MAX7219</a> first appeared on <a href="https://rux.vc">Hey, ruX is here.</a>.]]></description>
										<content:encoded><![CDATA[<p><a href="/blog/wp-content/uploads/2010/04/led-line-photo.jpg" target="_blank" data-lightboxplus="lightbox[467]" title="Внешний вид NONAME светодиодной линейки"><img decoding="async" src="/blog/wp-content/uploads/2010/04/led-line-photo-27x150.jpg" alt="" title="Внешний вид NONAME светодиодной линейки" width="27" height="150" class="alignright size-thumbnail wp-image-480" srcset="https://rux.vc/wp-content/uploads/2010/04/led-line-photo-27x150.jpg 27w, https://rux.vc/wp-content/uploads/2010/04/led-line-photo-54x300.jpg 54w, https://rux.vc/wp-content/uploads/2010/04/led-line-photo.jpg 166w" sizes="(max-width: 27px) 100vw, 27px" /></a></p>
<p>Попалась мне в руки светодиодная линейка неизвестного происхождения из 52 двухцветных светодиодов - красный и зелёный. Которая управлялась двумя микросхемами maxim <strong>max7919</strong>(драйвер). У этой платки было 8 пинов для подпайки, один из которых ни к чему не подключался. </p>
<p>Цель - разобраться что она из себя представляет, как работает и сделать что-нибудь с ней - погонять "бегущие огни" будет вполне достаточно.
</p>
<p><span id="more-467"></span></p>
<h2>Предыстория</h2>
<p>Конечно, сама она мне в руки не упала :). Дал мне её преподаватель нового предмета - Основы проектирования. Он очень много знает и <span title="сожалению не все преподы в этом заинтересованны" class="mycomment">желает делится</a> знаниями со студентами, предлагая создать различные проекты. </p>
<h2>Внутри</h2>
<p>Понятия не имею откуда эта линейка и для чего она предназначалась. Поэтому пришлось разбираться. Единственное что было на плате - цифры <strong>8485-01</strong>, видимо какой то серийный номер - ровным счётом ничего не дало. Осмотр схемы + чтение даташита - час ушёл на то, чтоб понять как она примерно работает.</p>
<p>Каждые 4 диода общим анодом к выходам "номерам цифр" драйвера, и к каждому цвету светодиода по ноге из сегментов. В итоге на первый драйвер приходится 8 "номеров цифр", на второй - 5. Под номерами цифр я подразумеваю номера цифр на 7ми сегментных дисплеев
</p>
<p>
Схему в общем виде линейку можно обрисовать так:<br />
<a href="http://rux.pp.ru/blog/wp-content/uploads/2010/04/led-line-two-max7219.jpg" data-lightboxplus="lightbox[467]" title="led-line-two-max7219"><img decoding="async" src="http://rux.pp.ru/blog/wp-content/uploads/2010/04/led-line-two-max7219.jpg" alt="" title="led-line-two-max7219" class="alignright size-full wp-image-469" width="50%" /></a><br />
Ага, рисовал карандашиком. Жутко не хотелось в каде. Посмотрел библиотеки компонентов gEDA, KiCad и даже eagle - там не было драйвера. Пробежался по гуглу - тоже нет. Рисовать - лень, да и не нужно это для одного раза.  Вот карандашиком.. как на начерталке ))
</p>
<p>Разводку платы знать и не нужно - главное,что есть интерфейс. На рисунке - он слева. Пару слов о нём:</p>
<ol>
<li>Пусто.. видимо для отсчёта</li>
<li><strong>GND</strong> - земля. Общая для двух драйверов</li>
<li><strong>DIN</strong> - данные. Также общий для драйверов - разумеется данные предназначаются тому, у которого активен <span style="border-top:1px solid"><strong>CS</strong></span></li>
<li><span style="border-top:1px solid"><strong>CS1</strong></span> - chip select для первой микросхемы. Выставляем в 0, когда хотим что-то сказать ей. На ней 5 сегментов(5 * 4 = 20светодиодов)</li>
<li><span style="border-top:1px solid">CS2</span> - аналочино, для второго драйвера. На этом драйвере висят 8 сегментов(8 * 4 = 32светодиода)</li>
<li><strong>CLK</strong> - clock. Тактируем..</li>
<li><strong>Iset</strong> - установка максимальной яркости led. <u>НЕ ЯРКОСТИ</u>, как многие(судя по форумам) понимают. Яркость задаётся ШИМом и устанавливается значением регистра. Для NONAME светодиодов которые попались - 37кОм слишком много - еле видны, а 31кОм - самое то. Значение устанавливается в зависимости от мощности нагрузки - читаем даташит.</li>
<li><strong>VCC</strong> - питание 5v</li>
</ol>
<p>Поэксперементировав, с зелёным цветом становится быстро понятно - определяется каждым нечётным номером бита. С красным - даже не то что ровно на оборот - они смещенные(но при этом чётные). Вдаваться в подробности не буду, т.к. пока делал - знал какие биты соответствуют какому номеру светодиода - написал прошивку и забыл. Ниже прошивка, в которой не требуется знать какой бит, номер сегмента и микросхемы отвечает за конкретный номер led.</p>
<p>
Для эксперементов подключил atmega8, вот таким способом:<br />
<a href="http://rux.pp.ru/blog/wp-content/uploads/2010/04/led-line-two-max7219-connected-to-atmega8.jpg" data-lightboxplus="lightbox[467]" title="led-line-two-max7219-connected-to-atmega8"><img decoding="async" src="http://rux.pp.ru/blog/wp-content/uploads/2010/04/led-line-two-max7219-connected-to-atmega8.jpg" alt="" title="led-line-two-max7219-connected-to-atmega8" class="aligncenter size-full wp-image-471" width="600"/></a><br />
Разумеется, можно было без кварца, для такой фигни-то. Просто он был на "отладочной плате" - ну и пусть. Также, не отображён коннектор для прошивки. Питалось это всё от USB. <br /><big>Забыл</big> нарисовать резистор 10кОм подключённый между <strong>VCC</strong> и ногой <span style="border-top:1px solid"><strong>RESET</strong></span> - без него мега если и запустится, то будет от каждого чиха перезагружаться
</p>
<h2>Прошивка</h2>
<p>Сначала хотел управлять через usb - но раздумал, не стоит это того, всё равно скоро отдавать, да и практической пользы мало. </p>
<p>Не смотря на то, что как описано в даташите многие значения регистров по дефолту совпадают с тем, что мне нужно, я очень долго бился пока не понял - их все нужно сначала инициализировать. После инициализации вычислил (посылая разные комбинации драйверам) как драйверы подключены к диодам, и уже по из этого вычислил схему подключения :)</p>
<h3>I/O</h3>
<p>Не буду пересказывать даташит. Комманда состоит из 2 байт - в старшем: старшие 4 бита - незначащие, младшие - комманда. Второй байт(младший) - если можно так выразится - аргументы для комманды, ну или значения которые нужно положить в определённый регистр драйвера.</p>
<p> Несколько вспомогательных функций для работы с <span style="border-top: 1px solid"><strong>CS</strong></span>, <strong>DIN</strong> и <strong>CLK</strong> линиями.<br />
<code lang="c" line_numbers="false"><br />
#define LOW 0<br />
#define HIGH 1</p>
<p>void led_cs1(char x) {<br />
    PORTC = x ? PORTC | _BV(4) : PORTC &amp; ~_BV(4);<br />
}<br />
void led_cs2(char x) {<br />
    PORTC = x ? PORTC | _BV(5) : PORTC &amp; ~_BV(5);<br />
}<br />
void led_clk(char x) {<br />
    PORTD = x ? PORTD | _BV(7) : PORTD &amp; ~_BV(7);<br />
}<br />
void led_din(char x) {<br />
    PORTD = x ? PORTD | _BV(6) : PORTD &amp; ~_BV(6);<br />
}<br />
</code><br />
Аргумент у них - должен отвечать на вопрос: установить ли 1 на линии?
</p>
<p>
Когда умеем дёргать линии, можно посылать данные:<br />
<code lang="c++" line_numbers="false"><br />
void outputByte(unsigned char val) {<br />
    for(signed char i = 7; i &gt;= 0; i--) {<br />
        led_din(val &amp; (1 &lt;&lt; i));<br />
        _delay_ms(CLOCK_TIME_MS /2);</p>
<p>        led_clk(HIGH);<br />
        _delay_ms(CLOCK_TIME_MS);</p>
<p>        led_clk(LOW);<br />
        _delay_ms(CLOCK_TIME_MS);<br />
    }<br />
}<br />
void outBytes(char pin, unsigned char reg, unsigned char dat) {<br />
    PORTC &amp;= ~_BV(pin);<br />
    outputByte(reg);<br />
    outputByte(dat);<br />
    PORTC |= _BV(pin);<br />
}<br />
</code><br />
Т.е. отправка комманды комманды(слова) заключается в опускании CS(установки в активное состояние) для нужного драйвера, и последовательной отправки 2 байт.
</p>
<p>
Для отправки какой то одной или сразу двум вынес отдельно:<br />
<code lang="c++" line_numbers="false"><br />
#define outBytesChip1(reg, dat) outBytes(PIN_CS1, reg, dat);<br />
#define outBytesChip2(reg, dat) outBytes(PIN_CS2, reg, dat);</p>
<p>void outBytesChips(unsigned char reg, unsigned char dat) {<br />
    outBytesChip1(reg, dat);<br />
    outBytesChip2(reg, dat);<br />
}<br />
</code><br />
<strong>outBytesChipN()</strong> - через дефайн, т.к. эксперементально определил что прошивка меньше места занимает :)
</p>
<h3>Инициализация</h3>
<p>Как я уже писал выше - промучился, пока жостко не проинициализировал.<br />
<code lang="c" line_numbers="false"><br />
void init() {<br />
    // configure pins to output<br />
    DDRC |= _BV(5) | _BV(4);<br />
    DDRD |= _BV(6) | _BV(7);</p>
<p>    // pre-init drivers line<br />
    led_cs1(HIGH);<br />
    led_cs2(HIGH);<br />
    led_clk(LOW);</p>
<p>    // setup clock interrupt and prescaler<br />
    TCCR0 |= (1&lt;&lt;CS02)|(1&lt;&lt;CS00);<br />
    TIMSK |= (1&lt;&lt;TOIE0);<br />
    TCNT0 = 0;</p>
<p>    // initialize drivers<br />
    outBytesChips(0xc, (1)); // shutdown<br />
    outBytesChips(0xa, (15)); // intensity<br />
    outBytesChips(0x9, 0); // decode mode<br />
    outBytesChips(0xf, 0); // test mode<br />
    outBytesChips(0xb, 7); // scan limit</p>
<p>    // finally, enable interrupts<br />
    sei();<br />
}<br />
</code><br />
Для чего нужны прерывания по таймеру? Ниже.
</p>
<h3>Управление светодиодами</h3>
<p>Весьма сложно вычислять адрес определённого цвета и светодиода. Он складывается из номера драйвера, номера сегмента, номера "цифры" в сегменте в зависимости от цвета. Сделать тупо бегущий огонь - это уже куча перерасчётов.
</p>
<p>
Я сделал нечто "видеопамяти". Некоторый буффер, в котором хранятся значения цветов для каждого светодиода. Элементарное обращение - через несколько функций, которые знают в какую часть массива "видеопамяти" полезть и какие биты прочитать/изменить. </p>
<p>Каждая ячейка состоит из 2х бит - цвета.<br />
<code lang="c++" line_numbers="false"><br />
enum LedStatus{<br />
    lsOff, lsGreen, lsRed, lsOrange<br />
};<br />
</code><br />
Говорящие названия - комментировать не нужно.
</p>
<p>
Выделяем память под массив "видеопамяти" и флажок - признак того, что содержимое памяти изменилось и нужно снова посылать новые значения в драйверы.<br />
<code lang="c++" line_numbers="false"><br />
char buffman_changed = 0;<br />
char buffman_data[13];<br />
</code>
</p>
<p>Функции для манипуляции с массивом таковы:<br />
<code lang="c++" line_numbers="false"><br />
LedStatus buffman_get(unsigned int num) {<br />
    if (num &gt; 52) return lsOff;<br />
    int bitcount = (num * 2);<br />
    int off_bit = bitcount % 8;<br />
    return (LedStatus) ((buffman_data[bitcount/8] &amp; (3 &lt;&lt; off_bit)) &gt;&gt; off_bit);<br />
}<br />
void buffman_setAll(LedStatus stat) {<br />
    unsigned char mask = stat &lt;&lt; 0 | stat &lt;&lt; 2 | stat &lt;&lt; 4 | stat &lt;&lt; 6;<br />
    for(int i = 0; i &lt; 13; i++) buffman_data[i] = mask;<br />
    buffman_changed = 1;<br />
}<br />
void buffman_set(unsigned char num, LedStatus stat) {<br />
    if (num &gt; 51) return;<br />
    int bitcount = (num * 2);<br />
    int off_byte = num &gt;&gt; 2, off_bit = bitcount % 8;<br />
    buffman_data[off_byte] = (buffman_data[off_byte] &amp; ~(3 &lt;&lt; off_bit)) | (((char)stat) &lt;&lt; off_bit);<br />
    buffman_changed = 1;<br />
}<br />
</code><br />
Суть одна - умеют работать с "видеобуфером".
</p>
<p> Самое интересное - то как эта "видеопамять" отображается на массив. По таймеру.<br />
<code lang="c++" line_numbers="false"><br />
ISR(TIMER0_OVF_vect) {<br />
    int mask = 0;<br />
    if (!buffman_changed) return; </p>
<p>    for(int i = 0; i &lt; 15; i++) {<br />
        mask = 0;<br />
        for(int j = 0; j &lt; 4; j++) {<br />
            switch(buffman_get(i*4+j)) {<br />
            case lsOff: continue;<br />
            case lsOrange: mask |= 2 &lt;&lt; redMatrix[j] | 1 &lt;&lt; greenMatrix[j]; break;<br />
            case lsRed: mask |= 2 &lt;&lt; redMatrix[j]; break;<br />
            case lsGreen: mask |= 1 &lt;&lt; greenMatrix[j]; break;<br />
            }<br />
        }</p>
<p>        if (i &lt; 8) {<br />
            outBytesChip2(i+1, mask);<br />
        } else {<br />
            outBytesChip1(i-7, mask);<br />
        }<br />
    }<br />
}<br />
</code><br />
По прерыванию в цикле пробегается по всем сегментам - группам светодиодов(по 4), в зависимости от значения в "видеобуфере" формируется с помощью масок формируется отправляемое значение.
</p>
<p>При том, маска для каждого номера светодиода и цвета в определённой позиции лежит в<br />
<code lang="c" line_numbers="false"><br />
static unsigned char redMatrix[] = {4, 2, 0, 6},<br />
                            greenMatrix[] = {6, 4, 2, 0};<br />
</code>
</p>
<p>А теперь можно в цикле рисовать в массиве через через <strong>buffman_set()</strong> с определённой задержкой - и эти изменения практически моментально отразятся на светодиодной линейке.</p>
<p>
Наример вот такая прошивка:<br />
<code lang="c++" line_numbers="false"><br />
int main(void)<br />
{<br />
    init();</p>
<p>    buffman_setAll(lsOff);</p>
<p>    int dir = 1, i = 1;<br />
    LedStatus ls = lsRed;<br />
    do {<br />
        buffman_set(i-1, lsOrange);<br />
        buffman_set(i, lsRed);<br />
        buffman_set(i+1, lsRed);<br />
        buffman_set(i+2, lsGreen);<br />
        if (i == 0 || i == 49) dir = - dir;<br />
        i+=dir;<br />
        wait(25);<br />
        if (i%2) buffman_set(0, (buffman_get(0) == lsOff ? lsRed : lsOff ));<br />
        if (i%2==0) buffman_set(51, (buffman_get(51) == lsOff ? lsRed : lsOff ));</p>
<p>    } while( 1 );</p>
<p>    return 0;<br />
}<br />
</code><br />
Делает вот такое:<br />
<object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/UPvac5EV5qY&hl=ru&fs=1"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param></object>
</p>
<p>
Ещё вот баловался:<br />
<object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/k6NtYiqG1cA&hl=ru&fs=1"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param></object>
</p>
<h2>На этом всё</h2>
<p>
На этом всё. Поиграл - и хватит. Делюсь файлами.<br />
Полный текст прошивки:<br />
<code lang="c++"><br />
#include &lt;avr/io.h&gt;<br />
#include &lt;avr/eeprom.h&gt;<br />
#include &lt;avr/interrupt.h&gt;<br />
#include &lt;avr/pgmspace.h&gt;<br />
#include &lt;util/delay.h&gt;</p>
<p>#define PIN_CS1 4<br />
#define PIN_CS2 5</p>
<p>// Clock duration<br />
#define CLOCK_TIME_MS 0.0005</p>
<p>#define LOW 0<br />
#define HIGH 1</p>
<p>static unsigned char redMatrix[] = {4, 2, 0, 6}, greenMatrix[] = {6, 4, 2, 0};</p>
<p>enum LedStatus{<br />
    lsOff, lsGreen, lsRed, lsOrange<br />
};</p>
<p>char buffman_changed = 0;<br />
char buffman_data[13];</p>
<p>LedStatus buffman_get(unsigned int num) {<br />
    if (num &gt; 52) return lsOff;<br />
    int bitcount = (num * 2);<br />
    int off_bit = bitcount % 8;<br />
    return (LedStatus) ((buffman_data[bitcount/8] &amp; (3 &lt;&lt; off_bit)) &gt;&gt; off_bit);<br />
}<br />
void buffman_setAll(LedStatus stat) {<br />
    unsigned char mask = stat &lt;&lt; 0 | stat &lt;&lt; 2 | stat &lt;&lt; 4 | stat &lt;&lt; 6;<br />
    for(int i = 0; i &lt; 13; i++) buffman_data[i] = mask;<br />
    buffman_changed = 1;<br />
}<br />
void buffman_set(unsigned char num, LedStatus stat) {<br />
    if (num &gt; 51) return;<br />
    int bitcount = (num * 2);<br />
    int off_byte = num &gt;&gt; 2, off_bit = bitcount % 8;<br />
    buffman_data[off_byte] = (buffman_data[off_byte] &amp; ~(3 &lt;&lt; off_bit)) | (((char)stat) &lt;&lt; off_bit);<br />
    buffman_changed = 1;<br />
}</p>
<p>void led_cs1(char x) {<br />
    PORTC = x ? PORTC | _BV(4) : PORTC &amp; ~_BV(4);<br />
}<br />
void led_cs2(char x) {<br />
    PORTC = x ? PORTC | _BV(5) : PORTC &amp; ~_BV(5);<br />
}<br />
void led_clk(char x) {<br />
    PORTD = x ? PORTD | _BV(7) : PORTD &amp; ~_BV(7);<br />
}<br />
void led_din(char x) {<br />
    PORTD = x ? PORTD | _BV(6) : PORTD &amp; ~_BV(6);<br />
}<br />
//#define led_din(x) PORTD = x ? PORTD | _BV(6) : PORTD &amp; ~_BV(6);</p>
<p>void outputByte(unsigned char val) {<br />
    for(signed char i = 7; i &gt;= 0; i--) {<br />
        led_din(val &amp; (1 &lt;&lt; i));<br />
        _delay_ms(CLOCK_TIME_MS /2);</p>
<p>        led_clk(HIGH);<br />
        _delay_ms(CLOCK_TIME_MS);</p>
<p>        led_clk(LOW);<br />
        _delay_ms(CLOCK_TIME_MS);<br />
    }<br />
}</p>
<p>void outBytes(char pin, unsigned char reg, unsigned char dat) {<br />
    PORTC &amp;= ~_BV(pin);<br />
    outputByte(reg);<br />
    outputByte(dat);<br />
    PORTC |= _BV(pin);<br />
}</p>
<p>#define outBytesChip1(reg, dat) outBytes(PIN_CS1, reg, dat);<br />
#define outBytesChip2(reg, dat) outBytes(PIN_CS2, reg, dat);</p>
<p>void outBytesChips(unsigned char reg, unsigned char dat) {<br />
    outBytesChip1(reg, dat);<br />
    outBytesChip2(reg, dat);<br />
}</p>
<p>void init() {<br />
    // configure pins to output<br />
    DDRC |= _BV(5) | _BV(4);<br />
    DDRD |= _BV(6) | _BV(7);</p>
<p>    // pre-init drivers line<br />
    led_cs1(HIGH);<br />
    led_cs2(HIGH);<br />
    led_clk(LOW);</p>
<p>    // setup clock interrupt and prescaler<br />
    TCCR0 |= (1&lt;&lt;CS02)|(1&lt;&lt;CS00);<br />
    TIMSK |= (1&lt;&lt;TOIE0);<br />
    TCNT0 = 0;</p>
<p>    // initialize drivers<br />
    outBytesChips(0xc, (1)); // shutdown<br />
    outBytesChips(0xa, (15)); // intensity<br />
    outBytesChips(0x9, 0); // decode mode<br />
    outBytesChips(0xf, 0); // test mode<br />
    outBytesChips(0xb, 7); // scan limit</p>
<p>    // finally, enable interrupts<br />
    sei();<br />
}</p>
<p>ISR(TIMER0_OVF_vect) {<br />
    int mask = 0;<br />
    if (!buffman_changed) return; </p>
<p>    for(int i = 0; i &lt; 15; i++) {<br />
        mask = 0;<br />
        for(int j = 0; j &lt; 4; j++) {<br />
            switch(buffman_get(i*4+j)) {<br />
            case lsOff: continue;<br />
            case lsOrange: mask |= 2 &lt;&lt; redMatrix[j] | 1 &lt;&lt; greenMatrix[j]; break;<br />
            case lsRed: mask |= 2 &lt;&lt; redMatrix[j]; break;<br />
            case lsGreen: mask |= 1 &lt;&lt; greenMatrix[j]; break;<br />
            }<br />
        }</p>
<p>        if (i &lt; 8) {<br />
            outBytesChip2(i+1, mask);<br />
        } else {<br />
            outBytesChip1(i-7, mask);<br />
        }<br />
    }<br />
}</p>
<p>inline void wait(float ms) {<br />
    for(; ms &gt; 0; ms-=1) _delay_ms(1);<br />
}</p>
<p>int main(void)<br />
{<br />
    init();</p>
<p>    buffman_setAll(lsOff);</p>
<p>    int dir = 1, i = 1;<br />
    LedStatus ls = lsRed;<br />
    do {<br />
        buffman_set(i-1, lsOrange);<br />
        buffman_set(i, lsRed);<br />
        buffman_set(i+1, lsRed);<br />
        buffman_set(i+2, lsGreen);<br />
        if (i == 0 || i == 49) dir = - dir;<br />
        i+=dir;<br />
        wait(25);<br />
        if (i%2) buffman_set(0, (buffman_get(0) == lsOff ? lsRed : lsOff ));<br />
        if (i%2==0) buffman_set(51, (buffman_get(51) == lsOff ? lsRed : lsOff ));</p>
<p>    } while( 1 );</p>
<p>    return 0;<br />
}</p>
<p></code><br />
А также запакованный вариант - вместе с мейкфайлом и прошивкой: <a href='/blog/wp-content/uploads/2010/04/led-line-firmware.tar.gz'>led-line-firmware.tar.gz</a>
</p>
</p>
<h2>UPD</h2>
<p>Выкладываю ещё одну демо-прошивку и видео к ней. Есть три функции, выполняющие каждая свой эффект, вызываются циклически по очереди, с плавным переходом(после каждого эффекта уменьшается яркость с помощью встроенного в драйверы ШИМа)</p>
<p>
<code lang="c++" line_numbers="false"><br />
inline void wait(int ms) {<br />
    for(; ms &gt; 0; ms-=1) _delay_ms(1);<br />
}</p>
<p>void e1() {<br />
    int dir = 1, i = 1;<br />
    for(int j = 0; j &lt; 300 ; j++) {<br />
        buffman_set(i-1, lsOrange);<br />
        buffman_set(i, lsRed);<br />
        buffman_set(i+1, lsRed);<br />
        buffman_set(i+2, lsGreen);<br />
        if (i == 0 || i == 49) dir = - dir;<br />
        i+=dir;<br />
        wait(25);<br />
        if (i%2) buffman_set(0, (buffman_get(0) == lsOff ? lsRed : lsOff ));<br />
        if (i%2==0) buffman_set(51, (buffman_get(51) == lsOff ? lsRed : lsOff ));<br />
    }<br />
}<br />
void e2() {<br />
    LedStatus ls = lsRed;<br />
    int i = 1, len=6, end = 52;;<br />
    int delay = 14;<br />
    while(end &gt; 0) {<br />
        for(i = 0; i &lt; end;i++) {<br />
            for(int k = 0; k &lt; len; k++) {<br />
                buffman_set(k+i, ls);<br />
            }<br />
            buffman_set(i-1, lsOff);<br />
            wait(delay);<br />
        }<br />
        delay++;<br />
        end--;end--;<br />
        if (ls == lsRed) ls = lsGreen;<br />
        else if (ls == lsGreen) ls = lsOrange;<br />
        else if (ls == lsOrange) ls = lsRed;<br />
    }<br />
}</p>
<p>void e3() {<br />
    for(int dir = 1, i = 1, j = 0; j &lt; 400; j++) {<br />
        buffman_set(i, lsRed);<br />
        buffman_set(dir&gt;0?i+1:i-1, lsRed);<br />
        buffman_set(i-dir, lsOff);</p>
<p>        buffman_set(52-i, lsGreen);<br />
        buffman_set(52-i-(dir&gt;0?+1:-1), lsGreen);<br />
        buffman_set(52-i+dir, lsOff);</p>
<p>        if(i &gt; 52/2-10) {<br />
            for(int k = 0; k &lt; i-20; k++) {<br />
                buffman_set(k, lsOrange);<br />
                buffman_set(52-k, lsOrange);<br />
            }<br />
        }</p>
<p>        i += dir;<br />
        if (i == 0 || i == 52/2) dir = - dir;<br />
        wait(31);<br />
    }<br />
}</p>
<p>void (*examples[]) (void) = { &amp;e3, &amp;e2, &amp;e1};</p>
<p>int main(void)<br />
{<br />
    init();</p>
<p>    buffman_setAll(lsOff);</p>
<p>    for(int i = 0; ; i = ++i % (sizeof(examples)/sizeof(examples[0]))) {<br />
        examples[i]();<br />
        for(int b = 15; b &gt; 1; b--) {<br />
            outBytesChips(0xa, (b)); // intensity<br />
            wait(150);<br />
        }<br />
        buffman_setAll(lsOff);<br />
        wait(300);<br />
        outBytesChips(0xa, (15)); // intensity</p>
<p>    }</p>
<p>    return 0;<br />
}<br />
</code><br />
Обожаю си за возможность писать такие выверты :)<br />
Всю прошивку можно скачать с исходниками: <a href='http://rux.pp.ru/blog/wp-content/uploads/2010/04/ledline-firmware-3-effects.tar.gz'>ledline-firmware-3-effects.tar</a>
</p>
<p> Ну и видео<br />
<object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/0zYaztTdUWk&hl=ru&fs=1"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param></object></p>The post <a href="https://rux.vc/2010.04/led-line-based-on-max7219/">Cветодиодная линейка на MAX7219</a> first appeared on <a href="https://rux.vc">Hey, ruX is here.</a>.]]></content:encoded>
					
					<wfw:commentRss>https://rux.vc/2010.04/led-line-based-on-max7219/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">467</post-id>	</item>
		<item>
		<title>CPU load indicator</title>
		<link>https://rux.vc/2010.03/cpu-load-indicator/</link>
					<comments>https://rux.vc/2010.03/cpu-load-indicator/#comments</comments>
		
		<dc:creator><![CDATA[ruX]]></dc:creator>
		<pubDate>Thu, 04 Mar 2010 09:26:39 +0000</pubDate>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[C/C++]]></category>
		<category><![CDATA[Coding]]></category>
		<category><![CDATA[Electronics]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[atmega8]]></category>
		<category><![CDATA[avr]]></category>
		<category><![CDATA[circuit]]></category>
		<category><![CDATA[embedded]]></category>
		<category><![CDATA[gadget]]></category>
		<category><![CDATA[led]]></category>
		<category><![CDATA[libgtop]]></category>
		<category><![CDATA[libusb]]></category>
		<category><![CDATA[make]]></category>
		<category><![CDATA[pwm]]></category>
		<category><![CDATA[usb]]></category>
		<category><![CDATA[v-usb]]></category>
		<category><![CDATA[шим]]></category>
		<guid isPermaLink="false">http://rux.pp.ru/blog/?p=378</guid>

					<description><![CDATA[<p>Что это? Этот проект может стать хорошим начальным опытом в разработке устройств на микроконтроллере и программировании его, как прошивки мк так и создании управляющей программы. Собственно это очень простое устройство, плавно показывающее текущую нагрузку процессора меняя яркость светодиода(ну или по желанию можно использовать другую нагрузку). Людям, которые занимаются моддингом особо думаю понравится - нужно только ... <a title="CPU load indicator" class="read-more" href="https://rux.vc/2010.03/cpu-load-indicator/" aria-label="More on CPU load indicator">Read more</a></p>
The post <a href="https://rux.vc/2010.03/cpu-load-indicator/">CPU load indicator</a> first appeared on <a href="https://rux.vc">Hey, ruX is here.</a>.]]></description>
										<content:encoded><![CDATA[<h2>Что это?</h2>
<p>
Этот <em title="Ага, именно проект как бы то громко не звучало - вбухал достаточно много времени на контролирующую программу(=драйвер) и описание тут">проект</em> может стать хорошим начальным опытом в разработке устройств на микроконтроллере и программировании его, как прошивки мк так и создании управляющей программы.
</p>
<p>
<img decoding="async" src="http://rux.pp.ru/blog/wp-content/uploads/2010/03/cpuload-indicator-processor-load-average.png" alt="" title="cpuload-indicator-processor-load-average" width="234" height="109" class="alignright size-full wp-image-395" srcset="https://rux.vc/wp-content/uploads/2010/03/cpuload-indicator-processor-load-average.png 234w, https://rux.vc/wp-content/uploads/2010/03/cpuload-indicator-processor-load-average-150x69.png 150w" sizes="(max-width: 234px) 100vw, 234px" />Собственно это очень простое устройство, плавно показывающее текущую нагрузку процессора меняя яркость светодиода(ну или по желанию можно использовать другую нагрузку). Людям, которые занимаются моддингом особо думаю понравится - нужно только приложить фантазию :) Работает через USB, причём программный, реализованный с помощью прооекта <a href="http://www.obdev.at/products/vusb/index.html" target="_blank">V-USB</a>. В качестве мк выбран Atmega8
</p>
<p><span id="more-378"></span></p>
<p>
Предполагается, что уже есть какие то начальные знания в области программирования и электроники. </p>
<h2>Принцип работы</h2>
<p>
Есть 2 стороны - девайса и компьютера. Компьютер периодически с помощью программы посылает через usb информацию о том, на сколько нужно зажечь ярко светодиод. А девайс слушает комманду и плавно приблежает яркость светодиода от текущего значения к новому.</p>
<p>
Хочу отметить, что я посторался сделать как можно более гибкую систему - интервалы опроса текущей загрузки процессора программой на компьютере и интервал с которым приблежается текущая яркость к новой можно задать в коммандной строке программы. Также можно задать верхнюю и нижнюю границу свечения.</p>
<h2>Подробнее</h2>
<h3> Девайс</h3>
<p>
Схема достаточно простая и вполне собирается легко на макетной плате(у кого она есть) или как у меня - на картонке :) Конечно же, при желании можно сделать печатную плату - будет шикарно - я делать не стал, потому, что CPU load indicator оказался промежуточным этапом к большему проекту который я сейчас делаю. Конечно, гик скажет, что это слишком просто, чтоб уделять этому внимание, но кто-то только учиться, вроде меня =:)<br />
<a href="http://rux.pp.ru/blog/wp-content/uploads/2010/03/cpuload-indicator-circuit.png" data-lightboxplus="lightbox[378]" title="CPU load indicator circuit. AVR and V-USB based project - displays current cpu load by change LED's brightness   smoothly"><img decoding="async" src="http://rux.pp.ru/blog/wp-content/uploads/2010/03/cpuload-indicator-circuit-tiny.png" alt="" title="CPU load indicator circuit. AVR and V-USB based project - displays current cpu load by change LED's brightness   smoothly" class="aligncenter size-full wp-image-385" /></a>
</p>
<p>
Комментарии по схеме:</p>
<ul>
<li>J1 - USB порт к компьютеру(D- это вторая нога, D+ это третья), J2 - SPI видимо к программатору :)</li>
<li>X1, C5, C6 - генератор. Кварц можно поставить, например, на 15МГц, главное, чтоб V-USB поддерживал эту частоту, а кондёры тут от 18 до 22пф можно выбирать. У меня 22пф стоят</li>
<li>R1 - подтягивающий резистор, лучше всё-таки 10кОм. Для работы мк ведь требуется reset пассивный, а т.к. он инверсный, нужно подать "1". По идее, там есть внутри 100кОм, но как пишут, нога ловит каждый чих</li>
<li>D2, D3 - стабилитроны для того, чтоб не превысить напряжение на линии USB - так должно быть по стандарту, единица - не должна привышать 3.6в. У меня стеклянные - чёрной полоской к сигнальным линиям(D+ & D-)</li>
<li>R4, R5 - везде стоят по 68 Ом, у меня нормально работает 100 Ом. Если я правильно понимаю, они нужны чтоб не получилось ситуации, когда можно спалить порт мк</li>
<li>R2 - нужно оставить именно таким, это некая индикация USB-хосту что подключённо низкоскоростное устройство. Для эксперемента можно подцепить к usb только этот резюк и ядро будет писать что обнаруженно новое низкоскоростное устройство.</li>
<li>C3 - сглаживает помехи по питанию</li>
</ul>
<h3>ШИМ (PWM) </h3>
<p>Наверное всё это мутно - интервалы, шаги, яркость.. Так вот, "<em>яркость</em>" - это численное значение от <strong>0..255</strong> - значение, которое подаётся на <span class="comment" title=" = PWM">ШИМ(Широтно - Импульсная Модуляция)</span> выход. Про ШИМ можно много где прочитать, мне понравилось <a href="http://www.myrobot.ru/stepbystep/rce_pwm.php" target="_blank">на myRobot</a>. Соответственно максимальной яркости(состоянию, в котором максимальное количество "1") соответствует <strong>255</strong>, минимальной - <strong>0</strong>(максимальное количество "0"), среднему - <strong>127</strong>(примерное равное количесво "1" и "0"). Думаю логика прослеживается.
</p>
<p>
Когда компьютер послал новое значение для ШИМ, которое нужно установить на выходе девайса, то девайс постепенно приблежает текущее значение к новому, с определённой задержкой. Благодаря этому яркость плавно меняется. Так, например, в темноте плавно повышается яркость после еле различимого свечения и место рядом с девайсом около компьютера краснеет - ну разумеется если стоит красный светодиод.
</p>
<p>
Как я уже указал, программа посылает уже конкретное значение ШИМ которое нужно установить. Но перед отправкой, нужно его ещё вычислить. Т.е. при загрузки процессора в 100% яркость индикатора должна быть максимальной, а не (если бы послать просто значение ШИМ <strong>100</strong>) меньше половины от полной. Для этого нужно пересчитать его по простой формуле: (cpu_load * 255/100), где cpu_load - текущая нагрузка процессора.
</p>
<p>
Надеюсь пока ещё понятно, я ж предупредил что минимальная подготовка должна быть =).<br />
А ведь вполне может быть такая ситуация, что светодиод начинает светиться только от значния <strong>80</strong> в ШИМ? Вполне может быть - значит при маленькой нагрузке мы вообще не увидим свечения. А что, если после ШИМ  <strong>200</strong> индикатор так ярко светит, что кажется, вот-вот сгорит? Можно прийти в выводу, что требуется поставить рамки от и до и высчитывать  соответственно величину ШИМ.  Вычисляется по формуле(выжимка из кода):<br />
<code line_numbers="false" lang="c">cpu_load = ((valueMax - valueMin) / 100.0 ) * cpu_load + valueMin ;</code><br />
Названия переменных говорят за себя, пояснения не требуются, как я думаю.
</p>
<h3>Управляющая программа(сторона компьютера) - драйвер</h3>
<p>
Основная программа сосредоточенна в <em>software/cpu_indicator.c</em>.<br />
<b>Внимание!</b> Для сборки приложения нужно воспользоваться коммандой <strong>make clean all</strong>. Для запуска(из папки software) ./cpuload_indicator.<br />
У вас <big>обязательно</big> должен быть установлен пакет <big>libusb-dev</big> и <big>libgtop-dev</big>, иначе ничего не соберётся. Разумеется в зависимости от дистрибутива исходные коды этих библиотек могут отличаться названием.
</p>
<p>
libusb нужен очевидно для работы с USB, а libgtop для получения информации о текущей нагрузке процессора.
</p>
<p>
В начале <em>software/cpu_indicator.c</em> подключаются хедеры и указываются дефолтные значения переменных.<br />
О функциях</p>
<ol>
<li><strong>bool parseOpts(int, char *)</strong> - служит для парсинга коммандной строки и проверки на корректность значений.</li>
<li><strong>bool connectUsb() </strong>- ищет устройство среди всех и открывает его, если нашла. А если не нашла то в зависимости от наличия аргумента коммандной строки <em>-catch</em> будет пытаться искать снова или просто попросит завершить работу программы с информацией о том, что устройство не найдённо. В противном случае, если указан -catch программа будет ждать пока подключат устройство. После открытия успешного устройства посылается комманда устанавливающая шаг времени, с которым значение ШИМ приблежаться к новому. Этот аргумент можно задать в коммандной строке ключом <em>-step N</em>, где N - значение задержки в мсек. </li>
<li> <strong>int main (int, char *)</strong> - собвственнно входная точка программы. Вызывает parseOpts() и connectUsb(), высчитывает нагрузку на процессор за время в процентах, переводит в соответствующее значение ШИМ с учётом верхних и нижних смещений границ(о чём речь шла ранее) и посылает значение в USB. При ошибке, в зависимости от <em>-catch</em>, либо завершается работа программы, либо пытается подсоединиться снова, если аргумент указан.<br />
Особенно сложным оказалось для меня получение информации о нагрузки на процессор. Я воспользовался статьёй <a href="http://colby.id.au/node/39" target="_blank">Calculating CPU Usage from /proc/stat</a>, где нагрузка вычисляется  bash скриптом и берётся информация из /proc/stat.
</li>
<li><strong> void usage(char *) </strong>- выводит информацию об использовании, лучше показать:<br />
<code lang="bash" line_numbers="false"><br />
$ ./cpuload_indicator -help<br />
Control program for CPU Load indicator (c) ruX 2010<br />
Usage ./cpuload_indicator [option=[value]] ..<br />
Options:<br />
   -min NN     - set minimal PWM value [0..255]<br />
   -max NN     - set maxmimum PWM value [0..255]<br />
   -step NN    - set step interval for LED (in msec)<br />
   -update NN  - interval for update load  about current CPU(in seconds)<br />
   -catch      - never quit(always trying to catch device)<br />
   -help       - this help promt<br />
Copyright by ruX, 2010, http://ruX.pp.ru/<br />
</code>
</ol>
</p>
<p>
Думаю на столько краткого описания достаточно. За подробностями - в исходник. Есть ещё файл obdev_usb.c - там лежат довольно стандартные функции для открытия устройства(по его VID:PID, имени, имени разработчика) - они качуют из различных проектов, иногда немного правясь. Так и я взял за из проекта <a href="http://johannes.krude.de/projects/usb-Relay/" target="_blank">usb-relay</a>.
</p>
<h3>Программа прошивки</h2>
<p>Разумеется, всё что относится к прошивке девайса лежит в <em>firmware</em>, как ни странно :)
</p>
<p>
Код программы для мк можно разделить условно на 2 части: работа с USB, реализованная с помощью библиотеки V-USB и основной логики.
</p>
<p>
Важный этап - настройка V-USB, которая находится в файле <em>firmware/usbdrv.h</em>. То, что там определенно будет решать каким будет устройство. Файл шаблонный, от obdev. Но добавил 2 строчки, которые определяют константы комманд, которые посылает компьютер - для установки нового значения ШИМ и установки интервала шага приближения к новому значению:<br />
<code lang="c">#define REQUEST_SET_TARGET      1<br />
#define REQUEST_SET_STEP        2</code>
</p>
<p>
В основном файле логики <em>firmware/cpuload_indicator.c</em> сначала устанавливается конфигурация перефирии: направление вывода и настройка ШИМ.<br />
<code lang="c">    // Configure port B pin 1 as output<br />
    DDRB = (_BV(1));</p>
<p>    // Setup PWM<br />
    TCCR1A=0xA1;<br />
    TCCR1B=0x09;<br />
    TCNT1H=0x00;<br />
</code><br />
Дальше вызывается process() в котором и происходит основная работа - один раз инициализируется USB и начинается бесконечный цикл, в котором происходит опрос usb - usbPoll() и приближение значения ШИМ, выполняется маленькая задержка:<br />
<code lang="c"><br />
void process(void)<br />
{<br />
    unsigned int dsec = 0;</p>
<p>    for(startUsb(); ;dsec++){<br />
        usbPoll();</p>
<p>        if (dsec % (delay * 10) == 0 &amp;&amp; OCR1A != target) {<br />
            if (OCR1A &gt; target) OCR1A--; else OCR1A++;<br />
        }</p>
<p>        _delay_ms(0.1);</p>
<p>        if (dsec == 10000) dsec = 0;<br />
    }<br />
}<br />
</code><br />
У меня в качестве выхода ШИМ используется <strong>T/C1</strong> - PORTB, бит 1, нога 15 в PDIP корпусе, соответственно имеем дело с <strong>OCR1A</strong>. Ещё нюанс: компьютер посылает интервал шага приближения в мсек, а внутри цикла задержка 0.1мсек, поэтому приходиться делать (delay * 10), чтоб привести к одному порядку - к примеру у нас компьютер передал,что шаг - 50мсек(=5 * 10<sup>-2</sup>, значит нужно сделать 50 * 10 = 500 циклов перед тем, как будет приблежение значения ШИМ к новому.
</p>
<p>
Если кто то не понял код выше - в цикле сначала происходит опрос, а дальше проверяется, если наступило время, когда нужно сделать шаг(т.е. интервал задержки прошёл) и при этом текущее значение ШИМ это не то, что компьютер "попросил" выставить, то приблежаемся к требуемому значению. Дальше задержка на 10<sup>-4</sup>сек и попытка избежать переполнения если число в счётчике циклов dsec достаточно большое.
</p>
<p>
Ещё определенна uchar usbFunctionSetup(uchar data[8]), которая вызывается, когда компьютер послал данные - в нашем случае это либо новое значение ШИМ, либо установка интервала шага приблежения.<br />
<code lang="c"><br />
uchar usbFunctionSetup(uchar data[8])<br />
{<br />
    usbRequest_t *request = (usbRequest_t*) data;<br />
    switch (request-&gt;bRequest) {<br />
    case REQUEST_SET_TARGET:<br />
        target = request-&gt;wValue.bytes[0];<br />
        break;</p>
<p>    case REQUEST_SET_STEP:<br />
        delay = (short int)(request-&gt;wValue.bytes);<br />
        break;<br />
    }</p>
<p>    return 0;<br />
}<br />
</code><br />
Структура usbRequest_t *request содержит информацию о том, что нам пришло, подробнее можно узнать в доках. request->bRequest определяет номер комманды, а request->wValue.bytes переданные от компьютера данные.<br />
<strong>target</strong> - значение ШИМ, которое нужно установить, фактически используется только 1 байт, поэтому и выбираем только первый байт из того, что пришло. А <strong>delay</strong> - задержка в милисекундах, поэтому тут одним байтом не обойтись, берём 2 сразу, делая тайпкастинг к short int.
</p>
<h3>Прошивка прошивки :)</h3>
<p>
В <em>firmware/</em> определён мэйкфайл, который можно настроить под себя - в моём случае я использовал мк atmega8, программатор usbasp и частота цварца - 12MГц. По желанию можно изменить:<br />
<code lang="bash" line_numbers="false"><br />
. . . .<br />
DEVICE = atmega8<br />
PROGRAMMER = usbasp<br />
FREQ = 12000000<br />
. . . .<br />
</code>
</p>
<p> Чтоб полностью откомпилировать, прошить программу и фьюзы, достаточно выполнить <strong>make clean all flash fuse</strong> :) Из фьюзов нужно отметить, что установленно тактирование от кварца, свыше 12МГц, кому интересно найдут интерпретацию фьюзов. Кстати о них(<b title="лучше ещё раз выделить..">для atmega8</b>) : старший байт -<strong> 0xC9</strong>, младший - <strong>0xEF</strong></p>
<h2>Фото</h2>
<p>
Повторюсь, это сделанно на картонке, из за отсутствия макетной платы, причём буквально на коленке и для другого проекта, поэтому, уведенное может показаться совсем не то, что на схеме было. Но так оно и есть, поверьте :) Итак, <a href="#showme_all_photo_please" onClick="document.getElementById('showme_all_photo_please').style.display = 'block';">показать фото</a></p>
<div id="showme_all_photo_please" style="display:none; text-align:center"><center><br />
<a href="http://rux.pp.ru/blog/wp-content/uploads/2010/03/cpuload-indicator-photo2.jpg" data-lightboxplus="lightbox[378]" title="cpuload-indicator-photo2"><img decoding="async" src="http://rux.pp.ru/blog/wp-content/uploads/2010/03/cpuload-indicator-photo2-150x122.jpg" alt="" title="cpuload-indicator-photo2" width="150" height="122" class="aligncenter size-thumbnail wp-image-388" srcset="https://rux.vc/wp-content/uploads/2010/03/cpuload-indicator-photo2-150x122.jpg 150w, https://rux.vc/wp-content/uploads/2010/03/cpuload-indicator-photo2-300x245.jpg 300w, https://rux.vc/wp-content/uploads/2010/03/cpuload-indicator-photo2.jpg 417w" sizes="(max-width: 150px) 100vw, 150px" /></a> <a href="http://rux.pp.ru/blog/wp-content/uploads/2010/03/cpuload-indicator-photo1.jpg" data-lightboxplus="lightbox[378]" title="cpuload-indicator-photo1"><img decoding="async" src="http://rux.pp.ru/blog/wp-content/uploads/2010/03/cpuload-indicator-photo1-150x92.jpg" alt="" title="cpuload-indicator-photo1" width="150" height="92" class="aligncenter size-thumbnail wp-image-387" srcset="https://rux.vc/wp-content/uploads/2010/03/cpuload-indicator-photo1-150x92.jpg 150w, https://rux.vc/wp-content/uploads/2010/03/cpuload-indicator-photo1-300x184.jpg 300w, https://rux.vc/wp-content/uploads/2010/03/cpuload-indicator-photo1.jpg 416w" sizes="(max-width: 150px) 100vw, 150px" /></a></center>
</div>
</p>
<h2>Финал</h2>
<p>На этом всё, буду рад если кому то это помогло. Хотя это уже помогло мне самому :)<br />
Такие простые штуки позволяют сразу много всего пощюпать, хоть и не глубоко. А это помогает разложить по полочкам тонны информации. </p>
<p>Это - всё таки посложнее просто миганием светодиодов. И даже посложнее чем мигание светодиодов через USB(кстати, огромное спасибо проекту <a href="http://johannes.krude.de/projects/usb-Relay/" target="_blank">usb-Relay</a>, который помог мне разобраться во многом).</p>
<p>Стоимость сборки такого устройства порядка 100-120р(по крайней мере с ценами, которые в мегаэлектронике в СПБ)</p>
<p>У линуксодидов проблемм быть не должно. У *bsd и solaris как я понимаю тоже нет(разве что поправить пути к инклюдам в мейкфайле). С виндой всё хуже. То, что нужно libusb это очевидно, кто чистал описание проекта V-USB сразу это поняли. По идее, как я понимаю, ничего не изменится, кроме места получения текущей нагрузки процессора - тут придётся разбираться самостоятельно. Или, если получится, воспользоваться cygwin(не из за libusb, а из за<strong> libgtop!</strong>), если умеете, я если честно практически не предствляю что он умеет и как :) Ну и разумеется нужно иметь make & gcc & winAvr</p>
<p>Скачать прошивку, программу и схему(в формате KiCad) в одном файле: <a href='http://rux.pp.ru/blog/wp-content/uploads/2010/03/cpuload_indicator_v0.1.tar.gz'>cpuload_indicator_v0.1.tar.gz</a></p>The post <a href="https://rux.vc/2010.03/cpu-load-indicator/">CPU load indicator</a> first appeared on <a href="https://rux.vc">Hey, ruX is here.</a>.]]></content:encoded>
					
					<wfw:commentRss>https://rux.vc/2010.03/cpu-load-indicator/feed/</wfw:commentRss>
			<slash:comments>13</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">378</post-id>	</item>
	</channel>
</rss>
