по аппаратному прерыванию
- Войдите на сайт для отправки комментариев
Пт, 30/08/2013 - 00:20
никак не соображу по этому вопросу, нужен генератор низких частот, и решил воткуть в свою прогу.
Надо - частота от 1 Гц до 300 Гц, и её можно менять с помощью кнопок, и ширину импульса. Операции с меню не должны заикать звук. Пока написал это
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 10, 11, 12, 13); // инициализируем LCD, указывая контакты данных
#define TOGGLE_IO 40 //Arduino pin to toggle in timer ISR
unsigned int latency;
unsigned int latencySum;
unsigned int sampleCount;
unsigned char timerLoadValue;
int freq=500;
int analogkey2;
#define TIMER_CLOCK_FREQ 2000000.0 //2MHz for /8 prescale from 16MHz
unsigned char SetupTimer2(float timeoutFrequency){
unsigned char result;
result=(int)((257.0-(TIMER_CLOCK_FREQ/timeoutFrequency))+0.5);
TCCR2A = 0;
TCCR2B = 0<<CS22 | 1<<CS21 | 0<<CS20;
TIMSK2 = 1<<TOIE2;
TCNT2=result;
return(result);
}
//Timer2 overflow interrupt vector handler
ISR(TIMER2_OVF_vect) {
digitalWrite(TOGGLE_IO,!digitalRead(TOGGLE_IO));
latency=TCNT2;
TCNT2=latency+timerLoadValue;
digitalWrite(49,HIGH);
delay (freq);
digitalWrite(49,LOW);
}
void setup(void) {
pinMode(TOGGLE_IO,OUTPUT);
pinMode(49,OUTPUT); // LED TESTER
lcd.begin(20, 4); // указываем размерность экрана и начинаем работать
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Timer2 Test");
lcd.setCursor(10, 0);
lcd.print(timerLoadValue);
delay(1000);
timerLoadValue=SetupTimer2(44100);
// Serial.println(timerLoadValue,HEX);
}
void loop(void) {
delay(1000); //Accumulate ISR latency every 10ms.
latencySum+=latency;
sampleCount++;
if(sampleCount>99) {
float latencyAverage;
float loadPercent;
latencyAverage=latencySum/100.0;
sampleCount=0;
latencySum=0;
loadPercent=latencyAverage/(float)(256.0-timerLoadValue);
loadPercent*=100; //Scale up from ratio to percentage;
latencyAverage-=(int)latencyAverage;
spy:
analogkey2 = analogRead (2);
if (analogkey2>650 && analogkey2<750){ // ->>
if (freq>30) {
freq=freq-10;
};
};// if
if (analogkey2>300 && analogkey2<380) { // <--
if (freq<1000) {
freq=freq+10;
};
}; // if
lcd.setCursor(5,1);
lcd.print (freq);
goto spy;
}
}
вырезал со статьи по прерывание, читаю и не очень понимаю, в коде много мусора, не понятно как на ходу менять частоту срабатывания прерывания и её расчитать.
В Delphi к примеру в основной программе достаточно было вызвать CreateThread и в теле потока написать подобие ВКЛ.LED, пауза1,ВЫКЛ.LED,пауза2. и управляя переменными пауз из основного потока программы достигли бы нужного.
нашел лучший пример,всё обернуто в обертку и вынесено в cpp, хотя не рабочий, с помощью библиотеки MsTimer2.cpp (добавил в либры, плата 2560, среда 1.0.1)
по коду должно через каждые 5 секунд включатся светодиод на 1 секунду, но этого не происходит.Кнопки в коде подключены, но пока не учавствуют в изменении параметров.
#include <LiquidCrystal.h> #include <MsTimer2.h> LiquidCrystal lcd(8, 9, 10, 11, 12, 13); // инициализируем LCD, указывая контакты данных int freq=500; int analogkey2; void flash_led() //обработчик прерывания { digitalWrite(49,HIGH); delay(1000); digitalWrite(49,LOW); } void setup(void) { pinMode(49,OUTPUT); // LED TESTER MsTimer2::set(5000, flash_led); // ms период MsTimer2::start(); //включить таймер lcd.begin(20, 4); // lcd.clear(); lcd.setCursor(0, 0); lcd.print("Timer2 Test"); delay(1000); } void loop(void) { delay(1000); //Accumulate ISR latency every 10ms. spy: analogkey2 = analogRead (2); if (analogkey2>650 && analogkey2<750){ // ->> if (freq>30) { freq=freq-10; }; };// if if (analogkey2>300 && analogkey2<380) { // <-- if (freq<1000) { freq=freq+10; }; }; // if lcd.setCursor(5,1); lcd.print (freq); delay(100); goto spy; }Бздынь.....
1. Что у вас с форматирование кода? Нажмите хотя-бы CTRL-T в Arduino IDE
2. GOTO - забудте про существование этого оператора ВООБЩЕ. Пишите так как будто не такого слова. Обходитесь другими средствами.
3. Раз нехотите заикание - откажитесь от функции delay(). И уж тем более в обработчике прервыния (тут нет многопоточности). Только millis() и таймеры (и то, аккуратно с ней обработчике). Вообщем начинайте с базовых примеров в разделе Программирование. Мигаем светодиодом без delay() , а не сразу "экраны", "генераторы" и т.п.
http://arduino.ru/forum/programmirovanie/arduino-push-pull
#include <LiquidCrystal.h> LiquidCrystal lcd(8,9,10,11,12,13); void (*mas[2]) (void)={poluper1, poluper2}; // массив указателей функций volatile int val_fr = 533.0; // длительность полупериода f=18000000/val_fr/2(Гц), byte uk=0; int f_val, d_val, fkr; float rpm, frc; // ******************************************************************** // ******************************************************************** void setup() { DDRD = B11111000; // нужные пины на выход PORTD = B00000100; // на втором пине устанавливаем "единицу" // TCCR1A=0; TIMSK1=0; // сбрасываем на всякий эти регистры TCCR1A=0; TIMSK=0; TCCR1B=0; // мало ли что arduino IDE туда записало TCNT1=0; // сбрасываем счетный регистр таймера 1 OCR1A=0; // задаем частоту, в Гц, по формуле f=F_CPU/OCR1A/2 где F_CPU тактовая частота // TIMSK1|=(1<<OCIE1A); // разрешаем генерацию прерывания таймера 1, по совпадению с регистром OCR1A TIMSK|=(1<<OCIE1A); // Скетч будет работать на дуинах с atmega168/328. // При использовании atmega8 меняем все TIMSK1 на TIMSK (убираем еденицу). TCCR1B|=((1<<CS10)|(1<<WGM12)); // запускаем таймер 1 без предделителя в режиме СТС lcd.begin(16, 2); lcd.print("arduino PushPull"); } // ******************************************************************** // ******************************************************************** void loop(){ if ((PIND&(1<<2)) == 0) l_c_d(); // если на пин 2 лог 0 } // ******************************************************************** // ******************************************************************** ISR(TIMER1_COMPA_vect) { OCR1A=val_fr; (*mas[uk])(); // вызываем функцию по указателю } // ******************************************************************** // ******************************************************************** void poluper1(void) { PORTD&=~(1<<5); // на пин 5 лог 0 PORTD|=(1<<4); // на пин 4 лог 1, формируем первый полупериод uk=1; } void poluper2(void) { PORTD&=~(1<<4); // на пин 4 лог 0 PORTD|=(1<<5); // на пин 5 лог 1, формируем второй полупериод uk=0; } // ******************************************************************** // ******************************************************************** void l_c_d() { // работаем с частотой от 15009(533) Гц до 30075(266) Гц (f=F_CPU/OCR1A/2) // работаем с частотой от 25000(320) Гц до 30075(266) Гц (f=F_CPU/OCR1A/2) f_val = analogRead(A3); frc = map(f_val, 0, 1023, 320.0, 266.0); d_val = analogRead(A2); fkr = map(d_val, 0, 1023, -10.0, 10.0); val_fr = frc+fkr; rpm = 16000000.0/val_fr/2.0; // частота в Герцах lcd.setCursor(0, 0); lcd.print("freq Hz"); lcd.setCursor(5, 0); lcd.print(rpm); lcd.setCursor(0, 1); lcd.print("correction "); lcd.setCursor(12, 1); lcd.print(fkr); //delay(400); }ага спасибо, чуток доходит, жалко железной мультипоточности нет.
Goto если правильно использовать, то ничего в этом нет,боятся только новички. Заместо него используют команды условного перехода, if (0==0) проверяя, то что всегда равно чему-то. loop тот же безусловный переход к адресу первого оператора loop.
3. Раз нехотите заикание - откажитесь от функции delay(). И уж тем более в обработчике прервыния (тут нет многопоточности).
таки есть многопоточность :) в DUE можно запустить несколько loop в одной программе..
это уже другая дурина) там чип другой.
Ещё про GOTO - иногда надо часть кода пропустить (перепрыгнуть), в DELPHI можно было ненужный блок взять в {} и он заремится, в этом языке это служебное слово, придется или на каждой строчке печатать // или брать весь ненужный код в блок условного кода тупо if (0==0), а быстрее добавить пару строк
ну если вы не обратили внимания то есть еще вариант
/* .... строчки которые ремарките..... */
и можеет хоть весь код так отметить
не знал, но иногда не надо заремить, а сохранить следующий код, так размер виден при компиляции ( в том числе в exe, правда сейчас размер программы в ехе уже не имеет значения, ранее приходилось на WinApi писать, используя встроенные фунции в dll виндовс)...
Ну вот не нужно тут петь диферамбы GOTO. Как раз новички его и не боятся. Обычно наличие GOTO говорит либо о том что это новичок который плохо знает синтаксис языка и лепить "костыль GOTO" куда угодно. Либо это писал человек привыкший к ASM и опять-таки ленящейся освоится с новым языком. Действующий по принципу "заработало и ладно".
Я не новичок. Про GOTO знаю. Моим первым языком был GW-BASIC с нумерацией строк. Где-то 1988-1989 году. Там без GOTO - было вообще никак :)
Но с переходом TurboPascal 3.0 (упоминаемая вами Delphi, на котором тоже не один год писали - его потомок) - надобность в GOTO отпала совершенно. Нет никаких "правильных использований GOTO". Само его использование - уже неправильно. Резко падает сопровождаемость и читабельность кода.
Ваш пример с комментированием, готорит не о том, GOTO нужен, а о том что вы плохо знаете синтаксис языка.
Во первых есть есть блочные коментаии которые спокойно решают вашу проблему. Коментировать можно не только одну строку, а сразу сколько захочешь
Во вторых само существование большого блока кода который нужно "закментить" говорит о низком качестве кода. Почему он не вынесен в отдельную функцию, вызов которой можно закоментировать одним пальцем?
Есть еще условная компиляция. Директивы препроцессора #if #ifdef #ifndef. Которая позволяет "включить/выключить" сразу несколько кусков кода. Не занимать не нужным кодом такты процессора и память. А не решать это в runtime
В третьих само "хранение старого кода" в закоментированом виде, типа "авось пригодится" говорит о том, что вы не знакомы с ситемами контроля версии (git, mercural, svn и т.п.). Которые спокойно решают эту задачу и сохраняют код чистым и опрятным, без "исторического мусора".
Ну и в конце концов. if(0==0) - никак не поможет в вашей ситуации. Код будет выполнен. Эту условие - всегда истино. Вам нужно было if(0==1) или более удобочитаем if(false) или аскетчино if(0)
Вообщем любое использование GOTO говорит либо о недостатке знаний пишущего, либо о крайне низком качестве кода (ошибках архитектуры и т.п.). Поэтому и говорится "забудте про него". Что-бы вы вынуждены были решать задачи более адекватными средствами.
Конечно плохо знаю, в пределах сайта по контроллеру, на другие не захожу - из специфики языка. И учеба по мере задач - если нужно прерывание их и разбираю, а не как работает функция tone().
ASM да было (jnz). BASIC был, ZX-SPECTRUM - там действительно никак, переход на строчку. GOSUB ещё был....Delphi начал с 4.0 (там уже VCL элементы) goto удобно использовать во врезках asm код end; благо язык позволяет в любом месте перейти на asm."существование большого блока кода " - это важный код который охота пропустить при отладке, это меню, вместо нудного и долгого выбора пункта в меню и выбора значения кнопками, достаточно прописать в начале эти настроенные переменные, в том числе номер меню и сделать переход) Но уговаривать не буду, кому как легче, после отладки данные команды затираются.
Кстати на Mega2560 не работает библиотека <MsTimer2.h>
#include <MsTimer2.h> void flash_led() //обработчик прерывания { digitalWrite(49,HIGH); } void setup(void) { pinMode(49,OUTPUT); // LED TESTER MsTimer2::set(500, flash_led); // ms период MsTimer2::start(); //включить таймер } void loop(void) { }не зажигает светодиод, если в сетап вынести - digitalWrite(49,HIGH); лед горит, исправен.
Залезте в библиотеку, поробуйте найти все условия содержащие
И заменить/дописать на
Про GOTO - ну как хотите. Желание использовать GOTO - не дает вам развиватся. По очередному вашему примеру видно что событийная архитектура у вас в приложении была "так себе", разделение логики и UI - плохое, Unit Testing-гом не пахло и т.п.
В конце концов, что вы ходите доказать? Даже задачу "обойти большой кусок кода" (хотя и задачи такой в нормальном приложении быть не должно, само наличие "большой кусок кода" - уже фигня) - можно решить без GOTO и более красиво. Я вам упоминал уже какими средствами? Вы хоть погуглили их?
Впрочем - каждый сам себе злобный буратино. В любой приличной конторе (и даже не очень приличной), при намеке на GOTO - собеседование сразу заканчивается. Если кто-то уже из работников будет использовать - ну очень удивятся. Объяснят (и скорее всего сделают выводы о компетенции), если же будет "упорствовать" - скорее всего сразу укажут на дверь. Никому потом не улыбается сопровождать код написаный таким "програмистом".
P.S. Стыдно "не отсуствие знание", а упроствование в этом.
не собираюсь быть платным программистом, или работать на дядю - главное написать работающий контроллер и забыть.
Уже дошло - взяв библиотеку FlexiTimer2, там ATmega2560 уже прописано, надо заглядывать в *.cpp, родное IDE 1.0.1 не хочет открывать, а в блокноте каша.
Ну что ж с профи говорить, извините.
Доброго времени суток !
1) Таймер 2 - 8-ми битный и по этому от 1 до 300 не получится, если только Вы не собираетесь таймером просто вести счет для CPU
2) Оператор GOTO использовать никто не запрещает, НО среди С-шников это считается дурным тоном. Когда это началось я не знаю, но когда я в 1992 переходил на С это уже было.
3) Паралельных потоков на 1 CPU не бывает - это просто быстрое переключение по прерыванию от таймера (сам когдато делал многозадачность 286/386)
4) Вы хотите использовать LCD и генерировать реалтайм сигнал - для этого необходимо хотябы что то одно делать по прерыванию (в фоне). Так как Вы используете LiquidCrystal который использует паузы (delay delayMicroseconds) то остается сделать генератор сигнала в фоне. Так как у Вас 300 градаций то таймеры 0/2 Вам не подходят. Используйте 1/3 они 16-ти битные. К примеру выберите режим FastPWM с ограничением по OCRA настройте делитель на /256 таким образом 1 сек = 62500 счетов скважность в примеру 50% 62500 / 2. Длительность заносим в OCRA скважность в OCRB и запускаем таймер. Более высокую частоту можете расчитать сами.
Доброго.
1) оказалось до 100 гц, далее просто не надо. Для LED например такая частота мерцаний сливается в почти ровное свечение.
2) да и в паскале. В бейсике обязательно, т.к там не было функций-процедур (про ZX-BASIC), в надстройках в виде BETA-BASIC,LASER,MEGA-BASIC было слабое подобие, уже не помню. Поэтому там и этот оператор был необходим.
Выбор - по какой-то нажатой клавише - GOTO строка. Вот когда полноценные процедуры-функции появились, тогда отпала не обходимость скакать по единой программе по кускам.
3) конечно, это прозрачно для программиста.
4) пока работает. Отдельный генератор помимо программы.