Arduino Output Tidsforhold

Fra Holstebro HTX Wiki
Skift til: navigering, søgning

Til normalt Arduino anvendes digitalWrite[1]

Denne metode/funktion tager noget tid, og det er dette der analyseres her.

Skrivning med digitalWrite

Et digitalt portben kan skrives højt eller lavt, og for at teste tiden omkring dette anvendes et lille test-program som vist herunder.

Programmet kan hentes som output_time1 i denne ZIP-fil.

byte pulsePin = 13;
byte signalPin = 8;

void setup() {
  pinMode(pulsePin, OUTPUT);
  pinMode(signalPin, OUTPUT);
}

void loop() {
  digitalWrite(signalPin, HIGH);
  digitalWrite(pulsePin, HIGH);
  digitalWrite(pulsePin, LOW);
  digitalWrite(pulsePin, HIGH);
  digitalWrite(pulsePin, LOW);
  digitalWrite(pulsePin, HIGH);
  digitalWrite(pulsePin, LOW);
  digitalWrite(pulsePin, HIGH);
  digitalWrite(pulsePin, LOW);
  digitalWrite(pulsePin, HIGH);
  digitalWrite(pulsePin, LOW);
  digitalWrite(pulsePin, HIGH);
  digitalWrite(pulsePin, LOW);
  digitalWrite(pulsePin, HIGH);
  digitalWrite(pulsePin, LOW);
  digitalWrite(pulsePin, HIGH);
  digitalWrite(pulsePin, LOW);
  digitalWrite(signalPin, LOW);
  delay(1);
}

Programmet sætter først et signal-output som man kan trigge på til måling af tiden og derefter skifter programmet et pulse-ben høj og lav, så hurtigt som muligt 8 gange.

Hvis man måler på dette får man følgende måling:
Måling af output med digitalWrite()
Måling af output med digitalWrite()

Som det kan ses på målingen, så tager det ca. 3,69μs for en høj periode og nogenlunde det samme for en lav periode. Der antages ikke at være forskel på det at sætte høj og lav.

Skrivning med digitalWrite

Et digitalt portben kan skrives højt eller lavt, og for at teste tiden omkring dette anvendes et lille test-program som vist herunder.

Programmet kan hentes som output_time2 i denne ZIP-fil.

byte pulsePin = 13;
byte signalPin = 8;

void setup() {
  pinMode(pulsePin, OUTPUT);
  pinMode(signalPin, OUTPUT);
}

void loop() {
  PORTB = B00000001;
  digitalWrite(pulsePin, HIGH);
  PORTB = B00100000;
  digitalWrite(pulsePin, LOW);
  PORTB = B00000001;
  delayMicroseconds(10);
  PORTB = B00000000;
  delay(1);
}

Programmet sætter først et signal-output, det gøres ved at skrive direkte i porten[2]. Derefter skifter programmet et pulse-ben højt med digitalWrite(), som man kan trigge på til måling af tiden. Hvorefter signalbenet sættes lavt igen (her er bit 5, der svarer til pin 13 holdt høj, for ikke at forstyrre det ben.

Fordelen ved at gøre det på denne måde er at en direkte skrivning i porten er det hurtigste vi kan gøre - det tage 0,0625μs, så vi kan næsten registrere hvornår der kaldes ind i digitalWrite og hvornår der er returneret fra den.

Der laves herefter det samme hvor digitalWrite kaldes for at sætte benet lavt.

Hvis man måler på dette får man følgende måling, hvor man kan se at koden forløber som forventet, også at signalbenet har en ekstra lang periode til sidst (lavet med delayMicroseconds):
Måling af output med digitalWrite()
Måling af output med digitalWrite()

Som det kan ses på målingen, så er benet højt i ca. 3,75μs, hvilket fint svarer til de 3,69μs som blev målt før for en høj periode med en ekstra instruktion på 0,0625μs ind imellem inden den sætter benet lavt igen.

Det man også kan se er at der går ret lang tid fra tidspunktet hvor digitalWrite kaldes til benet faktisk går højt (ca. 3,3μs), og fra bente går højt til der returneres går der kun omkring 0,4μs. Måler man nærmere på det som det gøres i visningen her under, så viser det sig at tiden fra kaldet til digitalWrite() til benet rent faktisk går højt er 3,25μs, mens tiden fra skiftet indtil den efterfølgende kode kører er 0,38μs. Usikkerheden i dette er at der bruges enkelt maskinoperationer til at etablere målingen, så de 0,0625μs en enkelt instruktion tager er fordelt ud over de to tider, men det giver en rigtig god ide om hvad der faktisk sker.

Måling af output med digitalWrite()
Måling af output med digitalWrite()

Præcist de samme tidsforhold han ses når digitalWrite() sætter benet lavt igen.

Skrivning til enkeltbit direkte til porten

Når vi nu har set at det går meget hurtigere at skrive direkte i port-registeret, så må det være en god ide at udnytte det, og for at teste tiden omkring dette anvendes et lille test-program som vist herunder.

Programmet kan hentes som output_time3 i denne ZIP-fil.

byte pulsePin = 13;
byte signalPin = 8;

void setup() {
  pinMode(pulsePin, OUTPUT);
  pinMode(signalPin, OUTPUT);
}

void loop() {
  PORTB = B00000001;

//  digitalWrite(pulsePin, HIGH);
  PORTB = PORTB | B00100000;

  PORTB = B00100000;

//   digitalWrite(pulsePin, LOW);
  PORTB = PORTB & B11011111;

  PORTB = B00000001;
  delayMicroseconds(10);
  PORTB = B00000000;
  delay(1);
}

Programmet sætter først et signal-output, det gøres ved at skrive direkte i porten. Derefter skifter programmet et pulse-ben højt med ved at bruge Bit-wise OR[3]. Hvorefter signalbenet sættes lavt igen (her er bit 5, der svarer til pin 13 holdt høj, for ikke at forstyrre det ben.

Der laves herefter det samme hvor hvor man bruger Bit-wise AND[4], hvor alle bit er 1, pånær den bit der er sat til 0 for at sætte benet lavt.

Hvis man måler på dette får man følgende måling, hvor man kan se at koden forløber som forventet, også at signalbenet har en ekstra lang periode til sidst (lavet med delayMicroseconds):
Måling af output med port-operationer til bit-ændring
Måling af output med port-operationer til bit-ændring

Som det kan ses på målingen, så er benet højt i ca. 0,12μs, hvilket fint svarer til at den operation kan gennemføres på 2 manskininstruktioner (0,125μs), herefter kommer en ekstra instruktion på 0,0625μs ind imellem inden den sætter benet lavt igen, hvilket her kan måles til 0,13μs, altså præcist de samme tidsforhold han ses når man med bitwise AND sætter benet lavt igen (2 maskininstruktioner).

Skrivning til hele byten direkte til porten

Vi kan faktisk få det til at gå endnu hurtigere ved at skrive hele byten til porten, da det kun tager en maskininstruktion.

Programmet kan hentes som output_time4 i denne ZIP-fil.

byte pulsePin = 13;
byte signalPin = 8;

void setup() {
  pinMode(pulsePin, OUTPUT);
  pinMode(signalPin, OUTPUT);
}

void loop() {
  PORTB = B00000001;

//  digitalWrite(pulsePin, HIGH);
  PORTB = B00100001;

  PORTB = B00100000;

//   digitalWrite(pulsePin, LOW);
  PORTB = B00000000;

  PORTB = B00000001;
  delayMicroseconds(10);
  PORTB = B00000000;
  delay(1);
}

Programmet sætter først et signal-output, det gøres ved at skrive direkte i porten. Derefter skrives pulse-ben højt ved at skrive med en byte, hvor bit 5 er sat til 1 og mønsteret fra sidste skrivning er bevaret. Hvorefter signalbenet sættes lavt igen (her er bit 5, der svarer til pin 13 holdt høj, for ikke at forstyrre det ben.

For at sætte pulse-benet lavt igen, så skrives 0 til bit 5 i byten sammen med mønsteret som porten havde ved sidste skrivning.

Hvis man måler på dette får man følgende måling, hvor man kan se at koden forløber som forventet:
Måling af output med direkte skrivning til hele porten
Måling af output med direkte skrivning til hele porten

Som det kan ses på målingen, så er benet højt i ca. 0,07μs, hvilket fint svarer til at den operation kan gennemføres på 1 manskininstruktion (0,0625μs), herefter kommer en ekstra instruktion på 0,0625μs ind imellem inden den sætter benet lavt igen, hvilket her kan måles til 0,06μs, altså præcist de samme tidsforhold kan ses når man sætter benet lavt igen (1 maskininstruktion).

Referencer

  1. Arduinos reference omkring digitalWrite, der kan skrive på en port-pin
  2. Arduinos reference omkring skrivning direkte i porten
  3. Arduinos reference omkring Bitwise OR
  4. Arduinos reference omkring Bitwise AND