Журнал LinuxFormat - перейти на главную

LXF163: Arduino: зажигаем светодиоды

Материал из Linuxformat
(Различия между версиями)
Перейти к: навигация, поиск
(Новая страница: «Категория: Учебники Категория: Электроника '''Элек­тро­ни­ка. Ап­па­рат­ные про­…»)
 
(Один из несколь­ких)
 
(не показаны 3 промежуточные версии 1 участника)
Строка 159: Строка 159:
 
что несо­мнен­но уп­ро­сит ис­поль­зо­вание это­го ко­да в бо­лее слож­ных слу­ча­ях.
 
что несо­мнен­но уп­ро­сит ис­поль­зо­вание это­го ко­да в бо­лее слож­ных слу­ча­ях.
  
Один из несколь­ких
+
===Один из несколь­ких===
  
 
Ду­маю, вы со­гла­си­тесь: это здо­ро­во. Те­перь без до­полнитель­ных схем мож­но управ­лять, на­при­мер, 12 све­то­дио­да­ми все­го с че­ты­рех кон­так­тов. Од­на­ко на дан­ный мо­мент у на­ше­го пла­на есть ма­лень­кий недоста­ток. Для про­стых слу­ча­ев он и прав­да удо­бен. Ес­ли нуж­но за­жечь све­то­ди­од – вы его за­жи­гае­те. Но когда нуж­но за­жечь несколь­ко све­то­дио­дов од­но­вре­мен­но, ис­ход­ный ме­тод – по од­но­му кон­так­ту на ка­ж­дый све­то­ди­од – луч­ше. В осно­ве на­шей те­ку­щей сис­те­мы – «ад­ре­са­ция» све­то­дио­дов с по­мо­щью кон­так­тов бла­го­да­ря муль­ти­п­лек­си­ро­ванию дан­ных. Те­перь нам нуж­но пол­но­стью муль­ти­п­лек­си­ро­вать вы­ход. Фи­зи­че­­ски ад­ре­со­вать несколь­ко све­то­дио­дов сра­зу невоз­мож­но, но мож­но пе­ре­клю­чать­ся ме­ж­ду ними так бы­ст­ро, что бу­дет ка­зать­ся, что они го­рят од­но­вре­мен­но.
 
Ду­маю, вы со­гла­си­тесь: это здо­ро­во. Те­перь без до­полнитель­ных схем мож­но управ­лять, на­при­мер, 12 све­то­дио­да­ми все­го с че­ты­рех кон­так­тов. Од­на­ко на дан­ный мо­мент у на­ше­го пла­на есть ма­лень­кий недоста­ток. Для про­стых слу­ча­ев он и прав­да удо­бен. Ес­ли нуж­но за­жечь све­то­ди­од – вы его за­жи­гае­те. Но когда нуж­но за­жечь несколь­ко све­то­дио­дов од­но­вре­мен­но, ис­ход­ный ме­тод – по од­но­му кон­так­ту на ка­ж­дый све­то­ди­од – луч­ше. В осно­ве на­шей те­ку­щей сис­те­мы – «ад­ре­са­ция» све­то­дио­дов с по­мо­щью кон­так­тов бла­го­да­ря муль­ти­п­лек­си­ро­ванию дан­ных. Те­перь нам нуж­но пол­но­стью муль­ти­п­лек­си­ро­вать вы­ход. Фи­зи­че­­ски ад­ре­со­вать несколь­ко све­то­дио­дов сра­зу невоз­мож­но, но мож­но пе­ре­клю­чать­ся ме­ж­ду ними так бы­ст­ро, что бу­дет ка­зать­ся, что они го­рят од­но­вре­мен­но.
Строка 189: Строка 189:
 
Этот код очень по­хож на пре­ды­ду­щий, но на сей раз пе­ред вы­хо­дом он от­клю­ча­ет свет по­сле ко­рот­кой за­держ­ки. Воз­мож­но, вам при­дет­ся уста­но­вить зна­чение за­держ­ки опыт­ным пу­тем в за­ви­си­мо­сти от чис­ла све­то­дио­дов в ва­шей схе­ме.
 
Этот код очень по­хож на пре­ды­ду­щий, но на сей раз пе­ред вы­хо­дом он от­клю­ча­ет свет по­сле ко­рот­кой за­держ­ки. Воз­мож­но, вам при­дет­ся уста­но­вить зна­чение за­держ­ки опыт­ным пу­тем в за­ви­си­мо­сти от чис­ла све­то­дио­дов в ва­шей схе­ме.
  
Те­перь мы мо­жем вклю­чать све­то­ди­од на ко­рот­кий пе­ри­од вре­мени, и по­ра по­ду­мать о том, как за­жи­гать несколь­ко све­то­дио­дов од­но­вре­мен­но. Оче­вид­ное ре­шение – цикл. Ес­ли у нас есть на­бор зна­чений, на­при­мер, би­то­вая мас­ка, для све­то­дио­дов, ко­то­рые нуж­но за­жечь, мы мо­жем прой­тись по ним в цик­ле, вклю­чая их. На са­мом де­ле, де­лать это бу­дет нуж­но неоднократно. Ес­ли нуж­но вклю­чить два све­то­дио­да на се­кун­ду, луч­ше вклю­чить ка­ж­дый на 1/500 се­кун­ды 250 раз, чем один раз на пол­се­кун­ды. Имея пе­ри­од од­но­го вклю­чения све­то­дио­да, мож­но прой­тись по цик­лу за­дан­ное ко­ли­че­­ст­во раз, и в ито­ге мы по­лу­чим за­дан­ную об­щую про­дол­жи­тель­ность вклю­чения. Это зву­чит несколь­ко сложнее, чем есть на са­мом де­ле:
+
Те­перь мы мо­жем вклю­чать све­то­ди­од на ко­рот­кий пе­ри­од вре­мени, и по­ра по­ду­мать о том, как за­жи­гать несколь­ко све­то­дио­дов од­но­вре­мен­но. Оче­вид­ное ре­шение – цикл. Ес­ли у нас есть на­бор зна­чений, на­при­мер, би­то­вая мас­ка, для све­то­дио­дов, ко­то­рые нуж­но за­жечь, мы мо­жем прой­тись по ним в цик­ле, вклю­чая их.  
  
 +
На са­мом де­ле, де­лать это бу­дет нуж­но неоднократно. Ес­ли нуж­но вклю­чить два све­то­дио­да на се­кун­ду, луч­ше вклю­чить ка­ж­дый на 1/500 се­кун­ды 250 раз, чем один раз на пол­се­кун­ды. Имея пе­ри­од од­но­го вклю­чения све­то­дио­да, мож­но прой­тись по цик­лу за­дан­ное ко­ли­че­­ст­во раз, и в ито­ге мы по­лу­чим за­дан­ную об­щую про­дол­жи­тель­ность вклю­чения. Это зву­чит несколь­ко сложнее, чем есть на са­мом де­ле:
 +
{{Врезка|right|Заголовок= Сде­ла­ем ил­лю­ми­на­цию|Ширина=60%|Содержание= Иногда нуж­но управ­лять не одним све­то­дио­дом, а це­поч­кой све­то­дио­дов (на­при­мер, как в елоч­ных гир­лян­дах). Мак­си­маль­ный ток для кон­так­та Arduino – 40 мА, и для управ­ления боль­шой це­поч­кой све­то­дио­дов по­на­до­бят­ся до­полнитель­ные схе­мы. Све­то­дио­ды про­слу­жат на­мно­го доль­ше, ес­ли на них по­дать пра­виль­ный ток!
 +
 +
Ис­точник по­сто­ян­но­го то­ка лег­ко со­брать са­мим из несколь­ких ре­зи­сто­ров и па­ры под­хо­дя­щих NPN-тран­зи­сто­ров (или по­ле­вых тран­зи­сто­ров, для боль­ших це­пей), но для при­ло­жений с боль­шим энер­го­по­треб­лением луч­ше восполь­зо­вать­ся спе­ци­аль­ной схе­мой, на­при­мер, ON Semiconduсtor CAT400 или се­ри­ей Infineon BCRxxx.}}
 
byte data = sequence[index];
 
byte data = sequence[index];
  
Строка 199: Строка 203:
 
if (data & (1<<y)) {
 
if (data & (1<<y)) {
  
dolight(y);
+
dolight(y);}}}
 
+
}
+
 
+
}
+
 
+
}
+
  
 
Здесь два цик­ла. Один цикл (с пе­ре­мен­ной y) оп­ре­де­ля­ет­ся ко­ли­че­­ст­вом све­то­дио­дов, ко­то­рые у нас есть. В ка­ж­дой ите­ра­ции зна­чение би­та (сдви­ну­тое, что­бы ока­зать­ся в нуж­ном мес­те) сравнива­ет­ся с бай­том, ко­то­рый мы на­зва­ли data – под­робнее о нем чуть поз­же. Ес­ли зна­чения сов­па­да­ют, со­от­вет­ст­вую­щий све­то­ди­од вклю­ча­ет­ся.
 
Здесь два цик­ла. Один цикл (с пе­ре­мен­ной y) оп­ре­де­ля­ет­ся ко­ли­че­­ст­вом све­то­дио­дов, ко­то­рые у нас есть. В ка­ж­дой ите­ра­ции зна­чение би­та (сдви­ну­тое, что­бы ока­зать­ся в нуж­ном мес­те) сравнива­ет­ся с бай­том, ко­то­рый мы на­зва­ли data – под­робнее о нем чуть поз­же. Ес­ли зна­чения сов­па­да­ют, со­от­вет­ст­вую­щий све­то­ди­од вклю­ча­ет­ся.
Строка 263: Строка 261:
 
if (data & (1<<y)) {
 
if (data & (1<<y)) {
  
dolight(y);
+
dolight(y);}}}}
 
+
}
+
 
+
}
+
 
+
}
+
 
+
}
+
  
 
Этот про­стой цикл пе­ре­би­ра­ет 12 зна­чений би­то­вых ма­сок из мас­си­ва sequence. В кон­це ка­ж­дой ите­ра­ции так­же мигнет све­то­ди­од на пла­те – так мы смо­жем об­на­ру­жить непра­виль­ные со­единения про­водников или стран­ное по­ве­дение схе­мы. Код в этом ви­де ра­бо­та­ет, но кое-что мож­но из­менить. Во-пер­вых, на вре­мя, в те­чение ко­то­ро­го го­рят све­то­дио­ды в од­ной ите­ра­ции, сла­бо влия­ет их ко­ли­че­­ст­во, но об этом вре­мени сто­ит по­за­бо­тить­ся, что­бы из­бе­жать бо­лее серь­ез­ной про­бле­мы.
 
Этот про­стой цикл пе­ре­би­ра­ет 12 зна­чений би­то­вых ма­сок из мас­си­ва sequence. В кон­це ка­ж­дой ите­ра­ции так­же мигнет све­то­ди­од на пла­те – так мы смо­жем об­на­ру­жить непра­виль­ные со­единения про­водников или стран­ное по­ве­дение схе­мы. Код в этом ви­де ра­бо­та­ет, но кое-что мож­но из­менить. Во-пер­вых, на вре­мя, в те­чение ко­то­ро­го го­рят све­то­дио­ды в од­ной ите­ра­ции, сла­бо влия­ет их ко­ли­че­­ст­во, но об этом вре­мени сто­ит по­за­бо­тить­ся, что­бы из­бе­жать бо­лее серь­ез­ной про­бле­мы.
Строка 277: Строка 267:
 
В об­щем слу­чае та­кие дей­ст­вия луч­ше все­го оформ­лять в ви­де про­це­ду­ры пре­ры­вания, в за­ви­си­мо­сти от то­го, что вам нуж­но. За­тем она мо­жет по­лу­чить на­бор зна­чений sequence из мас­си­ва или по­сто­ян­но про­хо­дить по «шаб­ло­ну», за­дан­но­му в гло­баль­ной пе­ре­мен­ной – ее за­тем мож­но бу­дет из­менить в основ­ном ко­де. Мы го­во­ри­ли о тай­ме­рах и пре­ры­ваниях во мно­гих из пре­ды­ду­щих ста­тей, и вы долж­ны су­меть сде­лать что-нибудь на ско­рую ру­ку!
 
В об­щем слу­чае та­кие дей­ст­вия луч­ше все­го оформ­лять в ви­де про­це­ду­ры пре­ры­вания, в за­ви­си­мо­сти от то­го, что вам нуж­но. За­тем она мо­жет по­лу­чить на­бор зна­чений sequence из мас­си­ва или по­сто­ян­но про­хо­дить по «шаб­ло­ну», за­дан­но­му в гло­баль­ной пе­ре­мен­ной – ее за­тем мож­но бу­дет из­менить в основ­ном ко­де. Мы го­во­ри­ли о тай­ме­рах и пре­ры­ваниях во мно­гих из пре­ды­ду­щих ста­тей, и вы долж­ны су­меть сде­лать что-нибудь на ско­рую ру­ку!
  
Не­достат­ки чар­ли­п­лек­си­ро­вания
+
===Не­достат­ки чар­ли­п­лек­си­ро­вания===
  
 
Хо­тя чар­ли­п­лек­си­ро­вание по­зво­ля­ет изящ­но и эф­фек­тив­но ис­поль­зо­вать вы­хо­ды, ряд про­блем ог­раничи­ва­ют его достоинства. Са­мая боль­шая из них – не слиш­ком хо­ро­шее мас­шта­би­ро­вание. По ме­ре уве­ли­чения ко­ли­че­­ст­ва све­то­дио­дов они не толь­ко го­рят все бо­лее туск­ло (све­тят­ся в те­чение мень­ше­го ин­тер­ва­ла вре­мени), но и код для управ­ления ими занима­ет все боль­ше и боль­ше доступ­но­го про­цес­сор­но­го вре­мени. Дру­гой недоста­ток про­яв­ля­ет се­бя, ес­ли один из све­то­дио­дов вы­хо­дит из строя. Неис­прав­но­сти све­то­дио­дов не всегда оз­на­ча­ют толь­ко то, что они не го­рят – сюда вклю­чается и неже­ла­тель­ное влияние на схе­му, на­при­мер, непре­ду­смот­рен­ная ем­кость, утеч­ки то­ка и про­чие непри­ят­ные ве­щи. В этих слу­ча­ях из-за од­но­го нера­бо­таю­ще­го све­то­дио­да весь дис­плей мо­жет на­чать вес­ти се­бя стран­но.
 
Хо­тя чар­ли­п­лек­си­ро­вание по­зво­ля­ет изящ­но и эф­фек­тив­но ис­поль­зо­вать вы­хо­ды, ряд про­блем ог­раничи­ва­ют его достоинства. Са­мая боль­шая из них – не слиш­ком хо­ро­шее мас­шта­би­ро­вание. По ме­ре уве­ли­чения ко­ли­че­­ст­ва све­то­дио­дов они не толь­ко го­рят все бо­лее туск­ло (све­тят­ся в те­чение мень­ше­го ин­тер­ва­ла вре­мени), но и код для управ­ления ими занима­ет все боль­ше и боль­ше доступ­но­го про­цес­сор­но­го вре­мени. Дру­гой недоста­ток про­яв­ля­ет се­бя, ес­ли один из све­то­дио­дов вы­хо­дит из строя. Неис­прав­но­сти све­то­дио­дов не всегда оз­на­ча­ют толь­ко то, что они не го­рят – сюда вклю­чается и неже­ла­тель­ное влияние на схе­му, на­при­мер, непре­ду­смот­рен­ная ем­кость, утеч­ки то­ка и про­чие непри­ят­ные ве­щи. В этих слу­ча­ях из-за од­но­го нера­бо­таю­ще­го све­то­дио­да весь дис­плей мо­жет на­чать вес­ти се­бя стран­но.
  
 
Но не сбра­сы­вай­те его со сче­тов – для мало­го ко­ли­че­­ст­ва све­то­дио­дов оно очень удоб­но и по­зво­ля­ет сэ­ко­но­мить на до­бавоч­ных ком­понен­тах, энер­го­по­треб­лении и про­стран­ст­ве. Оно го­дит­ся не толь­ко для за­жи­гания све­то­дио­дов. С под­хо­дя­щи­ми ком­понен­та­ми мож­но сберечь несколь­ко кон­так­тов для управ­ления дви­га­те­ля­ми (ко­то­рым не нуж­но несколь­ко вы­со­ких уровней сразу) или для вхо­дов – эти неудоб­ные мат­рич­ные кла­виа­ту­ры эф­фек­тивнее сканиро­вать с несколь­ки­ми дио­да­ми и под­хо­дя­щей схе­мой Чар­ли или це­ло­го мас­си­ва дру­гих вхо­дов. |
 
Но не сбра­сы­вай­те его со сче­тов – для мало­го ко­ли­че­­ст­ва све­то­дио­дов оно очень удоб­но и по­зво­ля­ет сэ­ко­но­мить на до­бавоч­ных ком­понен­тах, энер­го­по­треб­лении и про­стран­ст­ве. Оно го­дит­ся не толь­ко для за­жи­гания све­то­дио­дов. С под­хо­дя­щи­ми ком­понен­та­ми мож­но сберечь несколь­ко кон­так­тов для управ­ления дви­га­те­ля­ми (ко­то­рым не нуж­но несколь­ко вы­со­ких уровней сразу) или для вхо­дов – эти неудоб­ные мат­рич­ные кла­виа­ту­ры эф­фек­тивнее сканиро­вать с несколь­ки­ми дио­да­ми и под­хо­дя­щей схе­мой Чар­ли или це­ло­го мас­си­ва дру­гих вхо­дов. |

Текущая версия на 02:33, 21 октября 2018


Элек­тро­ни­ка. Ап­па­рат­ные про­ек­ты с от­кры­тым ко­дом, рас­ши­ряющие ваш кру­го­зор.


Содержание

[править] Arduino: Да бу­дет свет

Ник Вейч изо всех сил ста­ра­ет­ся не ос­леп­нуть от бле­ска, с ко­то­рым он за­жег столь­ко све­то­дио­дов все­го на не­сколь­ких вы­хо­дах.

(thumbnail)
Наш эксперт. Ко­гда LXF толь­ко поя­вил­ся, его дер­жа­ли на пла­ву исключительно скрип­ты Bash от Ни­ка Вей­ча. По­том их за­ме­ни­ли «лю­ди», и это, по мне­нию Ни­ка, ста­ло ша­гом на­зад...

В ту­ман­ном про­шлом, когда у всех нас на ков­ре бы­ло чуть мень­ше ожо­гов от при­поя, мы при­за­ду­ма­лись об ис­поль­зо­вании 8-сег­мент­ных дис­пле­ев – и чи­та­те­ли пред­ло­жи­ли нам муль­ти­п­лек­си­ро­вать вы­хо­ды. Это хо­ро­шее пред­ло­жение с ря­дом пре­иму­ществ, но оно име­ет и недостат­ки.

Глав­ный недоста­ток здесь в том, что на управ­ление дис­пле­ем нуж­но вре­мя. Ес­ли за­ста­вить Arduino по­сто­ян­но ме­нять зна­чения сег­мен­тов, у него не останет­ся вре­мени ни на что дру­гое. По­это­му ес­ли управ­ление дис­плея­ми – не глав­ная за­да­ча ва­шей схе­мы на Arduino, муль­ти­п­лек­си­ро­вание вы­хо­дов эф­фек­тив­но толь­ко в неболь­шом, бо­лее управ­ляе­мом мас­шта­бе. Су­ще­ст­ву­ет несколь­ко спо­со­бов муль­ти­п­лек­си­ро­вания (то есть, ис­поль­зо­вания од­но­го вхо­да/вы­хо­да для вы­полнения несколь­ких за­дач), и один из са­мых про­стых – муль­ти­п­лек­си­ро­вание ме­то­дом Чар­ли.

[править] Чар­ли­п­лек­си­ро­вание

Од­но из ог­раничений при под­клю­чении све­то­дио­дов к Arduino – кон­так­ты. Ес­ли под­клю­чать по све­то­дио­ду на ка­ж­дый вы­вод, вы­во­ды за­кон­чат­ся до­воль­но ско­ро. В пре­ды­ду­щих стать­ях мы рас­смот­ре­ли спо­со­бы уве­ли­чения ко­ли­че­­ст­ва ад­ре­суе­мых вы­во­дов, обыч­но с по­мо­щью до­полнитель­ных мик­ро­схем, на­при­мер, сдви­го­вых ре­ги­ст­ров, но есть и дру­гой ме­тод, до­полнитель­ных мик­ро­схем не тре­бую­щий – чар­ли­п­лек­си­ро­вание.

На­зван ме­тод именем Чар­ли Ал­ле­на [Charlie Allen], ин­женера из ком­пании Maxim, ко­то­рый столк­нул­ся с той же про­бле­мой, пы­та­ясь управ­лять дис­плея­ми со мно­же­ст­вом све­то­дио­дов. Ос­нов­ная идея это­го ме­то­да про­ста: кон­так­ты Arduino мож­но счи­тать вы­хо­да­ми, но они так­же и вхо­ды. Пред­ставь­те се­бе сле­дую­щую про­стую схе­му:

» Схе­ма 1 Два кон­так­та, два вы­хо­да. С их пе­ре­во­дом в «единицу» све­то­дио­ды за­го­ра­ют­ся. Все про­сто. Но те­перь по­ду­май­те о том, что вы­хо­ды мо­гут быть в «единице» или в «ну­ле», а све­то­дио­ды– будучи дио­дами – как-никак ра­бо­та­ют од­но­на­прав­лен­но.

Воз­мож­на и та­кая схе­ма:

» Схе­ма 2 Важней­шее от­ли­чие в том, что те­перь со­стояния «единица» и «ноль» применя­ют­ся для управ­ления вы­во­да­ми. Когда один в «единице», а дру­гой в «ну­ле», све­то­ди­од за­го­ра­ет­ся. Поменяйте их местами, и за­го­рит­ся дру­гой све­то­ди­од.

Ми­ло, правда? Но осо­бо прыт­кие в под­сче­тах за­ме­ти­ли, что све­то­дио­дов не ста­ло боль­ше. В «обыч­ной» схе­ме мы за­жгли два све­то­дио­да. В но­вой схе­ме их все еще два. Да, но этот шаг необ­хо­дим, что­бы пе­рей­ти к сле­дую­ще­му – ина­че он взо­рвет ваш мозг. При уве­ли­чении чис­ла кон­так­тов до трех, схе­ма станет та­кой:

» Схе­ма 3 Это боль­шой шаг впе­ред. С тре­мя вы­хо­да­ми и за­мы­сло­ва­той схе­мой мы мо­жем управ­лять ше­стью све­то­дио­да­ми.

Здесь важ­но от­ме­тить: что­бы это за­ра­бо­та­ло, нам при­дет­ся восполь­зо­вать­ся тем, что кон­так­ты Arduino мо­гут на­хо­дить­ся в трех со­стояниях. Вам зна­ко­мы «единица» и «ноль», но, конеч­но, есть и еще од­но – со­стояние боль­шо­го со­про­тив­ления (или со­стояние вхо­да), в ко­то­ром кон­такт по су­ти никак не влия­ет на схе­му. Пе­ре­ве­дя один из кон­так­тов в это со­стояние (и та­ким об­ра­зом от­клю­чив его) и пе­ре­во­дя дру­гие два в «единицу» или «ноль», мы мо­жем об­ра­щать­ся к ка­ж­до­му из шес­ти све­то­дио­дов.

[править] Вы­пол­ня­ем вы­чис­ления

Ес­ли по­раз­мыс­лить, то у нас есть два ва­ри­ан­та в на­бо­ре из трех пар све­то­дио­дов (три ва­ри­ан­та), но они мо­гут ра­бо­тать в лю­бом на­прав­лении, что да­ет нам 2 × 3, или 6. Уг­лу­бив­шись в ма­те­ма­ти­ку, мож­но вы­вес­ти фор­му­лу для N кон­так­тов – это N2-N или N(N-1) све­то­дио­дов. В боль­шин­ст­ве слу­ча­ев слож­ность за­клю­ча­ет­ся в том, что­бы на­ри­со­вать схе­му и за­помнить, как рас­по­ла­гать све­то­дио­ды. За­да­чу оп­ре­де­лен­но об­лег­ча­ет их рас­по­ло­жение в па­рах в про­ти­во­по­лож­ном на­прав­лении. Да, и не за­будь­те до­ба­вить к ка­ж­до­му кон­так­ту последовательно ре­зи­сто­р, для ог­раничения то­ка. Так как в схе­ме их всегда два, вы­бе­ри­те зна­чение со­про­тив­ления, ко­то­рым обыч­но поль­зуе­тесь, и раз­де­ли­те его на два. Те­перь пе­ре­хо­дим к управ­лению све­то­дио­да­ми.

LXF158.tut arduino.1-3.png

Конеч­но, манипу­ля­ции с тре­мя пор­та­ми для управ­ления на­бо­ром све­то­дио­дов несколь­ко об­ре­менитель­ны, но воз­мож­ны. На­стоя­щие труд­но­сти нач­нут­ся, когда вы пой­ме­те, что для это­го недоста­точ­но про­сто за­пи­сать в них зна­чения, так как мы ра­бо­та­ем с ло­ги­кой с тре­мя со­стояния­ми (1,0,X). Ос­ложнение еще в том, что для из­менения этих зна­чений нуж­но ис­поль­зо­вать раз­лич­ные вы­зо­вы из Arduino (да­же ес­ли пой­ти ко­рот­ким пу­тем и за­пи­сы­вать зна­чения на­пря­мую в ад­ре­са пор­тов, вы об­на­ру­жи­те, что все рав­но нуж­но из­ме­нять дру­гой ре­гистр). Как сде­лать это для на­шей схе­мы с тре­мя кон­так­та­ми? Допустим, это кон­так­ты 10, 11 и 12 Arduino. Пре­ж­де все­го инициа­ли­зи­ру­ем их в функ­ции setup():

void setup() {

pinMode(10, OUTPUT);

pinMode(12, OUTPUT);

pinMode(11, OUTPUT);

delay(6000);

}

В про­цес­се ра­бо­ты мы бу­дем из­ме­нять ре­жи­мы од­но­го из этих кон­так­тов, но нет ниче­го страш­но­го в том, что­бы за­дать все ре­жи­мы с са­мо­го на­ча­ла, что­бы мы ви­де­ли, ка­кие кон­так­ты ис­поль­зу­ют­ся. За­чем здесь за­держ­ка? Это про­сто при­выч­ка, поя­вив­шая­ся у ме­ня по­сле то­го, как я ча­са­ми пы­тал­ся ожи­вить нера­бо­таю­щие пла­ты Arduino. За­держ­ка да­ет по­сле­до­ва­тель­но­му ин­тер­фей­су вре­мя за­ме­тить, что его пы­та­ют­ся пе­ре­про­грам­ми­ро­вать. От ду­ши ре­ко­мен­дую де­лать так же. Те­перь пе­рей­дем соб­ст­вен­но к за­жи­ганию све­то­дио­дов:

void loop() {

// light each in sequence

digitalWrite(11, HIGH);

digitalWrite(12, LOW);

pinMode (10, INPUT);

delay(100);

pinMode (10, OUTPUT);

digitalWrite(11, LOW);

digitalWrite(12, HIGH);

pinMode (10, INPUT);

delay(100);

pinMode (10, OUTPUT);

digitalWrite(11, HIGH);

digitalWrite(10, LOW);

pinMode (12, INPUT);

delay(100);

pinMode (12, OUTPUT);

Здесь мож­но оста­но­вить­ся (конеч­но, оста­лись еще три со­че­тания кон­так­тов, но ход мыс­ли нам те­перь ясен, к то­му же вы всегда мо­же­те за­гля­нуть в код на DVD, ес­ли не на­пи­ше­те его са­ми). Для ка­ж­до­го све­то­дио­да нам нуж­но уста­но­вить один вы­вод в «единицу», дру­гой в «ноль», а тре­тий – в со­стояние вхо­да. По су­ти это со­стояние от­клю­ча­ет его – это лишь со­стояние вы­со­ко­го со­про­тив­ления, но для осталь­ной схе­мы кон­такт вы­гля­дит вы­клю­чен­ным, ес­ли не пы­тать­ся про­честь с него дан­ные. За­держ­ка по­зво­ля­ет нам уви­деть, как све­то­ди­од за­го­ра­ет­ся, по­том мы пе­ре­во­дим вы­вод в со­стояние «от­клю­че­но», так что не за­пу­та­ем­ся. Ес­ли по­ду­мать, то при­мер мож­но улуч­шить, по­сле­до­ва­тель­но об­ра­ба­ты­вая два све­то­дио­да, для за­жи­гания ко­то­рых нуж­но от­клю­чить оп­ре­де­лен­ный кон­такт; это сэ­ко­но­мит несколь­ко вы­зо­вов. Но это не глав­ное.

Бы­ва­ют, конеч­но, си­туа­ции, в ко­то­рых нуж­но прой­ти по всем имею­щим­ся све­то­дио­дам для соз­дания стро­бо­ско­пи­че­­ско­­го эф­фек­та, как на ав­то­мо­би­ле из се­риа­ла «Ры­царь до­рог», но ча­ще нуж­но толь­ко вклю­чать и вы­клю­чать оп­ре­де­лен­ные све­то­дио­ды.

Эта длин­ная запись в ко­де – не луч­ший ва­ри­ант, и для управ­ления све­то­дио­да­ми нам ну­жен спо­соб по­кру­че. Про­стой ва­ри­ант – мас­си­вы. Ес­ли за­дать несколь­ко мас­си­вов со зна­чения­ми кон­так­та, их мож­но ис­поль­зо­вать как ар­гу­мен­ты функ­ции, вклю­чаю­щей и вы­клю­чаю­щей све­то­дио­ды.

uint8_t cathode[6] = {12,11,10,11,12,10};

uint8_t anode[6] = {11,12,11,10,10,12};

uint8_t off[6] = {10,10,12,12,11,11};

Тип uint8_t – то же, что и байт, но это бо­лее яв­ное оп­ре­де­ление. Как ви­ди­те, мы соз­да­ли три мас­си­ва – для ка­то­да, ано­да и «вы­клю­чен­но­го» кон­так­та. Они со­дер­жат чи­сло­вые зна­чения кон­так­тов для ка­ж­до­го све­то­дио­да по­сле­до­ва­тель­но. На­при­мер, ес­ли нуж­но вклю­чить све­то­ди­од № 3, то кон­такт 11 нуж­но пе­ре­вес­ти в «ноль», кон­такт 10 – в «единицу», а кон­такт 12 – в со­стояние вхо­да.

Вы мо­же­те кое-что улуч­шить в этом ко­де, но все это во­прос ком­про­мис­са. На­при­мер, мож­но оста­вить толь­ко мас­си­вы для ка­то­да и ано­да, так как тре­тий кон­такт в лю­бом слу­чае вы­клю­чен. Вер­но, но тогда в ко­де при­дет­ся брать два су­ще­ст­вую­щих зна­чения и оп­ре­де­лять, зна­чение ка­ко­го кон­так­та не за­да­но. Ли­бо мож­но «вы­клю­чить» все кон­так­ты, а за­тем вклю­чить те, ко­то­рые ис­поль­зу­ют­ся. Оба ва­ри­ан­та воз­мож­ны, но неже­ла­тель­ны.

На дан­ном эта­пе это несу­ще­ст­вен­но, но в це­лом мы хо­тим, что­бы код, вклю­чаю­щий и вы­клю­чаю­щий вхо­ды, ра­бо­тал мак­си­маль­но бы­ст­ро. До­полнитель­ные дей­ст­вия и вы­чис­ления при­ве­дут лишь к тра­те цик­лов тай­ме­ра и к неже­ла­тель­ным пе­ре­клю­чениям, ко­то­рые мо­гут обусловить и мер­цание.

Так или ина­че, вот наш глав­ный цикл, ко­то­рый вы­пол­ня­ет ту же за­да­чу, что и пре­ж­де – вклю­ча­ет све­то­дио­ды по­сле­до­ва­тель­но:

void loop() {

for (int i=0;i<6;i++){

pinMode(off[i],INPUT);

pinMode(cathode[i],OUTPUT);

digitalWrite(cathode[i],LOW);

pinMode(anode[i],OUTPUT);

digitalWrite(anode[i],HIGH);

delay(250);

}

}

Этот код ниче­го не пред­по­ла­га­ет – он про­сто за­да­ет со­стояния вы­клю­чен­но­го кон­так­та, за­тем про­ве­ря­ет, что со­стояния двух осталь­ных кон­так­тов за­да­ны вер­но, и за­пи­сы­ва­ет в них зна­чения. Хо­тя для по­сле­до­ва­тель­но­го вклю­чения све­то­дио­дов мы обер­ну­ли это в цикл, мож­но офор­мить это и в ви­де функ­ции:

void loop() {

for (int i=0;i<6;i++){

lightlamp(i);

delay(250);

}

}

void lightlamp(int i){

pinMode(off[i],INPUT);

pinMode(cathode[i],OUTPUT);

digitalWrite(cathode[i],LOW);

pinMode(anode[i],OUTPUT);

digitalWrite(anode[i],HIGH);

}

что несо­мнен­но уп­ро­сит ис­поль­зо­вание это­го ко­да в бо­лее слож­ных слу­ча­ях.

[править] Один из несколь­ких

Ду­маю, вы со­гла­си­тесь: это здо­ро­во. Те­перь без до­полнитель­ных схем мож­но управ­лять, на­при­мер, 12 све­то­дио­да­ми все­го с че­ты­рех кон­так­тов. Од­на­ко на дан­ный мо­мент у на­ше­го пла­на есть ма­лень­кий недоста­ток. Для про­стых слу­ча­ев он и прав­да удо­бен. Ес­ли нуж­но за­жечь све­то­ди­од – вы его за­жи­гае­те. Но когда нуж­но за­жечь несколь­ко све­то­дио­дов од­но­вре­мен­но, ис­ход­ный ме­тод – по од­но­му кон­так­ту на ка­ж­дый све­то­ди­од – луч­ше. В осно­ве на­шей те­ку­щей сис­те­мы – «ад­ре­са­ция» све­то­дио­дов с по­мо­щью кон­так­тов бла­го­да­ря муль­ти­п­лек­си­ро­ванию дан­ных. Те­перь нам нуж­но пол­но­стью муль­ти­п­лек­си­ро­вать вы­ход. Фи­зи­че­­ски ад­ре­со­вать несколь­ко све­то­дио­дов сра­зу невоз­мож­но, но мож­но пе­ре­клю­чать­ся ме­ж­ду ними так бы­ст­ро, что бу­дет ка­зать­ся, что они го­рят од­но­вре­мен­но.

Ин­те­рес­но, что та­кое муль­ти­п­лек­си­ро­вание све­то­дио­дов ста­ло по­пу­ляр­ным не толь­ко из-за ог­раничений ад­ре­са­ции, но и из-за эко­но­мии энер­гии. Ес­ли один све­то­ди­од по­треб­ля­ет в среднем око­ло 20 мА, то шесть бу­дут по­треб­лять 120 мА. Ес­ли взять эквивалент схе­ме с чар­ли­п­лек­си­ро­ванием с ше­стью кон­так­та­ми, мы по­лу­чим 6 × 5 × 20 мА = 600 мА, а это боль­ше, чем обеспечивается стан­дарт­ным USB-под­клю­чением. Вряд ли несколь­ко све­то­дио­дов мо­гут при­чинить столь­ко непри­ят­но­стей (ра­зу­ме­ет­ся, к ним мож­но под­клю­чить внешний ис­точник пи­тания), но ес­ли учесть, что муль­ти­плек­си­ро­вание мо­жет снизить энер­го­по­треб­ление на 97 %, это хо­ро­шая идея, осо­бен­но для схем с пи­танием от ба­та­рей­ки.

Внесем несколь­ко про­стых из­менений в функ­цию вклю­чения све­то­дио­дов и бу­дем по­да­вать на ка­ж­дый из них неболь­шой им­пульс вме­сто то­го, что­бы про­сто вклю­чать его:

void dolight(int light_number){

pinMode(off[light_number],INPUT);

pinMode(cathode[light_number],OUTPUT);

digitalWrite(cathode[light_number],LOW);

pinMode(anode[light_number],OUTPUT);

digitalWrite(anode[light_number],HIGH);

delay(2);

pinMode(cathode[light_number],INPUT);

pinMode(anode[light_number],INPUT);

}

Этот код очень по­хож на пре­ды­ду­щий, но на сей раз пе­ред вы­хо­дом он от­клю­ча­ет свет по­сле ко­рот­кой за­держ­ки. Воз­мож­но, вам при­дет­ся уста­но­вить зна­чение за­держ­ки опыт­ным пу­тем в за­ви­си­мо­сти от чис­ла све­то­дио­дов в ва­шей схе­ме.

Те­перь мы мо­жем вклю­чать све­то­ди­од на ко­рот­кий пе­ри­од вре­мени, и по­ра по­ду­мать о том, как за­жи­гать несколь­ко све­то­дио­дов од­но­вре­мен­но. Оче­вид­ное ре­шение – цикл. Ес­ли у нас есть на­бор зна­чений, на­при­мер, би­то­вая мас­ка, для све­то­дио­дов, ко­то­рые нуж­но за­жечь, мы мо­жем прой­тись по ним в цик­ле, вклю­чая их.

На са­мом де­ле, де­лать это бу­дет нуж­но неоднократно. Ес­ли нуж­но вклю­чить два све­то­дио­да на се­кун­ду, луч­ше вклю­чить ка­ж­дый на 1/500 се­кун­ды 250 раз, чем один раз на пол­се­кун­ды. Имея пе­ри­од од­но­го вклю­чения све­то­дио­да, мож­но прой­тись по цик­лу за­дан­ное ко­ли­че­­ст­во раз, и в ито­ге мы по­лу­чим за­дан­ную об­щую про­дол­жи­тель­ность вклю­чения. Это зву­чит несколь­ко сложнее, чем есть на са­мом де­ле:

byte data = sequence[index];

for (int cycle=0; cycle<50; ++cycle){

for (int y=0; y<5; ++y) {

if (data & (1<<y)) {

dolight(y);}}}

Здесь два цик­ла. Один цикл (с пе­ре­мен­ной y) оп­ре­де­ля­ет­ся ко­ли­че­­ст­вом све­то­дио­дов, ко­то­рые у нас есть. В ка­ж­дой ите­ра­ции зна­чение би­та (сдви­ну­тое, что­бы ока­зать­ся в нуж­ном мес­те) сравнива­ет­ся с бай­том, ко­то­рый мы на­зва­ли data – под­робнее о нем чуть поз­же. Ес­ли зна­чения сов­па­да­ют, со­от­вет­ст­вую­щий све­то­ди­од вклю­ча­ет­ся.

Внешний цикл под управ­лением пе­ре­мен­ной cycle про­сто вы­пол­ня­ет­ся за­дан­ное ко­ли­че­­ст­во раз. Это оз­на­ча­ет, что в ка­ж­дой ите­ра­ции все необ­хо­ди­мые све­то­дио­ды за­го­ра­ют­ся и гас­нут нуж­ное ко­ли­че­­ст­во раз, соз­да­вая впе­чат­ление, что они го­рят.

Един­ст­вен­ная за­гад­ка – пе­ре­мен­ная byte. Как вид­но из пер­вой стро­ки ко­да, мы по­лу­ча­ем ее из дру­го­го мас­си­ва. Это про­сто мас­сив би­то­вых ма­сок, от­ра­жаю­щий по­сле­до­ва­тель­ность вклю­чения све­то­дио­дов. Мы за­пи­са­ли ее в дво­ич­ной но­та­ции, так ее го­раз­до про­ще по­нять:

uint8_t sequence[12] ={

B00000001,

B00000011,

B00000111,

B00001111,

B00011111,

B00111111,

B00100000,

}

Итак, нам нуж­но толь­ко пе­ре­дать эти би­то­вые мас­ки функ­ции, ко­то­рая бу­дет ото­бра­жать их в те­чение оп­ре­де­лен­но­го пе­рио­да вре­мени.

void loop() {

for (int i=0;i<12;i++){

dosequence(i);

delay(500);

digitalWrite(13,HIGH);

delay(1);

digitalWrite(13,LOW);

}

}

void dosequence(int index){

byte data = sequence[index];

for (uint8_t cycle=0; cycle<50; ++cycle){

for (uint8_t y=0; y<5; ++y) {

if (data & (1<<y)) {

dolight(y);}}}}

Этот про­стой цикл пе­ре­би­ра­ет 12 зна­чений би­то­вых ма­сок из мас­си­ва sequence. В кон­це ка­ж­дой ите­ра­ции так­же мигнет све­то­ди­од на пла­те – так мы смо­жем об­на­ру­жить непра­виль­ные со­единения про­водников или стран­ное по­ве­дение схе­мы. Код в этом ви­де ра­бо­та­ет, но кое-что мож­но из­менить. Во-пер­вых, на вре­мя, в те­чение ко­то­ро­го го­рят све­то­дио­ды в од­ной ите­ра­ции, сла­бо влия­ет их ко­ли­че­­ст­во, но об этом вре­мени сто­ит по­за­бо­тить­ся, что­бы из­бе­жать бо­лее серь­ез­ной про­бле­мы.

В об­щем слу­чае та­кие дей­ст­вия луч­ше все­го оформ­лять в ви­де про­це­ду­ры пре­ры­вания, в за­ви­си­мо­сти от то­го, что вам нуж­но. За­тем она мо­жет по­лу­чить на­бор зна­чений sequence из мас­си­ва или по­сто­ян­но про­хо­дить по «шаб­ло­ну», за­дан­но­му в гло­баль­ной пе­ре­мен­ной – ее за­тем мож­но бу­дет из­менить в основ­ном ко­де. Мы го­во­ри­ли о тай­ме­рах и пре­ры­ваниях во мно­гих из пре­ды­ду­щих ста­тей, и вы долж­ны су­меть сде­лать что-нибудь на ско­рую ру­ку!

[править] Не­достат­ки чар­ли­п­лек­си­ро­вания

Хо­тя чар­ли­п­лек­си­ро­вание по­зво­ля­ет изящ­но и эф­фек­тив­но ис­поль­зо­вать вы­хо­ды, ряд про­блем ог­раничи­ва­ют его достоинства. Са­мая боль­шая из них – не слиш­ком хо­ро­шее мас­шта­би­ро­вание. По ме­ре уве­ли­чения ко­ли­че­­ст­ва све­то­дио­дов они не толь­ко го­рят все бо­лее туск­ло (све­тят­ся в те­чение мень­ше­го ин­тер­ва­ла вре­мени), но и код для управ­ления ими занима­ет все боль­ше и боль­ше доступ­но­го про­цес­сор­но­го вре­мени. Дру­гой недоста­ток про­яв­ля­ет се­бя, ес­ли один из све­то­дио­дов вы­хо­дит из строя. Неис­прав­но­сти све­то­дио­дов не всегда оз­на­ча­ют толь­ко то, что они не го­рят – сюда вклю­чается и неже­ла­тель­ное влияние на схе­му, на­при­мер, непре­ду­смот­рен­ная ем­кость, утеч­ки то­ка и про­чие непри­ят­ные ве­щи. В этих слу­ча­ях из-за од­но­го нера­бо­таю­ще­го све­то­дио­да весь дис­плей мо­жет на­чать вес­ти се­бя стран­но.

Но не сбра­сы­вай­те его со сче­тов – для мало­го ко­ли­че­­ст­ва све­то­дио­дов оно очень удоб­но и по­зво­ля­ет сэ­ко­но­мить на до­бавоч­ных ком­понен­тах, энер­го­по­треб­лении и про­стран­ст­ве. Оно го­дит­ся не толь­ко для за­жи­гания све­то­дио­дов. С под­хо­дя­щи­ми ком­понен­та­ми мож­но сберечь несколь­ко кон­так­тов для управ­ления дви­га­те­ля­ми (ко­то­рым не нуж­но несколь­ко вы­со­ких уровней сразу) или для вхо­дов – эти неудоб­ные мат­рич­ные кла­виа­ту­ры эф­фек­тивнее сканиро­вать с несколь­ки­ми дио­да­ми и под­хо­дя­щей схе­мой Чар­ли или це­ло­го мас­си­ва дру­гих вхо­дов. |

Персональные инструменты
купить
подписаться
Яндекс.Метрика