Forum: Mikrocontroller und Digitale Elektronik mit einem 8051 Mikrocontroller einen Mlx90416 Infrarotsensor anstuern


von Martin H. (Gast)


Lesenswert?

Hi ich brauche dringend Hilfe, möchte einen MLX90614 Sensor ansteuern 
mit meinem Mikrocontroller T89C51CC01 der Familie 8051. habe ein c-code 
geschrieben aber der LCD-Display zeigt mir leider nix an und ich weiß 
nicht ob er mir die Daten schickt bin seit Tagen dran -.- kann mir vlt 
einer bitte den Fehler sagen oder helfen.

mfg Martin

C-Code:


 #include "t89c51cc01.h"
 #include "fvs_bib_lcd.h"
 #include "stdio.h"
 #include "math.h"
 #include "intrins.h"
 #include "string.h"

// ------------------------------------------------ 
-------------------------------------------------- 
-------------------------------------- //
// I / O-Ports
// ------------------------------------------------ 
-------------------------------------------------- 
-------------------------------------- //
sbit MLX = P0 ^1;

// Verwenden Sie MCU externe Interruptquelle um PWM Puls auf SDA Pin von 
MLX90614 zu messen
// ------------------------------------------------ 
-------------------------------------------------- 
-------------------------------------- //
// ------------------------------------------------ 
-------------------------------------------------- 
-------------------------------------- //
// Funktion: Berechnet die Temperatur nach PWM-Pulsbreite und 
Periodenbetrag
// ------------------------------------------------ 
-------------------------------------------------- 
-------------------------------------- //
int Berechnen (unsigned int t1pwm, unsigned int T1pwm)
{

int DC;
long int T;
int T1;
int K;
int T1max = 120; // Die maximale Objekttemperatur, die im EEPROM 00h 
gespeichert ist
int T1min = -20; // Die minimale Objekttemperatur, gespeichert im EEPROM 
01h
K = 2 * (T1max-T1min);

DC = t1pwm * 100000 / T1pwm;
// Berechnen Sie den Duty-Zyklus, mal 100.000 verschiebt den Fixpunkt 5 
Position nach rechts

T = (DC-0,125 * 100000) * K + T1min * 100000;
// Objekttemperatur berechnen, DC ist Tastverhältnis
T1 = T / 1000;
// Um ??die Auflösung auf 0.01 abzuschneiden, erfolgt eine Division von 
1000 auf den Ergebnissen
return T1;

}
void main (void)
{
char txt[10];
unsigned int A;
unsigned int B;
unsigned int C;
unsigned int D;
unsigned int Data1;
unsigned int Data2;
int Daten;

TMOD = 0x19; // Set Timer und Timer GATE =  Arbeit im Modus 1
TH0 = 0x00; // Löschen TH0, TL0
TL0 = 0x00;
ET0 = 1; // Open Timer 0 Interrupt-Freigabe
ET1 = 1; // Open Timer 1 Interrupt-Freigabe
EA = 1; // Gesamt-Interrupt-Freigabe öffnen
TL1 = 0x00; // Löschen TH1, TL1
TH1 = 0x00;
EX1 = 0; // INT1-Interrupt ausschalten

while (MLX == 1) // Warten INT1 niedrigen Puls
{;}
while (MLX == 0) // Warten INT1 Hochimpuls
{;}
TR0 = 1; // Timer öffnen 0
TR1 = 1; // Timer öffnen 1
while (MLX == 1) // Warten INT1 niedrigen Puls
{;}
TR0 = 0; // Timer löschen 0
C = TL0; // T0 Niedriges Byte sendet an C
D = TH0; // T0 High-Byte sendet an D
while(MLX == 0) // Warten INT1 Hochimpuls
{;}
TR1 = 0; // Timer löschen 1
A = TL1; // T1 Niedriges Byte sendet an A
B = TH1; // T1 High-Byte sendet an B
Data2 = (D << 8) + C;
Data1 = (B << 8) + A;

Daten = Berechnen (Data2, Data1); // Temperatur auf der Grundlage des 
Zählerwertes berechnen
      pos(40);
      sprintf(txt,"T=%i",(int)Daten);
      lcdsend(txt); // Temperatur anzeigen
}

von Joe F. (easylife)


Lesenswert?

versuche mal
1
init_lcd();
2
pos(0);
3
sprintf(txt,"T=%i",(int)Daten);
4
lcdsend(txt);

oder
1
init_lcd();
2
pos(0x40); // 2. Zeile
3
sprintf(txt,"T=%i",(int)Daten);
4
lcdsend(txt);

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

"factory default is SMBus)"

Das Ding spricht also erstmal nur SMBus (I2C). Für PWM mußt Du den 
EEPROM umprogrammieren.
Einfacher sollte allerdings sein, gleich I2C zu benutzen.

Kannst Du denn schon Zahlen auf dem LCD ausgeben?

von Martin H. (Gast)


Lesenswert?

Joe F. schrieb:
> versuche mal
>
1
> init_lcd();
2
> pos(0);
3
> sprintf(txt,"T=%i",(int)Daten);
4
> lcdsend(txt);
5
>
>
> oder
>
1
> init_lcd();
2
> pos(0x40); // 2. Zeile
3
> sprintf(txt,"T=%i",(int)Daten);
4
> lcdsend(txt);
5
>

Danke für die Antwort, aber hab schon alles mögliche versucht liegt 
leider nicht an der position. weis zwar nicht warum ich nix angezeugt 
bekomm der stoppt irgendwo und ab da geht gar nix mehr -.-....

von Joe F. (easylife)


Lesenswert?

Martin H. schrieb:
> while (MLX == 1) // Warten INT1 niedrigen Puls
> {;}
> while (MLX == 0) // Warten INT1 Hochimpuls
> {;}

Naja, klar, wenn wie Peter sagte das Teil keine PWM ausgibt, hängts bei 
einem dieser whiles...

von Martin H. (Gast)


Lesenswert?

Peter D. schrieb:
> "factory default is SMBus)"
>
> Das Ding spricht also erstmal nur SMBus (I2C). Für PWM mußt Du den
> EEPROM umprogrammieren.
> Einfacher sollte allerdings sein, gleich I2C zu benutzen.
>
> Kannst Du denn schon Zahlen auf dem LCD ausgeben?

also am Lcd bekomm ich nix raus keine zahlen nicht mal ein buchstaben, 
was es normal ausgeben muss/sollte. :/ ja genau einfacher schon aber 
will es so programmieren wird schlieslich meine Techniker arbeit später 
^^ find denn fehler leider nicht hab schon jegliche sachen getestet aber 
ohne erfolg :/ wie meinst du das mit dem EEPROM verstehe ich grad net 
sry ^^

von Mario M. (thelonging)


Lesenswert?

Vielleicht liegts einfach daran, dass in Deinem Programm nirgends 
init_lcd() ausgerufen wird?

von Martin H. (Gast)


Lesenswert?

Joe F. schrieb:
> Martin H. schrieb:
>> while (MLX == 1) // Warten INT1 niedrigen Puls
>> {;}
>> while (MLX == 0) // Warten INT1 Hochimpuls
>> {;}
>
> Naja, klar, wenn wie Peter sagte das Teil keine PWM ausgibt, hängts bei
> einem dieser whiles...

ok und wie soll ich es dann umschreiben hab da jetzt keine ahnung wie 
ich das machen soll ^^ ?

von Joe F. (easylife)


Lesenswert?

Fang doch mal Schritt für Schritt an.
Schreibe einen einfachen String auf das Display, und schmeisse sonst 
alles raus, was mit dem Sensor zu tun hat.
Dann weisst du, dass du zumindest mal auf das Display zugreifen kannst.
Als nächstes solltest du dich mit I2C auf deinem uC beschäftigen 
(Library suchen, API verstehen, I2C Protokoll verstehen, Protokoll des 
Sensors verstehen -> Datenblatt, Protokoll in deiner Firmware 
implementieren).

Wenn du schon nicht verstehst, warum die while()-Schleifen hängen 
bleiben, frage ich mich wie du diesen Code "geschrieben" haben möchtest.
Copy&Paste kommt da wohl näher an die Wahrheit heran.

: Bearbeitet durch User
von Martin H. (Gast)


Angehängte Dateien:

Lesenswert?

Bin schon seit Tagen dran, bin kein schritt voran gekommen. hab mich 
über i2c informiert und das Datenblatt Beschäftigt. hab ein I2C Code ein 
gespielt tut trotzdem nicht leider -.- hier ist mal der code hoffe 
kannst mir weiter helfen..

code:
 sbit SDA=P0^0;
 sbit SCL=P0^1;

 int t1,t2;


        void I2CInit()
        {
          SDA = 1;
          SCL = 1;
        }

        void I2CStart()
        {
          SDA = 0;
          SCL = 0;
        }

        void I2CRestart()
        {
          SDA = 1;
          SCL = 1;
          SDA = 0;
          SCL = 0;
        }

        void I2CStop()
        {
          SCL = 0;
          SDA = 0;
          SCL = 1;
          SDA = 1;
        }

        void I2CAck()
        {
          SDA = 0;
          SCL = 1;
          SCL = 0;
          SDA = 1;
        }

        void I2CNak()
        {
          SDA = 1;
          SCL = 1;
          SCL = 0;
          SDA = 1;
        }

        unsigned char I2CSend(unsigned char Data)
        {
           unsigned char i, ack_bit;
           for (i = 0; i < 8; i++) {
            if ((Data & 0x80) == 0)
              SDA = 0;
            else
              SDA = 1;
            SCL = 1;
             SCL = 0;
            Data<<=1;
           }
           SDA = 1;
           SCL = 1;
           ack_bit = SDA;
           SCL = 0;
           return ack_bit;
        }

        unsigned char I2CRead()
        {
          unsigned char i, Data=0;
          for (i = 0; i < 8; i++) {
            SCL = 1;
            if(SDA)
              Data |=1;
            if(i<7)
              Data<<=1;
            SCL = 0;
          }
          return Data;
        }


        void mian (void)
        {

            char txt[10];

          init_lcd();

          while(1)
          {
            I2CRead();
            I2CSend();


            t1=Data();
            t2=Data();


            pos(0);
            sprintf(txt,"%i",(int)t1);
            lcdsend(txt);
            pos(8);
            sprintf(txt,"%i",(int)t2);
            lcdsend(txt);

            msec(1);
          }

       }


angeschlossen hab ich es so..

von Peter D. (peda)


Lesenswert?

Lt. Bild initialisiert Dein LCD nichtmal.
Wie schon gesagt wurde, Du mußt schrittweise vorgehen.
Gib erstmal Text und Zahlen auf dem LCD aus.

von Andreas M. (andiator)


Lesenswert?

Ist der Code jetzt kopiert oder abgetippt?

Denn
1
void mian (void)
kann nicht funktionieren...

von Martin H. (Gast)


Lesenswert?

Text bekomm ich raus aber keine Zahlen Leider weis nicht wie ich das 
noch versuchen soll bekomm das nicht zum laufen -.- ist ein projekt den 
ich fertig bekommen muss hab da echt keine Ahnung mir gehen langsam die 
ideen aus :/

von Martin H. (Gast)


Lesenswert?

ja hast recht war ein fehler von mir aber tut trozdem leider.. zeigt mir 
auch kein fehler an weis nicht was ich noch machen soll -.-

von Patrick J. (ho-bit-hun-ter)


Lesenswert?

Hi

Kann es sein, daß Du, wenn Du die Zahl 34 senden willst, ein " 
Anführungszeichen bekommst?

Ja -> 34 ist der ASCII Code für ein "
Ja² -> Du musst Deine Zahlen in Einzelzeichen umrechnen

Wenn Nein ... was kommt, wenn Du welche Zahl auszugeben versuchst?

MfG

von Joe F. (easylife)


Lesenswert?

Patrick J. schrieb:
> Wenn Nein ... was kommt, wenn Du welche Zahl auszugeben versuchst?

Das Problem liegt eher nicht am sprintf... %i ist schon okay.

a)
Das Programm kann aber überhaupt nicht compilieren.
1
void mian (void)
ist nicht main().
1
t1=Data();
Die Funktion Data() gib es gar nicht.

b)
Selbst wenn es bauen würde, I2C hat ein Timing.
Einfach die Ports mit Maximalgeschwindigkeit toggeln funktioniert 
bestimmt nicht.

c)
1
I2CRead();
2
I2CSend();
3
t1=Data();

Da fehlt jegliches Verständnis, wie per I2C mit dem Sensor kommuniziert 
wird.
Es muss eine I2C Adresse gesendet werden, es muss mind. 1 Register 
ausgelesen werden.
Start-Stop Konditionen müssen beim reingepasteten Code an der richtigen 
Stelle gemacht werden.

Martin H. schrieb:
> zeigt mir
> auch kein fehler an

das kann schlichtweg nicht sein.

: Bearbeitet durch User
von Patrick J. (ho-bit-hun-ter)


Lesenswert?

Hi

Martin H. schrieb:
> code:
>  sbit SDA=P0^0;
>  sbit SCL=P0^1;

Was mir gerade noch auffällt - gehören die 'Dach-Pfeile' nicht nach 
links verdreht und verdoppelt?
1
sbit SDA=P0<<0;
2
sbit SCL=P0<<1;
Als Schiebe-Operation.
P0 wird wohl den Wert 0 zurück geben (Bit 0 im Port)
P0^0 -> 1 (jede Zahl hoch Null ist Ein)
P0^1 -> 0 (jede Zahl hoch Eins ist die Zahl selber)

Sicher, daß SDA und SCL überhaupt da sind, wo Sie vermutet werden?

(sofern sich der Code compilieren lässt, klar)

MfG

: Bearbeitet durch User
von Joe F. (easylife)


Lesenswert?

Patrick J. schrieb:
> hoch

^ ist XOR in C.

Der Code ist einfach stumpf zusammenkopiert, ohne jemals über 
Kompatibilität und Funktion nachzudenken.

von Peter D. (peda)


Lesenswert?

Patrick J. schrieb:
>>  sbit SDA=P0^0;
>>  sbit SCL=P0^1;
>
> Was mir gerade noch auffällt - gehören die 'Dach-Pfeile' nicht nach
> links verdreht und verdoppelt?

Nein, das ist schon richtig so. Damit definiert man im Keil C51 
Bitvariablen.

Aber der Rest enthält so viele Fehler, daß er unmöglich compiliert.
Man sieht ja am Display, daß es nichtmal initialisiert (obere Reihe 
Kästchen).

von Martin H. (Gast)


Lesenswert?

Ja leider, bekomm das nicht hin beim dht11 Sensor hat es wunderbar 
geklappt ohne Probleme. Beim mlx will das irgendwie nicht klappen, mir 
gehen die Ideen aus, wenn ich es ein speise bekomm ich nur 255 raus und 
ne 1 was mir aber überhaupt nicht weiter hilft und es lässt sich auch 
ohne Fehler kompilieren mäckern tut er nicht würd er mir Fehler anzeigen 
wäre ich froh würde vlt dann auf denn Fehler kommen aber tut es leider 
nicht :/ aber zeigen tut er schon mal etwas an. Hat jemand vlt einen 
Test Code oder so etwas weil im Internet findet man kaum was nur von 
arduino.. hier ist das Datenblatt 
https://www.melexis.com/-/media/files/documents/datasheets/mlx90614-datasheet-melexis.pdf 
brauch ein Taktsignal für scl damit ich Daten heraus lesen kann von sda 
das will nicht funktionieren ? Danke für die Hilfe euch allen hoffe wir 
finden da eine Lösung.. wäre euch sehr dankbar ist meine Abschluss 
Prüfung und sry für die schreib Fehler..

von Joe F. (easylife)


Lesenswert?

Martin H. schrieb:
> beim dht11 Sensor hat es wunderbar
> geklappt ohne Probleme.

Ganz ehrlich, ich glaube dir kein Wort!
Du hast keinesfalls ein funktionsfähiges one-wire Protokoll für den 
DHT11 implementiert.

Martin H. schrieb:
> und es lässt sich auch
> ohne Fehler kompilieren mäckern tut er nicht würd er mir Fehler anzeigen
> wäre ich froh

Das, kann, überhaupt, nicht, sein!
Ich weiss nicht was du machst, aber diese Programm compiliert so nicht.
Wo soll denn die Funktion Data() sein?
Wie soll I2CSend() ohne Argument aufgerufen werden können?

Entweder nimmst du uns hier alle auf den Arm, oder irgendwas stimmt mit 
deinen Beschreibungen nicht, was du genau machst und wie das Programm 
aussieht.

von D.I (Gast)


Lesenswert?

Klingt nach nem 4-tage spaeten Aprilscherz ??

von D.I (Gast)


Lesenswert?

D.I schrieb:
> Klingt nach nem 4-tage ZU spaeten Aprilscherz ??

von Bernhard S. (b_spitzer)


Lesenswert?

du musst zu allererst den Baustein Konfigurieren und ihm eine gültige 
I2C-Bus Adresse verpassen. Dies geschieht am Anfang über die 
General-Call Adresse 0x00 (Schreibadresse). Die benötigten Register sind 
PWMCTRL zum deaktivieren des PWM-Modus, dann ConfigRegister1, dann SMbus 
Address.

um mit deinen Funktionen einen ersten Kontakt mit dem Baustein zu 
bekommen sollte das genügen:
1
#define GenCall_Write 0x00
2
// beliebige Schreib- (gerade Zahl) und Leseadresse
3
// (Schreibadresse+1 einsetzbar
4
#define MeineMLX_Adresse_Write 0x10
5
#define MeineMLX_Adresse_Read  0x11
6
7
void main(void)
8
{
9
   // initialisierung
10
   I2CInit();
11
   I2CStart();
12
   I2CSend(GenCall_Write); // Baustein zum schreiben adressieren
13
   I2CSend(0x02);  // Adresse des PWMCTRL-Registers
14
   I2CSend(Low_Byte_der_Konfiguration);
15
   I2CSend(High_Byte_der_Konfiguration);
16
   I2CSend(Pruefsumme);  // CRC-Prüfsumme des 16-Bit Wertes
17
   I2CStop();
18
19
   I2CInit();
20
   I2CStart();
21
   I2CSend(GenCall_Write); // Baustein zum schreiben adressieren
22
   I2CSend(0x05);  // Adresse des Config-Registers
23
   I2CSend(Low_Byte_der_Konfiguration);
24
   I2CSend(High_Byte_der_Konfiguration);
25
   I2CSend(Pruefsumme);  // CRC-Prüfsumme des 16-Bit Wertes
26
   I2CStop();
27
28
   I2CInit();
29
   I2CStart();
30
   I2CSend(GenCall_Write); // Baustein zum schreiben adressieren
31
   I2CSend(0x0E);  // Adresse des I2C-Adress-Registers
32
   I2CSend(MeineMLX_Adresse_Write); // neue Adresse setzen
33
   I2CStop();
34
 
35
   while(1);
36
37
}
Kann sein, dass der Baustein vorkonfiguriert worden ist, dann entfällt 
die Initialisierung. Die Adressen müssen dann angepasst werden.

Ansonsten ist das vielleicht noch hilfreich:
http://www.warf.com/download/7011_6507_3.pdf
https://www.pololu.com/docs/pdf/0J33/mlx90614esf_smbus_orangutan.pdf

CRC8-Berechnung:
http://www.sbs-forum.org/marcom/dc2/20_crc-8_firmwa
re_implementations.pdf

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.