"Вы читаете о роботах и программировании и думаете: «Было бы здорово сделать что-то подобное самому!» Теми, кем эта идея овладевает чуть больше просто мыслей смотрят кто и как делал своего робота. Читают статьи, смотрят видео. На картинках все понятно. В видеороликах тоже обычно показываются уже готовые продукты, а также сжато показываются технологии их изготовления. И вроде бы то же всё понятно: отпилил, прикрутил, припаял, соединил, запрограммировал вон на той программе вот этим кодом."

среда, 27 ноября 2019 г.

Ардуино на чистом С

Поднимем вопрос программирования Arduino на языке Си. Зачем это может понадобиться, ведь на языке Arduino писать значительно проще? Во-первых, код на Си весит намного меньше, чем на Arduino (насколько меньше увидите дальше). Во-вторых, он может выполняться быстрее (для задач, где критична высокая скорость). Кроме того, это может стать первым шагом при освоении собственно микроконтроллеров. Как всегда здесь не будет теории, только практика.
Для начала необходимо подключить библиотеку, позволяющую отправлять-принимать сигналы. Делается это командой
 
#include <avr/io.h>
 
Если на Arduino было необходимо наличие функций loop и setup, то на Си должна быть функция main, возвращающая тип int. Внутри этой функции и будет находится наш код.
 
 int main (void) {
 
}
 
 Поставим себе простейшую задачу — зажечь светодиод на порту №13. И тут мы столкнемся с тем, что собственно на микроконтроллере нет 13 порта. Посмотрим распиновку (pinout) микроконтроллера, установленного в Ардуино (atmega328p).
 
 
 
http://studrobots.ru/wp-content/uploads/2016/12/atmega328w_pinout.png 
 
 Тут обращаем внимание на PB0 — PB7, PC0 — PC6, PD0 — PD7. Это и есть порты для подключения устройств, с ними и предстоит работать. Посмотрим, как эти порты соотносятся с портами Arduino.
 
 
http://foros.giltesa.com/otros/arduino/fc/docs/pinout/uno.jpg 
 
 
Мы задались целью зажечь светодиод на 13 порту. По распиновке Arduino мы видим, что там находится порт PB5. Собственно, правильнее сказать, что порт B, 5 бит. В программе будем работать сразу со битами порта B (0-7), но постараемся не затрагивать биты кроме 5.
Сначала нужно обозначить B5 как выход, то, что на Ардуино делалось командой pinMode (13, OUTPUT).
На Си для этого существует команда DDRB, где B — порт (соответственно, могло быть DDRC и DDRD).
У порта B 8 битов, каждый из которых может быть настроен на выход (1) и вход (0). Поэтому, мы можем задать двоичное число, где каждому биту соответствует 0 или 1.
Например, запись
 
DDRB = 0b00000001


говорит о том, что 0 бит порта B, т.е. PB0 (8 порт Ардуино) будет выходом (OUTPUT), остальные — входом (INPUT). 0b перед числом позволяет указывать двоичную запись числа.
Так как мы работает с PB5, то 1 мы должны поставить в 5 бит

 DDRB = 0b00100000

 Теперь нужно подать напряжение на данный порт. Делается это командой PORTB, где B — снова порт. Напряжение подается единицей, отсутствие напряжения — 0. По аналогии запишем команду

PORTB = 0b00100000

 чтобы подать напряжение на 5 бит.
Код целиком:
#include <avr/io.h>
 
int main (void) {
 
 DDRB = 0b00100000;
 
 PORTB = 0b00100000;
 
}
 
 Что в этом коде нехорошо, так это то, что мы указывали сразу все биты одного порта. Иногда мы не знаем заранее, подается питание на тот или иной бит и изменять мы его не должны, а значит, мы не можем сами подавать туда 0 или 1. Поэтому важно уметь настраивать нужный бит, без изменения остальных.
Для этого потребуется знание логических операций и операций над битами.
Логическое ИЛИ (|)
 Результат ИЛИ равен 1 если хотя бы один из операндов равен 1.

Логическое И (&)
Результат И равен 1 если оба операнда равны 1.


Побитовые сдвиги влево и вправо (<< и >>)
Данные операции сдвигают все биты числа вправо или влево на заданное количество позиций.
Например, запись 1<<2 означает, что биты изначального числа 00000001 сдвинутся влево на 2 позиции и получится 00000100.
Воспользуемся данными операциями, чтобы работать только с необходимыми битами портов.
Мы должны PB5 настроить на выход. Сделаем это так:

DDRB |= (1<<5);


1<<5 это 1 в 5 бите, т.е. 0b00100000. Применяем логическое ИЛИ для текущего состояния порта B и данного числа. Так как 1 находится только в 5 бите, то и в результате изменится лишь 5 бит порта B (станет 1), остальные биты останутся без изменений. Результат операций перезаписывается в DDRB.
Тоже самое проделаем и для отправки сигнала:

PORTB |= (1<<5);


Вновь, благодаря данным операциям изменится состояние лишь 5 бита порта B.
Код программы:

#include <avr/io.h>
 
int main (void) {
 
  DDRB |= (1 << 5);
 
  PORTB |= (1 << 5);
 
}


Теперь посмотрим, сколько памяти требует данный код и аналогичный код на Ардуино.

 http://studrobots.ru/wp-content/uploads/2016/12/%D1%81%D0%B8.jpg

 http://studrobots.ru/wp-content/uploads/2016/12/ard.jpg


 На языке Си код занимает 144 байта, на Ардуино — 710, т.е. разница почти в 5 раз и это всего при двух командах.



 по материалам http://studrobots.ru/arduino-c-1/