// 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. Биты и байты
Каждый бит можно использовать также для обозначения состояния «включено» или «выключено». То есть, чтобы включить или выключить подачу напряжения на какой-то контакт, нужно установить или сбросить некоторый бит.
Порты в ATmega328
На рис. 4.3 изображены порты в микроконтроллере ATmega328 и то, как они связаны с контактами на плате Arduino Uno.
Рис. 4.3. Порты в ATmega328
Каждый порт не случайно имеет по 8 бит (байт), хотя в портах B и C используется только по 6 бит. Каждый порт управляется тремя
Рис. 4.4. Регистры для порта D
Последний регистр называется
Каждый из трех портов имеет свои три регистра, для порта B они называются DDRB, PORTB и PINB, а для порта C — DDRC, PORTC и PINC.
Очень быстрый вывод цифровых сигналов
Следующий скетч обращается к портам напрямую, без применения pinMode и digitalWrite:
// sketch_04_09_square_ports
byte state = 0;
void setup()
{
DDRB = B00000100;
while (true)
{
PORTB = B00000100;
PORTB = B00000000;
}
}
void loop()
{
}