Skocz do zawartości
Komentator

Kurs Arduino II - #4 - przerwania, kontaktron, czujnik PIR

Pomocna odpowiedź

Witam

Mam pytanie odnośnie przerwań. Muszę przerwać program przy pomocy potencjometru, którego nie mogę podpiąć do pinu 2 lub 3 (arduino nano v3). Jak inaczej mogę zrobić przerwanie dla wyjścia np z pętli while. W programie chodzi o utrzymywanie obrotów w pewnym zakresie, jednak przy spadku poniżej 750obr i przy skręconym potencjometrze prawie w granice minimum program ma automatycznie podnosić dopływ wody do turbinki. Najbardziej chodzi mi o to żeby w danej chwili gdy przekręcę potencjometrem program natychmiast zareagował, odebrał dane i sterował servem z odczytów potencjometru.

Poniżej zamieszczam kawałek kodu programu.

while (obroty < 750 && potencjometr < 6) {
        potencjometr = potencjometr + 2 ;
}

  if (potencjometr > 10) {
     servoG.write(potencjometr);
  }

Edit:

Znalazłem taki program w tutorialu odnośnie używania timera jako przerwania.

#include <SPI.h>
// przypisanie pinów
#define ZATRZASK 4
// deklaracja rozmiaru matrycy
#define ILOSC_WIERSZY 5
#define ILOSC_BAJTOW 2
#define ROZMIAR_EKRANU ILOSC_WIERSZY*ILOSC_BAJTOW  // rozmiar pamięci ekranu (w bajtach)

// definicja struktury danych pamięci obrazu matrycy
struct t_Matryca {  
 char dane[ILOSC_WIERSZY][ILOSC_BAJTOW];
};
t_Matryca m_Ekran; // deklaracja zmiennej m_Ekran przechowującej zawartość ekranu
char m_Wiersz = 0; // numer aktualnie wyświetlanego wiersza (iterator)

unsigned int cykl = 0; // licznik do pomiaru czasu pomiędzy zmianami obrazu
char d_obrazek1[ROZMIAR_EKRANU] = {8,32,252,126,254,254,252,126,8,32}; // definicja obrazka1
char d_obrazek2[ROZMIAR_EKRANU] = {32,8,126,252,254,254,126,252,32,8}; // definicja obrazka2

// ****************** funkcje obsługi ekranu 

// funkcja wyświetla na ekranie zawartość tablicy podanej jako parametr
void mPoka(char zawartosc[ROZMIAR_EKRANU]){
 memcpy(&m_Ekran,zawartosc,ROZMIAR_EKRANU);  //kopiowanie zawartości zmiennej do pamięci ekranu
}

// funkcja odwraca wszystkie bity matrycy
void mNegatyw(){
 for(char wiersz=0;wiersz<ILOSC_WIERSZY;wiersz++){
   for(char bajt=0;bajt<ILOSC_BAJTOW;bajt++) {
     m_Ekran.dane[wiersz][bajt]=~m_Ekran.dane[wiersz][bajt];
   }
 }
}

// **************** kod główny

void setup()
{
 SPI.begin();
 pinMode(ZATRZASK, OUTPUT);  
 cli(); // zatrzymaj wykonywanie jakichkolwiek przerwań
 TCCR2A = 0;// zerujemy rejestr kontrolny A
 TCCR2B = 0;// zerujemy rejestr kontrolny B
 TCNT2  = 0;// zerujemy licznik 
 OCR2A = 124;// = (16000000) / (500*256) - 1 
 TCCR2A |= (1 << WGM21);  // ustawiamy timer2 w tryb obsługi przerwań (CTC)
 TCCR2B |= (1 << CS12);     // ustawiam dzielnik na 256
 TIMSK2 |= (1 << OCIE2A); // wzkazujemy że przerwanie ma być wywołane dla rejestro OCR2A
 sei();//zezwalamy na wykonywanie przerwań
};

// funkcja obsługi przerwania timera 2
// w której odświeżamy wiersz matrycy
ISR(TIMER2_COMPA_vect){ 
 digitalWrite(ZATRZASK,LOW);
 SPI.transfer(~(1<<3+m_Wiersz));
 SPI.transfer(m_Ekran.dane[m_Wiersz][1]);
 SPI.transfer(m_Ekran.dane[m_Wiersz][0]);
 digitalWrite(ZATRZASK,HIGH);
 m_Wiersz++; // przesunięcie do kolejnego wiersza
 if (m_Wiersz==ILOSC_WIERSZY) m_Wiersz=0; // sprawdzenie zakresu
}

void loop()
{
   mPoka(d_obrazek1); // wyświetlamy obrazek 1
   delay(500);        // czekamy 500ms
   mPoka(d_obrazek2); // wyświetlamy obrazek 2
   delay(500);
   mPoka(d_obrazek1); // wyświetlamy obrazek 1 w negatywie
   mNegatyw();
   delay(500);
   mPoka(d_obrazek2); // wyświetlamy obrazek 2 w negatywie
   mNegatyw();
   delay(500);
}

Wszystko spoko mniej więcej wiem jak ustawić ten czas Timera, jak ustawić który Timer ma to wykonywać. Dalej jednak nie rozumiem dwóch rzeczy.

1. Czy to przerwanie w podesłanym programie działa cały czas a po jego zakończeniu odpala się to co jest w loop, później znowu przerwanie i tak w kółko ?

2. Jak wywołać przerwanie aby zadziałało w moim przypadku. Zakończenie wykonywania pętli while przekręceniem potencjometru

Udostępnij ten post


Link to post
Share on other sites

RaQu, witam na forum 🙂 Raczej ciężko będzie z opcją generowania przerwania potencjometrem, ponieważ potencjometr normalnie podłączamy do wejść analogowych, a przerwania są na innych pinach. Mógłbyś podłączyć potencjometr bezpośrednio do pinu przerwania i wykrywać zmianę stanu wejścia (jednak koniecznie byłoby zawsze pełne przekręcenie potencjometru). W takim przypadku tracimy zalety potencjometru i ograniczmy się wykorzystywania go w dwóch skrajnych stanach - czyli identycznie, gdyby był tam zwykły przycisk 🙁

Udostępnij ten post


Link to post
Share on other sites

Witam 🙂

Właśnie dlatego zastanawia mnie fakt jak rozwiązać ten problem programowo. Bo gdybym np chciał przerwanie przy kliknięciu przycisku to wtedy sprzętowo sprawdza się fajnie, niestety potrzebuję przerwania na reakcję zmiany stanu na potencjometrze 😋. Może dałoby się zrealizować program tak żeby każda zmiana potencjometru wysyłała na pin 2 stan wysoki i wtedy sygnał odbierany byłby jako przerwanie ?

Udostępnij ten post


Link to post
Share on other sites

RaQu, nie wydaje mi się, aby było jakieś rozwiązanie programowe, które pozwoli w takiej sytuacji wywoływać przerwania sprzętowe na Arduino. Proponowałbym się zastanowić czy na pewno potrzebujesz takiego działania układu... Może program da się napisać jakoś inaczej? Ciężko mi wpaść na pomysł urządzenia, które wymagałoby sprzętowego przerwania, przy każdym dotknięciu potencjometru...

Ewentualnie zamiast potencjometru można podłączyć enkoder - takie coś jak potencjometr, ale obraca się ciągle, bez ograniczenia i przy każdym "kliknięciu" zmienia sygnał na swoim wyprowadzeniu. Tylko wtedy musisz programowo kontrolować wartość minimalną i maksymalną.

  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites

Witam,

Dlaczego mi nie działa czujnik ruchu PIR ? Działa tylko jak go dotknę z tyłu palcem albo w niego dmucham. 😥

Udostępnij ten post


Link to post
Share on other sites

Everox123, witam na forum! To bardzo dziwny objaw - czy na pewno wszystko masz podłączone tak jak w artykule + odpowiednio skręciłeś potencjometry?

Udostępnij ten post


Link to post
Share on other sites

Everox123, jeśli wszystko masz odpowiednio podłączone i czujnik nie wykrywa ruchu (ani z bliska, ani z daleka), to pozostaje tylko kontakt ze sprzedawcą i wymiana. Do tej pory nikt wcześniej nie miał takiego problemu - może to jakieś jednostkowe uszkodzenia 😉

Udostępnij ten post


Link to post
Share on other sites

Zabrakło słówka o wyłączeniu zezwolenia na przerwania 🙂

A zatem chciałbym bardzo konkretnie zapytać: czy jest możliwe w arduino wyłączenie zezwolenia na przerwanie od konkretnego externala? Znalazłem niestety tylko komendę globalnego wyłączenia zezwolenia na przerwanie, a nie o to mi chodzi (mam 3 enkodery, z czego jeden ma być odczytywany cały czas, a 2 pozostałe przez część programu mają nie wprowadzać żadnej reakcji).

Udostępnij ten post


Link to post
Share on other sites

mati3594, jeśli masz 3 enkodery i 3 przerwania to chyba nie korzystasz z opisywanego tutaj Arduino UNO? Jaki masz dokładnie układ? W przypadku Arduino Due mógłbyś wykorzystać funkcję detachInterrupt(), która pozwala na wyłączenie przerwania na danym pinie.

Udostępnij ten post


Link to post
Share on other sites

Dokładnie z DUE korzystam, właśnie tej opcji potrzebowałem, dzięki 🙂

Udostępnij ten post


Link to post
Share on other sites

hej

mega fajny artykuł! idealny do nauki :)

mam taki maly problem, bo napisalem prosty program ktory, jeśli odległość wskazania czujnika jest mniejsza niż 100 cm to włącza monitor i wyświetla tą wartość na monitorku przez 5 sek.

cały kod tutaj

#define trigPin 12
#define echoPin 11

// odpalenie monitorka
#include <LiquidCrystal_I2C.h>
#define I2C_ADDR 0x3F
LiquidCrystal_I2C lcd(I2C_ADDR, 16, 02);

void setup() {
  pinMode(trigPin, OUTPUT); //Pin, do którego podłączymy trig jako wyjście
  pinMode(echoPin, INPUT); //a echo, jako wejście

  // initialize the LCD
  lcd.init();  

}


void loop() {
  //urochomienie i ustawienie czujnika odległości
  long czas, dystans;
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  czas = pulseIn(echoPin, HIGH);
  dystans = czas / 58;

if (dystans<100) // jeśli dystans jest mniejszy uruchom procedurę poniżej

{

 lcd.backlight();
 lcd.clear(); 
// lcd.setCursor(0,0);
 lcd.setCursor(0,1);
 lcd.print("Dystans: ");
 lcd.print(dystans);
 lcd.print("cm");
 delay(5000);



}
else {
  lcd.noBacklight();
  delay(100);
      }

}

No i dziala calkiem fajnie, ale czasem, tak od tzw. czapy włacza sie monitor i pokazuje np 5 cm... chociaż nic przy nim nie ma.

O co może chodzić??

Udostępnij ten post


Link to post
Share on other sites

Ale czujnik twierdzi inaczej :-). Jeśli uważasz, że się myli to może nie wystarcza pojedynczy pomiar do podjęcia decyzji o włączeniu monitora, a np. tych pomiarów powinno być więcej coś jak ping w świecie sieci. Jedno zapytanie ICMP polecenia ping może dać wynik końcowy inny niż np. seria 4 takich zapytań. Popularne HC-SR04 to słabej jakości czujniki. Autor biblioteki newping próbował znaleźć na to receptę - zobacz dołączone przykłady.

  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites
2 minuty temu, Belferek napisał:

Ale czujnik twierdzi inaczej :-). Jeśli uważasz, że się myli to może nie wystarcza pojedynczy pomiar do podjęcia decyzji o włączeniu monitora, a np. tych pomiarów powinno być więcej coś jak ping w świecie sieci. Jedno zapytanie ICMP polecenia ping może dać wynik końcowy inny niż np. seria 4 takich zapytań. Popularne HC-SR04 to słabej jakości czujniki. Autor biblioteki newping próbował znaleźć na to receptę - zobacz dołączone przykłady.

dzięki za tak szybką odpowiedź 🙂 a dołączysz też wspomniane przykłady?

Udostępnij ten post


Link to post
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »

×