Так вроде как после обработки прерывания контроллер продолжит выполнение с того места где был прерван. Потому что при переходе на прерывание адрес сохраняется в стеке
Последний раз редактировалось Chip; 04.12.2009 в 01:03.
Тут дело в том, что переменная ptl, с которой происходит работа не 1-байтная. Поэтому загрузка ее в стек или в регистры (что более вероятно для этих контроллеров) для вызова функции происходит за несколько команд. Существует вероятность, что в течении этих команд произойдет вызов прерывания. И это может изменить часть содержимого, загружаемого в стек. А может также сыграть при очистке.
Пример - пусть переменная
uint16 volatile tpl
(volatile - чтобы в памяти была, иначе может оказаться в регистрах, тогда код будет чуть другой, но суть останется той же)
В ней находится какое-то значение. Происходит вызов функции, который внутри представляет последовательное чтение памяти и занесение ее в регистры
Выглядит это примерно так
LDD R24,Y+1 Load indirect with displacement - первый байт
LDD R25,Y+2 Load indirect with displacement - второй байт
CALL 0x0000010C Call subroutine
Потом очищение
тоже последовательными записями в память
LDI R24,0x00 Load immediate - загрузили 0 в регистр
STD Y+1,R24 Store indirect with displacement записали первый 0
STD Y+2,R24 Store indirect with displacement записали второй 0
Есть почти нулевая вероятность в момент считывания или записи значения только наполовину, получить прерывание, которое изменит содержимое памяти, причем обеих половинок!
Грубо говоря, в результате можно получить ситуацию, при которой первая половина уже обнулена, в этот момент вызывается прерывание, которое прописывает данные в ОБА байта памяти, а потом срабатывает второй STD и записывает 0 во второй байт памяти.
В результате у нас в переменной получится очень странное значение с точки зрения кода. Причем это будет крайне редкая ситуация, которую сымитировать невозможно.
Это я говорю как человек, собаку съевший на одновременном доступе к памяти, правда на x86 и многозадачности. Там все строго - пока переменная умещается в регистр и операция с ней производится за одну команду - делай с нейй почти чего хочешь (но все равно - в рамочках!). Но попробуешь такой финт провернуть с int64 - сходу можешь такого огрести... Там для этого существуют критические секции. Тут критических секций нет, но поскольку задержка в 10-20 тактов для прерываний не критична, можно спокойно вырубить прерывания на время прохождения такого куска.
UPD:
2 Chip: в обработке прерывания нет смысла выключать прерывания, это и так делает сам микроконтрорллер.
Вот кусок описания прерываний AVR
When an interrupt occurs, the Global Interrupt Enable I-bit is cleared and all interrupts are disabled. The user software can write logic one to the I-bit to enable nested interrupts. All enabled interrupts can then interrupt the current interrupt routine. The I-bit is automatically set when a Return from Interrupt instruction – RETI – is executed.
Последний раз редактировалось SBorovkov; 04.12.2009 в 05:22.
Подключение датчиков (тормоза, поворотники... (+) ) через транзисторы, как по схемам Urvin ?
Спасибо, за подробное разъяснение .
Хотя потеря 1 - 3 значений даже через раз, никак не скажется работе тахометра
PHP код:
#define etaho 2
unsigned long time, tpl;
void setup()
{
pinMode(etaho, INPUT);
digitalWrite(etaho, HIGH); // подключить подтягивающий резистор
attachInterrupt(0, taho, FALLING); // настроить прерывание при перепаде с высокого в никий
Serial.begin (115200);
}
void loop()
{
if (tpl > 0) //проверить срабатывание прерывания
{
cli;
temp_tpl = tpl;
tpl=0;
sei;
Serial.println( temp_tpl, DEC); // отправить значение компьютеру
}
}
// обработка прерывания
void taho()
{
tpl=millis()-time; //считаем время между импульсами
time = millis(); //обнулить счетчик
}
Последний раз редактировалось Chip; 04.12.2009 в 20:00.
Вот так будет оптимальней (без циклов и прерываний) определяет импульс от120мкс
Код HTML:unsigned long time, tpl ,temp_tpl; boolean act = false; void setup() { Serial.begin (115200); } void loop() { if (analogRead(1) > 600) { // проверка на высокий уровень if (!act){ //проверка было ли начало импульса tpl = micros(); act = true; // установить метку высокого уровня } }else{ if (act){ // при низком уровне зафиксировать длительность импульса time = micros()-tpl; act = false; // установить метку низкого уровня } }; if (micros() - temp_tpl > 500000){ // задержка на вывод результата Serial.println( time , DEC); // отправить значение компьютеру temp_tpl = micros(); // начало задержки } }
Последний раз редактировалось Rush; 04.12.2009 в 19:46.
С использованием прерывания , было бы лучше при выполнении нескольких задач.
Так теперь прерывание можно использовать для других целей
А если поставишь ИК приемник , будет либо посылки с пульта пропускать либо импульсы тахометра
Вот вы и пришли к тому, что не хватает прерываний на ардуине :-).
Atmega168 имеет очень развитый механизм периферии. В том числе при измении состояния любой ноги может быть вызвано прерывание. Правда прерываний меньше, чем ног у процессора, но это решаемая проблема.
А еще на atmega можно запустить АЦП на ноге и заниматься дальше делом. А как преобразование закончится, по прерыванию начать новое преобразование на этой же или другой ноге. И это все почти не будет есть процессорного времени, несмотря на то, что АЦП может работать до 260мкс.
Эту тему просматривают: 5 (пользователей: 0 , гостей: 5)