SPI mit 12 Bit A/D Wandler

Gast #2026034
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ß
Gast #2026047
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 ?
Gast #2026065
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;
#2026087
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
Gast #2026092
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).
#2026104
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
#2026166
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);
Gast #2026725
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?
Gast #2153569
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren