Трушин А.Н., Арутюнян М.Г. Установяване на връзка и обмен на данни чрез bluetooth между Arduino и iOS приложение. Параметри на протокола за комуникация между Arduino и ESP8266 arduino комуникация

Изтегли стандартен пример„Физически пиксел“ чрез менюто File\Examples\4.Communication\PhysicalPixel. Тази програма чака данни от компютъра. При получаване на знака „H“ тестовият индикатор светва, при получаване на знака „L“ изгасва. Нека анализираме неговия изходен код:

int outputPin = 13; // тук съхраняваме номера за контакт
int стойност; // полученият знак ще се съхранява тук

void setup()
{
Serial.begin(9600) ; //настройте порта на 9600 bps
pinMode(outputPin, OUTPUT) ; // задаване на пин 13 в изходен режим
}

void loop()
{
if(Serial.available())( //ако има приет знак,
val = Serial.read(); // след това го прочетете и го запазете във val
if (val == "H" ) ( // ако символът "H" е приет...
digitalWrite(outputPin, HIGH) ; // след това включете светодиода
}
if (val == "L" ) ( // ако символът "L" е приет,
digitalWrite(outputPin, LOW) ; // след това изключете светодиода
}
}
}

Обърнете внимание на вложените условия и реда на отварящите и затварящите фигурни скоби. За удобство при четене на програмния код всяко следващо ниво на влагане се измества надясно. Освен това редакторът помага за четене на кода - ако поставите курсора вдясно от скобата, той ще маркира съответната двойка скоби.

Как да проверите работата на тази програма, след като я изтеглите на микроконтролера? Трябва да намерим начин да изпращаме символи към COM порта на компютъра, така че микроконтролерът да ги получава и обработва. Има много възможности за решаване на този проблем.

Използваме вградения монитор на COM порта в средата за разработка Arduino

Това е най-простият и разбираем метод за начинаещи.

Мониторът на COM порта се стартира през менюто Tools\Serial Monitor или през лентата с инструменти. В по-старите версии на софтуера мониторът беше достъпен само през лентата с инструменти: . Когато извиквате монитора, уверете се, че е избрана същата скорост на предаване, както в програмата на микроконтролера. Сега можете да въведете произволни знаци в полето за въвеждане отдясно и да натиснете бутона "Изпрати" - въведените знаци ще бъдат изпратени до порта и вашата програма ще ги приеме там. Въведете там латинската буква "H", натиснете "Изпрати" - тестовият светодиод ще светне. Ако изпратите "L" - ще се изключи. Между другото, всички данни, които вашата програма ще изпрати на COM порта, ще бъдат показани в прозореца по-долу.

Използване на програмата за емулация на терминал HyperTerminal

Това е малко по-сложна опция за обмен.

Windows обикновено включва програма за емулация на терминал, наречена HyperTerminal. В Windows XP може да се намери в Start\All Programs\Programs\Accessories\Communications\HyperTerminal. При стартиране трябва да откажете да създадете връзка, изберете менюто File \ Properties. В диалоговия прозорец, който се появява, изберете вашия COM порт, щракнете върху „Конфигуриране“ и конфигурирайте комуникационните настройки в съответствие с фигурата:

Можете да използвате друг терминален емулатор - всички те обикновено имат сходна функционалност и подобни настройки.

Щракнете върху "OK" в двата прозореца и веднъж в главния прозорец на програмата, който и да е клавиш на клавиатурата - HyperTerminal ще се свърже към COM порта. Сега всички символи, въведени на клавиатурата, преминават през COM порта към микроконтролера и всичко, което микроконтролерът изпраща, отива на екрана. Натиснете клавишите "H" и "L" (следете избрания език и регистър) - тестовият светодиод трябва да светне и да изгасне.

Нека напишем наша собствена компютърна програма!

Тази опция е за истински ентусиасти, които искат да програмират не само Freeduino, но и компютър. Защо не? Не е нужно да научаваме подробности за програмирането сериен портпод Windows или някои други сложни неща. Специално за решаване на такива прости задачи има езикът за обработка (http://processing.org), който е много подобен по синтаксис и дори среда за разработка на софтуера Arduino.

Инсталирайте и стартирайте Processing - Ще видите среда за разработка, подобна на Arduino.

Изходният код за езика за обработка е в коментарите под основния текст на примера за Physical Pixel. Ето го с минимални промени - оправихме отварянето на порта, за да можете лесно да замените номера му:

import processing.serial.* ;
сериен порт;
void setup()
{
размер (200, 200);
noStroke() ;
frameRate(10) ;
порт = нов сериен (това, "COM5", 9600); // !!! Въведете своя COM порт тук!
}
булево mouseOverRect() //Връща true, ако курсорът е вътре в квадрат
{
return ((mouseX >= 50 ) && (mouseX<= 150 ) && (mouseY >= 50 ) & (мишка Y<= 150 ) ) ;
}
празно теглене ()
{
фон (#222222 );
ако (mouseOverRect() ) // Ако курсорът е вътре в квадрат....
{
запълване (#BBBBB0) ; // промяна на цвета към по-ярък
port.write("H") ; // изпрати "H" към микроконтролера
) иначе ( // ако не е вътре...
запълване (#666660 ) ​​​​; // промяна на цвета на по-тъмен
port.write("L") ; // изпрати "L" към микроконтролера
}
rect(50 , 50 , 100 , 100 ) ; // начертайте квадрат
}

Стартирайте програмата (чрез менюто Sketch \ Run) - ще се появи прозорец с квадрат, когато поставите курсора на мишката в него, светодиодът на Freeduino ще светне.

Описанието на езика за обработка и неговите възможности е извън обхвата на този прост разказ, но много от примерите за Arduino в коментарите под основната част на програмата показват код за обработка на компютър, който взаимодейства с Freeduino.

За него е жизненоважно да обменя информация с микроконтролера. Има ситуации, когато трябва ръчно, чрез управление от компютър или лаптоп, да активирате една или друга функция в програмата на микроконтролера.

Но да се заемем с работата. Не е толкова трудно да се обменят данни с Arduino, но уловката е, че данните се предават символ по символ, което е много лошо. В търсене на този проблем трябваше да прекарам доста време, докато не попаднах на една прекрасна библиотека на Habrahabr. Авторът е внедрил в него функцията за приемане на числа, т.е. можете да изпратите повече от една цифра към контролера и той ще работи правилно. Изтеглете библиотеката (връзка), разопаковайте я в хардуерни библиотеки и нека да преминем към практиката.

Първо, ще напишем скица и ще я качим в Arduino (Freeduino)

#include void setup() (

Serial.begin(9600); // задаване на скоростта на порта

PinMode(9, ИЗХОД); // задайте пин 9 като изход за високоговорител

) void loop()

Long intNumber; Serial.print("Въведете номер: ");

Номер = SerialInput.InputNumber(); // Въведете число Serial.print("Резултат = ");

Serial.println(число * число, DEC);

Звуков сигнал (500);

} невалиден звуков сигнал (закъснения без знак)(

analogWrite(9, 20); // стойността трябва да е между 0 и 255

// експеримент за добър тон

analogWrite(9, 0); // 0 - изключване на пиезото

Закъснение (закъснения); // пауза забавяния ms

Какво означава всичко това. Опитах се да предоставя кода с подробни коментари, всичко изглежда ясно. Тази скица ви моли да въведете произволно число, след което издава своя квадрат и възпроизвежда звуков сигнал през пиезо високоговорител, свързан към пин 9.

И сега, най-интересното - време е да опитате. За превключване с контролера препоръчвам да използвате безплатна програма замазка. В настройките за тип връзка изберете Сериен и въведете правилния номер на порт вместо COM1 (можете да надникнете в средата за програмиране на Arduino в менюто Инструменти->Сериен порт). Натискаме Open и виждаме надписа Въведете номер в конзолата, въвеждаме произволно число (в разумни граници), натискаме Enter и виждаме резултата.

Всичко, можете да се радвате и да скачате от радост. Естествено, всичко това може да се подобри, например първо да се покаже меню, което да се изпрати от контролера към конзолата, в което да се опишат подробно командите. Например въведете числото 0 - включва се LED светлини, натиснете 1 - изгасва. Така можете да набутате поне 100500 команди, само ако има достатъчно памет на микроконтролера (което е толкова малко). И ще говорим за това как да разширим наличната памет следващия път.

UPD: част от кода беше изрязан от анализатора на двигателя, така че ето го източникът

Подобно на много други домашни майстори, аз редовно използвам AVR микроконтролери за всякакви различни любителски занаяти. И благодарение на концепцията на "Arduino", тези занаяти сега придобиват елегантен вид. Наистина, за около 300-400 рубли получаваме миниатюрна многослойна платка с маска, ситопечат и периферия за микроконтролера, изцяло свързана към нея (и в SMD версия!). Не говоря за всички видове допълнителни модули от същата серия "Arduino": сензори, контролери, дисплеи и цели набори от допълнителни периферни устройства, от които се нуждаем толкова много. И отново, всичко също е евтино и с отлично представяне. На практика няма нужда да разреждате и запоявате нещо на „коляното“.

Но всички тези различни любителски занаяти изискват естествено, предварително програмиране.И в бъдеще, с различни подобрения, тези занаяти постоянно трябва презаредете. Ясно е, че е по-удобно да направите това дистанционно, отколкото постоянно да ги влачите към конвенционален програмист. Като цяло, благодарение на същата платформа Arduino, тук има много опции: Bluetooth, ZigBee, радиоканал с вашия личен протокол, IR и дори Wi-Fi. Всички те ви позволяват да установите безжичен контакт с вашия микроконтролер. Но ние ще се спрем на последния вариант. Тук има четири основни причини:

1: модерен интернет на нещата!

2: безжичен рутерналични във всеки апартамент, регистрирайте се на домашна мрежавашите устройства и готово!

3: вашите занаяти правят революционен скок в развитието си; те не само могат да бъдат програмирани от разстояние, но вече могат и да комуникират със света около тях: Цифров часовникнезависимо вземете точно времеот часовникови NTP сървъри, изпълнителните устройства се управляват от другия край на града или държавата, регистриращите устройства записват натрупаните данни в облака и т.н. и т.н.

4: има прекрасна серия от чипове ESP8266, на които не е много лесно да се приложи всичко това.

Освен това, в тази статия, използвайки примера на механично рамо на серво, дистанционно програмиране и обмен на данни от компютър (или нещо друго) с устройства, базирани на AVR микроконтролери. Искам веднага да отбележа, че всички програми, дадени по-долу, са чисто демонстрационни и нямат търговска стойност. Затова не се приемат претенции, като например защо програмистът е толкова кастриран и не много функционален или защо няма допълнителни услуги, които са навсякъде. Тъй като кодовете са отворени, всеки може да ги довърши по свое усмотрение, но за мен все още има достатъчно за работа.

Предполага се, че читателят вече е запознат с модулите "Arduino" (щитове) и с връзката и фърмуера на ESP8266. Всъщност в мрежата е публикувано огромно количество материали, обясняващи основите на работа с тези устройства, и не бих искал да се повтарям тук. За начинаещи има списък в края на статията. полезни връзкипо тези въпроси, където можете да намерите много информация защо всичко това не работи за вас. От моя опит като бивш инженер по електроника, мога отговорно да заявя, че 99% от проблемите се свеждат до следното:

1. Лоши контакти. Тъй като щитовете "Arduino" означават превключване помежду си чрез проводници от типа "баща-майка", а не чрез запояване, много често нещо, някъде, но напуска. Проверете. И като цяло, както се казва, електрониката е наука за контактите.

2. Проблеми с храненето. Не прилагайте 5 волта захранване, където се изисква 3,3. Понякога от ESP8266 излиза дим. Въпреки че, от друга страна, той смила логически сигнали от петволтови устройства без проблеми.

3. Проблеми с достатъчно захранване. ESP8266 има подъл характер и понякога може да черпи почти триста милиампера, въпреки че преди това можеше да се задоволи с тридесет. Съответно крехкият 3,3 волтов стабилизатор на платката Arduino, към който сте го свързали без колебание, веднага пада до микроскопични стойности. И не можете да разберете защо или работи, или не.

4. Объркване със заключения. Винаги проверявайте кои сигнали къде отиват. RXD приемникът трябва да бъде свързан към TXD предавателя, както и TXD към RXD, но MOSI трябва да бъде свързан към MOSI, MISO към MISO и т.н.

5. Не разчитайте на издърпващите резистори в схемата на ESP8266, винаги издърпвайте щифтовете до нула или захранване чрез външни резистори 5-10 kOhm, а не само джъмпер. В противен случай в най-добрия случай можете да получите безпрецедентен ток на консумация и след това да усетите неприятната миризма на изгоряла пластмаса.

6. Плевели софтуер. Тъй като софтуерът за отделни потребители е написан от едни и същи ентусиасти, проблемите на самия фърмуер и грешките периодично се появяват при актуализиране на версии на същия фърмуер. Лекува се чрез обхождане на съответните форуми, понякога дори на английски. Някои другари дори твърдяха, че самият ESP чип е влажен като времето в Санкт Петербург, но от друга страна има и мнение, че от 2014 г. (годината на първото му пускане) ситуацията се е подобрила драстично (за разлика от метеорологично време).

7. Мистериозни проблеми. Това е рядко, но отнемащо нерви явление. Например, нямах нито едно устройство „Arduino“, дистанционно зашито. По-скоро е шито, но с грешки. Но беше зашит без грешки, ако на него висеше кабел от програмиста (но без самия програмист). „YAH“, казах си аз и запоих кондензатор от 15 pF между предавателния щифт и щифта на часовника. Всичко работеше. Но уби деня.

Така че нека започнем с най-простото. Разполагаме с механичен крайник MechArm (но не този, който Хауърд Уоловиц е създал), произведен в Китай и Персонален компютърс Windows. Задачата е дистанционно да флашнете програмата и да я управлявате от компютър.


За контролния контролер вземете хубав миниатюрен шал Ардуино Нанос камък ATmega328P. Тази дъска пасва перфектно в механичната ръка.


Сега нека решим как ще го програмираме. Има три основни метода, най-подходящи за отдалечен фърмуер: чрез SPI интерфейса, чрез вградения буутлоудър, през JTAG порта.

Най-лесният вариант е, разбира се, вграденият буутлоудър (bootloader). Това е памет, предварително записана във FLASH, програма, която получава код, използвайки определен протокол (например, използвайки най-простия UART) и го записва със специални команди на мястото на изтеглената програма. Ето как работи например самият буутлоудър на ARDUINO IDE. След нулиране или стартиране, товарачът изчаква известно време за получаване на данни и ако не изчака, започва да изпълнява програмата от адрес нула. Ако постъпят данни, той ги записва в програмната секция. След следващото нулиране заредената програма започва да работи. В детайли може би съм описал неточно, но същността е точно такава. В резултат на това се нуждаем само от три пина за програмиране: RTD приемник, RESET и GND. По принцип TRD предавател също се използва за проверка на записаната програма, но за прости демонстрационни приложения (не за атомна електроцентрала) проверката може да бъде пропусната.

Самият буутлоудър е написан на асемблер, има примери за прости буутлоудъри в таблиците с данни на AVR. Можете да разкриете съществуващ буутлоудър, ако е вътре свободен достъпи просто да го използвате в готов вид, ако е известен протоколът, по който работи. Единственото предупреждение е, че за това трябва да конфигурирате AVR в специален режим, като мигате специални битове за предпазители, което се прави от обикновен програмист, и след това шиете самия буутлоудър в паметта на микроконтролера (тоест все още не можете правете без програмист веднъж).

Вторият вариант е програмиране сериен интерфейс SPI. Тук няма вътрешен буутлоудър, но ние програмираме, като изпращаме специални команди и след това данни през гореспоменатия интерфейс. Тук имаме външен буутлоудър, но все още трябва да го напишем. По време на предаване, в допълнение към RESET и GND, вече има четири допълнителни изхода MOSI, MISO - данни, SLK синхронизация, CS - избор на кристал. Но като цяло можете също да премахнете MISO и CS. Данните ще бъдат само получени (тогава няма да има проверка на програмата), а ние така или иначе имаме само един кристал.

Всеки подход има своите плюсове и минуси (а аз изобщо не взех предвид JTAG, тъй като човешкият живот е кратък). Но в крайна сметка се насочих към SPI, защото ме мързеше да пиша на асемблер и не намерих отворени готови зареждащи устройства (просто не изглеждах добре).

За изграждане безжичен каналАз, както вече споменах, избрах изключително широко известния в момента чип ESP8266 - микроконтролер или по-скоро цял SoC (System-on-Chip) от китайския производител Espressif с Wi-Fi интерфейс. В допълнение към Wi-Fi, той се отличава с възможност за изпълнение на програми от външна флаш памет. И специално за моя проект взех ESP8266-07 с 512 KB памет на борда.


Като цяло, всеки ESP8266 е подходящ, където има допълнителни крака за внедряване на SPI. Следователно най-простият ESP8266-01 няма да ни подхожда, тъй като има много малко крака за I / O портове. Но от друга страна, разликата в цената за тях е по-малко от сто рубли и те са еднакво достъпни. Е, големите платки за отстраняване на грешки с ESP, където куп периферни устройства са разделени за удобство, също не са подходящи за нас, тъй като не се побират там, където искаме да ги напъхаме в нашата механична ръка.

Глобалната същност на идеята като цяло беше следната. От компютъра към ESP тялото на програмата, заредена в микроконтролера, се предава безжично чрез WI-FI (в рамките на вашата домашна мрежа). И ESP вече по кабел, използвайки SPI интерфейса, записва тази програма директно във FLASH паметта на микроконтролера. След това естествено го нулира и позволява заредената програма да бъде изпълнена. Освен това ESP трябва да има независим модул, който също управлява обмена на данни с микроконтролера, тъй като искаме не само да програмираме, но и да обменяме данни с него. Специално за проекта MechArm, след като записваме програмата, ние също изпращаме сигнали за серво управление, за да задвижим тази ръка. Затова на самото ESP е желателно да вдигнем TCP сървърза прехвърляне на програмата и UDP сървъра за управление на MechArm. Съответно тези сървъри се присъединяват към домашната мрежа и слушат внимателно дали някой иска да качи нов код в MechaArm или да го размаха на някого.

И така, намерих в мрежата, фърмуерът вече ви позволява да произвеждате AVR програмиранепо въздуха, но там основният проблем е, че за какво друго този фърмуер вече не може да се използва. И бихме искали да комуникираме с AVR и дистанционно след програмиране.

Какъв софтуер ще използваме:

За PC написах всичко в JAVA, средата IntelliJ IDEA. Но по принцип можете да използвате всичко, основното за нас е да напишем клиент, за който ще изпратим програма AVR фърмуерна ESP8266.

Пиша програмите за AVR на ATMEL STUDIO, на C, рядко на асемблер. По принцип не използвам скици на Arduino, почти всяка необходима библиотека е написана за друг час и с пълно разбиране на нейната работа. Пробвах със скици, но засега го нямате на AVR операционна система, скиците ще продължат да вземат периферни устройства от приятел и редовно да се провалят. Да, самата Arduino IDE, в сравнение с ATMEL STUDIO, разбира се, е много примитивно нещо. Но тук въпросът, разбира се, е спорен, за хуманитарните науки и учениците ще бъде по-забавно и по-лесно, вероятно, със скици.

За програмиране на ESP8266 използвах фърмуера NodeMCU и написах програмите на Lua. Не, бих искал да пиша на Java и C, но няма такива на ESP. Езикът Lua в приложение към нашата задача не е труден, трябва да го овладеете с няколко дреболии. И всъщност, за да изтегля програми и да ги дебъгвам на ESP, взех IDE ESPlorer. Домашни безплатен продукт(но можете да направите дарение на автора), което, разбира се, не може да се сравни със средите, споменати по-горе, но както се казва на подарен кон ... Но за да използваме ESPlorer и да пишем в LUA, първо трябва да сменете основния фърмуер (доставен от производителя) в чипа ESP8266 на нов. В това предприятие ще ни помогне програмата NODE MCU PyFlasher. В известен смисъл ще помогне да го презаредите. И ние ще създадем самия фърмуер и ще го получим в ръцете си на уебсайта на създателите: NodeMCU. И можете да прочетете повече за този процес

Всичко е много достъпно и разбираемо. Добавяме поддръжка на SPI и битови операции към базовите библиотеки (в LUA, в нашия случай битовите операции са претоварени и нямат голяма полза). Не трябва да пъхате много библиотеки във фърмуера, защото поради наличието на всякакъв вид софтуер, на ESP8266 остава много малко памет, някои мизерни 20 kB.

Разбира се, можете просто да вземете готов фърмуер, от който вече има много висящи в интернет, но аз не го препоръчвам. Макар и само защото някои не поддържат битови операции (а имаме нужда от тях) и няма регулиране на скоростта на пренос на данни през SPI.
Съответно, те се предават по подразбиране със скорост 40 MHz, разделена на някакъв малък коефициент, и следователно AVR няма време да ги усвои.

Ако ви мързи да създавате фърмуер, можете да изтеглите моя от облака.

Сега имаме фърмуера и трябва да го заредим в ESP8266 вместо в базовия. За да направим това, се нуждаем от обикновен USB-UART адаптер.


Свързваме краката TXD към RXD и RXD към TXD, правим обща земя, но не използваме, както изглежда, удобен изход за захранване от 3,3 V на адаптера. В повечето случаи ESP8266 ще го пропилее напълно. Затова го питаме отделно. След това поставяме ESP в режим на програмиране (GP0 на земята, ако някой е забравил) и стартираме NODE MCU PyFlasher.

Най-важното е, че не забравяйте да изтриете флаш паметта (да, изтрива всички данни), в противен случай, в зависимост от версията на фърмуера, тя може да остане в паметта след програмиране ненужен боклук, което от своя страна ще излее боклук в конзолата по време на по-нататъшна работа. Преди това използвах софтуер, където нямаше опция за изтриване на паметта предварително, страдах ужасно, тъй като нищо не работеше. И ковчегът току-що се отвори, само истината е на англоезичния форум на създателите на NODE MCU.

Заимев желания фърмуервече можем да пишем и дебъгваме програми на езика LUA (има и MicroPython, но не го използвах), използвайки много удобни API от NODE MCU. Стартираме споменатия по-рано ESPlorer.

Също така го конфигурираме да работи с ESP8266, задаваме параметрите серийна връзка. Всичко е доста просто и многократно заявено в Интернет.

Сега пишем програма в LUA, която след това ще качим на ESP8266:

Lua буутлоудър за AVR, написан на ESP8266

функция InstrProgrammingEnable () -- инструкция за MC "разрешаване на програмиране" p=0 докато p<31 do p=p+1 pin=8 gpio.write(pin, gpio.LOW) spi.send(1, 0xAC,0x53) read = spi.recv(1, 8) spi.send(1,0,0) gpio.write(pin, gpio.HIGH) if (string.byte(read)== 83) then print("connection established") p=33 if(p==31) then print("no connection") end end end end functionProgrammingDisable() pin=2--КРАЙ НА ESET ЗА MK gpio.mode(pin, gpio.INPUT) pin=8 gpio.mode(pin, gpio.INPUT) pin=5--CLK MASTER за SPI gpio.mode(pin, gpio. INPUT) pin=6--MISO MASTER за SPI gpio.mode(pin, gpio.INPUT) pin=7--MOSI MASTER за SPI gpio.mode(pin, gpio.INPUT) край функция ProgrammingEnable() pin=2-- RESET ЗА MK gpio.mode(pin, gpio.OUTPUT) gpio.write(pin, gpio.LOW) pin=2--POZITIV ЗА 4MSEC RESET ЗА MK gpio.mode(pin, gpio.OUTPUT) gpio .write(pin, gpio.HIGH) tmr.delay(4) gpio.mode(pin, gpio.OUTPUT) gpio.write(pin, gpio.LOW) tmr.delay(25000) край функция InstrFlashErase() pin=8 gpio.write(pin, gpio.LOW) spi.send(1,0xAC,0x80,0,0) gpio.write(pin, gpio.HIGH) tmr.delay(15000) pin=2--НУЛИРАНЕ ЗА MK gpio.mode(pin, gpio.OUTPUT) gpio.write(pin, gpio.HIGH) tmr.delay(20000) gpio.write(pin, gpio.LOW) print("FLASH е изтрит") InstrProgrammingEnable () край функция InstrStorePAGE(H, адрес, данни) pin=8 gpio.write(pin, gpio.LOW) spi.send(1,H,0,address,data) gpio.write(pin, gpio.HIGH) tmr.delay(500) край функция InstrWriteFLASH(страница_адрес_нисък,страница_адрес_висок) pin=8 gpio.write(pin, gpio.LOW) spi.send(1,0x4C,page_address_high,page_address_low,0) gpio.write(pin, gpio.HIGH) tmr.delay(5000)-- понякога флаш не се записва когато кратките закъснения приключат функционално програмиране (полезен товар) pin=8--CS MASTER за SPI gpio.mode(pin, gpio.OUTPUT, gpio.PULLUP) pin=4-LED СВЕТЛИНИ НА НИСКО gpio.mode(pin, gpio.OUTPUT) gpio.write(pin, gpio. LOW) print(string.len(payload)) page_count = 7 -- запис на 1 килобайт за k =0,page_count,1 do--количество страници за i=0, 127, 2 do-- -1 адрес = i/ 2 data=payload:byte(i+1+128*k) if data == nil then data = 0xff end InstrStorePAGE(0x40,address,data) -- tmr.delay(100)-- в противен случай не навреме записване на данни = payload:byte(i+1+1+128*k) if data == nil then data = 0xff end InstrStorePAGE(0x48,address,data) -- tmr.delay(100) end page_address_low=bit.band(k ,3 )*64 -- 3 е двоичен 11 page_address_high=k/4+frame1024*2 tmr.delay(1000) InstrWriteFLASH(page_address_low,page_address_high) tmr.wdclr() end pin=4--LED gpio.mode(pin, gpio. OUTPUT) gpio.write(pin, gpio.HIGH) край --ОСНОВЕН БЛОК wifi.setmode(wifi.STATION) --wifi.sta.config("мрежово име","парола") -- задайте SSID и парола на вашата точка за достъп station_cfg=() tmr.delay(30000) station_cfg.ssid=" име на мрежата" tmr.delay(30000) station_cfg.pwd="парола" tmr.delay(30000) wifi.sta.config(station_cfg) tmr.delay(30000) wifi.sta.connect() tmr.delay(1000000) печат (wifi.sta.status()) print(wifi.sta.getip()) while (wifi.sta.status()~=1) do if(wifi.sta.status()==5) then break end end sv=net.createServer(net.TCP,30) tmr.delay(100) print("SERVER READY") sv:listen(4000,function(c) c:on("receive", function(c, payload) print (полезен товар) if (полезен товар =="програма\r\n") then c:send("готов\r\n") print("готов за програма\r\n") spi.setup(1, spi.MASTER , spi.CPOL_LOW, spi.CPHA_LOW, spi.DATABITS_8,320,spi.FULLDUPLEX) ProgrammingEnable () tmr.delay(100) InstrProgrammingEnable () tmr.delay(100) InstrFlashErase() tmr.delay(100) frame1024=0- -брой изпратени кадри st=net.createServer(net.TCP,30) st:listen(4001,function(c) c:on("receive" , функция(c, полезен товар) tmr.wdclr() Програмиране (полезен товар) frame1024=frame1024+1 end) край) край if (payload =="data\r\n") then c:send("ready\r\n ") print("готов за данни\r\n") srv=net.createServer(net.UDP) tmr.delay(1000) pin=10 gpio.write(pin, gpio.HIGH) uart.setup(0.9600 ,8 ,0,1,0) srv:listen(5000) srv:on("получаване", функция(srv, pl) pl=pl*1 --print(pl) uart.write(0,pl) tmr. wdclr( ) end) end if (payload =="stop\r\n") then if(st~=nil) then st:close() frame1024=0 ProgrammingDisable () print("stop program") end if(srv ~= нула) след това srv:close() print("стоп данни") край край край) край) край)


Където съответните функции правят следното:

функция InstrProgrammingEnable()- поставя микроконтролера в режим на програмиране със специална команда, изпратена през SPI.

функция ProgrammingEnable()– просто нулирайте AVR за 25ms преди програмиране

functionProgrammingDisable()- след програмиране прехвърляме SPI щифтовете в ESP8266 в неактивно състояние, така че да не ни пречат при изпълнение на код на микроконтролера (изведнъж те се използват там)

функция InstrFlashErase()- презапишете флаш паметта на микроконтролера преди да започнете програмирането. Защо това трябва да се обяснява, не е необходимо.

функция InstrStorePAGE(H, адрес, данни)- с тази команда се записва програмен байт във вътрешния буфер на микроконтролера. Но това не е самият флаш запис, тъй като флашът е записан тук на страница по 128 байта.

функция InstrWriteFLASH(страница_адрес_нисък,страница_адрес_висок)- но това е флаш запис и отнема време, обърнете внимание на времезакъснението от 5000 µs.

функционално програмиране (полезен товар)- най-голямата и най-важна функция, използваща горните функции. Той взема прехвърлената програма на части от 1024 байта, разделя ги на байтове и формира адреси за тях, след което ги изпраща към микроконтролера във вътрешния буфер и инициализира флаш записа на всеки 128 байта. След това взема следващия килобайт код и повтаря операцията, естествено с отместване в адресите, за да пише по-нататък и да не презаписва написаното. Първо се опитах да изпратя цели програми, но ако ESP8266 надвиши 6 килобайта, наличната памет просто свършва и той се срива. Един килобайт се оказа най-удобната единица, защото е спретнато разделен на части и удобно предаван чрез TCP (все пак трябва да го вземем от компютъра). По-голям размер също не е необходим, TCP, знаете ли, в текущата версия ограничава предавания пакет до 1500 байта или нещо подобно (но по някаква причина аз предадох 1440, нещо като).

Колкото и да е трудно, но трябваше да се преодолеят няколко клопки.

Регистрираме се в безжична мрежа.

Първо създаваме TCP сървър, който слуша три команди:

1. „програма“ (ще програмираме),

2. „данни“ (ще обменяме данни),

3. "стоп" (спираме всичко).

Ако програмираме, тогава първо инициализираме SPI и създаваме друг TCP сървър, който грабва данни (кода на програмата, която се флашва) на килобайт и извиква функциите за програмиране на микроконтролера за тях. Разбирам, че изглежда глупаво да се създаде втори сървър, но това е необходимост, защото локалният API поддържа създаването само на един сокет и трябва да разделим командите „program“ и „data“ със самите предавани данни, защото на око не се различават, тук има байтове и байтове.

Ако искаме не да програмираме, а да обменяме данни, изпращайки ги в нашия случай към микроконтролера, тогава първо изпращаме низа „данни“ през TCP. В отговор на това вече ще бъде създаден UDP сървър (напомням ви, че управляваме динамично с механична ръка и не се нуждаем от забавяне при формирането на TCP пакети и наистина изпращаме един байт като цял TCP кадър лоши маниери ). И UDP дейтаграмите ще бъдат малки и ще се формират бързо.

След това UART се инициализира и всеки байт, получен безжично, се изпраща по TXD проводника към микроконтролера, който е длъжен да го приеме, ако съответната програма е флашната там. Също така не е трудно да се организира обмен на данни в другата посока, но все още не съм го приложил.

Е, при командата „стоп“ гореспоменатите сървъри (с изключение на първия) затварят връзките и най-важният сървър отново преминава в състояние на изчакване на командите „програма“ и „данни“.

Тъй като SPI интерфейсът е програмно емулиран в ESP8266, можете да използвате всички I/O портове за CS, CLK, MISO, MOSI, RESET сигнали (за AVR), налични, а не тези, които са посочени в моя буутлоудър. Освен това се оказа, че CS и MISO по принцип също могат да бъдат отрязани в този случай, ще работи без тях. Е, един изход се използва на светодиода, вграден в платката ESP8266, така че понякога мига и показва, че програмата е все още жива.

Няма проверки за грешки при запис (с изключение на първата заявка към AVR, но тази информация просто се показва на конзолата), EEPROM не е програмиран, повече от 32 KB не се шият - накратко, все още има какво да работи На. Скоростта на обмен през SPI е приблизително 115 Kbps, всичко се флашва за няколко секунди, приблизително като конвенционален сериен програмист като ISP500).

Вземете кода, въведете вашите мрежи и пароли, компилирайте в ESplorer, наречете го „init“ (за да работи при рестартиране) и го изпратете до ESP8266. Трябва да работи. Поне в смисъл да работиш като безжичен програмист.

Сега ще се занимаваме с контролната страна - персонален компютър.

Всъщност трябва да вземем HEX файла, в който се превръщат вашите програми, написани в средата на ATMEL STUDIO, и да го изпратим чрез WI-FI до порта на сокета, който познаваме (в този случай 4000). Малката уловка е, че имаме нужда от двоичен BIN файл за изпращане, а ATMEL STUDIO ни радва само с HEX. Тук има два изхода; или го конвертирайте във формат BIN със специална програма за конвертиране, като WinHex, или го направете сами във вашата програма. Все още не съм го правил, но изглежда не е трудно, трябва да отрежете заглавието и да направите нещо друго.

В резултат на това написах програмата за зареждане на JAVA (главно защото не знам как да правя нищо друго), работейки в просто красивата и безплатна среда IntelliJ IDEA. Той създава TCP клиент, който търси сървър, работещ на ESP8266. Ако го открие, той се свързва с него и му изпраща файл, намиращ се на такъв и такъв адрес. Код по-долу.

Програма за качване на JAVA файлове, работеща от страна на компютъра

импортиране на java.io.*; импортиране на java.net.*; импортиране на java.util.ArrayList; импортиране на java.util.List; публичен клас Net( public static void main(String args) (нов Http_client(4000);)) class Http_client extends Thread ( int port; String s; String Greetings_from_S; Http_client(int port)( this.port = port; start(); ) public void run() ( //192.168.1.113 е ESP8266 адресът в моята мрежа Но като цяло се научава от комуникацията с рутера // по-добре е да стане статичен, рутерите могат да направят това, опитайте (Socket socket = new Socket("192.168.1.113", port)) ( PrintWriter pw = new PrintWriter( new OutputStreamWriter(socket.getOutputStream( )),true); pw.println("program");// Поздрави със SERVER System.out.println("program"); ​​​​BufferedReader br = new BufferedReader(new InputStreamReader(socket) .getInputStream())); Greetings_from_S = br.readLine(); System.out.println(Greetings_from_S); if(Greetings_from_S.equals("ready")) ( опитайте ( File file = new File("d:BlinkOUT.bin) ");// адрес на файла за качване BufferedInputStream bis = нов BufferedInputStream(нов FileInputStream(файл)); байт данни = нов байт; bis.read(данни); байт data_buffer = нов байт; int frames = data.length/1024 ; Система m.out.println(рамки); int резиденция = data.length%1024; за (int i = 0; i< frames;i++) { for (int k = 0; k< (1024); k++) { data_buffer[k] = data; } sendingChunk(data_buffer); } byte data_buffer2= new byte; for (int i = 0; i < residy;i++) { data_buffer2[i] = data; } sendingChunk(data_buffer2); pw.println("stop");// System.out.println("stop program"); } catch (Exception e) { System.out.println(e); } } } catch (Exception e) { System.out.println(e); } } public void sendingChunk (byte data_buffer){ try (Socket socket = new Socket("192.168.1.113", 4001)){ BufferedOutputStream bos = new BufferedOutputStream((socket.getOutputStream())); bos.write(data_buffer); bos.flush(); System.out.println(data_buffer.length); } catch (Exception e) { System.out.println(e); } } }


Тук, разбира се, се навиват излишни неща, всякакви готови по принцип не са необходими. Ако е установена TCP връзка, тя е установена. Единственият проблем беше, че файлът не искаше да бъде изпратен на равни части от 1024 байта, както наистина ми трябваше, въпреки че изрично посочих размера. Очевидно има някакъв краен буфер, недостъпен от JAVA, и той изпраща пакети в размера, който иска, което е напълно неприемливо за приемащата страна. Отначало се опитах да направя забавяне, така че буферът да се умори да чака следващите парчета и да го изпрати такъв, какъвто е. Но забавянето започна да работи, когато достигна 10 секунди, което някак си ми се стори малко прекалено за един предаван килобайт.

Но тогава забелязах, че по някаква причина първото парче винаги върви точно както е поръчано, а от второто започва непредвидима вакханалия. Затова направих така, че клиентът отвори връзка, изпрати част от код в 1024 байта и затвори връзката. И така до изпращане на целия файл. Всичко работи успешно.

Единственото нещо е, че трябва да инсталирате средата за изпълнение на JAVA на вашия компютър, за да я стартирате. Но обикновено започвам веднага от IntelliJ IDEA, защото там винаги можете да видите какво се случва в конзолата (но тук е необходима и среда JAVA). Въпреки че, разбира се, по интелигентен начин трябва да направите GUI. Тоест прозорец, където пътят до файла отпада, възможността за промяна на номерата на портовете в същия прозорец и, добре, и други необходими неща. И съберете всичко това под формата на изпълним файл.

И таперича, както казваше Коровиев, нека всъщност върнем гражданите към механичния крайник на MechArm, който беше споменат в самото начало. Вече имаме възможност да го програмираме дистанционно и след това да го контролираме. Нека да преминем към програмата за управление от страната на микроконтролера.

В този случай трябва да управляваме четири сервомотори. Това са.


Такова задвижване се управлява от правоъгълни импулси, период от 20 ms (50 Hz) с работен цикъл от 2 до 4 процента. Тоест 2% е пълен оборот в едната посока, 4% в другата. Задачата е само за вградения ШИМ в AVR.

Едно серво се използва за движение надясно-наляво; второто върху себе си - от себе си; трети горе-долу; четвъртият е самият нокът, който трябва да бъде компресиран и отпуснат. Всичко е написано на C и е компилирано в HEX файл в ATMEL STUDIO. Малко странен вид на програмата се дължи на факта, че първоначално ръката се управлява от клавиатура, свързана с кабели към микроконтролера. Но кабелите са вчерашни, трябва да се развиваме по-нататък.

Можете, разбира се, да използвате скици за сервомотори от "ARDUINO", но не ми харесаха. По-забавно е да пишеш сам. Освен това и четирите серво трябва да работят едновременно, а не в мултиплексиран режим, когато ШИМ се превключва към всяко серво на свой ред. Защото никой не е отменил гравитацията и повдигнатият крайник моментално ще падне, ако управляващите импулси спрат да получават управляващи импулси към съответното серво. Не съм сигурен дали скицата "ARDUINO" осигурява едновременна работа за четири серво. Но ние сами можем да напишем програма, която отговаря на необходимите изисквания. И като цяло, при липсата на операционна система, която да разделя овцете от козите, използването на скици, конкуриращи се за микроконтролерни периферни устройства (и ние дори не знаем предварително кои) създава твърде много грешки.

Ето действителния код, който пишем на Arduino Nano с помощта на ESP8266-07.

Програма за управление MechArm за микроконтролер AVRmega328P

#define F_CPU 16000000 #include #включи // стандартни цели числа #include #включи // математика #включване //стандартен I/O #включване #включи #включи //стандартни функции #define UART_BAUD_RATE 115200 // брояч T1 задава времеви интервал от 20ms #define COUNTER1_OFF TCCR1B=0b00000000 // CS02 CS01 CS00 - 000 - деактивиран; 001 без разделител; 010 с делител 8; 011-64; 100 -256; 101 -1024 #define COUNTER1_ON TCCR1B=0b00000011 // брояч T0 задава ширината на управляващия импулс за PB0 и PB1 сервомашини #define COUNTER0_OFF TCCR0B=0b00000000 // CS02 CS01 CS00 - 000 - деактивиран; 001 без разделител; 010 с делител 8; 011-64; 100 -256; 101 -1024 #define COUNTER0_ON TCCR0B=0b00000100 // брояч T2 задава ширината на управляващия импулс за сервосистемите РB2(PD6) и РВ3(PD7) #define COUNTER2_OFF TCCR2B=0b00000000 // CS02 CS01 CS00 - 000 - забранено; 001 без разделител; 010 с делител 8; 011-64; 100 -256; 101 -1024 #define COUNTER2_ON TCCR2B=0b00000110 volatile uint16_t period_20ms; volatile uint8_t State_of_keyboard; volatile uint8_t начална_позиция; volatile int8_t number_servo; ISR(USART_RX_vect)// прекъсване за UART ( State_of_keyboard=UDR0; return; ) ISR(TIMER0_COMPA_vect)// серво PB0 управляваща ширина на импулса ( PORTB &=~(1<<0); TIMSK0&=~(1<
Същността на програмата е ясна от текста и коментарите. Ние използваме брояча T1 за референтен период от 20 ms и броячите T0, T2 за подаване на PWM сигнали към четири I / O порт линии, тъй като всеки от тези два брояча може да работи за две устройства.
Програмата задава началните позиции на сервомеханизмите чрез зареждане на регистрите за броене OCR0A, OCR0B, OCR2A, OCR2B. Въведени са и ограничаващи константи, тъй като не винаги се нуждаем от обхват от 180 градуса. Е, освен това, чрез прекъсване от UART, програмата улавя номера, изпратен от ESP8266 (от 1 до 8) и го превежда в команда за съответното серво. Има четири задвижвания, всяко от които работи в две посоки, така че цели числа от едно до осем са достатъчни. След като бъде избрано число, съдържанието на гореспоменатите регистри на брояча се увеличава или намалява, съответно променяйки работния цикъл на управляващия импулс и ъгъла на въртене на избраното серво. Тези устройства, които не сме избрали, запазват старата стойност на ъгъла на въртене (тъй като съдържанието на съответните регистри, въпреки че е актуализирано, не се променя) и продължават да държат механичното рамо в същото положение.

Сега просто трябва да напишем програма за управление, извинете за тавтологията, която да управлява механичната ръка директно от компютъра чрез WI-FI.
Кодът също е написан на JAVA, но малко облагороден. Имаше GUI и възможност за редактиране на номерата на портовете и мрежовия адрес на ESP8266.

Какво се случва там се вижда ясно от прозореца. Тук не предоставям текста на програмата (достъпна е на

Имам устройство, създадено с Arduino uno:

    Софтуер Arduino, инсталиран на Arduino uno

    може да се управлява чрез серийни команди

    Може да се управлява с физически бутони и сензори

    когато някой бутон/сензор се промени, той записва текущото състояние в серийния номер

    Ако не е изпратено съобщение в рамките на 5 секунди, той изпраща серийно съобщение непроменено

Какво ти е необходимо:

    Използвайте ESP8266, за да осигурите мост между текущия софтуер на Arduino и MQTT/web

    Мога да програмирам ESP8266 като уеб сървър, MQTT клиент и т.н. с помощта на Arduino IDE или Lua (но предпочитам Arduino IDE, тъй като мога да използвам повторно части от кода за генериране/интерпретиране на комуникацията).

    ESP8266 ще се справи с всичко необходимо за wifi/web/MQTT; без MQTT модула частта Arduino ще работи автономно, само дистанционното управление ще липсва.

    Бих искал да направя минимални промени в кода на Arduino (или никакви, ако е възможно). Всички промени ще изискват задълбочено повторно тестване, което се опитвам да избегна.

    ESP8266 може да не е наличен при някои инсталации.

Какви опции намерих:

    <�Литий>Последователен

ESP8266 може да чете сериен изход и да бъде мост между мрежа/MQTT и сериен, ще съхранява текущото състояние в паметта, за да бъде изпратено при поискване, за да се избегне запитване на устройството всеки път.

Едно от предимствата е, че не се изискват промени в кода/тестване за частта Arduino.

Направете Arduino I2C master и ESP8266 slave (или обратното) и внедрете двупосочна комуникация. Разбрах тази идея, като прочетох тази тема.

Друга информация за серийните команди:

Пакет от данни (команда или описание на състояние) се състои от 1-20 знака с възможен пик от 20 пакета за 5 секунди и средно един пакет на всеки 3 секунди. Ако е необходимо, мога да накарам това да изпраща 5 цели числа без знак вместо буквено-цифрови символи.

Ако са необходими повече от I2C/серийни пинове, мога да надстроя до Arduino Mega (така че броят на безплатните пинове не е проблем).

Има ли други опции за това? (протоколи, готови библиотеки за серийна комуникация и др.). Опитвам се да не преоткривам колелото.

Благодаря ви за отделеното време!

3

1 отговора

Повечето I2C уроци правят всеки Arduino подчинен и главен, но това е по-добре, защото всеки Arduino е или главен, или подчинен (не и двете) и не е необходимо превключване. Това улеснява нещата.

I2C е по-добър от серийния, защото можете да добавите повече Arduinos към същата шина.

Приложих I2C между две Arduinos и не е по-трудно от четене/запис на сериен порт (което вече направихте). Сигурен съм, че можете да обобщите кода на вашия сериен порт, за да работи както със серийна, така и с I2C комуникация.

Това е моят пример (само доказателство за концепцията). Slave Arduino контролира някои щифтове, темп. сензор и таймер watchdog по поръчка на майстор Arduino. Ако подчиненото устройство не получи малко навреме, то нулира главния Arduino.

Главен код

#include #define CMD_SENSOR 1 #define CMD_PIN_ON 2 #define CMD_PIN_OFF 3 #define CMD_LUMEN 4 #define CMD_BEAT 5 const byte SLAVE_ADDRESS = 42; постоянен байт LED = 13; charbuffer; void setup() ( Serial.begin(9600); Serial.println("Master"); Wire.begin(); pinMode(LED, OUTPUT); digitalWrite(LED, HIGH); delay(1000); digitalWrite(LED, LOW); Wire.beginTransmission(SLAVE_ADDRESS); Serial.println("Изпращане на светодиода"); Wire.write(CMD_PIN_ON); Wire.write(2); Wire.write(10); Wire.endTransmission(); int x = Wire.requestFrom(SLAVE_ADDRESS, 1); Serial.print("status="); Serial.println(x); ) //край на празен цикъл на настройка () ( Serial.println("."); Wire.beginTransmission (SLAVE_ADDRESS); Wire.write(CMD_SENSOR); Wire.endTransmission(); int x = Wire.requestFrom(SLAVE_ADDRESS, 1); Serial.print("Disponibles = "); Serial.println(x); int temp = ( int) Wire.read(); Serial.println(temp); Wire.beginTransmission(SLAVE_ADDRESS); Wire.write(CMD_LUMEN); Wire.endTransmission(); Wire.requestFrom(SLAVE_ADDRESS, 2); int light = Wire.read ()<< 8 | Wire.read(); Serial.print("Light="); Serial.println(light); Wire.beginTransmission (SLAVE_ADDRESS); Wire.write (CMD_BEAT); Wire.endTransmission(); Wire.requestFrom(SLAVE_ADDRESS, 1); delay (5000); } //end of loop

управляван код

/* Esclavo I2C Recibe los siguientes commandos<- 1° byte -> <- 2° byte -> <- 3° byte ->CMD_SENSOR CMD_PIN_ON № на продължителността на щифта във втория CMD_PIN_OFF № на щифта CMD_LUMEN CMD_BEAT Когато командата се рецитира с отговор, вие трябва да имате доблест или статус. */ #include #include typedef struct ( int pin; unsigned long off; ) PIN_PGMA; /* Списъкът на боровете, който може да бъде активиран чрез CMD_PIN_ON. */ #define PIN_LUMEN A0 #define PIN_LED 2 #define PIN_RESET 3 PIN_PGMA pgma = ( (PIN_LED, 0), (PIN_RESET, 0) ); const int pgmaSize = sizeof(pgma)/sizeof(PIN_PGMA); #define CMD_SENSOR 1 #define CMD_PIN_ON 2 #define CMD_PIN_OFF 3 #define CMD_LUMEN 4 #define CMD_BEAT 5 #define ST_OK 0 #define ST_BAD_PIN 1 #define ST_TIME_0 2 #define ST_BAD_LEN 3 #define MY_ADDRESS entre de CMDespera.tiempo 42 // Maximospera tiempo. Пасадо // този момент се активира като PIN_RESET. // En milisegundos. #define BEAT_INTERVAL 10000 неподписан дълъг lastBeat; // Largo del reset en milisegundos. #define RESET_LENGTH 250 байта cmd = 0; статус на байт = 0; int thermoDO = 11; int thermoCS = 12; int thermoCLK = 13; MAX6675 термодвойка (thermoCLK, thermoCS, thermoDO); void setup () ( Serial.begin(9600); pinMode(PIN_LUMEN, INPUT); analogRead(PIN_LUMEN); for (int i = 0; i< pgmaSize; i++) { pinMode(pgma[i].pin, OUTPUT); digitalWrite(pgma[i].pin, LOW); } lastBeat = millis(); Wire.begin (MY_ADDRESS); Wire.onReceive (receiveCommand); Wire.onRequest (sendAnswer); } void loop() { unsigned long now = millis(); // Baja la linea de RESET si no ha recibido un beat ultimamente. unsigned long diff = now - lastBeat; if (diff >BEAT_INTERVAL) ( resetPin(); ) // Записване на списъка с борове и завършване на следния момент. за (int i = 0; i< pgmaSize; i++) { if (pgma[i].off >0 && pgma[i].изкл<= now) { Serial.print("off pin="); Serial.println(pgma[i].pin); pgma[i].off = 0; digitalWrite(pgma[i].pin, LOW); } } } // called by interrupt service routine when outgoing data is requested void sendAnswer() { byte temp; int lightReading; switch (cmd) { case CMD_SENSOR: temp = thermocouple.readCelsius(); Wire.write(temp); break; case CMD_LUMEN: lightReading = analogRead(PIN_LUMEN); Wire.write(lightReading >> 8); wire.write(lightReading % 0xFF); прекъсване; случай CMD_PIN_ON: случай CMD_PIN_OFF: случай CMD_BEAT: Wire.write(статус); състояние = ST_OK; прекъсване; ) cmd = 0; ) // извиква се от рутинна услуга за прекъсване, когато пристигат входящи данни void receiveCommand (int howMany) ( cmd = Wire.read (); status = ST_OK; switch (cmd) ( case CMD_PIN_ON: cmdPinOn();; break; case CMD_PIN_OFF: cmdPinOff (); break; case CMD_BEAT: lastBeat = millis(); break; ) ) //край на receiveEvent void cmdPinOff() ( if (Wire.available() != 1) ( status = ST_BAD_LEN; ) else ( int pin = Wire.read(); int i = searchPin(pin); if (i< 0) { status = ST_BAD_PIN; } else { pgma[i].off = 0; digitalWrite(pin, LOW); } } } int searchPin(int pin) { int i = pgmaSize - 1; while (i >= 0 && pgma[i].pin != pin) ( i--; ) return i; ) /* * Програмата за прекъсване и продължителност на RESET. */ void resetPin() ( if (digitalRead(PIN_RESET) == LOW) ( unsigned long now = millis(); int i = searchPin(PIN_RESET); pgma[i].off = now + RESET_LENGTH; lastBeat = сега; digitalWrite (PIN_RESET, HIGH); ) ) void cmdPinOn() ( if (Wire.available() != 2) ( status = ST_BAD_LEN; ) else ( int pin = Wire.read(); int len ​​​​= Wire.read( ); int i = searchPin(pin); Serial.print("pin="); Serial.print(pin); Serial.print(",index="); Serial.println(i); if (i< 0) { status = ST_BAD_PIN; Serial.println("bad pin"); } else { if (len == 0) { status = ST_TIME_0; Serial.println("ban len"); } else { pgma[i].off = millis() + len * 1000; digitalWrite(pin, HIGH); Serial.println("ok"); } } } }

COM портът най-често се използва за свързване на микроконтролера към компютър. В тази статия ще покажем как да изпращате команди за управление от компютър и да изпращате данни от контролер.

Подготовка за работа

Повечето микроконтролери имат множество I/O портове. Протоколът UART е най-подходящ за комуникация с компютър. Това е сериен асинхронен протокол за пренос на данни. За да го преобразувате в USB интерфейс, платката разполага с USB-RS232 конвертор - FT232RL.
Нуждаете се само от платка, съвместима с Arduino, за да изпълните примерите в тази статия. Ние използваме . Уверете се, че вашата платка има светодиод, свързан към пин 13 и бутон за нулиране.

Например, нека качим код на дъската, който показва ASCII таблица. ASCII е кодиране за представяне на десетични цифри, латински и национални азбуки, препинателни знаци и контролни знаци.

int символ = 33; void setup() ( Serial. begin(9600 ) ; Serial. println(" ASCII Table ~ Character Map " ) ; ) void loop() ( Serial. write(symbol) ; Serial. print(" , dec: ") ; Serial .print(символ); Serial.print(" , шестнадесетичен: ") ; Serial.print(символ, HEX) ; Serial.print(" , oct: ") ; Serial.print(символ, OCT) ; Serial.print( " , bin: " ) ; Serial.println(symbol, BIN) ; if (symbol == 126 ) ( while (true) ( ​​​​продължи ; ) ) symbol+ + ; )

Символната променлива съхранява кода на символа. Таблицата започва от 33 и завършва на 126, така че символът първоначално е зададен на 33.
За да стартирате работата на UART порта, използвайте функцията Serial.begin(). Единственият му параметър е скоростта. Скоростта трябва да се договори предварително от предаващата и приемащата страна, тъй като протоколът за предаване е асинхронен. В този пример скоростта е 9600bps.
Три функции се използват за запис на стойност в порт:

  1. Serial.write()– записва данни в порта в двоична форма.
  2. Serial.print()може да има много стойности, но всички те служат за показване на информация в удобна за хората форма. Например, ако информацията, посочена като параметър за предаване, е затворена в кавички, терминалната програма ще я покаже непроменена. Ако искате да покажете някаква стойност в определена бройна система, тогава трябва да добавите служебна дума: BIN-двоична, OCT - осмична, DEC - десетична, HEX - шестнадесетична. Например, Serial.print(25,HEX).
  3. Serial.println()прави същото като Serial.print(), но все пак превежда низа след показване на информацията.

За да проверите работата на програмата, е необходимо компютърът да има терминална програма, която получава данни от COM порта. Arduino IDE вече има вграден такъв. За да го извикате, изберете Tools->Port Monitor от менюто. Прозорецът на тази помощна програма е много прост:

Сега щракнете върху бутона за рестартиране. MK ще се рестартира и ще покаже ASCII таблицата:

Обърнете внимание на тази част от кода:

if (символ = = 126 ) ( while (true) ( ​​​​продължи ; ) )

Спира изпълнението на програмата. Ако го изключите, таблицата ще се показва за неопределено време.
За да консолидирате придобитите знания, опитайте да напишете безкраен цикъл, който ще изпраща вашето име към серийния порт веднъж в секунда. Добавете номера на стъпки към изхода и не забравяйте да преведете реда след името.

Изпращане на команди от компютър

Преди да направите това, трябва да получите представа как работи COM порт.
На първо място, целият обмен се извършва през буфера на паметта. Тоест, когато изпратите нещо от компютър към устройство, данните се поставят в някакъв специален раздел на паметта. Веднага след като устройството е готово, то чете данните от буфера. Функцията ви позволява да проверите състоянието на буфера serial.avaliable(). Тази функция връща броя на байтовете в буфера. За да извадите тези байтове, трябва да използвате функцията Serial.read(). Нека видим как работят тези функции с пример:

int val = 0; void setup() ( Serial. begin(9600 ) ; ) void loop() ( if (Serial. available() > 0 ) ( val = Serial. read() ; Serial. print(" Получих: " ) ; Serial. write(val) ; Serial.println() ; ) )

След като кодът се зареди в паметта на микроконтролера, отворете монитора на COM порта. Въведете един знак и натиснете Enter. В полето за получени данни ще видите: „Получих: X“, където вместо хще бъде знакът, който сте въвели.
Програмата се върти безкрайно в основния цикъл. В момента, когато байтът е записан на порта, функцията Serial.available() приема стойност 1, тоест условието е изпълнено Serial.available() > 0. Следваща функция Serial.read()чете този байт, като по този начин изчиства буфера. След това, използвайки вече познатите ви функции, се появява изходът.
Използването на вградения монитор на COM порта на Arduino IDE има някои ограничения. Когато изпращате данни от платката към COM порта, изходът може да бъде организиран в произволен формат. И когато изпращате от компютъра към дъската, прехвърлянето на знаци става в съответствие с ASCII таблицата. Това означава, че когато въведете например знака „1“, двоичният „00110001“ (т.е. „49“ в десетичен знак) се изпраща през COM порта.
Нека променим малко кода и проверим това твърдение:

int val = 0; void setup() ( Serial. begin(9600 ) ; ) void loop() ( if (Serial. available() > 0 ) ( val = Serial. read() ; Serial. print(" Получих: " ) ; Serial. println(val, BIN) ; ) )

След изтегляне, в монитора на порта, когато изпращате „1“, ще видите в отговор: „Получих: 110001“. Можете да промените изходния формат и да видите какво приема дъската с други знаци.

Управление на устройството чрез COM порт

Очевидно чрез команди от компютър можете да управлявате всички функции на микроконтролера. Изтеглете програмата, която контролира работата на светодиода:

int val = 0; void setup() ( Serial. begin(9600 ) ; ) void loop() ( if (Serial. available() > 0 ) ( val = Serial. read() ; if (val= = "H" ) digitalWrite(13, HIGH) ; if (val= = "L" ) digitalWrite(13 , LOW) ; ) )

Когато символът “H” бъде изпратен към COM порта, светодиодът на 13-ия изход светва, а когато се изпрати “L”, светодиодът ще изгасне.
Ако въз основа на резултатите от получаване на данни от COM порта искате програмата да извършва различни действия в основния цикъл, можете да проверите условията в основния цикъл. Например.