Программируем Arduino. Основы работы со скетчами
Шрифт:
Следующий пример также генерирует синусоиду, разбивая цикл на 64 шага, но использует прием поиска по таблице заранее подготовленных значений, которые выводит непосредственно в цифроаналоговый преобразователь (ЦАП).
byte sin64[] = {127, 139, 151, 163, 175, 186, 197,
207, 216, 225, 232, 239, 244, 248, 251, 253, 254,
253, 251, 248, 244, 239, 232, 225, 216, 207, 197, 186,
175, 163, 151, 139, 126, 114, 102, 90, 78, 67, 56, 46,
37, 28, 21, 14, 9, 5, 2, 0, 0, 0, 2, 5, 9, 14, 21, 28,
37, 46, 56, 67, 78, 90, 102, 114, 126};
void setup
{
}
void loop
{
for (byte i = 0; i < 64; i++)
{
analogWrite(DAC0, sin64[i]);
}
}
Этот
Таблицу синусов можно рассчитать разными способами. Можно сгенерировать числа по обычной формуле в электронной таблице или написать скетч, который будет выводить числа в монитор последовательного порта, откуда их можно скопировать и вставить в другой скетч. Далее приводится версия скетча sketch_04_03_sin, которая выводит значения один раз в монитор последовательного порта:
// sketch_-4_05_sin_print
float angle = 0.0;
float angleStep = PI / 32.0;
void setup
{
Serial.begin(9600);
Serial.print("byte sin64[] = {");
while (angle < 2 * PI)
{
int x = (int)(sin(angle) * 127) + 127;
Serial.print(x);
angle += angleStep;
if (angle < 2 * PI)
{
Serial.print(", ");
}
}
Serial.println("};");
}
void loop
{
}
Открыв окно монитора порта, вы увидите сгенерированную последовательность чисел (рис. 4.1).
Рис. 4.1. Использование скетча для получения массива чисел
Быстрый ввод/вывод
В этом разделе мы посмотрим, как увеличить скорость включения и выключения цифровых выходов. Мы увеличим максимальную частоту с 73 кГц почти до 4 МГц.
Простая оптимизация кода
Начнем с простого кода, включающего и выключающего цифровой выход с помощью digitalWrite:
// sketch_04_05_square
int outPin = 10;
int state = 0;
void setup
{
pinMode(outPin, OUTPUT);
}
void loop
{
digitalWrite(outPin, state);
state = ! state;
}
Если запустить этот скетч и подключить осциллограф или частотомер к цифровому контакту 10, вы получите частоту чуть выше 73 кГц (мой осциллограф показал 73,26 кГц).
Прежде чем сделать большой шаг в направлении непосредственного управления портом, можно попробовать немного оптимизировать программный код скетча. Прежде всего, ни одна из переменных не обязана иметь тип int, их вполне можно объявить с типом byte. Это изменение увеличит частоту до 77,17 кГц. Далее переменную с номером контакта можно сделать константой, добавив слово const перед объявлением переменной. Это изменение увеличит частоту до 77,92 кГц.
В главе 2 вы узнали, что функция loop — это не просто цикл while, так как дополнительно проверяет наличие входящих данных в последовательном порте. То есть следующим шагом в направлении увеличения производительности может стать отказ от функции loop и перенос кода в setup. Скетч, в котором выполнены все описанные изменения, приводится ниже:
// sketch_04_08_no_loop
const byte outPin = 10;
byte state = 0;
void setup
{
pinMode(outPin, OUTPUT);
while (true)
{
digitalWrite(outPin, state);
state = ! state;
}
}
void loop
{
}
В результате всего этого мы получили увеличение максимальной частоты до 86,39 кГц.
В табл. 4.2 перечислены все улучшения, которые можно выполнить для увеличения производительности простого программного кода, прежде чем сделать последний шаг и заменить digitalWrite чем-нибудь более быстрым.
Таблица 4.2. Увеличение производительности простого программного кода
Действие
Скетч
Частота, кГц
Исходная версия
04_05
72,26
Объявление с типом byte вместо int
04_06
77,17
Использование константы с номером контакта вместо переменной
04_07
77,92
Перенос содержимого loop в setup
04_08
86,39
Байты и биты
Прежде чем переходить к непосредственному управлению портами ввода/вывода, нужно сначала разобраться с двоичным представлением, битами, байтами и целыми числами.
На рис. 4.2 показано, как связаны биты и байты.
Рис. 4.2. Биты и байты
Бит (в английском языке bit, происходит от binary digit — двоичная цифра) может иметь одно из двух значений — 0 или 1. Байт — это коллекция из 8 битов. Так как каждый из битов в байте может иметь значение 1 или 0, всего возможно 256 разных комбинаций битов в байте. Байт можно использовать для представления любых чисел в диапазоне от 0 до 255.
Каждый бит можно использовать также для обозначения состояния «включено» или «выключено». То есть, чтобы включить или выключить подачу напряжения на какой-то контакт, нужно установить или сбросить некоторый бит.
Порты в ATmega328
На рис. 4.3 изображены порты в микроконтроллере ATmega328 и то, как они связаны с контактами на плате Arduino Uno.
Рис. 4.3. Порты в ATmega328
Каждый порт не случайно имеет по 8 бит (байт), хотя в портах B и C используется только по 6 бит. Каждый порт управляется тремя регистрами. Регистр можно считать специальной переменной, позволяющей присваивать ей значения и читать значение из нее. На рис. 4.4 изображены регистры для порта D.