www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik MAX6675 am ATmega128


Autor: Rush (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also im Datasheet vom MAX6675 steht geschrieben:

MAX   ->   AVR
SO         MISO
SCK        SCK
CS         SSB

MISO und SCK ist mir klar. Aber was soll der SSB sein? der SS-Pin am 
AVR?
Und wo muss der MOSI Pin am AVR hin?

Wie muss ich den AVR konfigurieren? Als Master nehme ich mal stark an.

Wenn dieser SSB-Pin tatsächlich wie von mir angenommen der SS-Pin vom 
AVR sein sol... verstehe ich das dann richtig: Wenn SS auf low gedrückt 
wird, fängt der MAX an zu senden und hört erst auf wenn der SS wieder 
auf high geht?

Danke schonmal für eure Hilfe.

Autor: Kai Franke (kai-) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie auch schon in deinem anderen Thread geschrieben solltest du etwas 
mehr Zeit mit lesen verbringen. Fragen ist ja nicht schlimm, aber man 
kann dir hier auch nicht alles von 0 an beibringen.
Wenn du dir mal überlegt hast was MOSI überhaupt heißt und wer damit was 
überträgt wird sich dir Frage schon erledigt haben

SSB ist der SS-Pin

Autor: Matthias Kölling (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Den MOSI kannst Du unbeschaltet lassen. Du schickst ja keine Daten zum 
Temperatursensor. Damit Du Deine Daten aus dem Sensor auslesen kannst, 
muss der Master den Takt vorgeben. Dazu schickt man ein Dummy-Byte. 
Damit wackelt der Clock. Das Byte ist nicht interessant, ausserdem ist 
die Leitung ja nicht angeschlossen. Nimm die Hardware SPI und schieb ein 
Byte raus und warte bis es versendet wurde. Dann kannst Du das erste 
Byte aus dem Datenregister der SPI lesen. Wenn ich es von Deinem letzten 
Thread richtig in Erinnerung habe, erwartet der Sensor 16 Bit. Also 
schiebst Du noch ein Dummybyte raus und erhältst nach dem Versenden das 
zweite Byte vom Sensor. Du mußt bei der Einstellung der SPI nur auf die 
Polarität und die Phasenlage des Clocks aufpassen. Die richtige 
Einstellung geht aus dem Datenblatt des Sensors hervor. Zur Not kann man 
mit den Einstellungen so lange herumspielen bis es passt, es gibt ja nur 
4.

Gruß Matthias

Autor: Rush (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gut, also ich initialisiere den Controller als Master, schreibe ein Byte 
ins SPDR Register, damit versende ich es praktisch. Richtig ?
Nachdem es verschickt wurde, kann ich das erste Byte aus meinem Sensor 
aus dem SPDR Register auslesen. Das SPDR Register ist Sende und 
Empfangsregister. Richtig ?

Das hier steht im DS vom Controller:
DDR_SPI, DD_MOSI und DD_SCK habe ich durch die Hardwareports ersetzt.
void SPI_MasterInit(void)
{
/* Set MOSI and SCK output, all others input */
DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK);
/* Enable SPI, Master, set clock rate fck/16 */
SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
}
void SPI_MasterTransmit(char cData)
{
/* Start transmission */
SPDR = cData;
/* Wait for transmission complete */
while(!(SPSR & (1<<SPIF)))
;
}
Was genau macht die Zeile
while(!(SPSR & (1<<SPIF)))

Kann ich das als eine Art Wartepunkt ansehen? Es geht praktisch erst 
weiter wenn das Byte SPIF im SPSR Register auf 0 steht ?


Zum Empfang brauche ich dann das hier? :
char SPI_SlaveReceive(void)
{
/* Wait for reception complete */
while(!(SPSR & (1<<SPIF)))
;
/* Return data register */
return SPDR;
}
Also sobald ich ins SPDR was reinschiebe gilt es als versendet?Oder muss 
ich da noch irgendwo sagen dass das Byte versendet werden soll?
Wenns versendet ist muss ich SPI_SlaveReceive() aufrufen. Die Funktion 
holt dann wiederrum das vom Sensor verschickte Byte wieder aus dem SPDR 
Register raus?

Ich brauche ja zwei Byte vom Sensor. Woher weiss denn der Controller 
welches Byte er gerade empfangen hat? Ob es Bit 1-7 oder
Bit 8-16 ist?

Man, das ganze hier irritiert mich total ;-)  Wäre dankbar wenn ihr mir 
etwas auf die Sprünge helfen könntet. Ein Beispielcode würde mir 
sicherlich gut weiterhelfen.

Danke schonmal im Voraus.

Konrad

Autor: Matthias Kölling (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Welches Byte welches ist, kann der Controller nicht wissen. Du mußt die 
Bytes laut Datenblatt des Sensors interpretieren. Die SPI ist weiter 
nichts wie ein Schieberegister. Mit jedem Bit, das vom Controller 
rausgeschoben wird, kommt von Sensor eins zurück. Damit ist die 
Zuordnung Deiner Bytes gewährleistet. Du mußt nur noch wissen, welches 
Byte der Sensor zuerst rausschickt, bzw. ob er MSB oder LSB zuerst 
schickt. Das ist dann reine Interpretationssache und hat mit der 
Übertragung an sich nichts zu tun. Ich würde sagen probier es erst mal 
aus. Wenn Du zwei Bytes empfangen kannst, die Werte aber nicht passen, 
mußt Du die Clock Polarität und Phase noch korrigieren. Das entspricht 
dem SPI Modus.

Gruß Matthias

Autor: Rush (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Werde ich machen. Aber stimmt der der Code überhaupt den ich oben 
angegeben habe ?

Autor: Jörg X. (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
> Woher weiss denn der Controller welches Byte er gerade empfangen hat?
Das erste Byte nachdem CS auf low geht ist das High-byte (bit15-8), das 
nächste das low-byte...
>Ein Beispielcode würde mir sicherlich gut weiterhelfen.
wahrscheinlich (genauso wie das Datasheet, das Tutorial etc..) ;)

hth. Jörg
ps.: der Anhang ist für den AVR-GCC/WinAVR gedacht (du hast nirgends 
angegeben, welchen Compiler du benutzt)

Autor: Rush (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke Jörg für den Code... jetzt versteht ich das Datasheet vom Maxim 
erst ;-)
Aber aus irgendeinem Grund bekomme ich trotzdem keine Daten vom Sensor

Das hier ist mein Code:
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <avr/io.h>
#include "lcd-routines.h"

/* Muss angepasst werden!!*/
#define CS_OUTP PORTB
#define CS_DDR DDRB
#define CS_PIN PB0

#define SPI_BUSY_WAIT() while(!(SPSR & (1<<SPIF)))
#define SEL_MAX6675() ((CS_OUTP) &= ~(1<<CS_PIN))
#define DESEL_MAX6675() ((CS_OUTP) |= (1<<CS_PIN))
#define spi_get_byte() spi_put_byte(0)

uint8_t spi_put_byte(uint8_t data)
{
  SPDR = data;
  //SPI_BUSY_WAIT();
  while(!(SPSR & (1<<SPIF)))
  return SPDR;
}

int16_t get_max6675_temp(void)
{
  int16_t act_temp;
  //SEL_MAX6675();
  CS_OUTP &= ~(1<<CS_PIN);
  act_temp = (spi_get_byte() << 8);
  act_temp |= spi_get_byte();
  return act_temp >> 3;
}

void init_spi(void)
{
  /* port initialisation 
  make sure /SS is output or high level*/
  DDRB |= (1<<PB0)|(1<<PB1)|(1<<PB2);// make MOSI output if necessary
  PORTB |= (1<<PB0);

#if CS_PIN != PB0
  //DESEL_MAX6675();
  CS_OUTP |= (1<<CS_PIN);
  CS_DDR  |= CS_PIN;
#endif
  /* set to < 4.3MHz; Mode 0 */
  SPCR = (1<<SPE)|(1<<SPR0);
}
/* convert the sensor output(0-4095) to sth. readable
  "0"
*/
char* temp_to_string(int16_t temp, char* string)
{
  /* take a look at the article "Fixpointarithmetik"
  */
  uint8_t len;
  //convert to tenth
  temp = (640L*temp)/256;
  // convert to string
  itoa(temp, string, 10);
  // insert decimal point
  len = strlen(string);
  string[len] = string[len-1];
  string[len-1] = '.';
  string[len+1] = 0;
  //! TODO: prevent memory corruption for temp < 1 ...
  return string;
}

int main(void)
{
  DDRA=0xFF;
  DDRG=0x00;
  lcd_init();
  init_spi();

  PORTA |= (1<<PA6);

  int16_t temperature;
while(1){

//    if (PING==30) {
    
    char temp[7]; // at least sizeof("1023.1\0") bytes
    temperature = get_max6675_temp();
    temp_to_string(temperature, temp);
    //lcd_string(string);
    lcd_string(temp_to_string(temperature, temp));
//    }
}

}
Ich bekomme auf dem Display nur ".0" angezeigt.

Die vier defines der Funktionen habe ich jeweils durch den Befehl direkt 
ersetzt. So wie es original in deinem Code drin steht kam nicht mal das 
.0
im Display.
Die init_spi habe ich auch angepasst wie du siehst. Aber es kommt 
einfach nichts raus der der Mühle :-(  Bin ich denn wirklich soooo blöd?

Autor: Rush (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe eben noch den MISO-Pin als Eingang initialisiert und erhalte 
jetzt einen Wert von -634.5
Das kann ja auch nicht sein, erst recht nicht bei Raumtemepratur...

Autor: Jörg X. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ok,
Du kannst noch testen, ob die umwandlung int->string korrekt 
funktioniert.
Hier musst du doch entscheiden:
>    temp_to_string(temperature, temp);
und das noch einbauen
>> lcd_string(temp);
oder
>    lcd_string(temp_to_string(temperature, temp));

obwohl, durch das zweimal-wandeln geht ja nichts kaputt ;)
Aber im MAX-Datasheet sind mir noch zwei 'Kleinigkeiten' aufgefallen:
> t_conv 0.17 bis 0.22 *Sekunden*
das ist lange, vor allem weil es später heißt:
> Forcing CS low immediately stops any conversion process.
.. und es gibt ja kein busy-Signal.
Teste mal
//... oben einbauen
#include<util/delay.h>
//...
int main (void)
{
  char temp_str[7];
  uint8_t i;
  DDRA=0xFF;
  DDRG=0x00;
  lcd_init();
  init_spi();

  PORTA |= (1<<PA6);

  int16_t temperature;
  while(1)
  {
    temperature = get_max6675_temp();
    temp_to_string(temperature, temp_str);
    lcd_string(temp_str);
    for(i = 23; i; i--)
    {
      _delay_ms(10);
    }
  }
}

hth. Jörg
ps.: ich hab da doch tatsächlich was vergessen ;)
int16_t get_max6675_temp(void)
{
  int16_t act_temp;
  SEL_MAX6675();
  act_temp = (spi_get_byte() << 8);
  act_temp |= spi_get_byte();
  DESEL_MAX6675();//NEU und wichtig...
  return act_temp >> 3;
}

Autor: Rush (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, werde ich mal ausprobieren wenn ich Feierabend habe....
Habe schon die nacht deswegen nicht schlafen können weil mir ständig 
C-Code vor den Augen hergeflimmert kam ;-)

Autor: Rush (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich will ja nicht unhöflich sein aber kann es sein dass die 
get_max6675_temp() doch etwas anders aussehen müsste? Ungefähr so
[c]
int16_t get_max6675_temp(void)
{
  int16_t act_temp;
  SEL_MAX6675();
  act_temp = (spi_get_byte() << 8);
  DESEL_MAX6675();
  SEL_MAX6675();
  act_temp |= spi_get_byte();
  DESEL_MAX6675();
  return act_temp >> 3;
}

Ich muss doch nach jedem übertragegenm Byte CS auf high und gleich 
wieder auf low stellen damit ich das zweite Byte vom Sensor bekomme. So 
habe ich es zumindest aus dem Datasheet verstanden.
Aber ich werde vorerst deine Lösung ausprobieren, du hast mehr drauf als 
ich ;-)

Autor: Jörg X. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Ich muss doch nach jedem übertragegenm Byte CS auf high und gleich
>wieder auf low stellen damit ich das zweite Byte vom Sensor bekomme.
  Nein! Nnachdem CS auf low geht musst du 16 Bit, also 2Bytes auslesen 
("Figure 1a"). Dann CS wieder auf high und dem MAXe ab und zu 'ein 
bisschen' (für den durchschnittlichen AVR eine halbe Ewigkeit ;) ) Zeit 
zum wandeln lassen...

hth. Jörg

Autor: Rush (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hm, geht immer noch nicht. Sehe nur 417.5 aufm Display ohne weitere 
Änderungen... :-(

Autor: Rush (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn ich mein Modul mit dem MAX einfach mal abklemme zeigt mir das 
Display auch nur 417.5 an. Kann es sein dass da was mit dem Pointer 
nicht stimmt ?

Autor: Jörg X. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bau mal die init-funktion um:
void init_spi(void)
{
  DESEL_MAX6675();
  DDRB |= (1<<PB0)|(1<<PB1)|(1<<PB2);
  SPCR = (1<<SPE)|(1<<SPR0)|(1<<MSTR);/* das master-Bit hat bisher gefehlt
  - du könntest ruhig auch aufmerksam das Datenblatt lesen ;) */
}
Wenn das nicht hilft, probier mal was passiert, wenn du folgendes 
machst:
a)
>   lcd_string("test123"), statt dem erzeugten string
b)
>   temp_to_string(0, temp_str);//(oder andere Zahlen unter 4096)
>   lcd_string(temp_str);

hth. Jörg

Autor: huhn (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich möchte auch einen solchen sensor proggen können, bitte helft mir.. 
ich baue aus alten backöfen  hühnerbrutautomaten.. die letzten eier 
wurden hartgekocht..

Autor: Jörg X. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@huhn:
den Sensor kann man gar nicht 'proggen' ;-)

Autor: Rush (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
int16_t get_max6675_temp(void)
{
  int16_t act_temp;
  //SEL_MAX6675();
  CS_OUTP &=~(1<<CS_PIN);
  act_temp = (spi_get_byte() << 8);
  act_temp |= spi_get_byte();
  //DESEL_MAX6675();
  CS_OUTP |= (1<<CS_PIN);
  return act_temp >> 3;
}
Also wenn ich mit dem Debugger nachschaue habe ich bei der zeile
act_temp |= spi_get_byte();
einen Wert von 517, nach dem   return act_temp >>3; sind es dann -1024.

Das Datenblatt lese ich mehr als genug, aber ich verstehe es ebe nicht 
was da steht. Bin zu hohl. Ich versuche im Nachhinein zu verstehen was 
der Code mach. Ich übernehme zwar deinen Code, aber was es dann macht 
möchte ich trotzdem gerne wissen ;-)

Autor: Rush (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Korrektur :

Beim ersten Programmaufruf habe ich ein act_temp einen wert von 517 drin 
stehen. Beim zweiten ändert sich er der Wert allerdings auf -32766 und 
bleibt dann unverändert.

Autor: Rush (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
und noch was
mit temp_to_string(4069, temp_str) bekomme ich 406.9 , mit
temp_to_string(317, temp_str) 31.7 und mit temp_to_string(0,temp_str) 
einfach nur .0

Autor: Rush (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was ist eigentlich mit dem CPOL und CPHA Bit im SPCR Register? Das gibt 
doch auch an wann die Daten gelesen werden sollen...

Ich habe zwar alle vier Möglichkeiten durchprobiert, hat auch nichts 
gebracht. Aber ich wollte es mal erwähnt haben.

Autor: Jörg X. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Beim ersten Programmaufruf habe ich ein act_temp einen wert von
> 517 drin stehen.
bei 517 ist das bit 2 gesetzt:
>517 -> 0b00000010 00000101
was bedeuten würde, dass du KEIN Thermoelement angeschlossen hast.
>>Bit D2 is normally low and goes high when the thermocouple input is open Was 
soll der Sensor denn dann für eine Temperatur liefern?

> mit temp_to_string(4069, temp_str) bekomme ich 406.9 , mit
> temp_to_string(317, temp_str) 31.7 und
Schön, d.h. die Stringwandlung funktioniert
> mit temp_to_string(0,temp_str) einfach nur .0
Da steht auch ein dickes TODO im Code -- der Code funktioniert nicht 
korrekt mit Sensorwerten unter 4 (1.0°C).

> Was ist eigentlich mit dem CPOL und CPHA Bit im SPCR Register? Das gibt
> doch auch an wann die Daten gelesen werden sollen...
Das ist richtig...
> Ich habe zwar alle vier Möglichkeiten durchprobiert,
Ist (war) nicht notwendig, der MAX verwendet Mode 0 - Vergleiche mal 
"Figure 1b" im Max-datasheet mit den Diagrammen "SPI Transfer format" im 
Kapitel "SPI" -> "Data Modes" im Mega128 Datasheet (bei mir Figure 77 
und 78, mein Datenblatt ist aber vom 10/06, kann also bei neueren anders 
sein).

Um also sinnvolle Ergebnisse zu bekommen, musst du:
 - ein Thermoelement (korrekt) anschließen
 - zwischen dem auslesen mindestens 170ms warten (besser: länger als 
220ms, das sind >1,7Mio Takte bei 8MHz </klugsch>)
hth. Jörg

Autor: Rush (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Naja, ich habe den sensor direkt angelötet. Ist also sehr 
unwahrscheinlich dass er "offen" ist. Aber gut, werd gucken dass ichso 
einen stecker beibekomme.

Autor: Rush (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mir ist noch was aufgefallen. Du hast geschrieben dass 517 0b00000010 
00000101 ist. Dann steht doch das 2. Bit auf 0. Also ist der Fühler 
richtig angeschlossen. Und noch was: Die 517 hatte ich ja auf dem 
Display stehen, und da du in deiner Funktion ja nur die 12 Bit für die 
Temperatur ausgefiltert hast, wird das Bit für den Temperaturfühler ja 
garnicht mit ausgegeben. Oder sehe ich das falsch?

Frohe Ostern wünsche ich dir übrigens :-)

Autor: Jörg X. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, langsam wirst du konfus, erst heißt es:
>> Also wenn ich mit dem Debugger nachschaue habe ich bei der zeile
>> act_temp |= spi_get einen Wert von 517,
Dann wieder
>> Die 517 hatte ich ja auf dem Display stehen,
was denn nun??? (unter Debugger verstehe ich ein JTAG-Interface o.ä.)

Poste nochmal:
- dein aktuelles Programm
- deine tatsächliche Schaltung
- Was Genau passiert und was nicht!

Ebenfalls Frohe Ostern!
hth. Jörg (dem langsam langweilig wird)

ps.: Wie kommst du nur auf die Idee "Bit 2" sei das zweite Bit ? ;)
Ein Byte sieht doch so aus:
Bit 7|Bit 6|Bit 5|Bit 4|Bit 3|Bit 2|Bit 1|Bit 0
(wegen 2 hoch 7, etc..), also ist "Bit 2" das dritte :D

Autor: Rush (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja Bit zwei ist das dritte, hast recht. Aber ich hatte jetzt das 
zweitwärtigste gemeint :-P
Und du hattest Recht, bei dem Debugger hatte ich 517 stehen. Hatte mich 
selbst verdacht..... langsam wirds konfus :)

Und ja, ich habe mir schon so gedacht dass es dir bald langweilig werden 
müsste...
Deshalb:  Ich habe es mittlerweile über die Software-SPI gelöst. Die 
erscheint mir irgendwie einfacher als diese ganze 
Konfigurationsgeschichte des Hardware SPI. Den Code für die Soft-SPI 
habe ich von Tobias Schlegel - http://www.tobias-schlegel.de/ und 
ihn ein wenig abgeändert.

Mein Sensor ist also richtig angeschlossen ;)

Autor: Jörg X. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Merkwürdig, das SPI ist ja schließlich noch eines der einfachsten 
Pheripherals.
Aber da der MAX ja ewig für die Wandlung braucht, hast du definitiv Zeit 
für Soft-SPI ;)
Schön, dass es geht
hth. Jörg

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.