Forum: Mikrocontroller und Digitale Elektronik AVR: ADC MCP3551 anschließen?


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Philipp K. (philipp_k94)


Lesenswert?

Hallo,

das hier ist mein erster Beitrag hier, deswegen stelle ich mich mal kurz 
vor.
Bin Philipp, 21 Jahre, aus Aachen. Studiere hier Elektrotechnik in der 
Vertiefung Automatisierungs- und Antriebstechnik.
Leider sind µCs in unserem Studium nie erwähnt worden und da ich mir ein 
Temperaturgeregeltes Wasserbad bauen möchte habe ich das zum Anlass 
genommen mich selbst damit zu beschäftigen.

Ich bastele nun schon seit ca. 4 Wochen mit einem Atmega8 herum den ich 
mit AVR Studio in C programmiere. PWM Ausgabe, Anschluss eines LCD 
Displays und den internen ADC habe ich bereits erfolgreich benutzen 
können.

Nun habe ich mir bei Reichelt einen MCP3551 bestellt (22 Bit ADC 
Wandler) und 2 Tage lang das Internet nach Theorie zum Anschluss und zur 
SPI Schnittstelle sowie das Datenblatt des ICs durchsucht.

Dabei habe ich einige Dinge verstanden, vieles ist aber noch nicht ganz 
klar.

Am wichtigsten: Wie Schließe ich den ADC überhaupt an den Atmega8 an?
Einige ähnliche  ADCs besitzen 4 Pins zur SPI Kommunikation (Clock, 
DataIN DataOut und ChipSelect). Dem 3551 fehlt jedoch ein DataIn Pin. 
Bleibt dann am AVR der MOSI unbelegt?

Das ist erstmal meine Hauptfrage, ich denke es werden aber noch viele 
weitere folgen bis ich das Teil am laufen habe.

Gruß,

Philipp

von Hubert G. (hubertg)


Lesenswert?

Beachte den CS Pin.

von Max H. (hartl192)


Lesenswert?

Philipp K. schrieb:
> Wie Schließe ich den ADC überhaupt an den Atmega8 an?
Frei -- MOSI
SDO  -- MISO
SCK  -- SCK
CS   -- Irgendein IO mit externem Pullup

: Bearbeitet durch User
von Philipp K. (philipp_k94)


Lesenswert?

Ich habe jetzt den CS Pin an PB0 gehängt, den ich vor dem Empfangen auf 
low ziehe. (Im Dattenblatt ist Dokumentiert, dass dadurch der ADC 
anfängt Daten zu senden)

Hier mal mein Code:

#include <avr/io.h>
#include "lcd-routines.h"
#include <util/delay.h>

char byte1, byte2, byte3;

void receiveSPI()

{
char dontcarebyte=0b10101010;
PORTB &= ~(1<<PB0);

SPDR = dontcarebyte;
while(!(SPSR & (1<<SPIF)));
byte1 = SPDR;

SPDR = dontcarebyte;
while(!(SPSR & (1<<SPIF)));
byte2 = SPDR;

SPDR = dontcarebyte;
while(!(SPSR & (1<<SPIF)));
byte3 = SPDR;

PORTB |= (1<<PB0);
}

void InitSPI(void)
{
DDRB = (1<<PB4)|(1<<PB5) | (1<<PB7) | (1<<PB0);
PORTB |= (1<<PB0);
SPCR = ( (1<<SPE)|(1<<MSTR) | (1<<SPR1) |(1<<SPR0));
}





int main(void)
{

  lcd_init();
  InitSPI();

  while (1)
  {
    lcd_clear();
  receiveSPI();
  lcd_data(byte1); lcd_data(byte2); lcd_data(byte3);
  _delay_ms(10);
  }


  return 0;
}

Natürlich funktioniert es nicht, war auch erstmal nur ein Versuch. Auf 
dem LCD Display sind für ein paar sekunden Wilde Zeichen zu lesen, dann 
gar nichts mehr.
Hat Jemand einen Tipp der mich in eine richtigere Richtung bringt?
Ist es überhaupt sinnvoll die 22 Bit in 3 Bytes zu teilen?

von Max H. (hartl192)


Lesenswert?

Versuch es mal so:
1
PORTB &= ~(1<<PB0);  // Start conversion
2
while (1)
3
{
4
  if(!(PINB & (1 << PINB4)))  // If data ready 
5
  {
6
    lcd_clear();
7
    receiveSPI();
8
    lcd_data(byte1); lcd_data(byte2); lcd_data(byte3);
9
    
10
    PORTB &= ~(1<<PB0);  // Start conversion
11
  }
12
}

> Wilde Zeichen
Was macht lcd_data()? Wenn sie nur das Byte 1:1 ans LCD schickt, wirst 
du nix sinnvolles lesen, da die Bytes als ASCII interpretiert werden.

> Ist es überhaupt sinnvoll die 22 Bit in 3 Bytes zu teilen?
Ich würde einen int24_t oder wenn es das nicht gibt eine int23_t 
verwenden

P.S.
In Zukunft bitte die C-Formatierung verwenden
1
[c]C-Code[/c]

: Bearbeitet durch User
von Philipp K. (philipp_k94)


Lesenswert?

Danke schonmal für die Antwort!
Ja das mit dem ACSII Code ist mir auch schon eingefallen, hier mal der 
verbesserte Code
1
#include <avr/io.h>
2
#include "lcd-routines.h"
3
#include <util/delay.h>
4
#include <stdlib.h>
5
6
uint8_t byte1, byte2, byte3;
7
char Buffer[20];
8
9
10
void receiveSPI()
11
12
{
13
14
PORTB &= ~(1<<PB0);
15
16
SPDR = 0;
17
while(!(SPSR & (1<<SPIF)));
18
byte1 = SPDR;
19
20
SPDR = 0;
21
while(!(SPSR & (1<<SPIF)));
22
byte2 = SPDR;
23
24
SPDR = 0;
25
while(!(SPSR & (1<<SPIF)));
26
byte3 = SPDR;
27
28
PORTB |= (1<<PB0);
29
}
30
31
void InitSPI(void)
32
{
33
DDRB = (1<<PB4)|(1<<PB5) | (1<<PB7) | (1<<PB0);
34
PORTB |= (1<<PB0);   
35
SPCR = ( (1<<SPE)|(1<<MSTR) | (1<<SPR1) |(1<<SPR0));  
36
}
37
38
39
40
41
42
int main(void)
43
{
44
45
  lcd_init();
46
  InitSPI();
47
48
  PORTB &= ~(1<<PB0);  // Start conversion
49
  while (1)
50
  {
51
    if(!(PINB & (1 << PINB4)))  // If data ready 
52
    {
53
      lcd_clear();
54
      receiveSPI();
55
      itoa(byte1,Buffer,2); lcd_string(Buffer); 
56
   // itoa(byte2,Buffer,2); lcd_string(Buffer); 
57
      //itoa(byte3,Buffer,2);  lcd_string(Buffer);
58
      PORTB &= ~(1<<PB0);  // Start conversion
59
    }
60
  }
61
62
63
  return 0;
64
}


Frage:

Max H. schrieb:
> PORTB &= ~(1<<PB0);  // Start conversion

Warum ziehst du PB0 am Anfang vor der Schleife und am Ende des If states 
auf 0? Der MCP reagiert an diesem Pin auf eine fallende Flanke.

Ich bekomme jetzt eine Reihe Einsen auf dem Display, unabhängig davon 
was am Eingang des ADCs anliegt...

: Bearbeitet durch User
von Max H. (hartl192)


Lesenswert?

Philipp K. schrieb:
> Warum ziehst du PB0 am Anfang vor der Schleife und am Ende des If states
> auf 0? Der MCP reagiert an diesem Pin auf eine fallende Flanke.
Die fallende Flanke am /CS Pin startet die Wandlung, siehe Datenblatt S. 
16 ff.

von Philipp K. (philipp_k94)


Lesenswert?

Das habe ich doch aber in der Funktion receiveSPI() schon am Anfang und 
Ende realisiert, oder sehe ich das falsch?

Gruß,

Philipp

von Max H. (hartl192)


Lesenswert?

Philipp K. schrieb:
> Ich bekomme jetzt eine Reihe Einsen auf dem Display, unabhängig davon
> was am Eingang des ADCs anliegt...
Wie sehen die Signale an den Datenleitungen aus?


Philipp K. schrieb:
> Das habe ich doch aber in der Funktion receiveSPI() schon am
> Anfang und
> Ende realisiert, oder sehe ich das falsch?
Ja, die Wandlung dauert aber ca. 72.73ms und man kann die Daten nicht 
sofort auslesen.

von W.S. (Gast)


Lesenswert?

Philipp K. schrieb:
> einen MCP3551 bestellt (22 Bit ADC
> Wandler) und 2 Tage lang das Internet nach Theorie zum Anschluss und zur
> SPI Schnittstelle sowie das Datenblatt des ICs durchsucht.

So, du bist also 21 und Student der Elektrotechnik.
Und du scheiterst schon an dem simplen und ausführlich beschriebenen 
Datenspiel zum Lesen des MCP3551 ?

Lies nochmal das Manual, programmiere dir ein paar Pins deines µC als 
GPIO Pins und mach das Datenspiel zu Fuß per Programm. Ist auch nicht 
langsamer als das Benutzen einer halben SPI Schnittstelle. Und lerne, 
aus den Angaben des Manuals herauszulesen, was nd wann die Beine des ADC 
tun.

W.S.

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.