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
voidSPI_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
voidSPI_MasterTransmit(charcData)
22
{
23
SPDR=cData;/* Start transmission */
24
while(!(SPSR&(1<<SPIF)));/* Wait for transmission complete */
25
}
26
27
28
29
intmain(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_tdwert;
39
charpuffer[7];
40
uint8_tMSB;
41
uint8_tLSB;
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ß
> 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;
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 ?
>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;
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;
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
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).
ja, ist ja auch richtig!
Dafür haste ja auch die Sendefunktion:
1
voidSPI_MasterTransmit(charcData)
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????
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);
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
voidSPI_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
voidSPI_MasterTransmit(charcData)
22
{
23
SPDR=cData;/* Start transmission */
24
while(!(SPSR&(1<<SPIF)));/* Wait for transmission complete */
25
}
26
27
28
29
intmain(void)
30
{
31
32
33
SPI_MasterInit();
34
lcd_init(LCD_DISP_ON);/* initialize display, cursor off */
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