[Из песочницы] Ускоряем свою Arduino |
Здравствуйте, гость ( Вход | Регистрация )
[Из песочницы] Ускоряем свою Arduino |
5.4.2012, 12:32
Сообщение
#1
|
|
Администратор Группа: Главные администраторы Сообщений: 14349 Регистрация: 12.10.2007 Из: Twilight Zone Пользователь №: 1 |
Программинг микроконтроллеров*, 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)") ; } void loop() { } Результат: скорость 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Гц. Подведём итоги digitalWrite() было 1800мкс, стало 0,2мкс digitalRead() было 1900мкс, стало 0,2мкс analogWrite() было 2000мкс, стало 51,2мкс analogRead() было 110мкс, стало 18,2мкс, а можно до 0,2мкс Original source: habrahabr.ru (comments, light). Читать дальше -------------------- |
|
|
Текстовая версия | Сейчас: 27.4.2024, 1:09 | |