Ultraäänipähkinä

Kehittelen tässä koodia jolla voisi lukea useita yhtäaikaa laukaistuja ultraäänisensoreita. Sensorit toimivat siten, että niille annetaan väh 10us pulssi trigger-pinniin, sensori lähtettää aallot matkaan. Kun ne palaavat, sensori palauttaa echo pinnistä n. 150us- 25ms pulssin joka on suhteessa mitattuun etäisyyteen. Tyypillisesti näitä käytetään siten että sensoreita luetaan vuoronperään.

Ajattelin koettaa lukea näitä kerralla useampia siten, että luetaan port registeristä inputtien tilaa nopeana luuppina ja aina muutoksen tullessa talletaan luuppien määrä ja tieto siitä mikä pinni on ylhäällä. Sitten voisi laskea mittanauhan avulla mitä matkaa yksi kierros laskurissa vastaa matkassa.

En kuitenkaan saanut tätä toimimaan järkevästi. Mikä alla olevassa kahden sensorin koodissa tai logiikassa mättää. Omat aivot jumittaa näköjään. Ohjelma pyörii mutta tuottaa vain vähän vaihtuvia lukemia joissa ei ole oikein järkeä.
esim.
128sensori
523aika
64sensori2
530aika2

Tämä riippumatta mikä on etäisyys ja kumpaan sensoriin on lyhyempi etäisyys. Aika vaihtelee hiukan. Ei kait tuossa luupissa voi niin kauan kestää ettei se ehdi lukemaan sisään tulevia pulsseja?

#define trigPin 12
#define echoPin 7
#define echoPin2 6

byte eka = 0; //näihin tallennetaan tulokset
unsigned long ekaAika = 0;
byte toka = 0;
unsigned long tokaAika = 0;


void setup() {
  Serial.begin (9600);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
   pinMode(echoPin2, INPUT);
//DDRD = B00000010;  // sets Arduino pins 2 to 7 as inputs, pin 0 as input
}

void loop() {
  byte portti = B00000000;
  byte maski =  B11000000;
  byte lukema = B00000000;
  unsigned long aika = 0;
  
  digitalWrite(trigPin, HIGH); // aktivoidaan sensorit, molempien
  delayMicroseconds(20); // triggerit kytketty samaan pinniin
  digitalWrite(trigPin, LOW);
  
  while(lukema == portti)// luetaan inputit kunnes joku pinneistä 
                          // saa signaalin
  {
  lukema = PIND & maski; //luetaan maskin avulla vain halutut pinnit
  ++aika;                // kasvatetaan laskuria
}
eka = lukema;       //tallentaan missä pinnissä signaali
ekaAika = aika; 
maski = lukema ^ maski; // poistetaan maskista jo luettu pinni
lukema = B00000000; 

  while(lukema == portti){
  lukema = PIND & maski;
  ++aika;
}
toka = lukema;
tokaAika = aika;
maski = lukema ^ maski;
lukema = B00000000;

  
  


   Serial.print(eka);
   Serial.println(" sensori");
      Serial.print(ekaAika);
   Serial.println(" aika");
      Serial.print(toka);
   Serial.println(" sensori2");
      Serial.print(tokaAika);
   Serial.println(" aika2");
   Serial.println(" XXX");

   portti = B00000000;
  maski = B11000000;
  aika = 0;

  delay(500);
}

Laita laskuri pyörimään. Silloin ei tarvitse arpoa silmukan kestoa.

Omista AVR seikkailuista on hieman aikaa ja Arduinoa en ole koskaan joten ota koodini reilun suolan kanssa.

Miten sitten meni pin change keskeytysten käyttö?

ISR voisi olla jotain tämän kaltaista:

volatile int sensorit[2][2]
PC_isr(){
   int sens =  selvitaMikaPinniMuuttui();
  if(mentiinYlos()){
    sensorit[sens][0] = laskurinArvo();
  }else{
    sensorit[sens][1]  = laskurinArvo();
  }
}

nyt tuosta sensorit taulukosta näkyy milloin muutos tapahtui. Ja keskeytykset pitää sallia, kun potkaisee sensorit käyntiin.

Kiitos Vuokko! Arvelinkin että koodipähkinä saattaa joutua pihteihisi :slight_smile:

Kuitenkin ettei heitetty pelastusrengas hukuta minua, pitää vähän tutkia noita avr-juttuja.

Sillävälin, onko koodin logiikassa joku ongelma, nimittäi olen miettinyt pääni puhki ja en keksi miksi tuo koodi ei toimisi…

Ainakin tuo toimii nyt väärin kuvaukseesi verrattuna.

ajan ei muuten tartte olla long. Jos Atmel kasvattaa lukua 10^6 kertaa sekunnissa, 32-bittiä riittää vallan mainiosti neljällä miljardilla. 16-bittiä pystyy mittaamaan 65ms kierroksella.

Tuolla pitäisi pystyä sanomaan, josko sensorit antavat jonkin mittaisen pulssin etäisyyden perusteella. Pulssin alkuhetkeä ei tuossa siis tiedetä, mutta sen lisääminen ei ole vaikeaa. Sillä ei tosin taida tehdä mitään.

#define trigPin 12
#define echoPin 7
#define echoPin2 6

unsigned long ekaAika = 0;
unsigned long tokaAika = 0;

void setup() {
  Serial.begin (9600);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(echoPin2, INPUT);
  //DDRD = B00000010;  // sets Arduino pins 2 to 7 as inputs, pin 0 as input
}

void loop() {
  byte maski =  B11000000;
  byte lukema = B00000000;
  
  digitalWrite(trigPin, HIGH); // aktivoidaan sensorit, molempien
  delayMicroseconds(20); // triggerit kytketty samaan pinniin
  digitalWrite(trigPin, LOW);
  ekaAika = 0;
  tokaAika = 0;
  //Hengataan ja odotetaan kunnes pinni värähtää
  while(lukema == 0){
    lukema = PIND & maski;
  }
  while(lukema != 0){
    //Pöljä tapa mitata. Kierrosaika vaihtelee. Proof of concept vain.
    lukema = PIND & maski;
    if(lukema & 0x80){
      ekaAika++;
    }
    if(lukema & 0x40){
      tokaAika++;
    }
  }
  Serial.println(" sensori");
  Serial.print(ekaAika);
  Serial.println(" aika");
  Serial.println(" sensori2");
  Serial.print(tokaAika);
  Serial.println(" aika2");
  Serial.println(" XXX");
  delay(500);
}

Ongelma taisikin olla kyseisen sensorin harhaanjohtavassa “datalehdessä” jota jotkut sen myyjistä jakelevat. Nimittäin toisin kuin siinä oppaassa sanotaan: lähtevän pulssin ja echon väliä mittaamalla ei taida voidakkaan mitata äänen kulkemaa matkaa.

Ilmeisesti laukaisun jälkeen on hyvin lyhyt tauko jonka aikana lähetetään ultraäänipulssit. Sitten echo pinni aktivoituu ja menee taas pois päältä kun kaiku palaa. Alkuperäinen koodini mittasi siis tämän lyhyen pulssin lähetysajan, siitä johtuen staattiset lukemat.

Niimpä sitä tuli haaskattua omaa ja lähimmäisten aikaa mokoman läpyskän takia…mrh

Virheisiin haaskattua aikaa ei ole olemassakaan. Mitä enemmän virheen selvittämiseen käyttää aikaa, sitä todennäköisemmin siitä oppii myös jotain :unamused:

Totta, aina oppii. Mutta olisi mukavampi haaskata aikaa omiin kuin muiden tekemiin virheisiin :slight_smile: