Различия

Показаны различия между двумя версиями страницы.

Ссылка на это сравнение

Предыдущая версия справа и слеваПредыдущая версия
Следующая версия
Предыдущая версия
products:laboratory_iot_c:exp36 [2024/11/17 16:19] – [Программный код эксперимента] labuser30products:laboratory_iot_c:exp36 [2024/11/17 17:04] (текущий) – [Программный код эксперимента] labuser30
Строка 65: Строка 65:
 } }
  
-void ICACHE_RAM_ATTR callback(){+void ICACHE_RAM_ATTR callback() {
   bool value_a = digitalRead(ENC_A);   bool value_a = digitalRead(ENC_A);
   bool value_b = digitalRead(ENC_B);   bool value_b = digitalRead(ENC_B);
Строка 92: Строка 92:
   lcd.init();    lcd.init(); 
   lcd.setBacklight(0);    lcd.setBacklight(0); 
-  pinMode(ENC_A, INPUT_PULLUP); +  pinMode(ENC_A, INPUT); 
-  pinMode(ENC_B, INPUT_PULLUP);+  pinMode(ENC_B, INPUT);
  
   attachInterrupt(digitalPinToInterrupt(ENC_A), callback, CHANGE);   attachInterrupt(digitalPinToInterrupt(ENC_A), callback, CHANGE);
Строка 104: Строка 104:
  
 Сначала настраиваем прерывания: Сначала настраиваем прерывания:
-<code python[enable_line_numbers="2", start_line_numbers_at="56"]> +<code python[enable_line_numbers="2", start_line_numbers_at="64"]> 
-encA.irq(trigger=Pin.IRQ_FALLING | Pin.IRQ_RISINGhandler=callback) +  attachInterrupt(digitalPinToInterrupt(ENC_A), callback, CHANGE); 
-encB.irq(trigger=Pin.IRQ_FALLING | Pin.IRQ_RISINGhandler=callback)+  attachInterrupt(digitalPinToInterrupt(ENC_B), callback, CHANGE);
 </code> </code>
  
-Мы настроили, что при возникновении события изменения сигнала на выводах encA и encB с высокого на низкий (''Pin.IRQ_FALLING''или с низкого на высокий (''Pin.IRQ_RISING''будет вызываться обработчик прерывания — функция ''callback''.+Мы настроили при помощи указание события ''CHANGE'', что при возникновении события изменения сигнала на выводах ENC_A и ENC_A с высокого на низкий или с низкого на высокий  будет вызываться обработчик прерывания — функция ''callback''.
  
 Какие могут быть события: Какие могут быть события:
-  * Pin.IRQ_FALLING изменение с 1 на 0 +  * FALLING изменение с 1 на 0 
-  * Pin.IRQ_RISING изменение с 0 на 1 +  * RISING изменение с 0 на 1 
-  * Pin.IRQ_LOW_LEVEL наличие логического 0 +  * CHANGE любое изменение 
-  * Pin.IRQ_HIGH_LEVEL наличие логической 1+  * LOW наличие логического 0 
 +  * HIGH_LEVEL наличие логической 1
  
-События можно комбинироватьНапример, если нужна реакция и на событие ''Pin.IRQ_FALLING'' и ''Pin.IRQ_RISING'', то можно записать так: ''trigger=(Pin.IRQ_FALLING | Pin.IRQ_RISING)''.+Обратите внимание на новое ключевое слово ''volatile''Все переменные изменяемые из функции вызываемой прерыванием должны быть объявлены с этим ключевым словомНеобходимость обусловлена особенностями работой с памятью микроконтроллера.   
 +<code arduino[enable_line_numbers="2", start_line_numbers_at="16"]> 
 +volatile int count = 0; 
 +volatile int state = 0; 
 +volatile int state_old = 0; 
 +</code>
  
-Рассмотрим функцию- обработчик прерывания: +Рассмотрим функцию-обработчик прерывания, она в свою очередь объявлена с атрибутом ICACHE_RAM_ATT. Причина аналогична указанной для переменных выше.   
-<code python[enable_line_numbers="2", start_line_numbers_at="26"]> +<code arduino[enable_line_numbers="2", start_line_numbers_at="34"]> 
-def callback(p): +void ICACHE_RAM_ATTR callback() { 
-    global count +  bool value_a = digitalRead(ENC_A); 
-    global encB +  bool value_b = digitalRead(ENC_B);
-    global encA +
-    global states +
-    global old_state+
  
-    value_a encA.value(+  state index(value_a, value_b);
-    value_b = encB.value()+
  
-    current_state = states.index((value_a, value_b)) +  if ((state state_old == 1) or (state == 0 and state_old == 3)) { 
-     +    count++; 
-    if (current_state  old_state == 1) or (current_state == 0 and old_state == 3): +    if (not(count % 2)){ 
-        count += 1 +      Serial.println("+"); 
-        if not (count % 2): +      printLcd(count / 2); 
-            print('+'); +    } 
-            print_lcd(int(count/2)) +    state_old = state; 
-        old_state = current_state +  } 
-    elif (current_state  old_state == -1)  or (current_state == 3 and old_state == 0): +  else if ((state state_old == -1)  or (state == 3 and state_old == 0)) { 
-        count -= 1 +    count--; 
-        if not (count % 2): +    if (not(count % 2)){ 
-            print('-'); +      Serial.println("-"); 
-            print_lcd(int(count/2)) +      printLcd(count / 2); 
-        old_state current_state+    } 
 +    state_old state; 
 +  } 
 +}
 </code> </code>
  
 Она начинается с  Она начинается с 
-<code python[enable_line_numbers="2", start_line_numbers_at="27"]> +<code arduino[enable_line_numbers="2", start_line_numbers_at="35"]> 
-    global count +  bool value_a = digitalRead(ENC_A); 
-    global encB +  bool value_b = digitalRead(ENC_B);
-    global encA +
-    global states +
-    global old_state+
 </code> </code>
  
-Ключеваое слово ''global'' сообщает интерпретатору Python о том, что мы хотим использовать переменную, объявленную за пределами текущей функции. По умолчанию, все переменные, созданные внутри функции доступны (имеют //область видимости//) в пределах именно этой функции. Как только функция завершается такие переменные уничтожаются. Такие переменные называются //локальными//. Ключевое слово ''global'' дает возможность обратиться к //глобальной// переменной.+Здесь мы впервые объявляем переменные внутри функции. По умолчанию, все переменные, созданные внутри функции доступны (имеют //область видимости//) в пределах именно этой функции. Как только функция завершается такие переменные уничтожаются. Такие переменные называются //локальными//, а объявленные в основной программе  — //глобальными//.
  
 Потом, как и раньше, мы определяем текущее состояние линий A и B энкодера. Определяем индекс состояния и проверяем можем ли мы сделать переход в данное состояние. Потом, как и раньше, мы определяем текущее состояние линий A и B энкодера. Определяем индекс состояния и проверяем можем ли мы сделать переход в данное состояние.
Строка 162: Строка 164:
 Как мы заметили ранее, при одном щелчке энкодера происходит смена двух состояний энкодера. Чтобы одному щелчку соответствовало изменение счетчика на 1, мы просто проверяем счетчик на четность.  Как мы заметили ранее, при одном щелчке энкодера происходит смена двух состояний энкодера. Чтобы одному щелчку соответствовало изменение счетчика на 1, мы просто проверяем счетчик на четность. 
  
-<code python[enable_line_numbers="2", start_line_numbers_at="40"]> +<code arduino[enable_line_numbers="2", start_line_numbers_at="42"]> 
-         if not (count % 2): +    if (not(count % 2)){ 
-            print('+'); +      Serial.println("+"); 
-            print_lcd(int(count/2))+      printLcd(count / 2)
 +    }
 </code> </code>
  
Строка 172: Строка 175:
 Теперь самое главное. Обратим внимание на основной цикл программы. Мы в нем ничего не делаем. Все действия, связанные с работой с энкодером, происходят в обработчике прерывания и обрабатываются независимо от основной программы. В основном цикле мы можем заняться чем-то другим. В этом и смысл использования прерываний. Теперь самое главное. Обратим внимание на основной цикл программы. Мы в нем ничего не делаем. Все действия, связанные с работой с энкодером, происходят в обработчике прерывания и обрабатываются независимо от основной программы. В основном цикле мы можем заняться чем-то другим. В этом и смысл использования прерываний.
  
-<WRAP center round important 60%> +<WRAP center round info 80%> 
-В этом эксперименте мы производили настройку аппаратных средств микроконтроллера, а именно настраивали прерывания. Как мы уже узнали, работа прерываний не зависит от программы и происходит автоматическиЭто значит, что обработчик прерывания будет вызываться даже после завершения работы нашей программы, ведь настройки никуда не исчезли. Это может оказать влияние на следующие эксперименты, в которых не нужны эти прерывания. Они могут мешать. Для того, чтобы следующие эксперименты проходили нормально, **необходимо перезагрузить микроконтроллер**. Это можно сделать выдернув на некоторое время кабель USB или нажать на кнопку Reset на плате конструктора.+[[https://arduino.ru/Reference/Volatile|Подробнее о ключевом слове volatile в Arduino]] 
 + 
 +[[https://arduino.ru/Reference/AttachInterrupt|Подробнее о прерываниях в Arduino]] 
 </WRAP> </WRAP>
 +
 +