Arduino с нуля

Начало работы

Arduino — это готовые печатные платы, с установленным на них каким-либо микроконтроллером(обычно это микроконтроллер семейства AVR) в качестве главной управляющей микросхемы, с открытым исходным кодом.

В микроконтроллеры изначально прошит загрузчик(bootloader).

Микроконтроллер — это микрокомпьютер со своей постоянной, оперативной памятью, центральным процессором и портами ввода\вывода.

Для устройств arduino  пишется один и тот же код на высокоуровневом языке так называемом Arduino programming language (язык основан на Wiring, который в свою очередь основан на языке Proccessing, язык сам по себе представляет из себя С++) для всего зоопарка устройств, без необходимости индивидуально разбирать порты ввода\вывода, так как они подписаны на каждой плате.

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

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

Низкоуровневый язык assembler:

;Регистр R16(mp) определен с целью временного хранения значения
;назначить свое имя одному из 32 8-битных регистров - mp
.def mp = R16
 
;при запуске avr код начинает выполняться с адреса 0000
;rjmp означает относительный прыжок
;main - произвольное имя, перейти(перепрыгнуть) на метку (адрес) main
rjmp main
main:
 
;загрузим бинарные данные 11111111 в регистр mp
;ldi-команда действительна только для регистров R16-R31
;после выполнения этой команды регистр mp имеет значение 11111111
;0b - говорит о том, что число является двоичным
;0x -является шестнадцатеричным
 
;Ноль в начале является сигналом для ассемблера, чтобы ожидать число
;Числа без 0b  или 0x являются десятичными
; ldi mp, 255 будет иметь тот же результат, что и ldi mp,255,0b1111111, так как 11111111=255
ldi mp,0b11111111
 
;назначить все порты B как выходные, установив все биты в 1
;нам не нужно заботиться о  реальном адресе порта, так как этот адрес содержит 
;tn13adef.inc-файл
;значения 0 делали бы порты входными
;записать данные из регистра mp(R16) в порты DDRB
;mp содержит значение 11111111
out DDRB,mp
 
;метка loop
loop:
 
;записать нули в регистр mp
ldi mp,0x00
 
;записать в порты B значение регистра mp т.е. сделать на выходах B
;низкий уровень(0 вольт) out
;потушить светодиод
PORTB,mp
 
;вызвать подпрограмму задержки в 250 миллисекунд
rcall delay_250_ms
 
;записать единицы в регистр mp(0b11111111=0xFF=255)
ldi mp,0xFF
 
;записать в порты B значение регистра mp т.е.сделать на выходе высокий уровень(напр.+5 вольт)
;зажечь светодиод
out PORTB,mp
 
;вызвать подпрограмму задержки
rcall delay_250_ms
 
;прыгнуть на метку loop, т.е.зациклить код
rjmp loop
 
;здесь подпрограмма задержки в 250 миллисекунд
;осуществляется вложенными циклами и декрементом регистров
;так частота процессора 9,6 MHz,  то 1 тик длится 1/9,6 = 0,1041666666666667 микросекунд
; формула расчета количества тиков для задержки N микросекунд такова:
;L_cnt = T_delay * F_clk+1)/N_mc , где:
; L_cnt=количество необходимых тиков(надо найти)
;F_clk - частота процессора в МГц
;T_delay - нужная задержка в микросекундах (250 000 микросекунд)
;N_mc- количество машинных тактов(4, так как команды выполняются в
;nop - 1 такт, dec - 1 такт, brne - 2 такта при условии ветвления)
 
;Итого L_cnt = (250 000 мкс * 9,6 МГц+1)/4=600 000,25 проходов
;возьмем максимальные значения первых двух регистров:255*255=65025
;маленькая цифра, необходим третий регистр
;65025*255=16 581 375 проходов, теперь подходит, теперь необходимо выяснить сколько раз
;нужно взять 65025, чтобы получить 600 000,25
;600 000,25/65025=9,227224144559785 раз
;следовательно первые два регистра должны быть со значением 0(0=255)
;третий должен быть 9, так как 255*255*9= 585 225 проходов, близко к 600 000
;значит 585 225 проходов выполнятся за * 0,1041666666666667 = 60960,93750000002*4=
;=243843,7500000001 микросекунд, близко к 250 миллисекундам
 
 
;подпрограмма задержки
delay_250_ms:
 
;помещаем значения в регистры
ldi r18, 0
ldi r19, 0
ldi r20, 9
 
L1:
nop
dec r18
brne L1
 
nop
dec r19
brne L1
 
nop
dec r20
brne L1
 
;вернуться
ret

Язык программирования Си, близок к низкоуровневому:

#define F_CPU 9600000UL
#include <avr/io.h> //библиотека ввода\вывода
#include <util/delay.h> //библиотека задержки
 
int main(void) // начало основой программы
{
 
	DDRB = 0xff; // установить все порты B как выводы
 
	while (1) { // бесконечный цикл
 
		PORTB = 0xff; // установить "1"(вкл) на всех линиях порта B
 
		_delay_ms(250); // ждем 250 миллисекунд
 
		PORTB = 0x00; // установить "0"(выкл) на всех линиях порта B
 
		_delay_ms(250); // ждем 250 миллисекунд
 
	}
 
}

Язык программирования Arduino:

void setup() {
pinMode(2, OUTPUT); // Сконфигурировать ножку 2 как выход
}
 
void loop() {
 
digitalWrite(2, HIGH); //зажечь светодиод
delay(250); //подождать 250 миллисекунд
digitalWrite(2, LOW); //потушить светодиод
delay(250); //подождать 250 миллисекунд
 
}

Практикум

Для того, чтобы начать программировать вы должны приобрести любую плату Arduino, либо можно эмулировать скетчи программно, но это сложнее и здесь рассматриваться не будет.Скетчем называется файл прошивки для устройств Arduino.

Далее скачиваем программу Arduino IDE для разработки с официального сайта:

https://downloads.arduino.cc/arduino-1.8.10-windows.zip

Либо здесь для своей ОС или с другим способом установки — https://www.arduino.cc/en/Main/Software

После того как программа скачана и плата приобретена,  плату следует подключить к компьютеру.

Подключение платы к компьютеру:

Подключить можно массой способов, например самый простой способ — через USB,

другие способы — через UART, USBAsp и т.д.

Через USB:

Здесь просто подключаем устройство к USB-порту компьютера.

Через UART:

Возьмем самый дешевый модуль ардуино с али — Arduino Pro Mini на ATMEGA168 5V 16Mhz. который не имеет USB, поэтому его необходимо подключать через UART, для этого необходим переходник USB-UART (например такой  — CP2102 на Orange Pi Zero .  или можно взять другой переходник, где уже будет готовый вывод:

).

Берем платку Arduino Pro Mini, припаиваем контакты-гребенку:

Схема данной платы:

Дальше соединяем эту плату с UART TO USB — переходником, по пяти проводам, в соответствии:

Плата ардуино — Плата переходника

VCC5V

GNDGND

RXTX

TXRX

DTRDTR

 

То есть:

Обратите внимание, что контакт RX первой платы соединяется с TX-контактом другой платы!

И соответственно контакт TX первой платы соединяется с RX-контактом второй платы.

Соединили — подключаем переходник к USB-порту компьютера.

Как можем дальше видеть, в ардуино уже залита некая прошивка, происходит мерцание светодиода:

Как считать данную прошивку?

Смотрите здесь — Как считать прошивку Arduino через UART

Находим порт

Чтобы найти порт, на котором находится устройство надо зайти в диспетчер устройств(диспетчер устройств можно вызвать так — нажать кнопки Win + R, ввести — «devmgmt.msc» без кавычек и нажать Enter).Перейти к списку — Порты(COM и LPT) и развернуть его.Видим наш переходник Silicon Labs CP210x и видим на каком порту он находится — COM7(у вас может быть или будет другое имя и порт).

Запускаем ранее скачанную программу — среду разработки Arduino IDE(предварительно распаковав ее, если она была в zip-архиве):

Выбираем свой модуль ардуино(у нас это Arduino Mini Pro):

Далее выбираем процессор, так как у нас не ATmega328, а ATmega168 на плате, которая будет питаться от 5 вольт, выбираем соответствующее(если питать плату от 3,3 вольт, то частота, то есть скорость процессора снижается в 2 раза):

Далее выбираем порт на котором сидит плата(это мы узнавали ранее):

Затем выбираем — Инструменты — Получить информацию о плате:

Если всё подключено правильно, то должно отобразиться такое окно:

Отлично.Теперь можно приступать к написанию программы.

 

Программирование

При запуске мы видим код:

void setup() {
// put your setup code here, to run once:
 
}
 
void loop() {
// put your main code here, to run repeatedly:
 
}

 

void setup(){} — так обозначаются функции в программе

Сам код пишется внутри фигурных скобок { здесь размещается код }


1.Что значит void?

void обозначает, что функция ничего не возвращает — никакого значения

например функция

int odin(){
 
return 1;
 
}

вернет цифру 1 (return — вернуть с англ.языка)

2.Что означает int?

int означает, что тип возвращаемого значения — целое число(без десятых)

3.Почему setup?

setup — это имя функции, которое может быть любым, но в данном случае имя функции должно быть setup и его нельзя изменять, так как это обязательная функция, в которой выбираются изначальные настройки микроконтроллера, также обязательна функция и loop, имя которой тоже менять нельзя.Исходя из этого удалять эти функции также нельзя.

4.Почему в функции void setup(){} отсутствует return?

Отсутствует, потому что функция ничего не возвращает, это указано перед именем функции, словом — void

5.Что означают скобки — ( ) ?

В скобках могут приниматься  какие либо переданные параметры, к примеру, имеется функция:

int summa(int c1, int c2){
 
return c1+c2;
 
}

Вызовем эту функцию в каком-либо другом месте программы так(здесь в скобках параметры передаются вызванной функции):

int x = summa(2,3);

После выполнения этой функции значение переменной x станет суммой 2+3, то есть 5

 

int x = summa(5,5);

А здесь переменная x примет значение 10 и т.д.

6.Что такое переменная?

Переменная это какая-либо неизвестная величина, которая может принимать любое значение

К примеру приведем уравнение X+5=10, здесь X можно назвать переменной

7.Что означает — // put your setup code here, to run once: ?

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

8.Что значит точка с запятой ; ?

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

9.Какие функции еще есть у Ардуино?

Все встроенные функции описаны здесь — https://www.arduino.cc/reference/en/#functions


Компилируем код

После того как написана программа её следует компилировать.

Компиляция — это перевод текста программы в двоичный бинарный файл, который потом записывается в память микроконтроллера Arduino.

 

В открытой программе нажимаем на галку в левом верхнем углу или выбираем вкладку Скетч — Проверить/Компилировать или же нажимаем на Ctrl + R.

Результат:

Скомпилированный файл сохраняется во временной папке:

C:\Users\ИмяПользователя\AppData\Local\Temp\arduino_build_ХХХ 

где XXX — любые цифры

После компиляции прошивку необходимо записать в микроконтроллер, для этого нажимаем кнопку со стрелкой вправо или Скетч — Загрузка или опять же Ctrl + U.

После этого микроконтроллер сбросится(об этом уведомит контрольный светодиод на плате Arduino мгновенным мерцанием) и начнется заливка прошивки в Ардуино , если используется переходник USB — UART, то  на нем начнут мелькать контрольные светодиоды передачи\приема данных.Сразу после прошивки, если в нем ранее была залита какая-либо прошивка, к примеру мелькание светодиода несколько раз в период времени, то сразу увидим, что это мелькание прекратилось.Почему?Потому что мы только что записали в Arduino пустую прошивку, которая ничего не делает.

Вернемся к коду, который был написан выше:

Язык программирования Arduino:

void setup() {
pinMode(2, OUTPUT); 
}
 
void loop() {
 
digitalWrite(2, HIGH); 
delay(250);
digitalWrite(2, LOW); 
delay(250); 
 
}

Разбор кода:

Функция setup вызывается один раз при запуске микроконтроллера(как только подано питание), в ней всё инициализируется, то есть задается изначальное значение, определение чего-либо.

Функция pinMode определяет, какое назначение будет у ножки(от которой проведен контакт до монтажного отверстия на плате и подписан на ней) микроконтроллера — вход или выход.Если ножка определена как выход, то на нее можно вешать какую-либо нагрузку, всё тот же светодиод или затвор транзистора и т.д.

Внимание!Нельзя напрямую вешать на ножку микроконтроллера нагрузку без ограничительного резистора и нагрузку с потреблением тока больше 20 мА!

Если ножка определена как вход, то к ней можно подключить кнопку, принять данные от другого устройства и т.д.

pinMode(2, OUTPUT); — Цифра 2 означает, что выбран контакт 2, OUTPUT — что данный контакт назначен ВЫХОДОМ, следовательно эта функция сделала это: назначила контакт номер 2выходом.

INPUT — назначит ножку входом, т.е. pinMode(2, INPUT); = назначить контакт 2 входом.

 

 

Функция loop вызывается бесконечно по кругу:

Если не написать в ней каких либо задержек, пауз, то она вызывается  равное частоте процессора количество раз в секунду, деленное на время, которое заняло выполнение кода внутри функции.

 

Функция digitalWrite определяет какой уровень будет на ножке — высокий или низкий, если выбран высокий уровень, то на ножке будет +5 вольт(или +3,3 вольт, если плата питается от такого напряжения), если выбран низкий уровень, то на ножке будет 0 вольт.

digitalWrite(2, HIGH); — Здесь же опять цифра 2 означает, что выбрана ножка 2 соответственно.HIGH — означает, что на ножке 2 будет высокий уровень(т.е. +5 вольт/3,3 вольт).

LOW — назначит низкий уровень(0 вольт), т.е. digitalWrite(2, LOW); = выбрать низкий уровень на ножке 2.

 

Функция delay означает задержку выполнения кода.delay(250); — число в скобках означает время задержки в миллисекундах , 1 секунда равна 1 000 миллисекунд.delay(250); = Ничего не делать 250 миллисекунд.1 000 миллисекунд/250 миллисекунд = 4, значит это 1/4 секунды или 0,25 секунд.

 

Полный листинг кода:

//Функция setup выполнится при запуске микроконтроллера
void setup() {
//при запуске микроконтроллера ножка 2 будет выходом
pinMode(2, OUTPUT);
}
 
//Функция loop повторяется бесконечное количество раз
void loop() {
 
//подать на ножку 2 высокий уровень(+5 вольт) 
digitalWrite(2, HIGH);
//ничего не делать(спать) 250 миллисекунд
delay(250);
//подать на ножку 2 низкий уровень(0 вольт) 
digitalWrite(2, LOW);
//ничего не делать(спать) 250 миллисекунд
delay(250);
 
//после выполнения последней команды delay(250);
//код начнет исполняться заново с функции digitalWrite(2, HIGH); до 
//последней команды delay(250); и так по кругу
}

 

 

Теперь присоединим светодиод к плате.Для этого нужен резистор.Какого номинала нужен резистор?Обычный светодиод для индикации потребляет примерно 20 миллиАмпер, в 1 Ампере  1 000 миллиАмпер.

Формула расчета резистора — R=(Uпит-Uled)/Iled.Где Uпит — Напряжение питания платы, Uled — напряжение питание светодиода(2 вольта), Iled — ток потребления светодиодом, в амперах, как уже знаем, он 20 мА, 20мА/1000мА=0,02 Ампера потребляет светодиод.Плата у нас питается от 5-ти вольт, значит R = (5 вольт — 2 вольта)/0,02 Ампера = 150 Ом, такого номинала нужен резистор(также можно взять бОльший номинал — светодиод просто будет светиться тусклее, номинал ниже брать нельзя — порты микроконтроллера могут выгореть от чрезмерной токовой нагрузки).

Наблюдаем результат:

Кроме отдельного светодиода и контакта для него, можно использовать встроенный светодиод, для этого вместо цифры 2 надо написать константу —  LED_BUILTIN (константа —  это  паттерн, т.е. неизменяемая, заранее определенная величина со своим именем, которая может указываться в разных местах в коде и при компиляции, все написанные константы в коде заменяются  заданной величиной).

Дальше можно сделать, что посложнее — Гирлянда на arduino

ОЦЕНИТЕ ДАННУЮ ПУБЛИКАЦИЮ:

Средний рейтинг / 5. Количество оценок:

Мы сожалеем, что эта публикация Вас не устроила.

Сохранить в:

Оставить комментарий

avatar
  Подписаться  
Уведомление о