Skip to content

This is small library files for Arduino for makes sketches smaller and faster...

Notifications You must be signed in to change notification settings

Arhat109/ArduinoFast

Repository files navigation

Описание библиотеки

(как работает, что содержит, куда пользоваться)

Введение

Библиотека предназначена для минимизации конечного кода скетчей. Разработка ещё "в процессе" (времени не так много), тестировано только то, что использовано в примерах.

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

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

Что есть и как работает

  1. Ардуино ИДЕ, перед компиляцией каждого скетча, производит его преобразование: ПОСЛЕ всех директив препроцессора, если они в нем есть, добавляет директиву подключения заголовочного файла Arduino.h. Кроме этого, как и положено в нем самом, стоит защита от повторного включения файла.

Этим и пользуемся: В начале файла arhat.h имитируем "как будто бы" этот файл (Arduino.h), УЖЕ был запущен и подключен.

  1. Полностью заменен главный файл Wiring - wiring.c, поскольку основное его "достоинство" - создание таймера времени и функция millis() - работают "практически" некорректно. Миллисекунды тикают "скачками". Кроме этого, начальная инициализация "всего" - есть безусловное "зло" для целей минимизации итогового размера.

Написана собственная реализация wiring.c, по большей части в виде ассемблерных вставок. Поскольку, теперь функция millis() считает "корректно но медленно", упрощен обработчик прерываний и снижены требования к хранению переменных. К сожалению, это иногда требует ручного отключения файла wiring.c путем его переименования.

  1. Передача параметров. Как выяснилось, основное увеличение типовых скетчей в размерах, особенно хоть сколько-то "сложных" связано с размером передаваемых параметров в имеющиеся функции. Соответственно, реализованы (и будут добавляться) функции с укороченными типами передаваемых параметров: uint8_t и uint16_t вместо uint32_t. Часть функций Wiring уже переименована именно в такие версии. В частности delay().

  2. Сохранена возможность переопределения деталей реализации конкретной машинки и её микроконтроллера.

Вся реализация, в настоящее время выполнена и частично тестирована под машинку Arduino Mega2560 USB. Тем не менее, расширение использования и портирование библиотеки на другие устройства не должно представлять "трудностеЙ": Все описания, связанные с машинкой вынесены в отдельный файл: arhat_pins2560.h. Его подключение делается в основной файле с использованием стандартных констант определения "какой процессор конкретно сейчас компиляется оболочкой". Можно легко добавить/заменить на собственный набор определений.

5.1. upd-20151120: Добавлена "распальцовка" для Arduino UNO на базе ATmega328P, также разрешено использование для процессоров совместимых и определённых в одном datasheet: ATmega48P, ATmega88P, ATmega168P.

Нумерация пинов плат:

Принято следующие правила: а) по возможности сохраняется нумерация контактов на платах Ардуино, начиная с 0; б) нумерация аналоговых входов продолжает нумерацию остальных контактов платы; в) макроорпеделения пинов по специальным функциям сохраняют сквозную нумерацию пинов.

Как следствие, традиционное макроопределение Analog3 тут имеет номер 57 для Ардуино Мега2560. .. и все остальные специальные названия контактов возвращают сквозной номер пина.

Макросы:

а) Типовые определения констант. Собрано из разных мест, по возможности то, что наиболее часто требуется: а1) Битовые: SET_MASK_x CLR_MASK_x, Bxxxxxxxx - "удобства для". Используются в самой библиотеке для указания конкретного бита; а2) Типовые Wiring: HIGH,LOW,INPUT,OUTPUT ... - "совместимости для". Часто указаны в скетчах, определены и тут; а3) Математика: PI, HALF_PI, ... - дабы не вспоминать "сколько это". Дополнены константами преобразования времени звука в расстояние; а4) Константы из Cyberlib - для совместимости с этой библиотекой.

б) макро-функции:

Особенности использования: НЕ ВСЕ макроопределения (особенно для работы с битами и портами напрямую) позволяют корректное преобразование для номеров ног, указанных в оперативной памяти, через переменные! Особенно те, которые в своем "нутре" имеют команду препроцессора "##" (слипание строки для создания имени макроса).

Это важно помнить. Ниже, такие макросы специально помечены в скобках: (##)

б1) "общие", "удобные" - взяты из разных библиотек. Это в частности маркосы для работы с битами "напрямую": cbi(sfr, bit), sbi(sfr, bit), bitRead(value, bit), bitSet(value, bit), bitClear(value, bit), bitWrite(value, bit, bitvalue)

названия говорящие, думаю "пояснений" не требуют.

б2) (##) "битовые для Cyberlib": D_In(p), D_Out(p), D_High(p), D_Low(p), D_Inv(p), D_Read(p)

аналогично, названия "говорящие", особенно тем кто пользуется этой библиотекой.

б3) "общеупотребительная математика и прочая ерунда" в основном взято из Wiring: min(a,b), max(a,b), constrain(amt,low,high), radians(deg), degrees(rad), sq(x), ChatToDec(char), DecToChar(dec)

б4) (##) "битовые, местные" для прямого управления ножками Ардуины: pinModeIn(), pinModeOut(), pinModePullup(), pinMode() - установка ножки в режим "на вывод", "на ввод" и "куда сказано". Основное назначение - функция setup();

б5) (##) "таймерные". Для прямого управления и настройки таймеров, а также для создания процедур обработки прерываний от таймеров стандартным макросом ISR(). Все они имеют префикс timer: timerCount(t) // получить/установить регистр счетчика таймер 8/16bit. Значения t:[0,2,[1,3,4,5]] timerControl(t,r) // получить/установить регистр управления таймером. Значения t:[0,2,[1,3,4,5]], r:[A,B[,C]] timerCompare(t,r) // получить/установить регистр сравнения канала таймера. t:[0,2,[1,3,4,5]], r:[A,B[,C]] timerCapture(t) // получить/установить регистр захвата таймера (только для 16-битных!) p:[1,3,4,5] timerIFlag(t,v) // получить флаг прерывания от таймера. t:[0,2[,1,3,4,5]] v:[OVF,COMPA,COMPB[,COMPC,CAPT]] timerIMask(t,v,b) // установить бит маски прерывания таймера: b==1: set | b==0: clear, остальное - выше. ISRtimer(t,v) // приготовить название вектора прерываний таймера для ISR() prescalerMode(p) // получить код для битов прескалера по макро-константе режима работы (arhat_pins2560.h)

** Здесь, в arhat.h и ниже: В каждой строке описания функции указаны допустимые значения параметров в квадратных скобках через запятую. Если скобки двойные, то внутри указана дополнительная разновидность/расширение набора значений. Так например, выше: [1,2,[3,4,5]] - согласно предыдущему тексту "таймер 8/16bit", означает: номер 8бит-таймера 1 или 2 и 16бит-таймера 3,4 или 5. Соответственно, такие же двойные скобки перечисляют допустимый набор параметеров для второго (и т.д.) параметра, если он есть. К примеру, для timerCompare(t,r) можно указать канал A или B если таймер 8-и битный (1 или 2) И можно ещё указать канал C, для остальных, 16-и битных таймеров. Поскольку макросы создают ИМЕНА типовых макросов avr-gcclib, то значения надо указывать ровно так, как они описаны в строке. Это не имена других макросов или чего ещё. Часто это часть формируемого имени! Так например макрос ISRtimer(3,CAPT) создает имя типового макроса, используя указанные параметры как его часть, в результате в код подставляется текст: TIMER3_CAPT_vect, что для файла interrupt.h является типовым названием обработчика соотвествующего прерывания.

б6) (##) "ШИМ" (PWM). Для "аналогового" вывода на ножки PWM2..13 и PWM44..46: pwmGetTime(p) // получить номер таймера по номеру пина PWM. Оказалось полезно. pwmGetChannel(p) // получить букву канала таймера по номеру пина PWM. pwmPinMode(p,m) // получить режим для его установки по номеру пина и режиму: p[2..13,44,45,46,T1C], m[PWM_DISABLE,PWM_TOGGLE,PWM_NORMAL,PWM_INVERSE] pwmSet(p) // Включить режим ШИМ для ноги платы (настройка "по умолчанию": FAST-PWM, 1/64 (250kHz), PWM_NORMAL. pwmOff(p) // Выключить режим ШИМ. Любой. pwmWrite(p,v) // Установить ширину импульса ШИМ: номер ноги - выше, "яркость"(v):[0..255] pwmSetServo(p) // Установить ШИМ "Серводвигатель" (50Гц) и пин в сервовывод (без pinMode()!). Только для 16-битных таймеров! timerSetServo(t,pm) // Тотже ШИМ "Серводвигатель", но по номеру таймера. Принимает вторым параметром маску какие каналы будут использованы. // Позволяет установить ШИМ одновременно на всех заданных каналах таймера и сам таймер в режим. Смотрите примеры

** примечания: Если требуется использовать таймер 1, канал С (13 ножка!), то его номер пина надо указывать как T1C. Иначе, для 13-ноги, будет задействован таймер 0, канал А. Они совмещены в ATmega2560 на одном выводе для возможности аппаратной реализации двойного ШИМ (подача пачки импульсов заданной скважности с заданной периодичностью);

б7) (##) "АЦП" (ADC). Для работы с аналоговым вводом с ножек Analog0..15. Номера ножек тыт с 0 по 15!: adcOn() // Включить АЦП и установить делитель: 16Mhz/128 (125kHz) adcOff() // Выключить АЦП. Позволяет экономить батарейку, если не используется АЦП. admuxSrc(s) // получить маску источника оцифровки s:[AREF,AVCC,110,256] для установки далее. admux1Channel(src,pin,adlar) // Типовой режим АЦП: оцифровка с одной ноги по источнику и со сдвигом результата. admux2Channel(src,neg,poz,adlar) // Дифференциальный режим оцифровки с двух ножек по источнику. admux2Gain(src,neg,poz,g,adlar) // Дифференциальный режим с предусилителем сигнала (х10, х200).

** примечания: Последние 2 макроса работают далеко не для всех сочетаний ножек! Ну не умеет микроконтроллер.. смотреть описание макросов в самом файле. Там есть все ограничения!

Выделены отдельно макросы включения и выключения работы АЦП блока. Он оказывается жрет существенно. По умолчанию изначально - выключен. Надо помнить, что желательно, чтобы после включения блока и ДО первой оцифровки сигнала проходило 108 микросекунд для его "прогрева и запуска"... иначе, первая оцифровка будет НЕВЕРНА. Нормальное применение макросов - функция setup().

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

В папке examples есть тестовый пример "как этим пользоваться": analogRead.ino

everyMillis() -- макрос для работы с задержками БЕЗ использования delay(). Хорошо и популярно описан во многих местах под разными названиями. Для удешевления работы дополнен макросом everyOvfCount() - делает тоже самое, но на основе счетчика переполнений таймера и соответственно работает в "тиках" по 1024 микросекунды

Нижеследующие функции заменены МАКРОСАМИ (ножку платы указывать числовой константой! Не переменная в памяти!):

pinMode(p,m), digitalRead(p), digitalWrite(p,v), turnOffPWM(t), analogWrite(p,v)

Ниже следующие функции изменены: millis() -> time_millis() micros() -> time_micros() delay() -> time_delay16(ms) -- использует 16-и битный параметр! Сокращает вызовы на 6 байт каждый, но считает только до 65.5секунд..

Примечание: возвращен выбор режимо компиляции скетчей константой ARHAT_MODE. В режиме совместимости все типовые имена функций

          не переименовываются и вызываются из Wiring.

Дополнение:

      ************ АВТОМАТНОЕ ПРОГРАММИРОВАНИЕ ************

В комплект библиотеки добавлены файлы tsc.h и tsc.c и примеры в папку examples, имеющие префикс TSC_ в названии.

В целом, там все достаточно просто и можно разобраться по примерам. Каждый "блок","устройство" представляет собой "конечный автомат" (КА) и работает "независимо" от других КА. Каждый КА имеет набор "состояний" и "функций" перехода между ними и "интервал времени ожидания". Для наглядности, управление КА вынесено в отдельную таблицу, в которой указывается интервал времени ожидания, команда и номера следующих команд. Табличку легко расширить и на более сложные виды КА, например для возвращающих значения текущей командой (true|false). порядок работы строки таблицы состояний КА:

  1. При выборе номера строки (первоначально в tsc_init() или tc_next()) фиксируется начало интервала ожидания;

  2. Завершение интервала ожидания происходит в tsc_step() или tsc_run();

  3. По истечению интервала, tsc_step() устанавливает новое значение номера текущего состояния И фиксирует начало нового интервала;

  4. И только потом вызывает выполнение команды. 3а. Функция tsc_run() по истечению интервала вызывает команду. И только. Переключение состояния, интервала и команды должно выполняться в текущей команде, вызываемой из tsc_run().

    Это позволяет реализовать несколько разновидностей конечных автоматов:

  5. Простой КА, логика управления которым сосредоточена в самих командах. Таблица состояний тут не требуется. Создается такой КА только структурой TSC_Control, в которую в setup() надо вручную прописать время начала первого интервала, длительность ожидания и первую исполняемую команду. В цикле loop() достаточно вызывать tsc_run() и, по истечению ожидания она вызовет указанную команду (функцию), которая должна установить "следующее действие" и "интервал ожидания". Повторно устанавливать стартовое время интервала уже не требуется.

  6. КА, управляемый таблицей состояний" (к нему и примеры). Таблица состояний должна иметь префикс PROGMEM также, как это указано в примерах. Тогда её размещение не будет занимать оперативную память. Если не требуется логика переходов по false, то вторую колонку "next::false" можно заполнить нулями и команды в этом случае должны возвращать ненулевое значение.

    Во всех КА допускается изменение следующего состояния в самих командах, исполняемых КА. Это возможно, поскольку tsc_step() СНАЧАЛА формирует данные о следующем состоянии КА, а вызов команды производит последним действием. Таким же образом можно управлять состоянием одного КА из действий другого.

**1 Для формирования КА, работающих с "двигателями" или иными "медленными" устройствами, крайне полезно выделять в отдельные состояния команды "запуска" действия с переходом на состояние "ожидания" его завершения, также как это показано в примере TSC_Servo.ino. В этом же примере показано изменение логики управления "сам себе мастер": при достижении крайнего положения серводвигателя, автомат переходит на обратное вращение.

**2 Для лучшего понимания "автоматного программирования" рекомендуется прочтение статьи в Википедии с таким названием.

Установка библиотеки.

В целом традиционна: распакуйте архив в каталоге ваших скетчей в подкаталог /libraries.

В результате, должна получиться следующая иерархия каталогов:

Arduino -- это мой каталог скетчей libraries -- подкаталог с библиотеками создается при установке, если нет - создайте сами. Arhat -- подкаталог с этой библиотекой arhat.h -- заголовочный файл для уменьшения размера скетчей и их ускорения. arhat.c -- файл реализации струткур, функций и методов arhat_pins2560.h -- файл "распиновки" Ардуино Мега2560. Макросы, преобразующие номер пина куда-то. arhat_pins***.h -- возможны и другие файлы распиновок. Делать по образцу! tsc.h -- заголовочный файл программирования конечных автоматов tsc.c -- файл реализации классов, структур, функций и методов автоматного программирования hcsr04.h -- template-файл библиотеки узв. датчика HCSR-04 keywords.txt -- файл подсветки синтаксиса help.txt -- краткое описание "чего и с чем" пользовать или не пользовать ... в разработке. ReadMe.txt -- этот файл. *** -- возможен ещё какой-нибудь мусор из отладки или недоделанного... examples -- подкаталог с примерами использования в скетчах.

Внимание!

Если у Вас при запуске скетчей из примеров появляется ошибка типа 'redefine __vector_23()', то Вам необходимо переименовать файл wiring.c, лежащий в папке Ардуино ...\hardware..\core. Где он конкретно лежит - зависит как от Вашей ОС, версии Ардуино ИДЕ, так и от метода установки (в Линукс). Для Линукс (Ubuntu), надо искать ту версию файла, на которую есть права для правки. Часто рабочая копия лежит в папке /usr/share/Arduino, а не в папке с программой! .. где-то работает нормально, а где-то глючит ... на Линуксах это зависит от способа установки Ардуино ИДЕ и её версии. Относительно устойчиво работает без переименования пока только в версии ИДЕ 1.6.4.

Внимание2!

Библиотека для уменьшения и ускорения скетчей базируется на макросах, преобразующих типовые названия функций Wiring в одно-двухкомандные последовательности, за счет того, что номер используемого пина - указан или явной числовой константой (число) или используется макроопределение из файла arhat_pins***.h При указании номера пина в переменной - этот подход НЕ РАБОТАЕТ! Макрос развернется в код, склеивающий название переменной с текстом макроса и Вы получите сообщение о синтаксических ошибках и только. Такой подход имеет место быть, поскольку все пины Ардуино имеют жесткую привязку к своим функциям, особенно специальным и, соответственно, всегда явно известны при разработке скетчей. Желание "сделать файл настроек" - тут избыточно и имеет больше вреда, чем пользы.

Внимание3

Если Вы хотите использовать библиотеку с другим контроллером, то Вам надо создать собственный файл "распиновки" по образцу arhat_pins2560.h И добавить в условную компиляцию в файл "arhat.h" также по образцу в нем. Константу наименования вашего процессора смотрите в файле "io.h" компилятора (у меня это avr-gcc) или его дочерних файлах.

Внимание4

Блок "автоматного программирования" подключается отдельно #include "tsc.h" (название от Time State Controller - Автомат, управляемый состояниями во времени). Его файлы - библиотеки автоматов будут пополняться далее.

Совместимость библиотеки с кодом Wiring - далее НЕ ПОДДЕРЖИВАЕТСЯ за ненадобностью.

About

This is small library files for Arduino for makes sketches smaller and faster...

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages