Генератор сигналов на Arduino, проблема с Serial
- Войдите на сайт для отправки комментариев
Здравствуйте! Собрал я тут генератор сигналов на Arduino подобный тому, что в переведенной статье http://cxem.net/arduino/arduino62.php . Но немного переделал его, чтобы был свободый Serial, чтобы управлять устройством с компьютера. И тут встала проблема, что данный код не позволяет принимать и отправлять сообщения по Serial. Если отправить что-либо, то все просто подвисает, а пришедшие сообщения не обрабатываются. Я подозреваю что все дело в прерываниях, благодаря которым и работает генератор. Но т.к. сам в них мало что понимаю, прошу помощи. Полностью код не буду копировать, можете по ссылке посмотреть.
Что я пытаюсь сделать:
void loop() { if (Serial.available() > 0) { // get incoming byte: char inChar = (char)Serial.read(); if (inChar == 'n') Serial.println("generator"); } checkFreq(); checkShape(); checkPW(); }
так вообще ничего не работает, сообщения пришедшие не обрабатываются.
После этого пытался просто отправить что-нибудь на компьютер.
if ((millis() % 100000) == 0) { Serial.println("generator"); }
тогда все просто зависало, никаких сигналов небыло.
Ну и ниже собственно часть где скорее всего настраиваются прерывания, из-за которых не работает Serial. Когда я комментировал отдельные строки, Serial включался и работал нормально, но не работал генератор.
void setup() { //set port/pin mode DDRD = B11111110;//all outputs DDRC = 0x00;//all inputs DDRB = 0xFF;//all outputs //TIMER INTERRUPT SETUP cli();//disable interrupts //timer 1: TCCR1A = 0;// set entire TCCR1A register to 0 TCCR1B = 0;// same for TCCR1B //set compare match register- 100khz to start OCR1A = 159; // = (16 000 000 / 100 000) - 1 = 159 //turn on CTC mode TCCR1B |= (1 << WGM12); // Set CS10 bit for 0 prescaler TCCR1B |= (1 << CS10); // enable timer compare interrupt TIMSK1 |= (1 << OCIE1A); samplerate = 100000; PORTB = 0; PORTB = 1<<type; //initialize variables frequency = analogRead(A5);//initialize frequency freqscaled = 48*frequency+1;//from 1 to ~50,000\ period = samplerate/freqscaled; pulseWidth = analogRead(A4);//initalize pulse width pulseWidthScaled = int(pulseWidth/1023*period); triInc = 511/period; sawInc = 255/period; sinInc = 20000/period; sei();//enable interrupts Serial.begin(9600); }
Подскажите, пожалуйста, как это можно обойти. Информацию по Serial можно обрабатывать не мгновенно. Через него будут просто переключаться режимы. Можно ли как-то остановить основную программу, считать данные, отправить ответ, и запустить дальше генератор? Я пробовал между noInterrupts() и interrupts() код вставлять, не помогло.
Дело не в прерываниях, а в том что если вы посмотрите на схему, то увидите, что для генерации сигнала используется весь порт D (все 8 выводов порта), а на 0 и 1 выводах которого как раз и реализованаппаратный UART. У ATmega328 нет больше полных свободных портов, поэтому либо два бита выводите на другой порт, либо используйте программный UART на других выводах, но для этого вам прийдется перепаять FTDI на эти выводы, освободив 0 и 1 выводы порта D.
Я же напсал, что переделал схему. у меня ножки 0 и 1 свободны. И Serial работает, если я закомментирую представленный выше текст в setup(). И чтобы он работал порт не весь на выходы делаю, а так DDRD = B11111110;
Так покажите что переделали или вы думаете здесь есть экстрасенсы? потому как если вы ничего не поменяли в обработчике ISR(TIMER1_COMPA_vect){ то ваша переделка бесполезна так как там есть строка PORTD = wave;
Да ну я же говорю, что освободил 0 и 1 ножку. Думал все понятно.
Вот как переделал строку PORTD = wave;:
Так не пойдет. Попробуйте так:
Или даже так
И еще даже вот так
Есть результат?
Ни к чему полезному это не привело) Только на осцилографе стал график рваный.
Не привело, но прийдется оставить так или UART не будет работать на передачу. Так а виснуть перестало? А так пробовали?
Залез тут в библиотеку TimerOne по аналогу сделал 2 такие функции:
и теперь когда делаю так, то все работает:
только частота меньше стала
пробовал не так, как у вас, а так:
не помогло. и вообще мне кажется if (Serial.available() > 0) не выполняется, когда прерывания работают.
а если так то не работает?
Да, не работает.
В общем на малых частотах можно работать так:
На больших уже картина ухудшается. Размазывается. Пока оставлю так. Если кто-то что-то подскажет, буду рад!
Картина размазывается всегда, просто на малых частотах это не очевидно.
Можно поиграться с RTS\DTS. Как минимум просто притащить RTS от FTDI на какой-нибудь пин, опрашиваемый в основном цикле, и открывать ком порт, только когда там что-то есть...
Вот эти ньюансы с RTS\DTS я как раз и не знаю) Еще одна проблема возникла. Если делать вот так:
И отправить например: "f1234". То придет только f12, иногда f1, и очень редко больше доходит. если отправлять "f12345678901234567890". То один раз из десяти доходит 5 символов. В общем либо только первые 2-3 символа приходят только, а остальные пропадают, либо остальные на втором цикле читаются.
В общем либо только первые 2-3 символа приходят только, а остальные пропадают, либо остальные на втором цикле читаются.
Так пропадают или на последующих циклах читаются?
Если первое, значит вы еще не умеете читать из последовательного порта. Дело поправимое.
Если второе, то что в этом такого удивительного? Процесс ведь асинхронный, передатчику нет дела до того, что вы там у себя в программе ожидаете - он строго по расписанию выдаст серию символов, а уж попадут они в один-единственный цикл или в несколько, зависит от сложности цикла (времени его прохождения) и метода чтения из порта.
Ну я говорю там когда как. Чаще проподают, чем во втором цикле доходят. Ну а читать может и не умею, в первый раз пробую что-то серьезное с Serial) Я как думал, если запустить цикл while (Serial.avalible()), то пока все данные не считаются с буфера, не выйдет программа из цикла. И следовательно думал, что в буфер если данных не сильно много, то все сразу записываются.
По большому счету правильней ждать конца посылки, например, ждать символа перевода строки. Иначе Вы в цикле очищаете входной буфер inString, затем считываете часть строки. А в следующем loop снова очищаете inString и получаете остаток строки. Более того, Вы даже и не знаете, где кончится входная строка. Сначала определите протокол обмена. Т.е. какие команды, какие у них параметры, как Вы определите на Ардуино, сколько символов в команде, сколько в ней параметров и какие они.
Еще, как вариант, со стороны компа посылать всю строку, а не посимвольно. Обычно это в настройках терминалов есть, но в ArduinoIDE мониторе - я не знаю, может это и есть.
Есть и другая сторона, если Вы не всю строку получаете, непонятно, где она теряется (возможно проблема пересечения интересов прерываний и Serial), но сначала лучше сделать правильное получение данных с компа по определенному протоколу.
Вы можете попробовать пообщаться с компом, убрав пока обработку прерываний, чтобы не мешать мух и котлеты, а когда отладите надежную работу, смешивайте эти две вещи и пробуйте дальше.
Всё правильно, для работы дуринского ком порта, нужны разрешенные прерывания и свободное время.
А последнего вы ему как раз не оставляете, так-что принять длинную строку он просто не успевает.
Как вариант, можно дать ему свободного времени, вставив некоторую паузу, НО.
Вам оно по любому не приемлимо, и если перспектива изучения исходников Sireal с целью последующего внедрения вашего таймера в оный, (возможного с некоторой вероятностью) не радует вас. Послушайте моего доброго совета.
Когда FTDI получает данные на выводе RTS появляется высокий уровень, заводите его в дурину и проверяйте програмно.
А когда появится, глушите таймер и слушайте ком порт в спокойной обстановке, ответе что-нибудь или просто дождитесь признака конца строки, а потом возвращайте таймер на место и радуйтесь безглючной работе.
RTS это третья нога FTDI, как правило не идущая куда-либо далее в схему.
Если оно слишком мелко для вас, можно зацепиться за DTR у дурины сброс по нему, так-что он как правило идёт на конденсатор не по далёку, к нему припаяться легоко, но у DTR есть своя специфика. На нём есть сигнал, вне зависимости от данных, а просто по факту открытия порта, программой, которая в свою очередь может делать это хоть на всю сессию. Но учитывая тот факт что абдурино использует DTR для сброса контроллера, а во время пользования дуриновским терминалом сброса не происходит, можно предположить, что DTR активен только на время посылки и вы можете слушать ком порт пока этот сигнал активен и глушить его, возвращая таймер, когда это не так...
А отдельно можно реализовать сигнал пила? меня именно пила сигнал интересует
Можно.
А как я чет не догнал
мне самое главное понять работу кода резистор какой взять
В самом первом сообщении есть ссылка на проект, там есть схема, кнопочки со светодиодами можно убрать, оставив только потенциометры. В конце статьи есть ссылки на исходники, качаете их правите так что бы остался только режим "пила" и все.
ок спасибо. будем пытаться