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

пятница, 28 февраля 2020 г.

Внимание конкурс


В соответствии с пунктом 1 перечня поручений Губернатора Санкт-Петербурга Беглова А.Д. по итогам посещения 21.09.2019 объектов Красногвардейского района Санкт-Петербурга от 22.10.2019 №3509, а также распоряжением Комитета по образованию от 27.01.2020 № 154-р «Об организации и проведении чемпионата профессионального мастерства «Кубок Губернатора Санкт-Петербурга по робототехнике» среди студентов профессиональных образовательных учреждений и обучающихся общеобразовательных учреждений Санкт-Петербурга в 2020 году» (далее – Чемпионат), а также в целях развития образовательной робототехники в Санкт-Петербурге и повышения интереса обучающихся к научно-техническому творчеству Комитет по образованию совместно с Санкт-Петербургским государственным бюджетным профессиональным образовательным учреждением «Малоохтинский колледж» (далее - Колледж) организует и проводит Чемпионат.
Участие в Чемпионате могут принять обучающиеся возрастом от 9 лет (в зависимости от номинации).
Дата проведения Чемпионата: 14-15.05.2020, подача заявок – до 25.03.2020

четверг, 20 февраля 2020 г.

Робот Гриша модернизация

На этом занятии мы рассмотрим вопрос о модернизации робота "Гриша". Изначально робот имел следующую  электрическую схему управления(рис1), которая давала ему возможность объезжать препятствие со стороны где препятствие дальше, предлагаемая модернизация позволит усложнить алгоритм объезда препятствия, чем повысит вариативность выбора  маневра. Для этой цели предлагается ввести в схему управления ручную регулировку количества оборотов двигателя, угол поворота ультразвукового датчика дистанции (УЗД) и регулировку выставления УЗД в диаметральной плоскости робота. Кроме этого предлагается изменить алгоритм выбора стороны поворота. Так же добавить инфракрасный датчик движения  (ИДД) для остановки робота на момент выполнения регулировок.
рис1

Для выполнения модернизации необходимо дополнительно разместить малую макетную плату с тремя вариометрами и отдельно разместить датчик ИДД.
Предполагается так же перепланировка подключений контактов управления мотором по новой схеме(рис2) показанной ниже.

рис 2

При монтаже надо учитывать использование переходного шилда(рис3) для подключения датчиков
рис 3


а так же использования драйвера управления электромоторами(рис 4) L298N
Драйвер мотора L298N элементы
рис 4
Логика микросхемы L298N питается напряжением 5 Вольт. Для этого на модуле предусмотрен стабилизатор напряжения 78M05. На вход этого стабилизатора можно подавать напряжение до 35 В, а на выходе всегда получается 5 В. Рабочий ток у 78M05 небольшой — до 500 мА. Однако, при желании, от него можно питать и саму плату Ардуино Уно, к которой мы будем подключать драйвер.
Тройная клемма снизу отвечает за питание модуля. Самый левый контакт — питание моторов. Сюда можно подавать до 35 В. Средний контакт — земля, которая должна быть общей для модуля и контроллера. Правый контакт имеет двоякую функцию. Если на модуле стоит перемычка питания стабилизатора, то на этом контакте будет +5В и к нему можно ничего не подключать, либо питать от него контроллер. Но если перемычку убрать, то к этому контакту нужно будет непременно подключить +5В от контроллера, чтобы питать драйвер. В нашем примере мы будем ориентироваться именно на вариант без перемычки.
Две другие винтовые клеммы (OUT1/2 и OUT 3/4) служат для подключения моторов. Надо отметить, что моторы постоянного тока неполярные, но от того на какой контакт мотора подается плюс, а на какой минус, зависит направление их вращения.
Наконец, осталось разобраться с контактами управления. Их по три штуки на каждый мотор. Контакты ENA и ENB позволяют управлять моторами с помощью ШИМ сигнала. Если ENA и ENB подключить строго к +5 В, то моторы будут всегда вращаться с максимальной возможной скоростью. Именно для этого режима на модуле предусмотрены две перемычки рядом с ENA и ENB.
С помощью контактов IN1,IN2,IN3,IN4 задаётся режим работы моторов. Таблица режимов для двигателя A имеет вид:


РежимIN1IN2
Вращение в одну сторону10

Вращение в обратную сторону
01
Блокировка мотора11
Отключение мотора00
Тут следует пояснить последние два режима. Если нам необходимо резко остановить мотор, то выбираем режим блокировки. Для плавной остановки — выбираем «отключение мотора»

среда, 19 февраля 2020 г.

Прерывания в Arduino


Параметры функции обработки прерываний ISR() в C

Для обработки прерываний в C мы используем функцию ISR(). В ней необходимо указать с каким прерыванием мы будем иметь дело. Далее перечислены все варианты параметра функции ISR() для микроконтроллеров ATmega328P:
  • INT0_vect - внешнее прерывание 0
  • INT1_vect - внешнее прерывание 1
  • PCINT0_vect - прерывание по изменению состояния нулевой группы выводов
  • PCINT1_vect - прерывание по изменению состояния первой группы выводов
  • PCINT2_vect - прерывание по изменению состояния второй группы выводов
  • WDT_vect - прерывание от сторожевого таймера
  • TIMER2_COMPA_vect - прерывание от таймера/счетчика T2 при совпадении с A
  • TIMER2_COMPB_vect - прерывание от таймера/счетчика T2 при совпадении с B
  • TIMER2_OVF_vect - прерывание по переполнению таймера/счетчика T2
  • TIMER1_CAPT_vect - прерывание от таймера/счетчика T1 по записи
  • TIMER1_COMPA_vect - прерывание от таймера/счетчика T1 при совпадении с A
  • TIMER1_COMPB_vect - прерывание от таймера/счетчика T1 при совпадении с B
  • TIMER1_OVF_vect - прерывание по переполнению таймера/счетчика T1
  • TIMER0_COMPA_vect - прерывание от таймера/счетчика T0 при совпадении с A
  • TIMER0_COMPB_vect - прерывание от таймера/счетчика T0 при совпадении с B
  • TIMER0_OVF_vect - прерывание по переполнению таймера/счетчика T0
  • SPI_STC_vect - прерывание по окончанию передачи модуля SPI
  • USART_RX_vect - прерыванию по окончанию приема модуля USART
  • USART_UDRE_vect - прерывание по опустошению регистра данных модуля USART
  • USART_TX_vect - прерывание по окончанию приема модуля USART
  • ADC_vect - прерывание по завершению преобразования АЦП
  • EE_READY_vect - прерывание по готовности памяти EEPROM
  • ANALOG_COMP_vect - прерывание от аналогового компаратора
  • TWI_vect - прерывание от модуля I2C (TWI)
  • SPM_READY_vect - прерывание по готовности flash памяти

Описание функции attachInterrupt для управления прерываниями в Arduino

Прерывание (англ. interrupt) -- сигнал, сообщающий процессору о наступлении какого-либо события. Основные методы:

void attachInterrupt(uint8_t, void (*)(void), int mode);


attachInterrupt(interrupt, function, mode); -- определяет, какую функцию вызывать, когда происходит внешнее прерывание.
Здесь
interrupt -- номер прерывания (int). Большинство плат Arduino/Freeduino имеют два внешних прерывания с номерами 0 (на digital pin 2) и 1 (на digital pin 3).
function -- функция, которая должны вызываться при прерывании. Функция не должна принимать параметров и не должна ничего возвращать.
mode -- определяет, когда должно сработать прерывание. Определены следующие константы:
LOW - вызов прерывания всякий раз, когда на порту низкий уровень напряжения;
CHANGE - прерывание вызывается при изменении значения на входе;
RISING - вызов прерывания при изменении уровня напряжения с низкого (LOW) на высокое(HIGH)
FALLING - вызов прерывания при изменении уровня напряжения с высокого (HIGH) на низкое (LOW)

void detachInterrupt(uint8_t);


detachInterrupt(interrupt); -- отключает указанное прерывание.
Подробнее здесь

ДРАЙВЕР ДВИГАТЕЛЕЙ L293D

Для управления двигателями робота необходимо устройство, которое бы преобразовывало управляющие сигналы малой мощности в токи, достаточные для управления моторами. Такое устройство называют драйвером двигателей.
 драйвер двигателей L293D
драйвер двигателей L293D
Существует достаточно много самых различных схем для управления электродвигателями. Они различаются как мощностью, так и элементной базой, на основе которой они выполнены.
Мы остановимся на самом простом драйвере управления двигателями, выполненном в виде полностью готовой к работе микросхемы. Эта микросхема называется L293D и является одной из самых распространенных микросхем, предназначенных для этой цели.
L293D содержит сразу два драйвера для управления электродвигателями небольшой мощности (четыре независимых канала, объединенных в две пары). Имеет две пары входов для управляющих сигналов и две пары выходов для подключения электромоторов. Кроме того, у L293D есть два входа для включения каждого из драйверов. Эти входы используются для управления скоростью вращения электромоторов с помощью широтно модулированного сигнала (ШИМ).
L293D обеспечивает разделение электропитания для микросхемы и для управляемых ею двигателей, что позволяет подключить электродвигатели с большим напряжением питания, чем у микросхемы. Разделение электропитания микросхем и электродвигателей может быть также необходимо для уменьшения помех, вызванных бросками напряжения, связанными с работой моторов.
Принцип работы каждого из драйверов, входящих в состав микросхемы, идентичен, поэтому рассмотрим принцип работы одного из них.
 Схема драйвера двигателей
Схема драйвера двигателей
К выходам OUTPUT1 и OUTPUT2 подключим электромотор MOTOR1. На вход ENABLE1, включающий драйвер, подадим сигнал (соединим с положительным полюсом источника питания +5V). Если при этом на входы INPUT1 и INPUT2 не подаются сигналы, то мотор вращаться не будет. Если вход INPUT1 соединить с положительным полюсом источника питания, а вход INPUT2 - с отрицательным, то мотор начнет вращаться.
Теперь попробуем соединить вход INPUT1 с отрицательным полюсом источника питания, а вход INPUT2 - с положительным. Мотор начнет вращаться в другую сторону.
Попробуем подать сигналы одного уровня сразу на оба управляющих входа INPUT1 и INPUT2 (соединить оба входа с положительным полюсом источника питания или с отрицательным) - мотор вращаться не будет. Если мы уберем сигнал с входа ENABLE1, то при любых вариантах наличия сигналов на входах INPUT1 и INPUT2 мотор вращаться не будет.
Представить лучше принцип работы драйвера двигателя можно, рассмотрев следующую таблицу:
ENABLE1
INPUT1
INPUT2
OUTPUT1
OUTPUT2
1
0
0
0
0
1
1
0
1
0
1
0
1
0
1
1
1
1
1
1

Теперь рассмотрим назначение выводов микросхемы L293D.
L293D
 L293D

* Входы ENABLE1 и ENABLE2 отвечают за включение каждого из драйверов, входящих в состав микросхемы.
* Входы INPUT1 и INPUT2 управляют двигателем, подключенным к выходам OUTPUT1 и OUTPUT2.
* Входы INPUT3 и INPUT4 управляют двигателем, подключенным к выходам OUTPUT3 и OUTPUT4.
* Контакт Vs соединяют с положительным полюсом источника электропитания двигателей или просто с положительным полюсом питания, если питание схемы и двигателей единое. Проще говоря, этот контакт отвечает за питание электродвигателей.
* Контакт Vss соединяют с положительным полюсом источника питания. Этот контакт обеспечивает питание самой микросхемы.
* Четыре контакта GND соединяют с "землей" (общим проводом или отрицательным полюсом источника питания). Кроме того, с помощью этих контактов обычно обеспечивают теплоотвод от микросхемы, поэтому их лучше всего распаивать на достаточно широкую контактную площадку.




Характеристики микросхемы L293D


* напряжение питания двигателей (Vs) - 4,5...36V
* напряжение питания микросхемы (Vss) - 5V
* допустимый ток нагрузки - 600mA (на каждый канал)
* пиковый (максимальный) ток на выходе - 1,2A (на каждый канал)
* логический "0" входного напряжения - до 1,5V
* логическая "1" входного напряжения - 2,3...7V
* скорость переключений до 5 kHz.
* защита от перегрева


По материалам https://myrobot.ru/stepbystep/el_driver.php

19.02.20 Окончание. PDM

  Пульс плотности модуляции , или ДПМ , является одной из форм модуляции используется для представления аналогового сигнала с двоичным сигналом . В сигнале PDM, конкретные амплитуды значение не кодируется в кодовые слова импульсов разного веса , как они были бы в импульсно-кодовой модуляции (PCM); а относительная плотность импульсов соответствует амплитуде аналогового сигнала. Выход в 1-битного ЦАП является таким же , как PDM кодирования сигнала. Широтно-импульсной модуляции (ШИМ) представляет собой частный случай ДПМ , где фиксируется частота коммутации и все импульсы , соответствующие одному образцу являются смежными в цифровом сигнале. Для 50% напряжения с разрешением 8 бит, ШИМ сигнал включится на 128 тактовых циклов , а затем выключить для остальных 128 циклов. С ДПМ и той же тактовой частоте сигнала будет чередоваться между включением и выключением любого другого цикла. В среднем составляет 50% для обоих сигналов, но сигнал ДПМ переключается чаще. При 100% или 0% уровня, они одинаковы.

Двигатель который может находиться в заданном положении, а при воздействии внешних факторов, например, принудительном отклонении вала, удерживает его положение неизменным – называется сервоприводом. Вообще определение звучит несколько иначе:
Сервопривод, это двигатель управляемый отрицательной обратной связью.
Обычно с сервопривода выходит три провода:
  • Плюс питания.
  • Минус питания.
  • Управляющий сигнал.
Блок управления сравнивает сигнал на встроенном датчике положения и сигнал, пришедший по управляющему проводу, если они различаются, то происходит поворот на угол, при котором разница между сигнала нивелируется.
Принцип работы сервопривода
Основные характеристики сервоприводов:
  • Скорость поворота (время, за которое вал поворачивается на угол 60°);
  • Крутящий момент (кг/см, т.е. сколько килограмм может выдерживать двигатель на рычаге в 1 см от вала);
  • Напряжение питания;
  • Потребляемый ток;
  • По способу управления (аналоговый или цифровой, существенной разницы нет, но цифровой более быстродействующий и стабильный).
Обычно период сигнала равен 20 мс, а длительность управляющего импульса:
  • 544 мкс – соответствует 0°;
  • 2400 мкс – соответствует углу 180°.

Сервопривод для Ардуино

Сервопривод – это такой вид привода, который может точно управлять параметрами движения. Другими словами, это двигатель, который может повернуть свой вал на определенный угол или поддерживать непрерывное вращение с точным периодом.

Схема и типы сервоприводов

 

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

Подключение серводвигателя к ардуино

Сервопривод обладает тремя контактами, которые окрашены в разные цвета. Коричневый провод ведет к земле, красный – к питанию +5В, провод оранжевого или желтого цвета – сигнальный. К Ардуино устройство подключается через макетную указанным на рисунке образом. Оранжевый провод (сигнальный) подключается к  цифровому пину, черный и красный – к земле и питанию соответственно. Для управления серводвигателем не требуется подключение именно к шим-пинам – принцип управления серво мы уже описывали ранее.
Подключение сервопривода к ардуино
Не рекомендуется подключать мощные серво напрямую к плате , т.к. они создают для схемы питания Arduino ток, не совместимый с жизнью – повезет, если сработает защита. Чаще всего симптомы перегрузки и неправильного питания сервопривода заключаются в “дергании” серво, неприятному звуку и перезагрузке платы. Для питания лучше использовать внешние источники, обязательно объединяя земли двух контуров.

Сервопривод SG90

Сервопривод SG90

Характеристики и подключение SG-90

Если вы собрались купить самый дешевый и простой сервопривод, то SG 90 будет лушим вариантом  Этот серво чаще всего используется в управлении небольшими легкими механизмами с углом поворота от 0° до 180°.
Технические характеристики SG90:
  • Скорость отработки команды 0,12с/60 градусов;
  • Питание 4,8В;
  • Рабочие температуры от -30С до 60 С;
  • Размеры 3,2 х 1,2 х 3 см;
  • Вес 9 г.

Описание SG90

Цвета проводов стандартные. Сервопривод стоит недорого, он не обеспечивает точных настроек начальных и конечных позиций. Для того, чтобы избежать  лишних перегрузок и характерного треска в положении 0 и 180 градусов лучше выставлять крайние точки в 10° и 170°. При работе устройства важно следить за напряжением питания. При сильном завышении  этого показателя могут повредиться механические элементы зубчатых механизмов.

Скетч для управления сервоприводом в Arduino

Управление сервоприводом напрямую через изменение в скетче длительности импульсов – достаточно нетривиальная задача, но у нас, к счастью, есть отличная библиотека Servo, встроенная в среду разработки Arduino. Все нюансы программирования и работы с сервоприводами мы рассмотрим в отдельной статье. Здесь же приведем простейший пример использования Servo.
Алгоритм работы прост:
  • Для начала мы подключаем Servo.h
  • Создаем объект класса Servo
  • В блоке setup указываем, к какому пину подключен серво
  • Используем методы объекта обычным для C++ способом. Самым популярным является метод write, которому мы подаем целочисленное значение в градусах (для сервопривода 360 эти значения будут интерпретироваться по-другому).

Для управления такими сервоприводами с ардуино в вашем распоряжении есть встроенная в IDE библиотека Servo, у неё небольшой набор команд:
  • attach() — добавить переменную к пину. Пример: названиеПривода.attach(9) – к 9 пину подключаем сервопривод. Если вашему приводу нужны нестандартные длины управляющих импульсов (544 и 2400 мкс), то их можно задать через запятую после номера пина, например: servo.attach(pin, min угол (мкс), max угол в МКС));
  • write() — задает угол поворота вала в градусах;
  • writeMicroseconds() — задает угол, через длину импульса в микросекундах;
  • read() — определяет текущее положение вала;
  • attached() — Проверяет, задан ли пин с подключенным сервоприводом;
  • detach() — отмена команды attach.

Пример простого скетча для работы с сервоприводом

Пример проекта, в котором мы сразу сначала устанавливаем серводвигатель на нулевой угол, а затем поворачиваем на 90 градусов.
  1. #include <Servo.h>

  2. Servo servo; // Создаем объект
  3. void setup() {
  4. servo.attach(9)// Указываем объекту класса Servo, что серво присоединен к пину 9
  5. servo1.write(0)// Выставляем начальное положение
  6. }

  7. void loop() {
  8. servo.write(90); // Поворачиваем серво на 90 градусов
  9. delay(1000);
  10. servo.write(1800);
  11. delay(100);
  12. servo.write(90);
  13. delay(1000);
  14. servo.write(0);
  15. delay(1000);
  16. }

Скетч для двух сервпоприводов

А в этом примере мы работаем сразу с двумя сервоприводами:
  1. #include <Servo.h>

  2. Servo servo1; // Первый сервопривод
  3. Servo servo2; // Второй сервопривод

  4. void setup() {
  5. servo1.attach(9)// Указваем объекту класса Servo, что серво присоединен к пину 9
  6. servo2.attach(10)// А этот servo присоединен к 10 пину

  7. }

  8. void loop() {
  9. // Выставялем положения
  10. servo1.write(0);
  11. servo2.write(180);
  12. delay(20);
  13. // Меняем положения
  14. servo2.write(0);
  15. servo1.write(180);
  16. }


Управление сервоприводом с помощью потенциометра

В этом примере поворачиваем серво в зависимости от значения, полученное от потенциометра. Считываем значение и преобразовываем его в угол с помощи функции map:
  1. //Фрагмент стандартного примера использования библиотеки Servo
  2. void loop() {
  3. val = analogRead(A0); // Считываем значение с пина, к которому подключен потенциометр
  4. val = map(val, 010230180); // Преобразуем число в диапазоне от 0 до 1023 в новый диапазон - от 0 до 180.
  5. servo.write(val);
  6. delay(15);
  7. }

map(value, fromLow, fromHigh, toLow, toHigh)

 

long map(long x, long in_min, long in_max, long out_min, long out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

понедельник, 17 февраля 2020 г.

17.02.20 Продолжение. PWM Широтно-импульсная модуляция

Pulse-width modulation (PWM), или pulse-duration modulation (PDM) или Широтно-импульсная модуляция(ШИМ)
PWM сигнал является цифровой волной прямоугольной формы , где частота постоянна, но в части времени когда сигнал включен (рабочий цикл) его уровень может изменяться от 0 до100%.
 
100% рабочий цикл будет таким же, как установка напряжения 5 вольт (высокий). 0% рабочий цикл будет таким же, как заземление сигнала.
Можно управлять яркостью светодиода Предоставление аналогового выходного сигнала; только если фильтруется цифровой выход, это обеспечит аналоговое напряжение между 0% и 100%. Создание звуковых сигналов. Управление скоростью моторов. Генерации модулированного сигнала, например управление инфракрасным светодиодом для пульта дистанционного управления.

Простая широтно-импульсная модуляция с analogWrite

Язык программирования Arduino делает PWM простой в использовании; просто выполните analogWrite (контакт, рабочий цикл), где рабочий цикл может иметь значение от 0 до 255, а контакт является одним из выводов ШИМ (3, 5, 6, 9, 10 или 11).Функция analogWrite предоставляет простой интерфейс для аппаратного ШИМ, но не обеспечивает никакого контроля над частотой. (Отметьте, что, несмотря на имя функции analogWrite, производится вывод цифрового сигнала представляющего волны квадратной формы.)


Использование ATmega PWM регистр напрямую

Чип ATmega168P / 328P имеет три ШИМ таймера, управляющие 6 выходами ШИМ. Манипулируя таймером чипа напрямую, вы можете получить больше контроля, чем обеспечивает функция analogWrite. Техническое описание AVR ATmega328P дает подробное описание ШИМ таймера, но техническое описание может быть трудно понятым, из-за различных контрольных и выходных режимов таймеров.



настройка таймеров
cli(); //запрет прерываний

//режим вывода не инверсный
TCCR1A|=(1<<COM1A1);  //1
TCCR1A&=~(1<<COM1A0);  //0

//режим шим c точной фазой и частотой
TCCR1A&=~(1<<WGM10);  //0
TCCR1A&=~(1<<WGM11);  //0
TCCR1B&=~(1<<WGM12);  //0
TCCR1B|=(1<<WGM13);  //1

//предделитель 8
TCCR1B|=(1<<CS11);  //1
TCCR1B&=~((1<<CS10)|(1<<CS12));  //0 0

OCR1A =25;  // 50% длительность импульса
ICR1=50;  // 20кГц
sei(); //разрешение прерываний
Код нужно добавить в Setup. Настраивается таймер - счетчик 1, только канал А, соответственно нужный сигнал будет только на пине D9. Частота задается значением в регистре ICR1. Ниже представлены протестированные значения и соответствующая им частота.
ICR1=10; // 100 кГц
ICR1=20; // 50 кГц
ICR1=30; // 33 кГц
ICR1=40; // 25 кГц
ICR1=50; // 20 кГц
ICR1=60; // 16,6 кГц
ICR1=70; // 14,3 кГц
ICR1=80; // 12,5 кГц
ICR1=90; // 11,1 кГц
ICR1=100; // 10 кГц

Если изменить предделитель, то частоты будут другие, например при предделителе 64 и ICR1=50, частота будет 2,5 кГц.
Скважность регулируется значением в регистре OCR1A, она зависит от значения в ICR1, таким образом, что максимальное значение OCR1A равно значению в ICR1, если они равны получится постоянный сигнал. При значении OCR1A = ICR1 / 2 получится меандр (длительность импульса и длительность паузы между импульсами равны). Еще пример: при ICR1 = 50 (20кГц) и OCR1A = 10, длительность импульса будет 20%.

В loop можно менять значение OCR1A и соответственно будет меняться скважность.

К стати о setup(), loop() и main() .
Когда мы подключаем плату Arduino к питанию, то внутри него начинается весьма бурная деятельность встроенных микропрограмм. Микроконтроллер сконфигурирован так, что при запуске системы управление получает программа-загрузчик. Первое, что делает загрузчик – проверяет в течение 1-2 секунд, не начнется ли от пользователя отправка новой программы. Если процесс перепрограммирования начат, то скетч загружается в память и управление отдается ему. Если новых программ нет, то загрузчик выполняет ранее сохраненную программу.
Начав выполнение программы, Arduino выполняет ряд рутинных операций по инициализации и настройке среды окружения и только затем приступает к выполнению того самого кода, который  содержится в наших с вами скетчах. Таким образом, ардуино избавляет нас от необходимости помнить все детали архитектуры микропроцессора и сконцентрироваться на стоящей перед нами задаче (это не значит, что мы не должны понимать, что же происходит за кадром).
Для иллюстрации сказанного приведем фрагмент исходников Arduino, в которых и производится вызов наших функций (файл main.cpp):
  1. int main(void)
  2. {
  3. init();

  4. initVariant();

  5. #if defined(USBCON)
  6. USBDevice.attach();
  7. #endif
  8. setup();
  9. for (;;) {
  10. loop();
  11. if (serialEventRun) serialEventRun();
  12. }
  13. return 0;
  14. }
Функция main() – это настоящая точка входа в программу, именно она вызывается первой. Как мы видим, в ней вызываются методы инициализации параметров и среды окружения, а затем и наши void setup() и, уже в цикле – void loop();

Для чего нужна функция void setup()

Загрузив программу, Arduino дает нашему коду возможность поучаствовать в инициализации системы. Для этого мы должны указать микроконтроллеру команды, которые он выполнит в момент загрузки и потом забудет про них (т.е. эти команды выполнятся только один раз при старте системы). И именно с этой целью в нашей с вами программе  мы должны выделить блок, в котором будут храниться эти команды. void setup(), а верней  пространство внутри фигурных скобок этой функции, и является таким местом внутри Arduino скетча.


Функция void loop()

Функция loop это то место, куда мы должны поместить команды, которые  будут выполняться все время, пока включена плата Arduino. Начав выполнение с первой команды, микроконтроллер дойдет до конца и сразу же перепрыгнет в начало, чтобы повторить ту же последовательность. И так бесконечное число раз (до тех пор, пока на плату будет подан электричество). Наиболее уместный перевод английского слова loop в даном случае – это цикл (петля). 





С помощью функций arduino void loop и void setup мы передаем микроконтроллеру  инструкции нашего скетча. Все то, что содержится внутри блока setup выполнится один раз. Содержимое блока loop будет выполняться в цикле до тех пор, пока останется включенным Arduino-контроллер.

Таким образом
 void analogWritePin3(int data) { 
TCCR2A |= 1 << COM2B1;
 OCR2B = data; // устанавливаем уровень ШИМ
}

 void analogWritePin5(int data) {  
TCCR0A |= 1 << COM0B1;
 OCR0B = data; // устанавливаем уровень ШИМ
}

 void analogWritePin6(int data) {  
TCCR0A |= 1 << COM0B1;
 OCR0A = data; // устанавливаем уровень ШИМ
}

 void analogWritePin9(int data) {  

TCCR1A |= 1 << COM1B1;
 OCR1A = data; // устанавливаем уровень ШИМ
}

 void analogWritePin10(int data) { 
TCCR1A |= 1 << COM1B1;
 OCR1B = data; // устанавливаем уровень ШИМ
}

 void analogWritePin11(int data) { 
TCCR2A |= 1 << COM2B1;
 OCR2A = data; // устанавливаем уровень ШИМ
}
Нам удалось сократить время исполнения примерно в 7 раз — до 0,69 мкс. Но как видно из примера такое достижение, как и в случае с digitalRead()/digitalWrite(), далось в ущерб гибкости, понятности и универсальности. Там где скорость исполнения не в приоритете, имеет смысл оставить штатную функцию analogWrite()














пятница, 14 февраля 2020 г.

14.02.20 Аналоговые и цифровые сигналы, обработка в микроконтроллере Arduino UNO




Как  и какие сигналы обрабатываются в микроконтроллере? Что такое аналоговый сигнал? Чем отличается от цифрового? На представленной ниже схеме указаны возможные сигналы на выходе и входе микроконтроллера. Аналоговый сигнал - непрерывный сигнал, значение которого мы знаем в любой момент времени. Цифровой сигнал - значения известны через равные промежутки времени и значений только два - 0 и 1.


На выше представленной схеме рассмотрены штатные команды (функции) языка Wiring
На официальном сайте пишут: "...is programmed using the Arduino programming language (based on Wiring)".
Фактически — нет никакого особого языка программирования и программы пишутся на C/C++, а компилируются и собираются с помощью широко известного avr-gcc (в версии для Windows — WinAVR).
Все особенности сводятся к тому, что имеется набор библиотек, включающий в себя некоторые функции (вроде pinMode) и объекты (вроде Serial), а при компиляции Вашей программы среда разработки создает временный .cpp файл, в который кроме Вашего кода включается еще несколько строчек, и полученный результат скармливается компилятору а затем линковщику с нужными параметрами.
К сожалению за все нужно платить, за универсальность тоже. Расплата это размер и скорость выполнения программы. Иногда штатные функции нам не всегда на 100% полезны, иногда возникают ситуации что они избыточны. Именно для этого мы рассмотрим альтернативные способы работы с сигналами в микроконтроллере. Начнем с цифровых сигналов.
В микроконтроллере Arduino UNO, имеются 3 порта работы с цифровыми сигналами B, C, D.
https://raspberry3.ru/wp-content/uploads/2017/05/arduinopinout-1024x724.jpg 
Каждый порт представляет собой три 8-ми битный регистр, в котором каждый бит имеет свой вывод(ногу, пин), два доступных для записи чтения и один только для чтения. Регистр DDRx (где х имя порта) отвечает за представления ножки как выхода или входа в зависимости от того что записано в данный бит 1- выход 0- вход. Таким образом записывая в соответствующий бит регистра 0 или 1  мы определяем его как вход или выход. Регистр PORTx ответственно отвечает зато  что находится на  выходе высокий или низкий уровень сигнала. Регистр PINx доступен только для чтения и позволяет считывать уровень сигнала на соответствующем выходе. Например:

DDRD = 0xff;
PORTD= 0b11000010;

Двумя строчками мы определили все выводы порта D (pin 0..7), как выходы где высокий уровень(HIGH) на pin 1,6,7 на остальных выводах низкий (LOW) 
Иногда обращаться ко всему порту бывает затруднительно, поэтому вместо digitalWrite()  можно использовать:

PORTD |= 1<<3; // УСТАНАВЛИВАЕМ НА pin_2 высокий уровень сигнала
PORTD &= ~(1<<3); //устанавливаем на pin_2 низкий уровень сигнала

В Н И М А Н И Е

команда PORTD = 1<<3; ЗАПИШЕТ в регистр 0b00000100, будьте осторожны. Соответственно PORTD = ~(1<<3) ----> 0b111110111.

Теперь что касается чтения с выводов порта. Условие которое определяет уровень сигнала на выводе (PIND & (1<<PD3)) если истинно то HIGH, ложно LOW.
С цифровыми сигналами разобрались. Теперь аналоговый сигнал.
 

Для работы с аналоговым сигналом необходимо преобразовать его в цифровой, для этого используется аналого-цифровой преобразователь (АЦП)

АЦП Arduino UNO имеет разрешение 10 бит, т.е. позволяет выводить значения в десятичном виде от 0 до 1023. В относительных единицах деление шкалы 5/1024 = 4.9 мВ;
analogRead(pin) -- Функция считывает значение с указанного аналогового входа. Возвращает: int (0 to 1023).
Считывание значение с аналогового входа занимает примерно 100 микросекунд (0.0001 сек), т.е. максимальная частота считывания приблизительно 10,000 раз в секунду.
analogReference(type) -- определяет опорное напряжение относительно которого происходят аналоговые измерения. Type принимает одно из следующих значений:
DEFAULT: стандартное опорное напряжение 5 В (на платформах с напряжением питания 5 В) или 3.3 В (на платформах с напряжением питания 3.3 В).
INTERNAL: встроенное опорное напряжение 1.1 В на микроконтроллерах ATmega168 и ATmega328, и 2.56 В на ATmega8.
EXTERNAL: внешний источник опорного напряжения, подключенный к выводу AREF (рекомендуется подключать к выводу AREF через резистор 5 кОм).
Примеч.: Опорное напряжение можно установить, используя функцию analogReference или при помощи битов REFT[1:0] в регистре ADMUX.
Используйте внутреннее опорное напряжение 1.1 В для точных измерений внешних напряжений:
analogReference(INTERNAL1V1); // выбираем внутреннее опорное напряжение 1.1В 
Разовая выборка - это на самом деле то, что Arduino делает при вызове функции analogRead()

Непрерывная выборка:
Хорошей идеей при непрерывной выборке сигнала является использование прерываний.
Микроконтроллеры ATMega328 и ATMega2560 могут быть переведены в режим непрерывной выборки (free running mode). В этом режиме АЦП запускается автоматически после завершения предыдущей обработки. Для включения режима непрерывной выборки необходимо установить три регистра: ADMUX, ADCSRA и ADCSRB

ADCSRB = 0x00;
ADMUX = 0b01100000;//A0
ADCSRA = 0b11101111;//делитель 128
//функция для работы с АЦП по прерыванию
volatile int result;
ISR(ADC_vect)
 { result = ADCH;
}
Продолжение следует