C Temperaturanzeige (DS1621) auf 4 - Digit 7-Segmentanzeige

Janiiix3

Aktives Mitglied
28. Sep. 2013
1.333
10
38
Hannover
Sprachen
  1. ANSI C
  2. C#
Hallo Freunde,

Ich habe da mal wieder eine kleine Frage...
Ich sitze gerade dabei meinen Temperatursensor "DS1621" aus zu werten & die Temperatur auf einer 4 - Stelligen 7- Segmentanzeige darzustellen.

Nun währe es ja am besten, wenn ich den Wert vom Sensor in BCD bekommen würde... Nun schickt er mir aber 2 Bytes...
Wie löse ich das Problem am elegantesten?

:confused::confused::confused:

*Datenblatt im Anhang
 

Anhänge

  • DS1621.pdf
    338,1 KB · Aufrufe: 54
Warum muß man Dir eigentlich immer erstmal alles aus der Nase ziehen?

Der Sensor liefert Dir in einem Byte die ganzzahlige Temperatur. Zu interpretieren ist der Wert als binäres Zweierkomplement, um negative Werte realisieren zu können. Da die Gesamtspannweite des Sensors (-55°C..125°C) 181 Werte beträgt, bekommt man die in einem Byte unter, für die halben Kelvin reicht das jedoch nicht mehr.
Deswegen gibt es ein zweites Byte. Dort wird nur das MSB verwendet. Beide Bytes zusammen wären dann quasi 'ne linksorientierte 9-Bit-Zahl, wobei ein bit 'nem halben °C entspricht. Wenn man damit rechnen wollen würde, müßte man das ganze erst "Rechtsschieben", aber unter Beachtung der Zweierkomplement-Darstellung (ASR). Da Du nur darstellen und nicht rechnen willst, brauchst Du das aber gar nicht.
Außerdem gibt es noch zwei weitere auslesbare Register (Bytes) des Sensors: Read Counter (0xA8) und Read Slope (0xA9). Aus diesen beiden kann mit dem ganzzahligen Wert ein wesentlich genauerer Wert errechnet werden.

Ergibt also 3 Möglichkeiten:
  • ganzzahlig nur das erste Byte verwenden
  • zusätzlich das "halb-Kelvin-Bit" miteinbeziehen, also ggf zusätzlich ",5" darstellen (cave! negative Werte)
  • genauere Werte darstellen
Du kannst ja erstmal nur das erste verwenden, und Dich dann steigern...

Zur eigentlichen Frage: Was ist denn so'ne "BCD-Darstellung" eigentlich genau? Also speichertechnisch gesehen?

Und was willst Du nun (erstmal) konkret auf den 4 Stellen darstellen?

P.S.: meiner Meinung nach sollte 'ne Hochsprache so'ne Wandlung bereits anbieten;)
 
Hallo zusammen,
Du kannst ja erstmal nur TH verwenden, und Dich dann steigern...

Zur eigentlichen Frage: Was ist denn so'ne "BCD-Darstellung" eigentlich genau? Also speichertechnisch gesehen?

Und was willst Du nun (erstmal) konkret auf den 4 Stellen darstellen?

P.S.: meiner Meinung nach sollte 'ne Hochsprache so'ne Wandlung bereits anbieten;)

Wenn es um eine Umwandlung in BCD Code geht bzw. um die dezimale Darstellung auf einem Display, hilft eventuell als Beispiel ein Projekt zu einem Siebensegment-LED Modul in meinem Blog weiter.

Atmel Studio C Library für Seven Segment LED Backpack

Für die Aufspaltung in BCD benötigt man keine komplexe Funktion. Siehe unten jeweils das zweite Argument in fett, das sind jeweils die 1.000er, 100er, 10er und 1er. Damit die Dezimalziffern richtig auf dem Display ausgegeben werden, nutze ich hier eine kleine Tabelle im Flash Memory.

Dirk :ciao:

Beispiel: 4 Dezimalstellen ausgeben
(aus SevenSegment_LEDBackpack.c)
Code:
void LEDDriver_DisplayDecimal8(uint8_t d)
{

    LEDDriver_WriteDigitNumber(0, [B]0[/B], false); // 1.000er
    LEDDriver_WriteDigitNumber(1,[B] (d / 100) % 10[/B], false); // 100er
    LEDDriver_WriteDigitNumber(3,[B] (d / 10) % 10[/B], false);  // 10er
    LEDDriver_WriteDigitNumber(4,[B] d % 10[/B], false);    // 1er
        
}
 
Zur eigentlichen Frage: Was ist denn so'ne "BCD-Darstellung" eigentlich genau? Also speichertechnisch gesehen?

Speichertechnisch gesehen ist BCD 2 Zahlen in einem Byte. Upper Nibble = Zehner, lower Nibble Einer.
Ich verwende das häufig bei Werten die angezeigt werden sollen. Man spart sich die Umrechnung Dezimal zu String, muss nur beim Rechnen auf den (halben) Überlauf achten, damit da kein a..f rein rutscht. So sinds nur 2x AND und 1x SWAP (und ggf. eine Addition um direkt das ASCII Zeichen zu bekommen).

Sprich:
Wert = 0x12
Einer = (Wert AND 0x0F)
Zehner = ((Wert >> 4) AND 0x0F)

Genau so speichern auch viele RTC Module, DCF77 nutzt das auch.
 
Aso, kam jetzt nicht so deutlich rüber ;)
 
Eigentlich wollte ich Janiiix3 noch'n bisschen denken lassen...:stupido3:

Ich denke schon die ganze Zeit darüber nach! Immer wenn ich denke, denke ich zu kompliziert oder denke das falsche :D
Also mein Ziel ist es... Auf einer 7 - Segmentanzeige die aktuelle Temperatur darzustellen. Diese empfange ich von einem "DS1621".
Jetzt habe ich das "Problem"... Sagen wir mal der Chip sendet mir eine 020 Hex... Soweit so gut... Diese 020 Hex möchte ich jetzt auf meiner Anzeige darstellen.
Wie kriege ich es nun hin... Das die "erste" Anzeige (von rechts gesehen) "0" anzeigt... die "zweite" "2" und die "dritte" die letzte Ziffer "0" anzeigt?!

Ich hatte mir ja vorgestellt eine art "Tablle" dafür zu erstellen. Wie TommyB mir schon sagte "via. Skype", bräuchte ich da unmengen von "Werten"...


So als Anfänger sich in die ganzen möglichkeiten rein zu denken ist ziemlich schwer.. Was jetzt "C" angeht... Darum bin ich noch auf Hilfe angewiesen
 
Die aktuelle Temperatur
... empfange ich von einem "DS1621"...
Nein, die forderst Du mit dem Command 0xAA an, und erhälst die beiden Bytes.
Du könntest mit den beiden anderen Commands (0xA8 bzw 0xA9) aber auch ebenso (bzw zusätzlich) Conter und Slope anfordern und empfangen, und dann aus Counter, Slope und dem ersten Temperatur-Byte den genauen Wert zusammenbasteln.
Du scheinst erstmal nur das erste erhaltene Temperaturbyte (nach Command 0xAA), also den ganzzahligen Wert zu nutzen.

Deine fiktiven 20hex wären also 0x20=0b00100000=32. Im AVR ist das immer die binäre Zahl, der rechnet immer mit den Bits. Daß das für Dich also 32 sind, ist ihm Wurscht. Diese 32 ist aber bereits Deine ganzzahlige Temperatur. (Warum willst Du da jetzt die 20 ausgeben lassen? Wäre natürlich einfacher - die 2 ist das obere Nibble, die 0 das untere)
Was Du jetzt (scheinbar) willst ist, eine Zahl (Byte) von einem binär (Basis 2 )arbeitenden Rechenwerk in Zehnerpotenzen (Basis 10) zerlegen zu lassen. Das ist zwar nicht ganz trivial, da mehrere Divisionen durch Zehnerpotenzen erforderlich sind (wobei es auf das ganzzahlige Ergebnis und/oder den Rest ankommt), aber in 'ner Hochsprache brauchst Du Dich ja damit nicht selbst rumzuschlagen -> da werden die entsprechenden Algorithmen ja bereits angeboten (-> Dirk).
Als Resultat hättest Du dann also "'n Byte" für jede Zehnerpotenz der Zahl, die diese Ziffer binär darstellt. Da für die Ziffern 0..9 lediglich die unteren 4 Bits verwendet werden (9dez=0b00001001), die obersten 4 Bis also immer 0 sind, kann man 2 BCDs in ein Byte packen (->TommyB).

Was dann noch nicht klar ist ist, wie der Controller das an Deine Anzeigen weiterleiten soll - da kommts ja auf die Hardware an...
  • der AVR steuert die 7 Segmentleitungen jedes Ziffern-Bausteines direkt an (benötigt bereits 4*7=28 Beinchen)
  • dasselbe, aber die einzelnen Ziffern werden "gemultiplext" (4+7=11 Beinchen)
  • jede Ziffer wird über einen BCD-7Segment-IC angesteuert (zB 4511) (4+4=8 Beinchen)
  • eine der oberen Möglichkeiten, wobei zusätzlich serielle Schieberegister eingesetzt werden, um Beinchen zu sparen
  • Verwendung eines mehr oder weniger intelligenten ICs zur Ansteuerung der Segmente, möglicherweise selbst via TWI/SPI ansteuerbar (Dirk hatte da AFAIR was im Shop, Cassio hatte bereits einige in Betrieb)
Außerdem ist noch unklar, wie Du das mit den negativen Werten darstellen willst

(Dirk, bei Deinem Code-Schnipsel wären dann so alle erhaltenen Zehnerpotenzen negativ, oder wie?)
 
(Dirk, bei Deinem Code-Schnipsel wären dann so alle erhaltenen Zehnerpotenzen negativ, oder wie?)

Was vom Sensor kommt, habe ich mir nicht angeschaut. Ich hatte auch keine Zeit eine fertige Lösung zu bringen. ;) Man muss ggf. das was vom Sensor kommt natürlich anpassen.

Im Prinzip wollte ich nur zeigen, wie man Dezimalstellen abspalten kann und da ist mir mein kleines Projekt für das LED Display von Adafruit eingefallen. Da könnte sich dann Janiiix auch mal die Tabelle anschauen, die müsste er entsprechend anpassen, abhängig auch von der Ausgaberoutine ... sind aber eigentlich alles nur ein paar Zeilen Code.

Dirk :ciao:
 
Hallo zusammen,


Wenn es um eine Umwandlung in BCD Code geht bzw. um die dezimale Darstellung auf einem Display, hilft eventuell als Beispiel ein Projekt zu einem Siebensegment-LED Modul in meinem Blog weiter.

Atmel Studio C Library für Seven Segment LED Backpack

Für die Aufspaltung in BCD benötigt man keine komplexe Funktion. Siehe unten jeweils das zweite Argument in fett, das sind jeweils die 1.000er, 100er, 10er und 1er. Damit die Dezimalziffern richtig auf dem Display ausgegeben werden, nutze ich hier eine kleine Tabelle im Flash Memory.

Dirk :ciao:

Beispiel: 4 Dezimalstellen ausgeben
(aus SevenSegment_LEDBackpack.c)
Code:
void LEDDriver_DisplayDecimal8(uint8_t d)
{

    LEDDriver_WriteDigitNumber(0, [B]0[/B], false); // 1.000er
    LEDDriver_WriteDigitNumber(1,[B] (d / 100) % 10[/B], false); // 100er
    LEDDriver_WriteDigitNumber(3,[B] (d / 10) % 10[/B], false);  // 10er
    LEDDriver_WriteDigitNumber(4,[B] d [B][COLOR="#FF0000"]% 10[/COLOR][/B][/B], false);    // 1er
        
}

Was genau bezweckt das "%", Wozu ist das gut ?
 
http://lmgtfy.com/?q=modulo

@Dirk: Der Sensor liefert den Temperaturwert in Form von 2 Bytes. Und zwar linksorientiert als vorzeichenbehaftete (Zweierkomplement) 9-Bit-Zahl. Die nicht genutzten restlichen 7 Bits sind 0. Ein Bit entspricht dann einem halben °C. Das Most Significant Byte allein wäre somit bereits die fertige ganzzahlige Temperatur in Zweierkomplement-Darstellung, was einem Integer entsprechen sollte.
Man könnte natürlich auch das "Halb-Kelvin-Bit" mitverwenden - zum Rechnen müßte man dazu einfach siebenmal rechtsschieben. Allerdings arithmetisch wegen dem Vorzeichen.
Zum Darstellen muß man es ja nur abfragen.
Liegt jetzt also 'ne negative Zahl vor, liefern Deine Divisionen eben auch negative Ergebnisse für jede Dezimalstelle. Da es hier ja nur um die Darstellung geht, sollte erst ausgewertet werden, ob die Zahl negativ ist. In diesem Falle wäre die entsprechende Anzeige zu setzen, und das ganze mit -1 zu multiplizieren (Betrag/Neg/...). Die resultierende positive Zahl kann dann in Dezimalstellen zerhackt werden.
Wobei immer noch unklar ist, wie Janiiix3 das dann auf die Ziffern-Steine bringen will...
 
Hi,

Was genau bezweckt das "%", Wozu ist das gut ?

also ich kenne das aus manchen Sprachen als Modulo-Funktion. In manchen Sprachen wird das aber auch als mod() ausgeschrieben. Hab ich jetzt einfach mal so getippt. Wenn ich mich nicht geirrt habe also eigentlich ne Integer-Division wo nur der Rest zurückgeliefert wird.

Gruß
Dino
 
Hallo Leute,

Habe mir ein Programm geschrieben ( mit Unterstützung von Tommy ) was meinen I2C Temperatursensor
(DS1621) auswertet und auf einer 7 - Segmentanzeige darstellt.

Das passt soweit alles. Das Problem ist jetzt. Das der Wert sehr stark
toggelt... Immer zwischen zwei Werten. Da habe ich mir gedacht, dass man
das mit hilfe einer Mittelwert ermittlung unterbinden könnte?!

Wie seht ihr das ?
Wie mache ich das am klügsten ?

Ich habe da an ca. 30 Messungen gedacht...

(Temperatur = ((Messwert_1 ... + Messwert_30) / 30);

Wie setze ich das in meinem Quellcode nun um ?...

Habe mich auch schon in einem anderen Forum umgehört, wollte jetzt aber mal eure Meinung dazu hören.
Einige sagen dass man dazu eine "Hysterese" programmieren sollen andere hingegen sagen wieder man solle eine Mittelwertbildung nehmen.

Was denkt ihr ?


Code:
#define F_CPU 8000000

#define DS1621_Write  0x9E
#define DS1621_Read   0x9F

#define Segment_1_AN PORTB &= ~(1<<PB3)
#define Segment_1_AUS PORTB |= (1<<PB3)

#define Segment_2_AN PORTB &= ~(1<<PB2)
#define Segment_2_AUS PORTB |= (1<<PB2)

#define Segment_3_AN PORTB &= ~(1<<PB1)
#define Segment_3_AUS PORTB |= (1<<PB1)

#define Segment_4_AN PORTB &= ~(1<<PB0)
#define Segment_4_AUS PORTB |= (1<<PB0)

#define Segmentanzeige PORTD 

int Zahlen[13]= {
          0b00111111, // 0
          0b00000110, // 1
          0b01011011, // 2
          0b01001111, // 3
          0b01100110, // 4
          0b01101101, // 5
          0b01111101, // 6
          0b00100111, // 7
          0b01111111, // 8
          0b01101111, // 9
            0b01100011, // *
            0b01000000, // Minus
          0b00000000  // alle Aus
        };

#include <avr/io.h>
#include <util/delay.h>
#include "i2cmaster.h"
#include <avr/interrupt.h>

volatile unsigned char  TempCounter, TempH, TempL = 0;
volatile int16_t Wert, Slave_Anwesenheit = 0;
volatile int8_t Temp, TempAbs = 0;
volatile uint8_t IsNegative;
 

int main(void)
{

  
  DDRB |= ((1<<PB0) | (1<<PB1) | (1<<PB2) | (1<<PB3));
  DDRD |= ((1<<PD0) | (1<<PD1) | (1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD5) | (1<<PD6));
  
  TIMSK = (1<<OCIE1A); // Compare Match Enable
  TCCR1B = ((1<<CS10)); // Prescaler 64
  OCR1A = 100;
  sei();

  i2c_init();
  
  i2c_start(DS1621_Write); // Starten der Umwandlung (Messung)
  i2c_write(0xEE);
  i2c_stop();
  
  
  i2c_start(DS1621_Write); // Starten der Auslesung (Temperaturregister)
  i2c_write(0xAA);
  i2c_stop();
     
  Segment_1_AUS; Segment_2_AUS; Segment_3_AUS; Segment_4_AUS;

  
  while (1)
  {
    
    i2c_start(DS1621_Read);
    TempH = i2c_readAck();
    TempL = i2c_readNak();
    i2c_stop();

    Temp = TempH;
    
    
    if (Temp < 0)
    {
      IsNegative = 1;
      TempAbs = ~(Temp) + 1;
    }
    else
    {
      IsNegative = 0;
      TempAbs = Temp;
    }

    
    Wert = ((((TempAbs / 10) % 10) << 8) | ((TempAbs % 10) << 4) | (0x0A)); // Wert entspricht dem "Wert" aus dem Array (Zahlen)
    
    if (TempAbs == 0)
    {
      Wert = 0xCC0A;
    }
    else if (TempAbs >= 100)
    {
      Wert = (Wert | 0x1000);
    }
    else if (TempAbs < 10)
    {
      Wert = (Wert | 0xCC00);
    }
    else if (TempAbs < 100)
    {
      Wert = (Wert | 0xC000);
    }
    
    if (IsNegative == 1)
    {
      Wert = (Wert & 0x0FFF) | (0xB000);
    }
    
      _delay_ms(5000);    
  }
  

}


ISR (TIMER1_COMPA_vect)
{

    Segment_1_AN;
    PORTD = Zahlen[Wert & 0x000F];
    _delay_ms(1);
    Segment_1_AUS;
    asm volatile ("nop");
    asm volatile ("nop");
  
    Segment_2_AN;
    PORTD = Zahlen[(Wert & 0x00F0) >> 4];
    _delay_ms(1);
    Segment_2_AUS;
    asm volatile ("nop");
    asm volatile ("nop");
  
    Segment_3_AN;
    PORTD = Zahlen[(Wert & 0x0F00) >> 8];
    _delay_ms(1);
    Segment_3_AUS;
    asm volatile ("nop");
    asm volatile ("nop");
  
    Segment_4_AN;
    PORTD = Zahlen[(Wert & 0xF000) >> 12];
    _delay_ms(1);
    Segment_4_AUS;
    asm volatile ("nop");
    asm volatile ("nop");
  
}
 
Mal 'ne andere Sache vorweg:
Du denkst im Dezimalsystem - mit Zehnerpotenzen zu arbeiten, mit zehn, hundert, tausend zu multiplizieren oder dadurch zu teilen ist für Dich 'n Klacks. Einfach das Komma verschieben...
Der AVR arbeitet binär - also mit Zweierpotenzen. Entsprechend wird das Komma hier beim verdoppeln/halbieren verschoben.
Extrem leicht wird es, wenn man zusammengesetzte Bytes miteinbezieht (Word), also einfach 256mal einen Wert aufaddiert. Dann würde man eigentlich durch 256 teilen müssen (binäres Komma um 8 Stellen verschieben) - aber man kann ja auf das high-Byte des Word auch direkt zugreifen, und das low-Byte verwerfen.
Das ist genau so, als wenn Du im Dezimalsystem zehnmal addierst (integrierst), und die letzte Stelle nicht anzeigst.

Da Du hier aber eh auf BCDs umrechnest, wird 'ne Mittelwertbildung auch im Dezimalsystem einfacher. Du kannst zehn Temperaturen zusammenaddieren, und in Deiner Ausgabe alles um 'ne (Dezimal-)Stelle nach rechts verschoben ausgeben.

ABER!!!
Eigentlich stellt sich ja die Frage, warum die Werte bei Dir so extrem schwanken.
Du scheinst den Sensor im continious mode laufen zu lassen. Du liest mit Kommando 0xAA die Temperatur in Form von 2 Bytes ein (müßte nicht eigentlich jedesmal das 0xAA-Kommando gesendet werden? Laut DB sollte es doch jedesmal so sein: Start, Adresse_schreiben, Kommando0xAA, repeatedStart, Adresse_lesen, byte-lesen, byte-lesen, Stop).
Du verarbeitest jedenfalls nur das High-Byte, den ganzzahligen Anteil der Temperatur. Dieser scheint bei Dir bereits zu schwanken (bekommst Du das mehr oder weniger stark manipuliert, also wenn Du den Sensor langsam erwärmst oder so?)

Derzeit hackst Du einfach die erhaltene Temperatur nach der letzten Dezimalstelle ab, Du verwendest nur den ganzzahligen Anteil. Wenn der Wert jetzt also zwischen 24,9 und 25,0 (dezimal) schwankt, schwankt Deine Anzeige zwischen 24 und 25. Was soll sie aber da Anzeigen?
Im Low-Byte (welches Du nach TempL einliest, aber nie verwendest) befindet sich aber noch 'ne (binäre) Nachkommastelle, die dezimal 0,5 entspricht. wenn dieses bit gesetzt ist (also das low-Byte=128 bzw ungleich 0 ist) sollte die absolute ganzzahlige Temperatur "aufgerundet" werden, bevor das dann in Dezimalstellen zerhackt wird. Was heißt "aufrunden" dann hier?

P.S.: Dein Zahlen-Array sollte korrekterweise Ziffern heißen;)
 
Ich möchte mich hiermit offiziell von dem oben genannten Code distanzieren!

Ich würde niemals ein Multiplex LED Display innerhalb eines Timers umsetzen (der zumindest laut altem Quelltext) nur 1x die Sekunde ausgeführt wird. Schon garnicht in Timer1.
Ebenfalls würde ich den trägen Temperatursensor (eine Wandlung dauert 750mS) niemals kontinuierlich in der Main Loop abfragen.

So war es im altem Code (der im übrigem tadellos funktionierte) auch nicht.
Ich habe dir auch gesagt dass kaum was geändert werden muss, und nu ist das komplette Programm durcheinander.

:mad:
 
Ich möchte mich hiermit offiziell von dem oben genannten Code distanzieren!

Ich würde niemals ein Multiplex LED Display innerhalb eines Timers umsetzen (der zumindest laut altem Quelltext) nur 1x die Sekunde ausgeführt wird. Schon garnicht in Timer1.
Ebenfalls würde ich den trägen Temperatursensor (eine Wandlung dauert 750mS) niemals kontinuierlich in der Main Loop abfragen.

So war es im altem Code (der im übrigem tadellos funktionierte) auch nicht.
Ich habe dir auch gesagt dass kaum was geändert werden muss, und nu ist das komplette Programm durcheinander.

:mad:

Ich habe das Multiplexing in den Timer verschifft, da ich was getest habe. Hier klappt das Multiplexing auch tadelos (ISR Aufruf jede 1 ms.) ob es nötig ist oder nicht, lässt sich dahin gestellt sein.
In der While Schleife... Lasse ich die Abfrage kontinuierlich laufen. Hier habe ich ein _delay von 5000 ms eingebaut. Nun ändert sich der Wert halt auch nur alle 5 Sek. auf meinem Display... Schwankt aber trdz.
 
...Hier klappt das Multiplexing auch tadelos (ISR Aufruf jede 1 ms.) ...
Wie das denn, wenn Du in der ISR bereits mindestens 4ms warten läßt?

Ich würde pro Timer-Überlauf (ob nun CTC oder nicht) eine Ziffer darstellen, und für das Abschalten den 2ten Compare-IRQ verwenden. Dann kann man erstend Dimmen, und braucht sich 2tens nicht mit dem rechtzeitigen abschalten vorm umschalten der Ziffern beschäftigen...

0,75s sind für den AVR ja Zeitalter - da kann man doch entweder 'ne Zeitbasis (Timerüberläufe) nutzen um nur ab und zu, also vielleicht jede Sekunde die Daten zu lesen, oder (wenn man schnellere Reaktionen auf 'ne Temperaturänderung wünscht) in der main das "hab 'ne Messung fertig Bit" des Sensors auslesen, und darauf reagieren...

P.S. Thomas: Deine favorisierte Darstellung zweier BCD-Ziffern in einem Byte nennt sich gepackte BCD
 
Ich habe den Code jetzt wieder verschoben... So das ich in der While... meine Anzeige multiplexe und in der ISR den Sensor abfrage...
Was mache ich nun am besten mit dem Schanken ?!

Code:
/* PD.0 = A
   PD.1 = B
   PD.2 = C
   PD.3 = D
   PD.4 = E
   PD.5 = F
   PD.6 = G
   
   
0 = 0b00111111
1 = 0b00000110
2 = 0b01011011
3 = 0b01001111   
4 = 0b01100110
5 = 0b01101101   
6 = 0b01111101   
7 = 0b00100111
8 = 0b01111111 
9 = 0b01101111
* = 0b01100011
C = 0b01000000
   
*/


#define F_CPU 8000000

#define DS1621_Write  0x9E
#define DS1621_Read   0x9F

#define Segment_1_AN PORTB &= ~(1<<PB3)
#define Segment_1_AUS PORTB |= (1<<PB3)

#define Segment_2_AN PORTB &= ~(1<<PB2)
#define Segment_2_AUS PORTB |= (1<<PB2)

#define Segment_3_AN PORTB &= ~(1<<PB1)
#define Segment_3_AUS PORTB |= (1<<PB1)

#define Segment_4_AN PORTB &= ~(1<<PB0)
#define Segment_4_AUS PORTB |= (1<<PB0)

#define Segmentanzeige PORTD 

int Zahlen[13]= {
					0b00111111, // 0
					0b00000110, // 1
					0b01011011, // 2
					0b01001111, // 3
					0b01100110, // 4
					0b01101101, // 5
					0b01111101, // 6
					0b00100111, // 7
					0b01111111, // 8
					0b01101111, // 9
				    0b01100011, // *
				    0b01000000, // Minus
					0b00000000  // alle Aus
				};

#include <avr/io.h>
#include <util/delay.h>
#include "i2cmaster.h"
#include <avr/interrupt.h>

volatile unsigned char  TempCounter, TempH, TempL = 0;
volatile int16_t Wert, Slave_Anwesenheit = 0;
volatile int8_t Temp, TempAbs = 0;
volatile uint8_t IsNegative;
 

int main(void)
{

	
	DDRB |= ((1<<PB0) | (1<<PB1) | (1<<PB2) | (1<<PB3));
	DDRD |= ((1<<PD0) | (1<<PD1) | (1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD5) | (1<<PD6));
	
	TIMSK = (1<<OCIE1A); // Compare Match Enable
	TCCR1B = ((1<<CS12) | (1<<CS10)); // Prescaler 1024
	OCR1A = 50000;
	sei();

	i2c_init();
	
	i2c_start(DS1621_Write); // Starten der Umwandlung (Messung)
	i2c_write(0xEE);
	i2c_stop();
	
	
	i2c_start(DS1621_Write); // Starten der Auslesung (Temperaturregister)
	i2c_write(0xAA);
	i2c_stop();
     
	Segment_1_AUS; Segment_2_AUS; Segment_3_AUS; Segment_4_AUS;

	
	while (1)
	{
		
	Segment_1_AN;
	PORTD = Zahlen[Wert & 0x000F];
	_delay_us(500);
	Segment_1_AUS;

	
	Segment_2_AN;
	PORTD = Zahlen[(Wert & 0x00F0) >> 4];
	_delay_us(500);
	Segment_2_AUS;

	
	Segment_3_AN;
	PORTD = Zahlen[(Wert & 0x0F00) >> 8];
	_delay_us(500);
	Segment_3_AUS;

	
	Segment_4_AN;
	PORTD = Zahlen[(Wert & 0xF000) >> 12];
	_delay_us(500);
	Segment_4_AUS;

	}
}

ISR (TIMER1_COMPA_vect)
{
		
	i2c_start(DS1621_Read);
	TempH = i2c_readAck();
	TempL = i2c_readNak();
	i2c_stop();
	
	Temp = TempH;
	
	if (Temp < 0)
	{
		IsNegative = 1;
		TempAbs = ~(Temp) + 1;
	}
	else
	{
		IsNegative = 0;
		TempAbs = Temp;
	}

		
	Wert = ((((TempAbs / 10) % 10) << 8) | ((TempAbs % 10) << 4) | (0x0A)); // Wert entspricht dem "Wert" aus dem Array (Zahlen)
	
	if (TempAbs == 0)
	{
		Wert = 0xCC0A;
	}
	else if (TempAbs >= 100)
	{
		Wert = (Wert | 0x1000);
	}
	else if (TempAbs < 10)
	{
		Wert = (Wert | 0xCC00);
	}
	else if (TempAbs < 100)
	{
		Wert = (Wert | 0xC000);
	}
		
	if (IsNegative == 1)
	{
		Wert = (Wert & 0x0FFF) | (0xB000);
	}
		


}
 
Code:
        if (TempCounter <= 10)
        {
	i2c_start(DS1621_Read);
	TempH = i2c_readAck();
	TempL = i2c_readNak();
	i2c_stop();
	
	Temp = TempH + TempH;
        }
          Temp = Temp / 10;

könnte das nicht so ungefähr funktionieren ?! Das ich so meinen Mittelwert erhalte?!
 
Waahhhhhhhhhhhhh!!!:shout:

Warum denn die Division?
Was ist denn Deine Hunderter-Stelle, wenn Du sie durch 10 teilst?

Trotzdem würde ich statt der Mittelwertbildung erstmal mit dem Halb-Kelvin-Bit runden

P.S.: beachte auch, daß durch die Integration der Variablenbereich überlaufen kann
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)