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

LXF154:Arduino

Материал из Linuxformat
Перейти к: навигация, поиск

Arduino Пре­ры­ва­ем се­рию, что­бы рас­смот­реть про­грам­ми­ро­ва­ние встро­ен­ной функ­ции

=Arduino: Поль­за пре­ры­ва­ний= Arduino – это не толь­ко мон­таж. Ник Вейч по­ка­жет па­ру по­лез­ных прие­мов про­грам­ми­ро­ва­ния и соз­даст ра­дар кон­тро­ля ско­ро­сти с точ­но­стью ла­зе­ра.

LXF154.80.1.png
(thumbnail)
Прин­ци­пи­аль­ная схе­ма триг­ге­ра Шмит­та, по­стро­ен­ная все­го из не­сколь­ких ре­зи­сто­ров и па­ры тран­зи­сто­ров.

Ранее мы уз­на­ли, как объ­е­ди­нять ком­понен­ты раз­лич­ных ти­пов в про­ек­тах Arduino, но се­го­дня мы пре­рвем­ся на спе­ци­аль­ное ру­ко­во­дство о том, как про­грам­ми­ро­вать в Arduino встро­ен­ную функ­цию.

Взгляните на этот про­стень­кий фраг­мент ко­да:

int sensorValue=0;

void setup() {

pinMode(2, INPUT);

digitalWrite(2, HIGH);

pinMode(13, OUTPUT);

}

void loop() {

sensorValue = digitalRead(2);

digitalWrite(13, !sensorValue);

}

Цепь пред­ста­вить се­бе лег­ко: в ней все­го од­на на­жим­ная кноп­ка, по­ме­щен­ная ме­ж­ду вы­во­дом 2 и Зем­лей, и при ее на­жа­тии за­го­ра­ет­ся встро­ен­ный све­то­ди­од на вы­во­де 13.

Един­ст­вен­ный во­прос, ко­то­рый мог у вас возник­нуть – по­че­му мы уста­нав­ли­ва­ем зна­чение вы­во­да в «единицу» (HIGH) и про­грамм­но ин­вер­ти­ру­ем счи­ты­вае­мое зна­чение для управ­ления све­то­дио­дом. А это эко­но­мит вре­мя на до­бы­вание ре­зи­сто­ра 10 кОм, что­бы он вы­сту­пал в ка­че­­ст­ве понижаю­ще­го, ес­ли вы хо­ти­те под­клю­чить кноп­ку к плю­со­во­му вы­во­ду на­пря­жения пи­тания и вклю­чать све­то­ди­од сиг­на­лом «единица» (HIGH).

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

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

Ну, а те­перь взгляните на сле­дую­щий фраг­мент ко­да:

int sensorValue=0;

void setup() {

pinMode(2, INPUT);

digitalWrite(2, HIGH);

pinMode(13, OUTPUT);

}

void loop() {

int j;

sensorValue = digitalRead(2);

digitalWrite(13, !sensorValue);

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

j = j+i*i;

delay(100);

j= 1;

}

}

В чем разница? Мы здесь до­ба­ви­ли в цикл некие произвольные дей­ст­вия. Их смысл роли не игра­ет: они встав­ле­ны лишь для ил­лю­ст­ра­ции. Что произой­дет, ес­ли вы­полнить этот код на нашей це­пи? На вид все то же, да? Ес­ли да, вы про­сто слиш­ком мед­лен­но нажимае­те кноп­ку... по­про­буй­те еще!

(thumbnail)
Это внутренняя принципиальная схема микросхемы 74123. Тригеры Шмидта на входах улучшают ваши сигналы

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

Та­кая неот­зыв­чи­вость мо­жет раз­доса­довать конеч­но­го поль­зо­ва­те­ля: для ре­ги­ст­ра­ции со­бы­тия ему при­дет­ся це­ле­на­прав­лен­но и убедительно да­вить на кноп­ку. Бы­ва­ет и ху­же. Пе­ре­клю­чаю­щий сиг­нал дат­чи­ка для на­блю­дения за оп­ре­де­лен­ны­ми со­бы­тия­ми час­то очень непро­дол­жи­те­лен (по­ряд­ка несколь­ких де­сят­ков мик­ро­се­кунд, в за­ви­си­мо­сти от применяе­мых дат­чи­ков), и его лег­ко про­пустить со­всем. А если вам требуется обес­пе­чить дей­ст­вие поч­ти сра­зу же по сра­ба­ты­ванию триг­ге­ра? На­при­мер, ес­ли дат­чи­ки бли­зо­сти ро­бо­та го­во­рят, что он вот-вот рухнет со ска­лы, на­до, что­бы дви­га­те­ли за­сто­по­ри­лись немед­лен­но, а не когда от ро­бо­та останет­ся ды­мя­щая­ся ку­ча смя­тых де­та­лей «Ле­го».

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

Про­цес­сор вы­пол­ня­ет се­бе свою обыч­ную ра­бо­ту, но когда про­ис­хо­дит нечто важ­ное, он по­лу­ча­ет вы­зов от менед­же­ра пре­ры­ваний, ко­то­рый ве­лит ему за­пустить про­це­ду­ру об­слу­жи­вания пре­ры­вания (Interrupt Service Routine – ISR). По су­ти де­ла, заданное усло­вие са­мо­стоя­тель­но про­ве­ря­ет­ся осо­бой ча­стью мик­ро­кон­трол­ле­ра – без затра­т вре­мени на­ше­го ко­да.

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

Из-за воз­мож­ной пе­ре­груз­ки на стан­дарт­ных мик­ро­схе­мах Atmega доступ­ны все­го два пре­ры­вания, свя­зан­ных с вы­во­да­ми 2 и 3. Про­це­ду­ра об­слу­жи­вания пре­ры­вания мо­жет быть за­пу­ще­на по воз­рас­таю­ще­му фрон­ту (т. е. вы­вод пе­ре­клю­ча­ет­ся в со­стояние «единица»), по спа­даю­ще­му фрон­ту или по из­менению со­стояния – эти слу­чаи по­кры­ва­ют все воз­мож­ные си­туа­ции.

Для ко­да Arduino су­ще­ст­ву­ют спе­ци­аль­ные ко­ман­ды пре­ры­вания, но глав­ное – восполь­зо­вать­ся ме­то­дом attachInterrupt() для уста­нов­ки ISR. Он принима­ет три па­ра­мет­ра: ис­поль­зуе­мое пре­ры­вание (0 = вы­вод 2, 1 = вы­вод 3), имя за­пускае­мой про­це­ду­ры об­ра­бот­ки пре­ры­вания и со­бы­тие, вы­зы­ваю­щее пре­ры­вание. Упо­мя­ну­тым на­ми со­бы­ти­ям в ко­де со­от­вет­ст­ву­ют кон­стан­ты RISING, FALLING и CHANGE. Вот наш при­мер, в ко­то­ром управ­ление на сей раз осу­ще­ст­в­ля­ет­ся пре­ры­вания­ми:

int sensorValue=0;

void setup() {

pinMode(2, INPUT);

digitalWrite(2, HIGH);

pinMode(13, OUTPUT);

attachInterrupt(0,caught0,CHANGE);

}

void loop() {

int j;

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

j = j+i*i;

delay(100);

j= 1;

}

}

void caught0(){

sensorValue = digitalRead(2);

digitalWrite(13, !sensorValue);

} 

Мы взя­ли код, ко­то­рый вклю­ча­ет и вы­клю­ча­ет све­то­ди­од, и свя­за­ли его с пре­ры­ванием. Так как со­бы­тие возника­ет при из­менении зна­чения вы­во­да, оно и вклю­ча­ет, и вы­клю­ча­ет све­то­диод, по­это­му мы счи­ты­ва­ем те­ку­щее зна­чение.

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

(thumbnail)
На этой схе­ме, на­ри­со­ван­ной во Fritzing, по­ка­за­на дос­та­точ­но про­стая сбор­ка с дву­мя фо­то­дат­чи­ка­ми. На прак­ти­ке мож­но раз­мес­тить дат­чи­ки и по­даль­ше друг от дру­га!

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

int sensorValue=0;

void setup() {

pinMode(2, INPUT);

pinMode(3, INPUT);

digitalWrite(2, HIGH);

digitalWrite(3, HIGH);

pinMode(13, OUTPUT);

attachInterrupt(0,caught0,FALLING);

attachInterrupt(1,caught1,FALLING);

}

void loop() {

int j;

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

j = j+i*i;

delay(100);

j= 1;

}

}

void caught0(){

digitalWrite(13, HIGH);

}

void caught1(){

digitalWrite(13, LOW);

} 
(thumbnail)
Схе­ма пла­ты для оп­ре­де­ле­ния ско­ро­сти, с дву­мя фо­то­дат­чи­ка­ми. Ин­фор­ма­цию о пра­виль­ном под­клю­че­нии ЖК-эк­ра­на сто­ит по­смот­реть в до­ку­мен­та­ции

Лю­бо­пыт­ст­вуе­те, когда мо­жет возник­нуть та­кая си­туа­ция? Про­стой при­мер – дат­чик ско­ро­сти. Что­бы вы­чис­лить ско­рость дви­жения че­го-ли­бо, мож­но взять два дат­чи­ка, об­на­ру­жи­ваю­щих, когда объ­ект про­хо­дит две за­дан­ные точ­ки. Из­ме­рение вре­мени ме­ж­ду эти­ми мо­мен­та­ми позволит вы­чис­лить сред­нюю ско­рость.

В Arduino есть встро­ен­ный тай­мер, под­счи­ты­ваю­щий вре­мя в мил­ли­се­кун­дах. Его зна­чение мож­но уз­нать в лю­бой мо­мент вы­зо­вом функ­ции millis(), ко­то­рая воз­вра­тит без­зна­ко­вое це­лое чис­ло [unsigned long] – ко­ли­че­­ст­во мил­ли­се­кунд, про­шед­ших с мо­мен­та вклю­чения тай­ме­ра. Уч­ти­те, что это зна­чение не всегда точ­ное: про­це­ду­ры об­ра­бот­ки пре­ры­ваний, осо­бен­но длин­ные, влия­ют на ра­бо­ту ча­сов (по­то­му что пре­ры­вания важнее все­го), но для про­стой ISR за­мет­ной разницы не бу­дет. По­про­буй­те сле­дую­щий код:

int sensorValue=0;

boolean running = LOW;

unsigned long startTime;

unsigned long intervalTime;

void setup() {

pinMode(2, INPUT);

pinMode(3, INPUT);

digitalWrite(2, HIGH);

digitalWrite(3, HIGH);

pinMode(13, OUTPUT);

attachInterrupt(0,caught0,FALLING);

attachInterrupt(1,caught1,FALLING);

Serial.begin(9600);

}

void loop() {

int j;

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

j = j+i*i;

delay(100);

j= 1;

}

}

void caught0(){

digitalWrite(13, HIGH);

if (!running) {

running = HIGH;

startTime=millis();

}

Serial.println(millis(), DEC);

}

void caught1(){

if (running){

running = LOW;

digitalWrite(13, LOW);

intervalTime=millis()-startTime;

Serial.println(intervalTime, DEC);

}

} 

В этой вер­сии ко­да есть ряд из­менений. Мы соз­да­ли несколь­ко пе­ре­мен­ных для хранения вре­мени, а так­же бу­лев­скую пе­ре­мен­ную, вы­сту­паю­щую в ка­че­­ст­ве фла­га. При на­жа­тии пер­вой кноп­ки про­це­ду­ра об­ра­бот­ки пре­ры­вания уста­нав­ли­ва­ет флаг в зна­чение «единица» (HIGH), ес­ли оно еще не за­да­но, и за­пуска­ет тай­мер. Если флаг уже в со­стоянии «единица», со­бы­тие пол­но­стью иг­но­ри­ру­ет­ся. Это по­ве­дение оз­на­ча­ет, что мы не по­лу­чим мно­же­ст­вен­ных

(thumbnail)
Ку­сок кок­тей­ль­ной со­лом­ки за­бло­ки­ру­ет боль­шую часть рас­се­ян­но­го све­та. В схе­ме так­же есть све­то­ди­од — он сиг­на­ли­зиру­ет, что фото­рези­стор дос­та­точно ос­ве­щен.

сра­ба­ты­ваний триг­ге­ра – тай­мер ра­бо­та­ет и про­дол­жит ра­бо­ту до тех пор, по­ка не бу­дет оста­нов­лен вто­рым на­жа­ти­ем кноп­ки/пре­ры­ванием. Оно про­ве­рит, что флаг на­хо­дит­ся в со­стоянии «единица» (HIGH), и ес­ли да, то оста­но­вит ча­сы и оп­ре­де­лит разницу во вре­мени – еще раз по­вто­рю, что под­ход с про­вер­кой фла­га оз­на­ча­ет, что слу­чай­ное сра­ба­ты­вание триг­ге­ра не оста­но­вит ча­сы до то­го, как они за­пу­ще­ны. За­тем ре­зуль­тат от­прав­ля­ет­ся по по­сле­до­ва­тель­ной линии свя­зи, по­то­му что по­ка у нас нет вы­вод­но­го уст­рой­ст­ва (мы пе­рей­дем к нему че­рез ми­ну­ту).

В ре­аль­ной сис­те­ме не пред­по­ла­га­ет­ся, что че­ло­век на­жмет кноп­ку, про­бе­жит ми­мо и за­тем на­жмет дру­гую кноп­ку – нуж­на ка­кая-то пуско­вая сис­те­ма, не влияю­щая на ско­рость объекта. Су­ще­ст­вует мно­же­ст­во спо­со­бов ее сде­лать: от бэй­джи­ков ра­дио­час­тот­ной иден­ти­фи­ка­ции до дат­чи­ков дав­ления, дат­чи­ков дви­жения PIR и т. д. С точ­ки зрения точ­но­сти и де­ше­виз­ны ком­понен­тов, луч­ший ва­ри­ант – сис­те­ма с пре­ры­ви­стым ла­зер­ным лу­чом.

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

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

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

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

Идем за по­куп­ка­ми

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

Шесть триг­ге­ров Шмит­та в стан­дарт­ном 14-кон­такт­ном DIP-кор­пу­се доступ­ны в мик­ро­схе­ме 74ACT14 – ка­ж­дый обой­дет­ся пен­сов в 10. Я обыч­но при­об­ре­таю чуть бо­лее удоб­ные мик­ро­схе­мы 74F132 или HCF4093 со сдво­ен­ны­ми триг­ге­ра­ми Шмит­та, по­сту­паю­щи­ми на вход вен­ти­ля «И-НЕ». Это оз­на­ча­ет, что мож­но по­дать сиг­нал на один из вхо­дов вен­ти­ля «И-НЕ» и управ­лять сиг­на­лом на дру­гом вхо­де (или по­да­вать ту­да дру­гой сиг­нал), что­бы пе­ре­во­дить вы­ход­ной сиг­нал схе­мы «И-НЕ» в со­стояние «единица» или «ноль». Ес­ли вам ну­жен оди­ноч­ный ин­вер­тор, про­сто со­едините оба вхо­да.

Не­доста­ток мик­ро­схем тот, что вы­ход­ные уровни име­ют ма­лую мощ­ность (с то­ком по­ряд­ка несколь­ких де­сят­ков мА) – для ло­ги­че­­ских уровней они под­хо­дят пре­крас­но, но ес­ли вы хо­ти­те с их по­мо­щью управ­лять све­то­дио­дом или чем-то дру­гим, все рав­но при­дет­ся ис­поль­зо­вать тран­зи­стор.

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

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

На­конец, для ото­бра­жения ре­зуль­та­та нуж­но при­ду­мать спо­соб по­лу­чше. Для это­го су­ще­ст­ву­ют мо­ду­ли мно­го­строч­ных ЖК-эк­ра­нов. Боль­шин­ст­во из них ис­поль­зу­ют мик­ро­схе­му HD44780 как па­рал­лель­ный ин­тер­фейс к раз­ме­щен­ным на пла­те опе­ра­тив­ной па­мя­ти и ло­ги­ке управ­ления дис­пле­ем, по­это­му пе­ре­да­вать ту­да дан­ные про­сто (су­ще­ст­ву­ет биб­лио­те­ка Arduino спе­ци­аль­но для этих це­лей). Ей требуется шесть до­полнитель­ных вы­во­дов, так как она ис­поль­зу­ет по­лу­бай­то­вый па­рал­лель­ный ин­тер­фейс (че­ты­ре линии с дан­ны­ми), но ре­сур­сов Arduino тут вполне хва­тит.

В на­ча­ле ко­да биб­лио­те­ку нуж­но под­клю­чить яв­но:

  1. include <LiquidCrystal.h>

и соз­дать эк­зем­п­ляр дис­плея:

LiquidCrystal lcd(11,12,5,6,7,8);

При­ве­ден­ные здесь па­ра­мет­ры – вы­во­ды ре­ги­ст­ра вы­бо­ра (Register Select – RS) и «досту­пен» (Enable – E) дис­плея, за ко­то­ры­ми сле­ду­ют че­ты­ре вы­во­да дан­ных (DB4-7). Дис­плей, как правило, име­ет боль­ше вы­во­дов, чем ука­за­но здесь (обыч­но 16), но точ­ное ме­сто­по­ло­жение вы­во­дов мо­жет от­лич­аться, по­это­му пе­ред уста­нов­кой дис­плея в схе­му оз­на­комь­тесь с до­ку­мен­та­ци­ей.

Так­же дос­туп­ны не­сколь­ко по­лез­ных ме­то­дов:

lcd.begin(16,2); // ус­та­нов­ка дис­плея с 2 стро­ка­ми и 16 столб­ца­ми

lcd.display(); // вклю­че­ние дис­плея

lcd.nodisplay(); // вы­клю­че­ние дис­плея

lcd.print(“Hello, World!”); // пе­чать стро­ки

lcd.print(variable, DEC); // пе­чать де­ся­тич­но­го зна­че­ния пе­ре­мен­ной

В до­ку­мен­та­ции есть и дру­гие функ­ции (www.arduino.cc/en/Tutorial/LCDLibrary), но почитайте до­ку­мен­та­ци­ю по ЖК-эк­ра­ну – у ва­шей мо­де­ли дис­плея мо­гут быть персональ­ные свойства.

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


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