• Witaj na Forum Arduino Polska! Zapraszamy do rejestracji!
  • Znajdziesz tutaj wiele informacji na temat hardware / software.
Witaj! Logowanie Rejestracja


Ocena wątku:
  • 0 głosów - średnia: 0
  • 1
  • 2
  • 3
  • 4
  • 5
Milisekundomierz do badania czasu trwania impulsów i przerw.
#1
Witam, od jakiegoś czasu walczę z programem dla arduino uno. Postanowiłem zaryzykować i zamiast zdawać egzaminu na studiach zrobić milisekundomierz do badania spz na laboratorium. Jako iż wcześniej programowałem tylko plc, arduino było dla mnie dość nowe (ld czy fb a c to jednak różnica). Zadanie zaczęło mnie trochę przerastać gdyż doświadczenia z arduino miałem mało. 
Ogólne założenia programu:
- jeden impuls wejściowy (stan wysoki gdy spz wykrywa zwarcie), co prawda ma ona wewnętrznie przełączalne styki ale jest to "zabudowane" w logice i raczej nie mam do tego dostępu więc zostaje tylko ten jeden.
- program ma mierzyć czas trwania każdego z impulsów (maksymalnie 3) i czas trwania przerw między impulsami (dwie), zprzypisywać każdy czas do osobnej zmiennej, jeśli spz był np jednokrotny i po jednym impulsie w stanie wysokim, czas przerwy jest dłuższy niż 7 sekund, ma wyświetlać komunikat "spz jednokrotny"
- wszystko zrobione jest na czterosegmentowym wyświetlaczu, program ma wyświetlać czasy trwania impulsów, a po wciśnięciu przycisku czasy trwania przerw.

Program zrobiłem, korzystając funkcji millis(), tylko mam z nim kilka problemów z którymi nie mogę sobie poradzić. Udało mi się ustawić to tak że mierzy czas od zera dla każdego z impulsów, jednak gdy np zmierzy czas pierwszego impulsu i zostanie on utrwalony (na wyświetlaczu) to podczas trwania drugiego, ten pierwszy przyjmuje jego wartość itd. Gdy zmienia się czas jakiegokolwiek czasu, cała reszta zmienia wartości, przy czym warunek to żeby każdy czas został zapamiętany.

Kod:
int sygnal_pin = 13;
float tz1;
float tz2;
float tz3;
float tw1;
float tw2;
int impuls;
float zegar;
float zegar1;
float zegar2;
float zegar3;
float zegar4;
int cykl_spz;
boolean spz_jednokrotny;
boolean spz_dwukrotny;
boolean spz_trzykrotny;





void setup()
{
 pinMode(sygnal_pin, INPUT);
 pinMode (2, INPUT);
 lcd.begin(16,2);
}

void loop()
{
 if(digitalRead(sygnal_pin) == LOW)
 {
   zegar=millis();
 }
 if(digitalRead(sygnal_pin) == HIGH) // pierwsze zadziałanie spz
 {
   tz1=(millis() - zegar)/100;
   zegar1=millis();
 }
 if (digitalRead(sygnal_pin) == LOW && tz1>0 && spz_jednokrotny == false) // pierwsza przerwa
 {
   tw1 = (millis()-zegar1)/100;
   cykl_spz = 1;
   zegar2 = millis();
 }
 if (cykl_spz == 1 && tw1>=7.0) //informacja że spz był jednokrotny jeżeli przerwa trwa dłużej niż 7 sekund
 {
   spz_jednokrotny = true;
   lcd.setCursor(0,2);
   lcd.print("spz jednokrotny");
 }
 if (digitalRead(sygnal_pin) == HIGH && cykl_spz == 1 && spz_jednokrotny == false)
 {
  tz2 = (millis() - zegar2)/100;
  zegar3 = millis();
 }    
 if (digitalRead(sygnal_pin) == LOW && tz2>0)
 {
   tw2=(millis()-zegar3)/100;
   zegar4 = millis();
   cykl_spz = 2;
 }
  if (cykl_spz == 2 && tw2>=7.0) //informacja że spz był dwukrotny jeżeli przerwa trwa dłużej niż 7 sekund
 {
   spz_dwukrotny = true;
   lcd.setCursor(0,2);
   lcd.print("spz dwukrotny");
  }
 if(digitalRead(sygnal_pin) == HIGH && cykl_spz == 2 && spz_dwukrotny == false)
 {
  tz3=(millis() - zegar4)/100;
  cykl_spz = 3;
  spz_trzykrotny = true;
 }
 if (digitalRead(sygnal_pin) == LOW && spz_trzykrotny == true) // koniec pomiaru - spz trzykrotny.
 {
   lcd.setCursor(0,4);
   lcd.print("spz trzykrotny");
 }
 if (digitalRead(2) == HIGH)
 {
   lcd.setCursor(0, 0);
     lcd.print("tz1");
   lcd.setCursor(7, 0);
     lcd.print(tz1);
    lcd.setCursor(0, 1);
     lcd.print("tz2");
   lcd.setCursor(7, 1);
     lcd.print(tz2);
   lcd.setCursor(0, 2);
     lcd.print("tz3");
   lcd.setCursor(7, 2);
     lcd.print(tz3);
 }
 else
 {
   lcd.setCursor(0, 0);
     lcd.print("tw1");
   lcd.setCursor(7, 0);
     lcd.print(tw1);
   lcd.setCursor(0, 1);
     lcd.print("tw2");
   lcd.setCursor(7, 1);
     lcd.print(tw2);
}
}
 
Wiem że kod programu jest przepełniony błędami i pewnie zawiera dużo błędów, ale czy jest ktoś kto będzie w stanie mnie naprowadzić co robię źle ? np czas tz1, gdy tylko zaczyna bić licznik tz2 zmienia wartość na tz1=tz2. Będę wdzięczny za jakieś wskazówki.

Ewentualnie może znajdzie się ktoś chętny aby pomóc przy tym kodzie, poprawić go, rozumiem że nikt nie chce tracić czasu więc mogę zaoferować jakąś opłatę za pomoc. Oczywiście układ fizycznie już mam.


Dzięki.
 
Odpowiedź
#2
Witam,
Jeśli ma to być dokładne to użyj funkcji micros() lub przerwań do wykrywania impulsu.
Pozdrawiam.
 
Odpowiedź
#3
Po co się tak męczyć? Poczytaj o funkcji pulseIn.
Jak będziesz miał z nią problem, to Ci pomogę, ale w tej chwili leżę chory, więc ni mogę o tym myśleć.
Jeśli masz problem z kodem lub sprzętem, zadaj pytanie na forum. Nie odpowiadam na PW, jeśli nie dotyczą one spraw forum lub innych tematów prywatnych.

[Obrazek: SsIndaG.jpg]
 
Odpowiedź
#4
Tylko czy funkcja pulseIn pozwoli na bezstratny pomiar czasu wszystkich pięciu następujących po sobie zmian stanu?
 
Odpowiedź
#5
Poczytam, priorytetem jak iż ma to służyć na stanowisku laboratoryjnym jest dokładność. Aczkolwiek będę porównywał wynik z arduino z milisekundomierzem laboratoryjnym i programowo mogę wprowadzić jakieś korekty ewentualnego laga. O funkcji pulseIn z pewnością poczytam jutro z rana.
 
Odpowiedź
#6
Próbowałem funkcji pulseIn ale nie wiem dlaczego przy prostym kodzie:

Kod:
#include <LiquidCrystal.h>


LiquidCrystal lcd(7, 8, 9, 10, 11, 12);


unsigned long tz1;


void setup()

{

 pinMode(13, INPUT);
 lcd.begin(16, 2);

}

void loop()
{
if(digitalRead(13) == HIGH)
{
 tz1 = pulseIn(13, HIGH);
}
 lcd.setCursor(0,0);
 lcd.print(tz1);
}
Mierzy czas trwania impulsu ale dopiero drugiego. Tzn jak podam raz, to pokazuje 0, po rozwarciu pinu i ponownym zwarciu dopiero wyświetli się czas jego trwania. Jakiś mój błąd w programie czy po prostu to tak działa ?

Dzięki za poprzednie podpowiedzi.
 
Odpowiedź
#7
Ano dla tego, że program wywoła funkcję pulseIn dopiero po spełnieniu warunku if(digitalRead(13) == HIGH)
Funkcja pulseIn czeka na stan pinu określony w parametrach i mierzy czas trwania tego stanu, więc sama sobie poczeka na ten warunek.
Wystarczy więc napisać:

Kod:
void loop()
{

tz1 = pulseIn(13, HIGH);

lcd.setCursor(0,0);
lcd.print(tz1);
}
Jeśli masz problem z kodem lub sprzętem, zadaj pytanie na forum. Nie odpowiadam na PW, jeśli nie dotyczą one spraw forum lub innych tematów prywatnych.

[Obrazek: SsIndaG.jpg]
 
Odpowiedź
#8
Witam,
Coś w deseń (bez uwzględniania 7 s kontroli):
void loop()
{
long time1, time2, time3.......
while(!digitalRead(13)) {};
time1 = millis();
while(digitalRead(13)) {};
time2 = millis();
while(!digitalRead(13)) {};
time3 = millis();
...
long imp1high = time2 - time1;
long imp1low = time3 - time2;
...
}
 
Odpowiedź
#9
A ja bym to zrobił miej więcej tak.
Trzeba tylko wywalić wyświetlanie wyników do tych ifów, bo one zabierają cykle zegara.
Później to zmienię.
Kod PHP:
void pomiar(){

tz1 pulseIn(13HIGH);
 
   lcd.setCursor(00);
 
   lcd.print("tz1");
 
   lcd.setCursor(70);
 
   lcd.print(tz1);


tw1 pulseIn(13LOW,7000000);
 
   lcd.setCursor(00);
 
   lcd.print("tw1");
 
   lcd.setCursor(70);
 
   lcd.print(tw1);

if (
tw1==0
{
    
lcd.setCursor(0,2);
 
   lcd.print("spz jednokrotny");
    return;
}


tz2 pulseIn(13HIGH);
 
   lcd.setCursor(01);
 
   lcd.print("tz2");
 
   lcd.setCursor(71);
 
   lcd.print(tz2);



tw2 pulseIn(13LOW),7000000;
 
   lcd.setCursor(01);
 
   lcd.print("tw2");
 
   lcd.setCursor(71);
 
   lcd.print(tw2);

if (
tw2==0
{
    
lcd.setCursor(0,2);
 
   lcd.print("spz dwukrotny");
    return;
}


tz3 pulseIn(13HIGH);
 
   lcd.setCursor(02);
 
   lcd.print("tz3");
 
   lcd.setCursor(72);
 
   lcd.print(tz3);


Funkcja pulseIn liczy z dokładnością do 3μS.
Jeśli chcesz większej dokładności, to przesiądź się na inną platformę.
Ja mam na przykład płytkę Nucleo F091 napędzaną generatorem 48Mhz i dokładność wzrasta do 1μS, ale STM'y F411 śmigają na 100Mhz i podejrzewam, że błąd pomiarowy będzie mniejszy niż w urządzeniach laboratoryjnych.
Jeśli masz problem z kodem lub sprzętem, zadaj pytanie na forum. Nie odpowiadam na PW, jeśli nie dotyczą one spraw forum lub innych tematów prywatnych.

[Obrazek: SsIndaG.jpg]
 
Odpowiedź
#10
Robsonie, czy Twoja propozycja nie będzie określać parametrów co któregoś impulsu? Jeśli funkcja mierzy długość stanu high to kończy mierzyć gdy nastąpi stan Low. Kolejne wywołanie funkcji, tym razem dla stanu niskiego będzie czekać aż taki się zacznie, czyli w tzw. międzyczasie nie będą zmierzone stan niski i stan wysoki. Czy moje rozumowanie jest poprawne?
 
Odpowiedź
  


Skocz do:


Przeglądający: 1 gości