Forum: Mikrocontroller und Digitale Elektronik MAX6675 am ATmega128


von Rush (Gast)


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.

von Kai F. (kai-) Benutzerseite


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

von Matthias Kölling (Gast)


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

von Rush (Gast)


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.
1
void SPI_MasterInit(void)
2
{
3
/* Set MOSI and SCK output, all others input */
4
DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK);
5
/* Enable SPI, Master, set clock rate fck/16 */
6
SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
7
}
8
void SPI_MasterTransmit(char cData)
9
{
10
/* Start transmission */
11
SPDR = cData;
12
/* Wait for transmission complete */
13
while(!(SPSR & (1<<SPIF)))
14
;
15
}
Was genau macht die Zeile
1
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? :
1
char SPI_SlaveReceive(void)
2
{
3
/* Wait for reception complete */
4
while(!(SPSR & (1<<SPIF)))
5
;
6
/* Return data register */
7
return SPDR;
8
}
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

von Matthias Kölling (Gast)


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

von Rush (Gast)


Lesenswert?

Werde ich machen. Aber stimmt der der Code überhaupt den ich oben 
angegeben habe ?

von Jörg X. (Gast)


Angehängte Dateien:

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)

von Rush (Gast)


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:
1
#include <stdint.h>
2
#include <stdlib.h>
3
#include <string.h>
4
#include <avr/io.h>
5
#include "lcd-routines.h"
6
7
/* Muss angepasst werden!!*/
8
#define CS_OUTP PORTB
9
#define CS_DDR DDRB
10
#define CS_PIN PB0
11
12
#define SPI_BUSY_WAIT() while(!(SPSR & (1<<SPIF)))
13
#define SEL_MAX6675() ((CS_OUTP) &= ~(1<<CS_PIN))
14
#define DESEL_MAX6675() ((CS_OUTP) |= (1<<CS_PIN))
15
#define spi_get_byte() spi_put_byte(0)
16
17
uint8_t spi_put_byte(uint8_t data)
18
{
19
  SPDR = data;
20
  //SPI_BUSY_WAIT();
21
  while(!(SPSR & (1<<SPIF)))
22
  return SPDR;
23
}
24
25
int16_t get_max6675_temp(void)
26
{
27
  int16_t act_temp;
28
  //SEL_MAX6675();
29
  CS_OUTP &= ~(1<<CS_PIN);
30
  act_temp = (spi_get_byte() << 8);
31
  act_temp |= spi_get_byte();
32
  return act_temp >> 3;
33
}
34
35
void init_spi(void)
36
{
37
  /* port initialisation 
38
  make sure /SS is output or high level*/
39
  DDRB |= (1<<PB0)|(1<<PB1)|(1<<PB2);// make MOSI output if necessary
40
  PORTB |= (1<<PB0);
41
42
#if CS_PIN != PB0
43
  //DESEL_MAX6675();
44
  CS_OUTP |= (1<<CS_PIN);
45
  CS_DDR  |= CS_PIN;
46
#endif
47
  /* set to < 4.3MHz; Mode 0 */
48
  SPCR = (1<<SPE)|(1<<SPR0);
49
}
50
/* convert the sensor output(0-4095) to sth. readable
51
  "0"
52
*/
53
char* temp_to_string(int16_t temp, char* string)
54
{
55
  /* take a look at the article "Fixpointarithmetik"
56
  */
57
  uint8_t len;
58
  //convert to tenth
59
  temp = (640L*temp)/256;
60
  // convert to string
61
  itoa(temp, string, 10);
62
  // insert decimal point
63
  len = strlen(string);
64
  string[len] = string[len-1];
65
  string[len-1] = '.';
66
  string[len+1] = 0;
67
  //! TODO: prevent memory corruption for temp < 1 ...
68
  return string;
69
}
70
71
int main(void)
72
{
73
  DDRA=0xFF;
74
  DDRG=0x00;
75
  lcd_init();
76
  init_spi();
77
78
  PORTA |= (1<<PA6);
79
80
  int16_t temperature;
81
while(1){
82
83
//    if (PING==30) {
84
    
85
    char temp[7]; // at least sizeof("1023.1\0") bytes
86
    temperature = get_max6675_temp();
87
    temp_to_string(temperature, temp);
88
    //lcd_string(string);
89
    lcd_string(temp_to_string(temperature, temp));
90
//    }
91
}
92
93
}
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?

von Rush (Gast)


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...

von Jörg X. (Gast)


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
1
//... oben einbauen
2
#include<util/delay.h>
3
//...
4
int main (void)
5
{
6
  char temp_str[7];
7
  uint8_t i;
8
  DDRA=0xFF;
9
  DDRG=0x00;
10
  lcd_init();
11
  init_spi();
12
13
  PORTA |= (1<<PA6);
14
15
  int16_t temperature;
16
  while(1)
17
  {
18
    temperature = get_max6675_temp();
19
    temp_to_string(temperature, temp_str);
20
    lcd_string(temp_str);
21
    for(i = 23; i; i--)
22
    {
23
      _delay_ms(10);
24
    }
25
  }
26
}

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

von Rush (Gast)


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 ;-)

von Rush (Gast)


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 ;-)

von Jörg X. (Gast)


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

von Rush (Gast)


Lesenswert?

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

von Rush (Gast)


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 ?

von Jörg X. (Gast)


Lesenswert?

Bau mal die init-funktion um:
1
void init_spi(void)
2
{
3
  DESEL_MAX6675();
4
  DDRB |= (1<<PB0)|(1<<PB1)|(1<<PB2);
5
  SPCR = (1<<SPE)|(1<<SPR0)|(1<<MSTR);/* das master-Bit hat bisher gefehlt
6
  - du könntest ruhig auch aufmerksam das Datenblatt lesen ;) */
7
}
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

von huhn (Gast)


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..

von Jörg X. (Gast)


Lesenswert?

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

von Rush (Gast)


Lesenswert?

1
int16_t get_max6675_temp(void)
2
{
3
  int16_t act_temp;
4
  //SEL_MAX6675();
5
  CS_OUTP &=~(1<<CS_PIN);
6
  act_temp = (spi_get_byte() << 8);
7
  act_temp |= spi_get_byte();
8
  //DESEL_MAX6675();
9
  CS_OUTP |= (1<<CS_PIN);
10
  return act_temp >> 3;
11
}
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 ;-)

von Rush (Gast)


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.

von Rush (Gast)


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

von Rush (Gast)


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.

von Jörg X. (Gast)


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

von Rush (Gast)


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.

von Rush (Gast)


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 :-)

von Jörg X. (Gast)


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:
1
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

von Rush (Gast)


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 ;)

von Jörg X. (Gast)


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

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.