Arduino как ускорить wire

от admin

Ускоряем свою Arduino

Месяца 3 назад, как и многие горе-электроники, купил себе на мой тогдашний взгляд самую навороченную микропроцессорную плату из семейства Arduino, а именно Seeeduino Mega, на базе процессора Atmega1280. Побаловавшись всласть вращающимся сервоприводом и моргающим светодиодом, встал вопрос: «зачем же я её купил?».

Я работаю одним из ведущих конструкторов на одном крупном военном Зеленоградском заводе, и в данный момент веду проект по разработке метрологического средства измерения. В данной задаче существует бесконечное множество проблем, которые требуют индивидуального решения. Одной из таких задач является управление шаговым двигателем без шумов и с шагом не 1.8 градуса, как сказано в документации шагового двигателя, а до 0.0001 градуса. Казалось бы, задача сложна и нерешабельна, но, повозившись немного со схемами управления, пришёл к выводу, что всё реально и возможно. Требуется только генерация двух сигналов специфичной формы и со сдвигом фаз и частотой изменения напряжения до 1 МГц. (Подробное исследование шагового мотора и раскрытие всех тайн управления напишу в следующей статье) Сразу же в голове стали появляться проблески надежды, что я не зря потратил 1500 рублей на свою красненькую Seeeduino, и я, набравшись энтузиазма, начал разбираться.

Первоначальный ужас:

Подключив микропроцессорную плату к осцилографу, и написав цикл digitalWrite(HIGH), и ниже digitalWrite(LOW), на осцилографе обнаружил довольно унылый меандр с частотой 50Гц. Это кошмар. Это крах, подумал я, на фоне требуемых 1Мгц.
Далее, через осцилограф, я изучил еще несколько скоростей выполнения:
AnalogRead() — скорость выполнения 110 мкс.
AnalogWrite() — 2000 мкс
SerialPrintLn() — при скорости 9600 около 250мкс, а при максимальной скорости около 3мкс.
DigitalWrite() — 1800мкс
DigitalRead() — 1900мкс

На этом я, всплакнув, чуть не выкинул свою Seeeduino. Но не тут-то было!

Глаза боятся, руки делают!

Не буду рассказывать свои душевные муки и описывать три долгих дня изучения, лучше сразу скажу всё как есть!
Подняв всю возможную документацию на Arduino и на процессор Atmega1280, исследовав опыт зарубежных коллег, хочу предложить несколько советов, как заменять чтение/запись:

Улучшаем AnalogRead()

#define FASTADC 1

// defines for setting and clearing register bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &=

_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

void setup() <
int start ;
int i ;

#if FASTADC
// set prescale to 16
sbi(ADCSRA,ADPS2) ;
cbi(ADCSRA,ADPS1) ;
cbi(ADCSRA,ADPS0) ;
#endif

Serial.begin(9600) ;
Serial.print(«ADCTEST: «) ;
start = millis() ;
for (i = 0 ; i < 30000 ; i++)
analogRead(0) ;
Serial.print(millis() — start) ;
Serial.println(» msec (30000 calls)») ;
>

Результат: скорость 18,2 мкс против бывших 110 мкс.
Кстати, максимальная скорость АЦП Атмеги как раз 16мкс. Как вариант — использовать другую микросхему, заточенную именно под АЦП, которая позволит уменьшить скорость до 0,2мкс (читать ниже, почему)

Улучшаем digitalWrite()

Каждая Arduino/Seeeduino/Feduino/Orduino/прочаяduino имеет порты. Каждый порт — 8 бит, которые сначала надо настроить на запись. Например, на моей Seeeduino PORTA — c 22 по 30 ножку. Теперь всё просто. Управляем с 22 по 30 ножки с помощью функций
PORTA=B00001010 (битовая, ножки 23 и 25 — HIGH)
или
PORTA=10 (десятичная, всё так же)
Результат = 0,2мкс против 1800мкс, которые достигаются обычным digitalWrite()

Улучшаем digitalRead()

Практически то же самое, что и в улучшении с digitalWrite(), но теперь настраиваем ножки на INPUT, и используем, например:
if (PINA==B00000010) <. >(если на ножке 23 присутствует HIGH, а на 22 и 24-30 присутствует LOW)
Результат выполнения этого if() — 0.2мкс против 1900мкс, которые достигаются обычным digitalRead()

Улучшаем ШИМ модулятор, или analogWrite()

Итак, есть данные, что digitalRead() исполняется 0,2мкс, и ШИМ модулятор имеет дискретность 8 разрядов, минимальное время переключения ШИМ 51,2мкс против 2000 мкс.
Используем следующий код:
int PWM_time=32; //Число, которое мы как бы хотим записать в analogWrite(PIN, 32)
for (int k=0;k<PWM_time) PORTA=B00000001;
for (int k=0;k<256-PWM_time) PORTA=B00000000;

Вот и получили ШИМ с частотой 19кГц против 50Гц.

Ускоряем Arduino в 20 раз

Библиотека «CyberLib» даёт существенный прирост скорости (запись/чтение цифровых портов в 20 раз) и уменьшает размер используемой памяти.

Синтаксис предельно прост и будет понятен даже новичкам.

Ссылка на скачивание находится в конце статьи.

Примеры использования:

Стандартный скетч Blink без delay():

Занимает 874 байта и выдаёт на пин 13 частоту 120 кГц

С библиотекой «CyberLib»

Занимает 566 байт и выдаёт частоту 2650 кГц

Управление пинами:

Dx_Out; — установка пина Х как выход
Dx_In; — установка пина Х как вход
Dx_Hihg; — установка высокого уровна на пине Х
Dx_Low; — установка низкого уровня на пине Х
Dx_Read; — чтение пина Х
Dx_Inv; — инвертирует значение на пине Х

Стандартный скетч:

Скорость чтения 112 мкс

С библиотекой «CyberLib»

Скорость чтения 68 мкс

Управление пинами:

Ax_Read; — чтение аналогового пина Х

Стандартный скетч:

Скетч занял 1650 байт

С библиотекой «CyberLib»

Скетч занял 800 байт

UART_Init(57600); — инициализация последовательного порта
UART_ReadByte(b); — получить байт данных из последовательного порта
UART_SendByte(b); — отправить байт данных в последовательный порт

Буфферизируется только 1 байт данных, принятый с Serial порта

Увеличена пропускная спсобность 1.85 раза

StartSPI(0, 2, 1); — Первый параметр это режим mode от 0 до 3.
Второй — это делитель тактовой частоты, может принимать значения 2, 4, 8, 16, 32, 64, 128.
Для вычисления частоты SPI нужно тактовую частоту контроллера 16000000 разделить на любой делитель из списка.
Третий параметр это какой бит пойдет первым. Если 1 то первым пойдет старший бит если 0 то первым пойдет младший бит.

Отправить байт: SendSPI(b);
Получить байт: MyData=ReadSPI();
Выключить SPI: StopSPI();

WriteEEPROM_Long(0, 4000000); — записать 4000000 в EEPROM по адресу 0 тип Long
uint32_t tmp=ReadEEPROM_Long(0); — прочитать из EEPROM с адреса 0 значение типа Long
WriteEEPROM_Word(0, 4000); — записать 4000 в EEPROM по адресу 0 тип Word
uint16_t tmp=ReadEEPROM_Word(0); — прочитать из EEPROM с адреса 0 значение типа Word
WriteEEPROM_Byte(0, 40); — записать 40 в EEPROM по адресу 0 тип Byte
uint8_t tmp=ReadEEPROM_Byte(0); — прочитать из EEPROM с адреса 0 значение типа Byte

Адресует максимум 256 адресов для типа Byte
Для Word максимум 128
Для Long максимум 64

Start — Начало цикла
End — Конец цикла

Цикл выполняется внутри конструкции Start-End.

Скачать
Здесь находится автор библиотеки, Admin.

Распаковываем архив в папку с библиотеками и пользуемся.
Не забудьте прописать в скетче:

Вступайте в Telegram-группу Arduino

Arduino как ускорить wire

Месяца 3 назад, как и многие горе-электроники, купил себе на мой тогдашний взгляд самую навороченную микропроцессорную плату из семейства Arduino, а именно Seeeduino Mega, на базе процессора Atmega1280. Побаловавшись всласть вращающимся сервоприводом и моргающим светодиодом, встал вопрос: «зачем же я её купил?».

Я работаю одним из ведущих конструкторов на одном крупном военном Зеленоградском заводе, и в данный момент веду проект по разработке метрологического средства измерения. В данной задаче существует бесконечное множество проблем, которые требуют индивидуального решения. Одной из таких задач является управление шаговым двигателем без шумов и с шагом не 1.8 градуса, как сказано в документации шагового двигателя, а до 0.0001 градуса. Казалось бы, задача сложна и нерешабельна, но, повозившись немного со схемами управления, пришёл к выводу, что всё реально и возможно. Требуется только генерация двух сигналов специфичной формы и со сдвигом фаз и частотой изменения напряжения до 1 МГц. (Подробное исследование шагового мотора и раскрытие всех тайн управления напишу в следующей статье) Сразу же в голове стали появляться проблески надежды, что я не зря потратил 1500 рублей на свою красненькую Seeeduino, и я, набравшись энтузиазма, начал разбираться.

Читать:
Как подключить трехфазный двигатель
Первоначальный ужас:

Подключив микропроцессорную плату к осцилографу, и написав цикл digitalWrite(HIGH), и ниже digitalWrite(LOW), на осцилографе обнаружил довольно унылый меандр с частотой 50Гц. Это кошмар. Это крах, подумал я, на фоне требуемых 1Мгц.
Далее, через осцилограф, я изучил еще несколько скоростей выполнения:
AnalogRead() — скорость выполнения 110 мкс.
AnalogWrite() — 2000 мкс
SerialPrintLn() — при скорости 9600 около 250мкс, а при максимальной скорости около 3мкс.
DigitalWrite() — 1800мкс
DigitalRead() — 1900мкс

На этом я, всплакнув, чуть не выкинул свою Seeeduino. Но не тут-то было!

Глаза боятся, руки делают!

Не буду рассказывать свои душевные муки и описывать три долгих дня изучения, лучше сразу скажу всё как есть!
Подняв всю возможную документацию на Arduino и на процессор Atmega1280, исследовав опыт зарубежных коллег, хочу предложить несколько советов, как заменять чтение/запись:

Улучшаем AnalogRead()

#define FASTADC 1

// defines for setting and clearing register bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &=

_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

Результат: скорость 18,2 мкс против бывших 110 мкс.
Кстати, максимальная скорость АЦП Атмеги как раз 16мкс. Как вариант — использовать другую микросхему, заточенную именно под АЦП, которая позволит уменьшить скорость до 0,2мкс (читать ниже, почему)

Улучшаем digitalWrite()

Каждая Arduino/Seeeduino/Feduino/Orduino/прочаяduino имеет порты. Каждый порт — 8 бит, которые сначала надо настроить на запись. Например, на моей Seeeduino PORTA — c 22 по 30 ножку. Теперь всё просто. Управляем с 22 по 30 ножки с помощью функций
PORTA=B00001010 (битовая, ножки 23 и 25 — HIGH)
или
PORTA=10 (десятичная, всё так же)
Результат = 0,2мкс против 1800мкс, которые достигаются обычным digitalWrite()

Улучшаем digitalRead()

Практически то же самое, что и в улучшении с digitalWrite(), но теперь настраиваем ножки на INPUT, и используем, например:
if (PINA==B00000010) (если на ножке 23 присутствует HIGH, а на 22 и 24-30 присутствует LOW)
Результат выполнения этого if() — 0.2мкс против 1900мкс, которые достигаются обычным digitalRead()

Улучшаем ШИМ модулятор, или analogWrite()

Итак, есть данные, что digitalRead() исполняется 0,2мкс, и ШИМ модулятор имеет дискретность 8 разрядов, минимальное время переключения ШИМ 51,2мкс против 2000 мкс.
Используем следующий код:
int PWM_time=32; //Число, которое мы как бы хотим записать в analogWrite(PIN, 32)
for (int k=0;k<PWM_time) PORTA=B00000001;
for (int k=0;k<256-PWM_time) PORTA=B00000000;

Вот и получили ШИМ с частотой 19кГц против 50Гц.

How to make Arduino do High Speed I2C

I wired up two MCP4725 DAC’s to my Arduino and wrote a little demo sketch to test functionality. The sketch draws a Lissajous curve on my oscilloscope. The output frequency is a bit disappointing (approx. 1.5kHz sample rate), but the datasheet to the DAC mentions High Speed I2C mode. Does Arduino (Mega1280) support High Speed I2C mode and if ‘yes’ how?

1 Answer 1

I would consider going one level below the C++ object «Wire» and use their C files found here:

There is a constant of interest in twi.h :

#define TWI_FREQ 100000L

And the register is set in the file twi.c like so:

Going by that comment, and without having to go into the datasheet (although I suggest that you do if you want to understand what those lines mean), it appears that the Arduino Mega (16 MHz) defaults to 100 kHz I2C clock. Following the formula given, change the value of TWI_FREQ to achieve a desired I2C clock frequency.

However, after reading the datasheet of the Atmega, it appears to me that the fastest you can get [See edit]. Take a look at the section 24.5.2 Bit Rate Generator Unit to confirm this. If you define «High Speed» to be 3.4 MHz I2C, then the answer appears to be no, you can’t achieve that with your current hardware, but you should be able to get something faster than the default 100 kHz if you really want to.

EDIT: It may be possible to achieve 1 MHz if I’m reading the datasheet correctly. Formula used from the datasheet: SCL = (F_CPU)/(16 + 2*TWBR*4^TWPS) The disclaimer below still stands :p

Disclaimer: I just took a quick glance at the docs to come up with the above, it’s totally possible that I missed something. Please read the datasheet to confirm any of this and familiarize yourself with your microcontroller, since you are wanting to do something that the Arduino library does not offer.

Arduino.ru

В любой момент времени по двум проводам могут поступить команды, которые необходимо обработать и молниеносно отправить ответ.

Сначала пользовался SoftwareSerial, но там максимальная скорость ограничена 9600, соответственно, всё жутко тормозило. Вдовесок некоторые байты терялись, либо перемешивались, что приводило к глюкам.

Перешёл на «железный» Serial, где можно поднять скорость до 112500 — сразу заметил прибавку в скорости работы, тем не менее, хотелось бы меньшей задержки.

Я не совсем понимаю, как работает порт, но в теории цикл программы должен прерываться как только приходят байты с порта. По факту этого нет, пока писал, подумал, что как раз задержка в 20мс всё и портит. Но именно такая задержка и нужна мне в основной программе (мне надо выполнять цикл каждые 20 мс)

Для наглядности цикл loop (не буду писать начало программы для более быстрого восприятия). Что я делаю не так?

How to make Arduino do High Speed I2C

I wired up two MCP4725 DAC’s to my Arduino and wrote a little demo sketch to test functionality. The sketch draws a Lissajous curve on my oscilloscope. The output frequency is a bit disappointing (approx. 1.5kHz sample rate), but the datasheet to the DAC mentions High Speed I2C mode. Does Arduino (Mega1280) support High Speed I2C mode and if ‘yes’ how?

1 Answer 1

I would consider going one level below the C++ object «Wire» and use their C files found here:

There is a constant of interest in twi.h :

#define TWI_FREQ 100000L

And the register is set in the file twi.c like so:

Going by that comment, and without having to go into the datasheet (although I suggest that you do if you want to understand what those lines mean), it appears that the Arduino Mega (16 MHz) defaults to 100 kHz I2C clock. Following the formula given, change the value of TWI_FREQ to achieve a desired I2C clock frequency.

However, after reading the datasheet of the Atmega, it appears to me that the fastest you can get [See edit]. Take a look at the section 24.5.2 Bit Rate Generator Unit to confirm this. If you define «High Speed» to be 3.4 MHz I2C, then the answer appears to be no, you can’t achieve that with your current hardware, but you should be able to get something faster than the default 100 kHz if you really want to.

EDIT: It may be possible to achieve 1 MHz if I’m reading the datasheet correctly. Formula used from the datasheet: SCL = (F_CPU)/(16 + 2*TWBR*4^TWPS) The disclaimer below still stands :p

Disclaimer: I just took a quick glance at the docs to come up with the above, it’s totally possible that I missed something. Please read the datasheet to confirm any of this and familiarize yourself with your microcontroller, since you are wanting to do something that the Arduino library does not offer.

Похожие публикации