Forum: Mikrocontroller und Digitale Elektronik SPI mit 12 Bit A/D Wandler


von unwissend (Gast)


Lesenswert?

Hallo zusammen,

für eine Entfernungsmessung mit einen Lasertriangulationssensor möchte 
ich den 12Bit A/D Wandler vom TYP ADS7816 verwenden.
Leider kriege ich es einfach nicht mit der SPI hin.

Hier mal der Code:
1
#include <stdlib.h>
2
#include <avr/io.h>
3
#include <avr/pgmspace.h>
4
#include "lcd.h"
5
#include <util/delay.h>
6
#include<avr/interrupt.h>
7
8
9
#define MOSI PB5
10
#define MISO PB6
11
#define SCK PB7
12
13
14
void SPI_MasterInit(void)
15
  {
16
  DDRB = (1<<PB5)|(1<<PB7)|(1<<PB4);          /* Set MOSI,SS and SCK output, all others input */
17
  PORTB=  (1<<PB5)|(1<<PB7)|(1<<PB4);  
18
  SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0)|(1<<SPIE);    /* Enable SPI, Master, set clock rate fck/16 */
19
  }  
20
21
void SPI_MasterTransmit(char cData)
22
  {  
23
  SPDR = cData;                    /* Start transmission */
24
  while(!(SPSR & (1<<SPIF)));            /* Wait for transmission complete */
25
  }
26
27
28
29
int main(void)
30
{
31
  
32
  
33
  SPI_MasterInit();
34
  lcd_init(LCD_DISP_ON);          
35
  DDRD|=0xff;//Anschluss für Display
36
  sei();
37
  
38
  uint16_t dwert;
39
   char puffer[7];
40
  uint8_t MSB;
41
  uint8_t LSB;
42
  
43
44
  while(1){
45
  
46
    _delay_ms(500);
47
  
48
    lcd_clrscr();
49
50
  
51
    MSB&=0x00;
52
    LSB&=0x00;
53
  
54
    PORTB|=(1<<MOSI);//fallende Flanke startet AD
55
    _delay_us(2);  /* Time the ADC needs to convert. */
56
    SPI_MasterTransmit(0);
57
  
58
    MSB=SPSR;
59
    MSB=SPDR;
60
  
61
    
62
    SPI_MasterTransmit(0);
63
    LSB=SPSR;
64
    LSB=SPDR;
65
66
  PORTB&=~ (1<<MOSI);// AD Wandler aussachlten
67
68
  
69
  
70
  
71
  itoa( MSB , puffer, 2);
72
  lcd_puts(puffer);
73
  lcd_putc(':');
74
  itoa( LSB,puffer, 2);
75
  lcd_puts(puffer);
76
77
78
;
79
80
  
81
82
  }
83
}

Der A/D wandelt zwar irgendwas wenn ich die Spannung (Entfernung ändere) 
aber nicht das was er soll bzw ist das MSB immer gleich dem LSB. Warum 
geht mir das LSB verloren?

Weiß jemand Rat? Ich bin am verzweifeln....

Achso: Datenblatt des ADS7816 findet ihr hier:
http://focus.ti.com/lit/ds/sbas061/sbas061.pdf

Vielen Dank

Gruß

von holger (Gast)


Lesenswert?

>    MSB=SPSR;
>    MSB=SPDR;

>aber nicht das was er soll bzw ist das MSB immer gleich dem LSB.

Du hast SPI nicht verstanden.

    SPI_MasterTransmit(0);
    LSB=SPSR;
    SPI_MasterTransmit(0);
    LSB=SPDR;

von unwissend (Gast)


Lesenswert?

und dann mit dem MSB das ganze nochmal??

Warum ist das so? Im datenblatt steht doch nur dass man beide Register 
lesen muss und nicht das man nachdem man SPSR gelesen hat nochmal ein 
Dummybyte schicken muss. Oder irre ich mich da ?

von holger (Gast)


Lesenswert?

>und dann mit dem MSB das ganze nochmal??

Hast du es ausprobiert?
SPI braucht 8 Takte Clock für ein Byte.

>    LSB=SPSR;

Wo kommen hier noch 8 Takte?

>    LSB=SPDR;

von unwissend (Gast)


Lesenswert?

Nein, ich kann es erst morgen auf der Arbeit ausprobieren. Da steht das 
ganze Zeusch. Habe vorher noch nie mit SPI gearbeitet, bin neu auf dem 
Gebiet.

Ist es so dann richtig ?

    SPI_MasterTransmit(0);
    MSB=SPSR;
    SPI_MasterTransmit(0);
    MSB=SPDR;

    SPI_MasterTransmit(0);
    LSB=SPSR;
    SPI_MasterTransmit(0);
    LSB=SPDR;

von Stephan W. (sir_wedeck)


Lesenswert?

Nabend,

schau dir bitte nochmal die Doku im DB an!!!
Wenn du es nicht verstehst, siehe hier in der Artikelsammlung unter SPI 
nach.
http://www.mikrocontroller.net/articles/Serial_Peripheral_Interface
spezial hier die APP: AVR151

Im DB deines MCs stehen auch Code-Schnipsel die du mal durch arbeiten 
könntest.

Denn so wüsstest du, das dieses Register "SPSR" das "SPI Status 
Register" ist und nichts mit Nutzdaten zu tun hat.

Stephan

von unwissend (Gast)


Lesenswert?

Stephan W. schrieb:
> Im DB deines MCs stehen auch Code-Schnipsel die du mal durch arbeiten
> könntest.
>
> Denn so wüsstest du, das dieses Register "SPSR" das "SPI Status
> Register" ist und nichts mit Nutzdaten zu tun hat.

Soweit klar, aber im DB des Mikrocontrollers (übrigens ich verwende den 
AtMega16) steht folgendes:

• Bit 7 – SPIF: SPI Interrupt Flag
When a serial transfer is complete, the SPIF Flag is set. An interrupt 
is generated if SPIE in
SPCR is set and global interrupts are enabled. If SS is an input and is 
driven low when the SPI is
in Master mode, this will also set the SPIF Flag. SPIF is cleared by 
hardware when executing the
corresponding interrupt handling vector. Alternatively, the SPIF bit is 
cleared by first reading the
SPI Status Register with SPIF set, then accessing the SPI Data Register 
(SPDR).

von Stephan W. (sir_wedeck)


Lesenswert?

ja, ist ja auch richtig!
Dafür haste ja auch die Sendefunktion:
1
void SPI_MasterTransmit(char cData)
2
  {  
3
  SPDR = cData;                    /* Start transmission */
4
  while(!(SPSR & (1<<SPIF)));            /* Wait for transmission complete */
5
  }

Die legt cData in Datenregister und die SPI gibs raus.
Du wartest bis das SPIF Bit gesetzt ist und verlässt die Funktion.
Alles soweit in Ordnung, nur warum dann noch mal im Hauptprogramm????
1
SPI_MasterTransmit(0);
2
MSB=SPSR;
Das hat da nichts zu suchen!!!!
Stephan

von Karl H. (kbuchegg)


Lesenswert?

Was hast du eigentlich mit deiner CS Leitung gemacht?

Du musst die bedienen! Siehe das Diagramm auf Seite 9 des Datenblattes 
unten. Der ADC beginnt zu arbeiten wenn CS auf 0 geht. Das kann ich in 
deinem Code nicht erkennen.

Ich bin mir jetzt nicht sicher, ob du bei eingeschaltetem SPI den MOSI 
Pin noch vom Programm aus schalten kannst. Ganz abgesehen davon, dass

       PORTB|=(1<<MOSI);//fallende Flanke startet AD

sowieso keine fallende Flanke erzeugt, sondern eine steigende (ausser du 
hast noch einen Inverter da dazwischen)

Aber wie gesagt: Ich bin mir nicht sicher, ob das überhaupt geht.




   char puffer[7];

das ist zu kurz für

  itoa( MSB , puffer, 2);

von unwissend (Gast)


Lesenswert?

hm also irgendwie funzt das ned. der AD wandelt zwar, geht auch auf null 
wie er soll aber ansonsten sind die Bytes immer gleich.
Ich weiß eifnach nicht was ich noch tun könnte.
Ich habe nun den Code wie folgt:
1
#include <stdlib.h>
2
#include <avr/io.h>
3
#include <avr/pgmspace.h>
4
#include "lcd.h"
5
#include <util/delay.h>
6
#include<avr/interrupt.h>
7
8
9
#define MOSI PB5
10
#define MISO PB6
11
#define SCK PB7
12
13
14
void SPI_MasterInit(void)
15
  {
16
  DDRB = (1<<PB5)|(1<<PB7)|(1<<PB4);          /* Set MOSI,SS and SCK output, all others input */
17
  PORTB=  (1<<PB5)|(1<<PB7)|(1<<PB4);  
18
  SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0)/*|(1<<SPIE)*/;    /* Enable SPI, Master, set clock rate fck/16 */
19
  }  
20
21
void SPI_MasterTransmit(char cData)
22
  {  
23
  SPDR = cData;                    /* Start transmission */
24
  while(!(SPSR & (1<<SPIF)));            /* Wait for transmission complete */
25
  }
26
27
28
29
int main(void)
30
{
31
  
32
  
33
  SPI_MasterInit();
34
  lcd_init(LCD_DISP_ON);          /* initialize display, cursor off */
35
  DDRD|=0xff;
36
  sei();
37
  
38
  uint16_t dwert;
39
   char puffer[15];
40
  uint8_t MSB;
41
  uint8_t LSB;
42
  PORTB|=(1<<MOSI);//MOSI(CS AUF DEF. PEGEL)
43
44
  while(1){
45
  
46
    _delay_ms(500);
47
  
48
    lcd_clrscr();
49
50
  
51
    MSB&=0x00;
52
    LSB&=0x00;
53
  
54
    PORTB&=~(1<<MOSI);
55
    _delay_ms(2);  /* Time the ADC needs to convert. */
56
    SPI_MasterTransmit(0);
57
    MSB=SPDR;
58
  
59
  
60
    SPI_MasterTransmit(0);
61
    LSB=SPDR;
62
63
  PORTB|= (1<<MOSI);
64
  dwert=MSB*LSB;  
65
  
66
  
67
  itoa( MSB , puffer, 16);
68
  lcd_puts(puffer);
69
  lcd_putc(':');
70
  itoa( LSB,puffer, 16);
71
  lcd_puts(puffer);
72
73
74
  lcd_putc('\n');
75
  lcd_puts("Dwert:");
76
  itoa( dwert , puffer, 10);
77
  lcd_puts(puffer);
78
  
79
  
80
81
  }
82
}


Hat noch jdm. einen Tip?

von Spätzünder (Gast)


Lesenswert?

Hallo,

hier geht's schon schief
PORTB|=(1<<MOSI);//MOSI(CS AUF DEF. PEGEL)
Das CS bzw SS und MOSI sind zwei total verschiedene Dinge.

Schaut man sich diese Zeile an
  DDRB = (1<<PB5)|(1<<PB7)|(1<<PB4);          /* Set MOSI,SS and SCK 
output, all others input */

Ist SS offensichtlich auf PB4, wird aber nicht bedient. wird also jetzt 
an MOSI "rumgespielt", kann beim AD-Wandler auch nichts rechtes mehr 
ankommen.

Und was soll daraus werden ?:  dwert=MSB*LSB;

Schöne Grüße

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.