Скачет задержка.
- Войдите на сайт для отправки комментариев
Добрый день. Сразу замечу что я не очень разбираюсь в програмирование и, надеюсь, что в этом разделе форума это допускается.
Мой вопрос в следующем. Я решил сделать простенькое устройство, генератор импульсов с задержкой на Arduino nano (китайская копия, если это важно) и что я не пытался делать, задержка, необходимая мне между двумя импульсами всегда скачет в диапазоне около 10мкс. Сначала я пытался сделать это считывая micros() в цикле while(), задержка скакала, я решил, что это возможно из-за случайного времени выполнения всех мат. операций и считываний в цикле, в общем, не буду излагать здесь всю трогательную историю моей борьбы, скажу лишь, что закончил я так
PORTD |=1<<2;
asm("nop");
// повторяется сто раз просто скопированная строка
asm("nop");
PORTB |=1<<3;
То есть в моём понимание болтаться просто нечему. Но на деле выходит картина приведённая на иллюстрации ниже
Здесь красный первый импульс и жёлтый второй видно, что он бывает в двух разных местах, разница между которыми 6,26 мкс. С более сложными (но более удобными и понятными мне кодами) типа циклов while(t<T){t=micros();...} ,разброс достигает 10 мкс и положения не 2, а больше. Болтанка от абсолютной величины задержки, на мой взгляд, не зависит.
Подскажите, пожалуйста, что я делаю не так.
Спасибо
всё так, так и должно быть, если болтанка критична, переходить на авр студию
Запретить все прерывания. Не запускать никакие библиотеки. И лучше выложить полный код, а не кусочек, который теоретически должен работать корректно.
Код я могу выложить без проблем, но он у меня в отвратительном тестовом виде с кучей процедур не имеющих отношения к делу и, мне кажется, что просто как-то не вежливо его так выкладывать. Но, на всякий случай, я его приложу, но никому смотреть и разбираться в полном коде не советую :-)
Из билиотек я использую
#include <Arduino.h> #include <TM1637Display.h> #include <EEPROM.h> //PINS byte out1=2; byte out2=11; byte CLK1=3;//valcoder1 byte DT1=4; byte SW1=5; byte CLK2=10;//valcoder2 byte DT2=9; byte SW2=8; unsigned char encoder_A1, encoder_B1, encoder_A_prev1; // valcoder1 unsigned char SW_State1,SW_State_prev1; unsigned char encoder_A2, encoder_B2, encoder_A_prev2; // valcoder2 unsigned char SW_State2,SW_State_prev2; int sw_counter; int sw1_counter; int sw_delay=5000; byte adr_freq=3; byte adr_del=7; byte freq_mass[3]={10,25,50}; //frequences byte freq; byte freq_i; //frequency nomber int T_cor=70; //float mult=1; //int d=2; int del;//delay int del_mult=1; byte pulse_wide=25; unsigned long t1,t2,dt;//,tee1,tee2,dtee; unsigned long td1,td2,dt_del,dt_wide,i,j; float T,dT; //int dTee=10000; //delay before puting to eepromt //long dTd=10000;//delay for d set //int d[4]; byte u1_flag=0; byte u2_flag=0; byte eet_flag=1; byte d_flag=0; byte beg_flag=1; byte work_flag=0; TM1637Display display(7, 6); void setup() { //Serial.begin(9600); display.setBrightness(0x0f); EEPROM.get(adr_freq,freq_i); EEPROM.get(adr_del,del); DDRD = B00000100; DDRB = B00001000; //pinMode(out1,OUTPUT); //pinMode(out2,OUTPUT); freq=freq_mass[freq_i]; T=1000000/freq; //t1=micros(); display.showNumberDec(freq); delay(1500); display.showNumberDec(del); delay(1500); display.setBrightness(0); display.showNumberDec(work_flag); delay(1500); display.showNumberDec(freq); } void loop() { while(1) {if(work_flag==1) cycle(); //cycle1(); encoder1(); encoder2(); } } void cycle1() { if(beg_flag==1) {t1=micros(); PORTD |=1<<2; PORTD &=~(1<<2); beg_flag=0; } t2=micros(); dt=t2-t1; if(dt>T) beg_flag=1; } void cycle() { if(beg_flag==1) { t1=micros(); dt_wide=t1+pulse_wide; dt_del=t1+del; u1_flag=1; PORTD |=1<<2; // digitalWrite(out1,HIGH); /* while(t2<dt_del) {t2=micros(); if(u1_flag==1) if(t2>dt_wide) {u1_flag=0; //PORTD &=~(1<<2); digitalWrite(out1,LOW); } }*/ asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); PORTB |=1<<3; // digitalWrite(out2,HIGH); u2_flag=1; beg_flag=0; } t2=micros(); dt=t2-t1; if(u2_flag==1) if(dt>del+pulse_wide) {u2_flag=0; // PORTB &=~(1<<3); digitalWrite(out2,LOW); } if(u1_flag==1) if(dt>pulse_wide) {u1_flag=0; // PORTD &=~(1<<2); digitalWrite(out1,LOW);} if(dt>=T-T_cor) beg_flag=1; } /*t2=micros(); dt=t2-t1; if(dt-puls_wide<=0) {if(u1_flag==0) { PORTD |=1<<2; u_flag=1;} } else if(u_flag==1) { PORTD &=~(1<<2); u_flag=0; { if(dT<dt-T/d) dT=dt-T/d; } } if(dt-T>=0) {t1=micros()-dt+T-47; }*/ void encoder1() { encoder_A1 = digitalRead(CLK1); encoder_B1 = digitalRead(DT1); SW_State1 = digitalRead(SW1); if(!encoder_A1 && encoder_A_prev1) { /* tee1=millis(); tee2=tee1;*/ //eet_flag=0; if(encoder_B1) { freq_i=freq_i-1; } else { freq_i++; } if(freq_i<0||freq_i>250) freq_i=0; if(freq_i>1) freq_i=2; freq=freq_mass[freq_i]; T=1000000/freq; display.showNumberDec(freq); } encoder_A_prev1 = encoder_A1; if(!SW_State1) { if(SW_State_prev1) { work_flag=0; EEPROM.put(adr_freq,freq_i); EEPROM.put(adr_del,del); display.showNumberDec(work_flag); display.setBrightness(0); sw1_counter=0; } if(!SW_State_prev1) sw1_counter++; if(sw1_counter==sw_delay) { sw1_counter=0; display.setBrightness(7); work_flag=1; display.showNumberDec(freq); EEPROM.put(adr_freq,freq_i); EEPROM.put(adr_del,del); } } SW_State_prev1=SW_State1; } void encoder2() { encoder_A2 = digitalRead(CLK2); encoder_B2 = digitalRead(DT2); SW_State2 = digitalRead(SW2); if(!encoder_A2 && encoder_A_prev2) { /* tee1=millis(); tee2=tee1;*/ //eet_flag=0; if(encoder_B2) { while(del_mult>del) del_mult=del_mult/10; if(del_mult<1) del_mult=1; del=del-del_mult; if(del<0) del=0; } else { del=del+del_mult; if(del>9999) del=9999; if(del<pulse_wide) del=pulse_wide; } display.showNumberDec(del); } encoder_A_prev2 = encoder_A2; if(!SW_State2) sw_counter++; { if(sw_counter==sw_delay) { del_mult=del_mult*10; if(del_mult>1000) del_mult=1; sw_counter=0; display.showNumberDec(del_mult); } } if(sw_counter!=0) if(SW_State2) sw_counter=0; //SW_State_prev2=SW_State2; }Спасибо, обязательно попробую при случае, но пока это выше моего понимания.
Так у Вас кроме генератора еще столько наворочено. По хорошему диспле и энкодер работают только пр установке параметров генератора, а дальше все это отрубается и запускается генератор. Выход из него только по сбросу. Тогда можно говорить о стабильности.
Запретил прерывания. В приведённом варианте болтанка пропала. С циклом while(){micros();...} всё равно не работает, но, как я понимаю это уже из-за случайности момента считывания micros(); не так удобно, но зделаю цикл for(){nop}, наверное. Больше спасибо за совет. Проблема скорее решена
Запретил прерывания. В приведённом варианте болтанка пропала. С циклом while(){micros();...} всё равно не работает, но, как я понимаю это уже из-за случайности момента считывания micros(); не так удобно, но зделаю цикл for(){nop}, наверное. Больше спасибо за совет. Проблема скорее решена
Успехов!
Спасибо
Запретил прерывания. В приведённом варианте болтанка пропала. С циклом while(){micros();...} всё равно не работает, но, как я понимаю это уже из-за случайности момента считывания micros(); не так удобно, но зделаю цикл for(){nop}, наверное. Больше спасибо за совет. Проблема скорее решена
а микрос работает после запрета прерывания?
Ну, как-то да - работает. Выдаёт примерно похожие на правду результаты. В интернетах пишут, что так делать нельзя, но мне, благо и не подходит по вышеописанным причинам, но когда я сейчас пробовал - работает. Ошибку не выдаёт в плату заливается, плата работает как нужно, но с болтанкой, которую я списываю на сучайность времени считывания.
Болтанки быть не должно, если программа написана правильно. Для выдачи стабильного результата на высоких скоростях надо использовать таймер с прямой выдачей на ногу м.с. В этом случае результат не будет зависить от прерываний и команд внутри цикла loop. В интернете много примеров програмирования таймера. Даже здесь на форуме. Например http://arduino.ru/forum/proekty/generator-s-reguliruemoei-chastotoi-na-arduino
Большое спасибо. Обязательно попробую что-то такое - давно хотел разобраться с таймерами. Сейчас требуемую мне задачу я решил, возможно, конечно, не самым прямым методом, но задержка совершенно стабильна для моих задач и регулируется с точностью, примерно в 1мкс от 20 до 1000. Абсолютное значение задержки и для меня не важно - в основном важна была стабильность.
Если интересно - вот конечный код, который работает
#include <Arduino.h> #include <TM1637Display.h> #include <EEPROM.h> //PINS byte out1=2; byte out2=11; byte CLK1=3;//valcoder1 byte DT1=4; byte SW1=5; byte CLK2=10;//valcoder2 byte DT2=9; byte SW2=8; unsigned char encoder_A1, encoder_B1, encoder_A_prev1; // valcoder1 unsigned char SW_State1,SW_State_prev1; unsigned char encoder_A2, encoder_B2, encoder_A_prev2; // valcoder2 unsigned char SW_State2,SW_State_prev2; int sw_counter; int sw1_counter; int sw_delay=5000; byte adr_freq=3; byte adr_del=7; byte freq_mass[3]={10,25,50}; //frequences byte freq; byte freq_i; //frequency nomber int T_cor=70; //float mult=1; //int d=2; int del;//delay int del_mult=10; byte pulse_wide=25; unsigned long t1,t2,dt;//,tee1,tee2,dtee; unsigned long td1,td2,dt_del,dt_wide,i,a,b; float T,dT; float k=1.331;// recount mks to nop int d=4; //int dTee=10000; //delay before puting to eepromt //long dTd=10000;//delay for d set //int d[4]; byte u1_flag=0; byte u2_flag=0; byte eet_flag=1; byte d_flag=0; byte beg_flag=1; byte work_flag=0; TM1637Display display(7, 6); void setup() { //Serial.begin(9600); display.setBrightness(0x0f); EEPROM.get(adr_freq,freq_i); EEPROM.get(adr_del,del); DDRD = B00000100; DDRB = B00001000; //pinMode(out1,OUTPUT); //pinMode(out2,OUTPUT); freq=freq_mass[freq_i]; T=1000000/freq; a=k*pulse_wide-d; b=del*k-d; //t1=micros(); display.showNumberDec(freq); delay(1500); display.showNumberDec(del); delay(1500); display.setBrightness(0); display.showNumberDec(work_flag); delay(1500); display.showNumberDec(freq); } void loop() { while(1) {if(work_flag==1) cycle(); //cycle1(); encoder1(); encoder2(); } } void cycle() { if(beg_flag==1) { t1=micros(); dt_wide=t1+pulse_wide; dt_del=t1+del; u1_flag=1; noInterrupts(); PORTD |=1<<2; //digitalWrite(out1,HIGH); for(i=0;i<a;i++) asm("nop"); PORTD &=~(1<<2); for(i=0;i<b-a;i++) asm("nop"); //PORTD |=1<<2; PORTB |=1<<3; for(i=0;i<a;i++) asm("nop"); PORTB &=~(1<<3); interrupts(); //PORTB |=1<<3; //digitalWrite(out2,HIGH); u2_flag=1; beg_flag=0; } t2=micros(); dt=t2-t1; if(dt>=T-T_cor) beg_flag=1; } /*t2=micros(); dt=t2-t1; if(dt-puls_wide<=0) {if(u1_flag==0) { PORTD |=1<<2; u_flag=1;} } else if(u_flag==1) { PORTD &=~(1<<2); u_flag=0; { if(dT<dt-T/d) dT=dt-T/d; } } if(dt-T>=0) {t1=micros()-dt+T-47; }*/ void encoder1() { encoder_A1 = digitalRead(CLK1); encoder_B1 = digitalRead(DT1); SW_State1 = digitalRead(SW1); if(!encoder_A1 && encoder_A_prev1) { /* tee1=millis(); tee2=tee1;*/ //eet_flag=0; if(encoder_B1) { freq_i=freq_i-1; } else { freq_i++; } if(freq_i<0||freq_i>250) freq_i=0; if(freq_i>1) freq_i=2; freq=freq_mass[freq_i]; T=1000000/freq; display.showNumberDec(freq); } encoder_A_prev1 = encoder_A1; if(!SW_State1) { if(SW_State_prev1) { work_flag=0; EEPROM.put(adr_freq,freq_i); EEPROM.put(adr_del,del); display.showNumberDec(work_flag); display.setBrightness(0); sw1_counter=0; } if(!SW_State_prev1) sw1_counter++; if(sw1_counter==sw_delay*10) { sw1_counter=0; display.setBrightness(7); work_flag=1; display.showNumberDec(freq); EEPROM.put(adr_freq,freq_i); EEPROM.put(adr_del,del); } } SW_State_prev1=SW_State1; } void encoder2() { encoder_A2 = digitalRead(CLK2); encoder_B2 = digitalRead(DT2); SW_State2 = digitalRead(SW2); if(!encoder_A2 && encoder_A_prev2) { /* tee1=millis(); tee2=tee1;*/ //eet_flag=0; if(encoder_B2) { while(del_mult>del) del_mult=del_mult/10; if(del_mult<1) del_mult=1; del=del-del_mult; if(del<pulse_wide) del=pulse_wide; } else { del=del+del_mult; if(del>9999) del=9999; if(del<pulse_wide) del=pulse_wide; } b=del*k-d; display.showNumberDec(del); } encoder_A_prev2 = encoder_A2; if(!SW_State2) sw_counter++; { if(sw_counter==sw_delay) { del_mult=del_mult*10; if(del_mult>1000) del_mult=1; sw_counter=0; display.showNumberDec(del_mult); } } if(sw_counter!=0) if(SW_State2) sw_counter=0; //SW_State_prev2=SW_State2; }Ещё раз всем большое спасибо за помощь