Управляем всем с помощью регистров cдвига.
- Войдите на сайт для отправки комментариев
Доброго всем время суток. Прошу сильно не пинать, за то-что создал новую тему а не начал задовать вопросы тут: (регистры сдвига).
Я думаю что кучу моих вопросов, которые у меня назрели, желательно отпочковать от основной темы. Если администрация не согласна с этим, прошу перенисти этот топик в (регистры сдвига).
Начну как многие форумчане словами: "мол я начинающий, с ардуиной сильно не знаком и т.д. и т.п. бла-бла-бла."
Хватит болтавни, перейдём к сути.
Что имеется: 74HC165, 74HC595, Servo RS-2, HC-SR04, LED's, кнопки, Arduino Uno.
Что хочится: Создать более или мение универсальную возможность управлять перечисленными деталями с помощью 5 проводов (2 для 74HC165, 2 для 74HC595, 1 общий для такта). Получаем "для начала" 8-входов и 8-выходов. Все входы и выходы должны работать "полноценно" т.е. как будьто это ардуиновские входы/выходы.
Проблемма: "полноценно" Понимаю что это не возможно, так как мне тяжело обмануть регистровые задержки. А именно это и является для меня самой большой проблемой.
Что я уже напоял:
Что я уже на програмировал:
MultiIO.h
/* * MultiIO.h * * Created on: 06.10.2012 * Author: Ich */ #ifndef MULTIIO_H_ #define MULTIIO_H_ #include "Arduino.h" /* * uint8_t = 8 Bit = 256 Kombinationen * */ #define BIT_COUNT 8 // Anzahl von Bit's pro IC #define SERVO_MIN_PULSE 350 #define SERVO_MAX_PULSE 2150 #define SERVO_REFRESH 20 class MultiIO{ public: // Allgemeine Konstruktor MultiIO(uint8_t clock_clk); // Für beide 165 und 595 MultiIO(uint8_t clock_clk, uint8_t data_DS, uint8_t latch_ST, uint8_t pload_SH, uint8_t data_QH, uint8_t ic595_count = 1, uint8_t ic165_count = 1); // Nur für 595 void init595(uint8_t data_DS, uint8_t latch_ST, uint8_t ic_count = 1); // Nur für 165 void init165(uint8_t pload_SH, uint8_t data_QH, uint8_t ic_count = 1); // Taktgeber für beide (595 und 165) void initCLK(uint8_t clock_clk); // Schreiben in 595 void shiftWrite(uint8_t writeValue); // Schreiben in 595 void write(uint8_t pin, bool state); // Servo positionieren void writeToServo(uint8_t pin, uint8_t pos); // Lesen von 165 uint8_t shiftRead(); // Passives Lesen von bestimmte Pin. Es werden alte Registerdaten genutzt ohne shiftRead() zu aufrufen. bool readPassiv(uint8_t pin); // Lesen von bestimmte Pin. Bei jedem Aufruf wird shiftRead(); aufgerufen um aktuellste Zustand zu bekommen. bool read(uint8_t pin); // PulseIn timeout = 10000µs = 10ms unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout = 10); // Hollt Abstand bis zum Hinderniss in mm unsigned long getDdistance(uint8_t trig, uint8_t echo); private: uint8_t i; // Zaehlvariable für Schleifen uint8_t outPinsCount; // Anzahl von Ausgabepins (für ein 595 ist 8, für n 595 ist n*8) "Anzahl von Bit" uint8_t inPinsCount; // Anzahl von Eingabepins (für ein 165 ist 8, für n 165 ist n*8) "Anzahl von Bit" uint8_t writeValue; // Bitfolge die in Register geschrieben wird uint8_t readValue; // Bitfolge die aus Register gelesen ist uint8_t data_DS; // serial data input (595) uint8_t latch_ST; // storage register clock input (595) uint8_t clock_clk; // clock input (LOW-to-HIGH edge-triggered) (595_165) uint8_t pload_SH; // asynchronous parallel load input (active LOW) (165) uint8_t data_QH; // serial output from the last stage (165) }; #endif /* MULTIIO_H_ */
MultiIO.cpp
/* * MultiIO.cpp * * Created on: 06.10.2012 * Author: Ich */ #ifndef MULTIIO_CPP_ #define MULTIIO_CPP_ #include "MultiIO.h" // Algemeine Konstruktor MultiIO::MultiIO(uint8_t clock_clk){ initCLK(clock_clk); } // Für beide 165 und 595 MultiIO::MultiIO(uint8_t clock_clk, uint8_t data_DS, uint8_t latch_ST, uint8_t pload_SH, uint8_t data_QH, uint8_t ic595_count, uint8_t ic165_count){ initCLK(clock_clk); init595(data_DS, latch_ST, ic595_count); init165(pload_SH, data_QH, ic165_count); } // Initialisieren von 595 void MultiIO::init595(uint8_t data_DS, uint8_t latch_ST, uint8_t ic_count){ this->writeValue = 0; this->outPinsCount = BIT_COUNT * ic_count; // Anzahl von Ausgabebits this->data_DS = data_DS; this->latch_ST = latch_ST; pinMode(data_DS, OUTPUT); pinMode(latch_ST, OUTPUT); } // Initialisieren von 165 void MultiIO::init165(uint8_t pload_SH, uint8_t data_QH, uint8_t ic_count){ this->readValue = 0; this->inPinsCount = BIT_COUNT * ic_count; // Anzahl von Eingabepins this->pload_SH = pload_SH; this->data_QH = data_QH; pinMode(pload_SH, OUTPUT); pinMode(data_QH, INPUT); } // Taktgeber für beide (595 und 165) void MultiIO::initCLK(uint8_t clock_clk){ this->clock_clk = clock_clk; pinMode(clock_clk, OUTPUT); } // Schreiben in 595 void MultiIO::write(uint8_t pin, bool state){ if(state){ this->writeValue |= (1 << pin); }else{ this->writeValue &= ~(1 << pin); } shiftWrite(writeValue); } // Schreiben in 595 alle Ausgänge gleichzeitig void MultiIO::shiftWrite(uint8_t writeValue) { this->writeValue = writeValue; digitalWrite(latch_ST, LOW); i = outPinsCount; do{ digitalWrite(data_DS, !!(writeValue & (1 << ((i--)-1)))); // Takt geben, um Änderungen vorzunehmen. digitalWrite(clock_clk, HIGH); digitalWrite(clock_clk, LOW); }while(i>0); digitalWrite(latch_ST, HIGH); } // Servo positionieren void MultiIO::writeToServo(uint8_t pin, uint8_t pos){ for(int i=0; i<20; i++){ this->write(pin, HIGH); delayMicroseconds(map(pos,0,180,SERVO_MIN_PULSE,SERVO_MAX_PULSE)); this->write(pin, LOW); delay(SERVO_REFRESH); } } // Lesen von 165 uint8_t MultiIO::shiftRead(){ readValue = 0; digitalWrite(pload_SH, LOW); digitalWrite(pload_SH, HIGH); for(i=0; i<inPinsCount; i++){ readValue |= (digitalRead(data_QH) << ((inPinsCount-1)-i)); digitalWrite(clock_clk, HIGH); digitalWrite(clock_clk, LOW); } return readValue; } // Passives Lesen von bestimmte Pin. Es werden alte Registerdaten genutzt ohne shiftRead() zu aufrufen. bool MultiIO::readPassiv(uint8_t pin){ return bitRead(readValue, pin); } // Lesen von bestimmte Pin. Bei jedem Aufruf wird shiftRead(); aufgerufen um aktuellste Zustand zu bekommen. bool MultiIO::read(uint8_t pin){ shiftRead(); return readPassiv(pin); } // PulseIn unsigned long MultiIO::pulseIn(uint8_t pin, uint8_t state, unsigned long timeout){ // TimeOut unsigned long numloops = 0; unsigned long maxloops = microsecondsToClockCycles(timeout) / 16; // wait for any previous pulse to end while(this->read(pin) == state) if (numloops++ == maxloops) return 0; unsigned long width = 0; // wait for the pulse to start while (this->read(pin) != state) if (numloops++ == maxloops) return 0; // wait for the pulse to stop while (this->read(pin) == state) { if (numloops++ == maxloops) return 0; width++; } return clockCyclesToMicroseconds(width * 21 + 16); /* //check to see if the pin is already in the value state, if so, the pulse has already begun and the function needs to wait for the next one to "catch" the leading edge. //while(this->read(pin) == state); // wait for pin state while (this->read(pin) != state); unsigned long start = micros(); // wait for pin to change state while (this->read(pin) == state); unsigned long end = micros(); // return time in micro seconds return (end - start); */ } // Hollt Abstand bis zum Hinderniss in mm unsigned long MultiIO::getDdistance(uint8_t trig, uint8_t echo){ this->write(trig, LOW); delayMicroseconds(2); this->write(trig, HIGH); delayMicroseconds(10); this->write(trig, LOW); return this->pulseIn(echo, HIGH); } #endif // #ifndef MULTIIO_CPP_
Отпишусь сразу, на случай если эксперты забракуют мой код. На С++ не програмировал не разу, начал совсем недавно из за ардуинки. По этому любая конструктивная критика, только приветствуется.
Крик о помощи:
На данный момент я могу читать все пины одним разом shiftRead, читать каждый пин по одиночки read (основанно на предидущем), писать во все пины shiftWrite, писать в каждый пин по одиночки write (основанно на предидущем), крутить сервы writeToServo (не совсем идеально, плюс delay's всё тормозят) и последняя функция pulseIn (вообще тупик, работает но странно. Думаю проблемма из за потери времени в регистрах).
Как мне улучшить writeToServo, избавить от остоновки скетча? Моргание без delay думаю тут не поможет. Нужно как то с прерываниями. А вот как не знаю. Надеюсь на помощь "потомственных избоалятелей" от delay. ;-)
Как быть с pulseIn? Прнимаю что без остоновки скетча не обойтись, но это и не страшно, пускай остонавливается, главное получить валидные данные. Куда рыть, чтобы победить эту проблемму?
Ну и естественно эти все функции не должны друг другу мешать. Пока есть конфликты между shiftWrite и write, так как первая переписывает статус второй. Но это тоже пол беды, нужно просто во время пользования функциями не забывать о этой особенности.
Надеюсь что я доступно описал проблемму и вам не прейдётся обращатся к годалкакм и шаманам. :-)
Могу посоветовать вам воспользоваться аппаратным SPI, у него при частоте МК 16 МГц частота линии тактирования может достигать 4 МГц, запись и чтение происходит одновременно.
Тоесть, Вы предлогаете зпбить на 74HC165 и 74HC595 и воспользоваться другой IC? Если да то каоую лучше посоветуете?
Почитав про SPI в интернете, сложилось мнение, что 74HC165 и 74HC595 можно тоже к этому отнести. Принцип та тот же. Или я что-то не допонял?
Да, принцип тот же. И работать оно будет. И проводок сэкономите (микрухи должны сидеть на одном селекте, они же друг другу не мешают, одна передает, другая принимает)
Еще поищите (я где-то натыкался) быстрый shiftOut - на управлении регистрами напрямую. Но вариант SPI - самый лучший.
Статья на Робокрафте Подключаем кучу устройств к Arduino по 5 проводам - специально для Вас! :) Там как раз используют для этой цели SPI
> Моргание без delay думаю тут не поможет
Ну полностью "Решить проблему" может и не сможет. Но вот, все-таки избавлятся от delayMicroseconds - нужно.
Либо, все-таки по принципу "мигаем без delay". Либо смотреть в сторону таймеров.
Можно еще погуглить - не вы первый задались сервой рулить через сдвиговые
Например вот:
http://letsmakerobots.com/node/3829
Не совсем "ардуино", но родственный AVR/C - подсмотреть "идею" - можно.
Возможно и "ардуино way" нагуглите (в youtube видел, но там нет ссылки на "как это сделали").
А вообще, IMHO, через сдвиговые PWM изображать - слишком гиморно :( И накладывает кучу ограничений на остальную логику скетча.
Есть специально для этого предназначенные микрухи (дороже правда существенно). Рулятся, как правило, по I2C. Но вот они, как раз умеют приять команду типа "установи на такой-то своей ноге - такой PWM". И все. И сами его там генерят/держат. Не напрягая, по этому поводу, сам микроконтроллер.
Как вариант, идея:
Вот только сколько ему времени на это потребуется, вызывается то прерывание через 8 мкс... Не успеет... Разве что ШИМы не на 500 Гц делать, а на 50 хотя бы. Тоже не успеет...
Понимаю, идея туповата, но может на что-нибуть натолкнет...
Красивую вы платку выложили.
Есть ли печатка?
Где продают такие готовые и по чем?
Спасибо всем за помощь и наводки. Понятия не имею где были мои глаза, когда я читал эту статью. Возможно не прешлось бы и тему создавать.
Для начало подружу всю эту бедень с Servo ну а потом уж и за pilseIn возьмусь, вот тогда-то и вернусь для задования очередных вопросов.
Красивую вы платку выложили.
Есть ли печатка?
Где продают такие готовые и по чем?
Платка срисованна 1 в 1 с той что я споял, рисовал с помощью MSPaint (самому тоже нравится ).
Обошлось мне это всё не больше 5€, схемы конкретной нету так как по Даташидам ориентировался.
Могу и Вам такую скрутить, это уже зависит от того как просить будите .
Спасибо всем за подсказки, теперь мой MultiIO работает на прямую, без digitalWrite/Read, и правдо стало на много быстрей, это даже на глаз заметно . Servo тоже работает таперь без остановки скетча, для эого я воспользовался трюком с манипуляцией Servo.h из этой статьи.
Ну вот добрался и до pulseIn.
Для начало я написал обыкновенный скетч, без сдвиговиков, пользуясь штатными функциями.
Вот что у меня показал монитор.
Т.е. отталкиваясь от полученных данных мне надо реализовать функцию которая хотябы преблезительно делает тоже самое. Не долго думая я залез в штатную функцию pulseIn и немного её модифицируя воткнул в свой MultiIO.
Как это выглядет:
Вот что выдаёт эта функция работая уже с регистрами и через мою MultiIO
Воошпе бред какой-то . Я даже и не знаю что делать.
Разковырял ещё парачку данных, но они мне тоже не очём не говорят. Например microsecondsToClockCycles(timeout=1000000L) из pulseIn в оригинальном случае возвращает: 16000000 а в моём 3115098. Как так? Ведь эта функция получает одинаковые данные, да и как я понял в итоге она не делает ни чего другого как:
# define F_CPU 1000000UL
#define microsecondsToClockCycles(a) ( ((a) * (F_CPU / 1000L)) / 1000L )
Т.е. Я задаю 1000000L => (((1000000L)*(1000000UL / 1000L )) / 1000L) = 1000000 а не 16000000 и уж точно не 3115098.
В интернэте искал, поисковиком тоже пользовался. Ничего стоющего не нашол.
Кроме вот этого кода, который тоже не к чему ожидаемому не привёл.
Что мне делать, как заставить это всё работать?
Вы должны понимать, что когда у вас работает функция pulseIn, то все остальное останавливается в том числе и SPI, если конечно у вас работа с регистрами не в прерывании по таймеру сидит, вам нужно что бы функция pulseIn не тормазила основную программу, двигайтесь вот в этом напрвлении Мигаем светодиодом без delay(), скорее всего в любом случае пострадает точность, но подругому никак.
То что всё остольное остонавливается, я понимаю. На данный момент у меня задача реализовать полную копию pulseIn которая работает через регистры (то что точность пострадает я с этим смерился. Но не так же как у меня на данный момент). SPI у меня не остонавливается, так как моя pulseIn юзает мою функцию this->read(pin) а она читает состояние не ардуиновского пина, а пин регистра. Т.е. моя this->read(pin) работает именно с SPI.
Когда я пишу SPI, я не имею в веду библиотеку SPI, я имею в виду прямой доступ на ардуино с помощью PINB / PIND.
Вот как у меня выглядит весь MultiIO. Отличается от исходной добавленными функциями digitalWriteDirect и digitalReadDirect (Для увеличения скорости обращения). Они заменяют стандартные функции.
А вот и зря вы не используете SPI, с его помощью вы одновременно сможете читать из 165 регистра и писать в 595. Сделайте тестилку, которая выводит время обработки ваших init595(); и init165();, объявите переменную, перед этими функциями присвойте ее значение micros() и после этих функций выведите разницу текущего значения micros() и переменной. Так вы сможете увидеть за какое время выполняются выши функции и определить точность пульсИн.
Вы возможно не поняли сути функций init595(); и init165(); они ведь просто устанавливают ардуиновские пины для управления регистрами и на pulseIn обсалютно не как не влияют так как они один раз вызываются в void setup().
К стати, с помощью моей MultiIO возможно так же однавременно писать и читать 595 / 165. Просто я пока этим не где не пользуюсь, по этому эти функции и не имплементированны.
А вот на счёт замерения времени, это да, надо с этим по эксперементировать.
Да имел ввиду те функции, которые записывают/читают в/из регистров.
Аппаратный SPI работает на частоте 4МГц - Вам никогда его не догнать никаким прямым управлением портами. А вот с SPI без библиотеки (через те же порты) работать можно.
Не копался в регистрах SPI у мег, поэтому не знаю можно ли задавать тактирование программно, но у тинек на USI в режиме SPI (у USI тактирование линии CLK задается программно, по прерыванию счетчика или внешним источником) можно разогнать до половины частоты МК! То есть при частоте 16 МГц можно разогнать SPI до 8 МГц. Вот этот способ:
Так что если и у мег можно тактирование задать программно, то тоже можно разогнать до такой частоты.
Судя по всему, 8Мгц можно получить и без извратов:
SPI CONTROL REGISTER (SPCR):
Биты 1, 0 – SPR1, SPR0: SPI Clock Rate Select 1 and 0 Соместно с битом SPI2x в регистре SPSR задают скорость передачи данных Биты 1, 0 – SPR1, SPR0: SPI Clock Rate Select 1 and 0 Соместно с битом SPI2x в регистре SPSR задают скорость передачи данных
SPI STATUS REGISTER (SPSR).
Полный текст статьи
Блин во это статейка, ажно страшно стало. Надо будит почитать и по вникать, я так близко с железом ещё не работал и по этому мне это всё, на данный момент, сложновато кажется. Но как говориться: "глаза бояться а руки делают".
Может кто подскажет статейки где хорошо описанно SPI с примерами. Желательно для чайников. Не хочется рыться в куче гоглевских предложений, а хочеться просто прочитать статью и понять. По этому и клянчу нагло готовую статью.
Только не смейтесь: "Если я всётаки разгоню 595 и 165 до 4 или даже до 8МГц, будет тогда работать pulseIn ?".
Инфы полно по SPI.
8'000'000/8 = 1'000'000 то есть примерно одна - две микросекунды на получение/отправку одного байта.
Вот, здесь попроще - без ассемблера и без прерываний :) Можно еще вспомнить, что интерфейс при передаче байта еще и принимает байт, поэтому SS можно для обоих регистров обЪединить(буду большой твёрдый знак теперь писать - чтобы жирность не выскакивала :)
Не надо даже копаться в регистрах: arduino.cc/en/Reference/SPI
Где то здесь на форуме выяснилось, что 595 и 165 принимают и отдают биты по разным фронтам сигнала тактирования, что как раз вам и нужно. По поводу SS, если SS у 165 регистрирует состояние ног (срабатывает защелка) по переднему фронту, а у 595 выводятся значения (срабатывает защелка) по заднему (что и наблюдается у 595), то линия SS может и должна быть общая.
Пример:
И вот вам 8 Мгц счастья )
Красиво.
Вывод - не ленитесь читать библиотечные хедеры - оттуда можно почерпнуть информации больше, чем в описаниях из интернета :)
Лишь бы на такой частоте смогли работать регистры... но думаю даташит ответит на этот вопрос.
Регистры - могут. Они, кажется, до 30МГц могут.
На сколько мне известно, 74HC165 работает до 56MHz а 74HC595 до 100MHz. В любом случае хватит.
Меня интересует вот такое вот высказывание из статьи. В самом конце.
Интерфейс SPI может быть реализован программно на любых ножках МК, но лучше пользоваться встроенным в МК
Как мне эти "любые" пины настроить?
"Любые" пины настраиваются точно так же, как и "нелюбые" Но дергать такты, принимать биты и передавать биты нужно самостоятельно, "ручками" :) А "железный" - просто кинул байт в регистр, байт сам передается.
Понятно, так я и предпологал. Буду юзать "железный", зачем себе жизнь усложнять. :-D
На выходных попробую всё это дело реализовть, в буднии всё руки не доходят. Да и после 8 часов пяленья на монитор на работе охото дома отдохнуть ;-)
Просто погуглите Arduino SPI software library не вы же первый столкнулись с такой задачей :)
И софтовый SPI будет медленнее аппаратного.
Это к гадалке не ходи :)
Из того что я видел, даже "а вот мы написали новую быструю библиотеку софтварного SPI он аж 2mHz выжать может".
Просто погуглите Arduino SPI software library не вы же первый столкнулись с такой задачей :)
Да вы что, правдо думаете что я не искал? А нет, не угадали.
А это случайно не то что я уже писал и выкладывал?
Да этой скоросит не достаточно :-(. Буду пробовать как правельно, через "железо". Ну очень хочется 8MHz ;-)
Пытался разобратся с SPI но вот что-то не получилось. Проблемма в следующем:
Если пользуюсь библиотекой SPI.h, то всё работает именно так как мне надо. А надо так: подключил, в первом посту указанную платку, к ардуине соединив Latch_ST и Pload_SH в месте. Спасибо подсказки AlexFisher. Написал следующиё код:
Подключил к 595 светодиоды а к 165 кнопки. Заливаю код в ардуину, светодиоды заморгали. Запустил Serial монитор, светодиоды моргают дальше, при нажатии на кнопки на мониторе появляются соотвецтвующие цифры.
Этого я и хотел добиться, но только написав собственную SPI передачу.
Для написания кода, пользовался следующей информацией:
samou4ka.net/page/interfejs-spi-mikrokontrollerov-avr
code.google.com/p/arduino/source/browse/trunk/libraries/SPI/
www.arduino.cc/en/Tutorial/SPIEEPROM
Вот что получилось:
Но к сожелению это не работает так как мне надо. Заливаю код в ардуину, диоды замигали. Пока все как надо. Стоит открыть Serial монитор, всё, диоды останавливаются и ничего не происходит. Так же ни какой реакции на нажатие кнопок. Закрываю монитор, диоды начинают моргать.
В чём дело, почиму программа останавливается? Что я сделал не так, что упустил?
Подскажите пожалуйста.
Вот функции из библиотеки SPI
_BV - это тоже самое что и 1<< . Перепроверьте, что бы нумерация битов соответствовала названию битов и при настройке скорости еще что то меняют в регистре SPSR.
Спасибо, заработало.
Теперь буду дальше ковырять, подключу к MultiIO. Попробую добить pulseIn.
Ну вот, проблемы не заставили себя долго ждать.
Не пойму в чём дело. Если управляю Servo с помощью ардуиновских digitalWrite то всё работает как надо. Если пытаюсь управлять Servo с помощью (мной написаного) SPI то Моторчик потихоньку поворачивается на 180° (без разници сколько ° я устанавливаю, один фиг крутится к 180) и его можно рукой двигать. Серва конечно сопративляется но слабо.
Вот весь код:
обе функции (writeToServo и writeToServoSPI) не используют не каких сторонних библиотек.
Мой SPI прекрасно справляется с зажиганием светодиодов на 595 и считыванием состояние каждого пина с 165. Понять не могу почему серва на слушается через SPI.
Пожалйста глянте на код зорким профессиональным взгдядом. Очень уж хочится победить эту проблемку.
Да, вот ещё парачка цифр которые возможно помогут в решении проблемы.
Эти цифры показывают с какой скоростью работают функции (digitalWrite(0,HIGH), digitalRead(1), writeMIO(7,HIGH), readMIO(7))
Arduino (digitalWrite(0,HIGH), digitalRead(1)) #####################
Read 1 = 8 microsec
Write 1 = 8 microsec
Read 1000 = 4152 microsec
Write 1000 = 4300 microsec
Read 1000000 = 4652856 microsec
Write 1000000 = 4778652 microsec
SPI 8-MHz (writeMIO(7,HIGH), readMIO(7)) ######################
Read 1 = 4 microsec
Write 1 = 4 microsec
Read 1000 = 2264 microsec
Write 1000 = 4172 microsec
Read 1000000 = 2639176 microsec
Write 1000000 = 4652356 microsec
P.S.: Не хочу пользоваться ни какими сторонними библиотеками. Хотелось-бы запустить этот код.
Да, странно, вроде все нормально, вам бы осцилографом посмотреть, что у вас с регистра на серву идет.
Кстати, это вам в копилку - bitRead можно заменить
А если так:
у вас же мигание занимает 320 миллисекунд - серва в это время "отключена"
Вам стоит задуматься о постоянном обмене данными с регистрами - то есть в прерывании по таймеру выполнять функцмю transport().
К сожалению, я не обладаю осцилоскопом. :-(
А если так:
...
Тот же эфект. Может это из за скорости? Хотя как то тупо, я с разными MIN и MAX пробывал один фиг вертится к 180°.
Вам стоит задуматься о постоянном обмене данными с регистрами - то есть в прерывании по таймеру выполнять функцмю transport().
а зачем? Я думаю достаточно вызвать её по нужде!
Все просто. Серва не управляется отдельными импульсами, фактически, серва управляется скважностью (длиной импульса при постоянной частоте следования импульсов). Так что нужно действительно делать постоянный обмен. Точнее, нужно думать, как вывести на SPI ШИМ, это аналогичная проблемма.
Библиотека адуино использует прерывания от таймеров (в случае UNO - только от таймера 1) . Период следования импульсов 20 мс
Все просто. Серва не управляется отдельными импульсами, фактически, серва управляется скважностью (длиной импульса при постоянной частоте следования импульсов).
да. Но если я вызываю только вот это:
зачем тут прерывания? У меня SERVO_REFRESH равен именно 20 мс.
И что с того? Она же тупо прибавляется к длине импульса! Вы еще и выполнение программы останавливаете на полсекунды. И позицию она после установки все равно держать не станет, потому что импульсы ей нужно давать постоянно, то есть в фоне, а это делается прерываниями обычно.
Исправте, хотя бы функцию:
Да это понятно что не будет держать. Пока стоит задача только повернуть на нужный ° не удерживая. По этому и цикл с 20 оборотами, чтобы хватало импульсов от 0 до 180 повернуть.
именно так, ибо нехорошо считать одно и то же 20 раз :)
Согласен, не доглядел. Вот это тоже интересно "delayMicroseconds(SERVO_REFRESH-imp);" сегодня попробую, отпешусь.
Как и претпологал, проблема изменениями не решилась. Но вот работать стало быстрей. Спасибо maksim #37 , AlexFisher #42
Надо гдето искать осцилограф, смотреть что за сигнал я посылаю на серву.
Советую расковырять библиотеку Servo и поменять там весь вывод на свой. Там все управление идет через digitalWrite, но работает по прерыванию.
Я уже это попробывал, вот по этой статье.
К сожелению результат тотже. Куда бы не крутил серву, она один фиг по тихоньку подползает к 180° и гудит так-же возможно сдвинуть рукой с места.
Если в обычном варианте работает нормально, то остается только смотреть осциллографом сигналы и анализировать.
Но я бы на Вашем месте все же попробовал поковыряться в библиотеке Серво.
Но я бы на Вашем месте все же попробовал поковыряться в библиотеке Серво.
Я уже ковырялся. До того как я перешел на SPI, с Servo всё отлично работало на старом коде там я обходил стандартные digitalRead/digitalWtite и юзал прямое управление портами Arduino для быстрого управления 595 и 165.
Но вот когда перестроил в старом коде shiftWrite на transport, начался гон. Т.е. проблема в передачи информации.
Или что Вы имели в виду говоря: "поковыряться в библиотеке Серво"?
Я имел в виду в функции static inline void handle_interrupts() заменить digitalWrite() на связку setBit(buf_var, x); transport(buf_var); и clearBit(buf_var, x); transport(buf_var);
По идее, должно работать, SPI же быстро выплюнет данные.
Именно это я и делал:
Не помогло. Надо осцилографировать! Может кто подскажет програмку для компа, чтобы симулировать осцилограф для ардуины?
Эта почемуто не рааботает.