Forum: Compiler & IDEs AVR TSIC Auswertung => riesen Programm


von rogger (Gast)


Angehängte Dateien:

Lesenswert?

Hallo!

Ich habe gerade ein Programm zur Auswertung eines TSIC-Temperatursensors 
zur Steuerung von einigen Ausgängen geschrieben. Dazu benutze ich den 
C-Code von Beitrag "wie Daten an MSP430F1611 seriell einlesen?" . Allerdings 
erzeugt der avr-gcc compiler daraus eine ziemlich große Datei... Wenn 
ich alles andere weglasse und nur die Funktion zum Auslesen und die 
Umwandlung in einen String im Programm (Anhang) drin lasse ist die 
erzeugte binary immer noch 4406 bytes groß.

Kann mir einer sagen wie ich das Programm kleiner bekomme?

von Rolf Magnus (Gast)


Lesenswert?

> Temp_celsius = ((float)temperatur / 2047 * 200) - 50;

Diese Berechnung durch eine integer-Berechnung ersetzen.

von rogger (Gast)


Lesenswert?

Ahh ok vielen Dank!

ich habs jetzt mal in
1
 Temp_celsius = ((temperatur*100 / 2047 * 200) - 5000)/10;

geändert... Sollte eigentlich rein Mathematisch funktionieren, odeer hab 
ich da was übersehen?
jetzt muss ich mich nur noch um das richtige setzen des Kommas 
kümmern...

von Peter D. (peda)


Lesenswert?

rogger schrieb:
> ist die
> erzeugte binary immer noch 4406 bytes groß.

Dann hast Du den Compilerschalter "-lm" vergessen.


Peter

von rogger (Gast)


Lesenswert?

auch mit "-lm" komme ich auf 4406 bytes...

von Peter D. (peda)


Lesenswert?

rogger schrieb:
> auch mit "-lm" komme ich auf 4406 bytes...

Komisch, ich komme auf 1438 Byte:
1
4.3.2
2
   text    data     bss     dec     hex filename
3
   1438       0       0    1438     59e test.out


Peter

von Stefan E. (sternst)


Lesenswert?

rogger schrieb:
> auch mit "-lm" komme ich auf 4406 bytes...

-lm ist ja auch eigentlich kein Compilerschalter, sondern ein 
Linkerschalter. ;-)
Also wahrscheinlich einfach in die falsche "Schalterliste" eingetragen.

von rogger (Gast)


Lesenswert?

Ich bin im AVR-Studio scheinbar noch nicht so fit... Hab jetzt "-lm" als 
Linkerschalter eingetragen und komm immernoch auf 4kb...
Ich werds morgen nochmal unter gewohnter Umgebung (linux + avr-gcc) 
probieren da kann ich wenigstens die Linkeroptionen selbst verändern^^

Ich glaube ich werde trotzdem die festkommarithmetische Lösung benutzen 
die ist ja trotzdem nur halb so groß. Damit komme ich nur auf 720 bytes.

rogger...

von Jörg G. (joergderxte)


Lesenswert?

Darf ich noch ketzerisch ein "Optimierung aktiviert?"  einwerfen?

von rogger (Gast)


Lesenswert?

wenn du die Compileroption -Os meinst, dann muss ich sagen die ist 
aktiviert...

Gibt es sonst noch Möglichkeiten eine Optimierung zu Aktivieren?

von Jörg G. (joergderxte)


Lesenswert?

>wenn du die Compileroption -Os meinst, dann muss ich sagen die ist aktiviert...
Ja, die meinte ich.
Beim AVR-Studio (wieso hast du das nicht im ersten post erwähnt?) setzt 
man das "-lm", indem man in den project-options, linkeroptions (oder 
hieß das libraries? -- hab kein Avr-studio hier) die 'libm.a' auswählt.

hth, Jörg

von Karl H. (kbuchegg)


Lesenswert?

rogger schrieb:

> ich habs jetzt mal in
1
 Temp_celsius = ((temperatur*100 / 2047 * 200)
2
> - 5000)/10;
>
> geändert... Sollte eigentlich rein Mathematisch funktionieren, odeer hab
> ich da was übersehen?

Warum stellst du nicht einfach so um
1
   Temp_celsius = (temperatur * 200 / 2047) - 50;

(Hintergedanke:
Du willst die Division so spät wie möglich machen. Bei der Division 
gehen dir die Nachkommastellen flöten, daher willst du es solange wie 
möglich hinauszuögern. Bei den anderen Operationen kann dir nichts 
verloren gehen, dafür droht allerdings die Gefahr eines Overflow. Das 
muss man mit den tatsächlichen Werten abklären, ob die Multiplikation 
mit 200 einen Overflow generieren kann.

von Karl H. (kbuchegg)


Lesenswert?

Das ist eine teure Operation
        temp_value1 |= 1 << (8-i);         // get the bit

Um mit einer variablen Bitanzahl zu schieben, muss ein AVR ganz schönen 
Aufwand treiben. Besser ist es eine 'Maske' zu haben und die Maske nach 
jeder Operation eine Stelle weiterzuschieben.

In deinem Fall ist es allerdings noch einfacher, einfach das Ergebnis um 
1 Stelle weiterzuschieben und immer nur das Bit 0 bei Bedarf zu setzen
1
  for (i = 0; i < 9; i++) {
2
    while (TSIC_SIGNAL_HIGH);              // wait for falling edge
3
    _delay_us(60);
4
    if (TSIC_SIGNAL_HIGH)
5
        temp_value1 |= 1;
6
    temp_value1 <<= 1;
7
    while (TSIC_SIGNAL_LOW);           // wait until line comes high again
8
  }

Und warum hast du den Code um Bits einzulesen doppelt im Code anstelle 
einer Funktion die 2 mal aufgerufen wird?

Selbiges nochmal in grün für das Checken der Parity.

Wobei du dem AVR viel Arbeit (und damit auch einiges an Code) abnehmen 
kannst, wenn du von vorneherein das Parity Bit extra betrachtest und nur 
8 Bit + Parity Bit empfängst. Dann brauchst du dafür keine 16 Bit 
Variablen und der AVR muss nicht nutzlose Bits durch die Gegend 
schieben.

von rogger (Gast)


Lesenswert?

Ich hätte ja nicht gedacht dass man noch so viel aus dem Programm 
rausholen kann!

Ich werde mich dann nacher wenn ich Zeit habe mal hinsetzen und das 
ganze Etwas umbauen...
Meine Lösung werde ich dann wieder hier Posten.

Vielen Dank soweit!

roggerb

von rogger (Gast)


Angehängte Dateien:

Lesenswert?

so ich bin endlich mal wieder dazu gekommen etwas weiter zumachen und 
habe einmal versucht eure Vorschläge einzubauen. Das Ergebnis findet ihr 
im Anhang.
Im Moment komme ich auf 752 Bytes.

Ich konnte meine Änderungen bisher noch nicht auf dem Atmega testen, 
deswegen weiß ich auch noch nicht ob mein Programm fehlerhaft ist.

rogger

von Dude (Gast)


Lesenswert?

Das Programm hat noch ein paar Macken:

- Zuviele bits werden gelesen
- Daten werden einmal zuviel nach links geschoben
- parity prüft zu wenig bits
- zu großer datentyp als zählvariable
- itoa aus der bibliothek scheint kleiner
- temperatur zu klein (z.B. 930*200=186000)
- konstanten ggf. mit "L" kennzeichnen
- ein else kann eingespart werden

Ansonsten danke für den Code!

von dagdag (Gast)


Lesenswert?

@ Dude könntest Du Deine korrigierte Codevariante hier mal reinstellen?

Danke

dagdag

von roger.k (Gast)


Lesenswert?

Dieser Beitrag ist zwar schon kalter Kaffee, aber ich kann es mir mein 
Unverständnis über solche Leute nicht verkneifen.

@ Dude schrieb:
...
> Ansonsten danke für den Code!

Das sind sie, das Forum nutzen und nur nehmen. Mir würde dieser Code 
bestimmt auch weiterhelfen. Ist zwar in C, aber ein Debuggerlauf zeigt 
mir ja auch Assembler.

mfg Roger

von peter (Gast)


Lesenswert?

Hallo,
ich versuche mich gerade auch mit dem TSIC-206. Die ausgewerteten 
Temperaturen gebe ich momentan per UART aus. Jedoch kommen keine 
vernünftigen Werte zustande. Gibt es eine funktionierdende Version von 
testtemp.c?

Gruß

von Peter II (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Temp_celsius = (temperatur * 200 / 2047) - 50;

eventuell noch in

Temp_celsius = (temperatur * 200 / 2048) - 50;

ändern, damit hat es der µC noch ein wenig einfacher.

von Anton A. (bingo_)


Angehängte Dateien:

Lesenswert?

So ich poste jetzt hier eine Version, die die vorgeschlagenen Änderungen 
von Dude beinhaltet.
Das Beispiel ist ein Eclipse Projekt mit LCD.
Die gleichen Dateien aus dem Projekt sind nochmal extra angehängt.

Diese Version kommt ohne Interrupt oder Timer aus

PS: Ich sehe den Derben Umgangston hier im Forum immer mit einem Lächeln 
im Gesicht an, weil es erschreckend ist, wie kurz bei einigen hier die 
Soziale Kompetenz kommt.
Das Verhalten von "Dude" passt ganz dazu. Und jetzt macht mich und 
"mein" Code fertig, ich warte schon darauf...  ;) ;) ;)

von Carsten (Gast)


Angehängte Dateien:

Lesenswert?

Ahoi!

Ich habe heute gerade an einer ZACwire-Implementierung per Interrupt 
gearbeitet. Danach bin ich auf diesen (alten) Thread gestoßen.

Vielleicht hilft mein Code ja jemanden, der's per INT bauen will.

Der TSic wird hier kontinuierlich ausgelesen, auf eine Steuerrung der 
Spannungsversorgung des TSic habe ich deshalb verzichtet. Das ist meiner 
Meinung nach auch nur beim Polling sinnvoll.
Lt. Datenblatt verheizt der TSIC 80µA bei 5V.

Als Eingang benutzt der Code Pin D4 mit der PCINT20-Funktion.
Zugegebenermaßen ist es ein schneller Hack aber es sollte nicht 
schwierig zu sein, den Code an eigene Bedürfnisse anzupassen.
So können natürlich auch andere Pin-Change-Interrupteingänge oder 
INT0/INT1 benutzt werden, wobei die Polarität fallend sein muss. Bei 
Benutztung von PCINT wird die steigende Flanke in der ISR rausgefiltert.

Als einzige Verbesserungen zum Code von Anton sind lediglich das Timeout 
bei der Flankenerkennung und die im Datenblatt empfohlene Messung der 
Breite des Startbits zu nennen. Ersteres bewirkt, dass das Programm 
nicht hängenbleibt, wenn der TSic ausfällt/abgezogen wird, Zweiteres 
sollte für ein genaueres Timing sorgen und das Auslesen robuster machen.

Durch die Strobemessung und das Timing beim Einlesen der einzelnen Bits 
ist die Laufzeit der ISR etwas größer als die Übertragungsdauer eines 
Datenwortes. Geschätzt sind es 2,7mS: (1 Startbit + 18 Datenbits inkl. 
Parity + 1/2 Stopbit) * 125µS. Der TSic sendet 10 Messungen/Sekunde, 
also verbraucht die ISR ca. 27,5mS/S.

Grundsätzlich ist das Interruptverfahren also nicht unbedingt 'besser'. 
Je nach Andwendungsfall kann es aber bequemer sein. Auf jeden Fall 
verbraucht es insgesamt mehr Rechenzeit und Strom als das Polling mit 
Spannungssteuerung des TSic. Wobei beim Polling zu beachten ist, dass 
der TSic nach dem Einschalten zwischen 65mS und 85mS braucht, um das 
Messergebnis zu liefern und empfohlen wird, V+ des TSic mit einem 
Tiefpassfilter an den µC zu koppeln -> mehr Bauteile.


/Carsten

von Anton A. (bingo_)


Lesenswert?

Die Version die ich gepostet habe hat noch ein Problem.
Es wird eine temperatur ca 2°C zu hoch angezeigt. Das Problem liegt 
irgendwo in der Parrity-Verarbeitung.
1
uint8_t readParity() {
2
  while (TSIC_SIGNAL_HIGH)
3
    ;             // wait for falling edge
4
  _delay_us(63);
5
  if (TSIC_SIGNAL_HIGH)
6
    return 1;
7
  return 0;
8
}

müsste heißen:
1
uint8_t readParity() {
2
  while (TSIC_SIGNAL_HIGH)
3
    ;             // wait for falling edge
4
  _delay_us(63);
5
  if (TSIC_SIGNAL_HIGH){
6
      while (TSIC_SIGNAL_LOW)
7
  ;           // wait until line comes high again
8
      return 1;
9
  }
10
   while (TSIC_SIGNAL_LOW)
11
      ;           // wait until line comes high again
12
  return 0;
13
}

Leider ist noch mehr faul, da dann nur noch gerade Zahlenwerte am LSB 
rauskommen.
Vielleicht liegt es auch irgendwie an der Pointer Verarbeitung, weil 
meiner Meinung nach macht das Programm genau das was die Version von 
Carsten macht.

@Carsten: mein Compiler meint das die parity_even_bit-Fkt. nichts macht.

Schade die Version von Rogger finde ich sehr elegant und schön 
geschrieben..
Aber nach mehreren Tagen des Versuchens gebe ich an dieser Stelle auf :(

von Anton A. (bingo_)


Angehängte Dateien:

Lesenswert?

So jetzt hier eine Version die wirklich geht, auch ohne Fehler soweit 
ich das jetzt beurteilen kann.

PS: es ist eine Mischung aus der Version von rogger und Carsten, jedoch 
komplett neu aufgebaut.

von Holger W. (holgerw)


Angehängte Dateien:

Lesenswert?

Hier mal meine Version, beide Bytes werden eingelesen und gleich die 
Parität geprüft. Das läuft so seit Monaten erfolgreich.
Geschrieben für PIC 18F2620 mit C18.
Vielleicht lässt sich aus dem Code noch die eine oder andere Anregung 
entnehmen.

Holger

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.