Hallo zusammen,
habe auf meinen AT90CAN folgendes Programm aufgespielt.
1
/* ADC initialisieren */
2
voidADC_Init(void)
3
{
4
5
6
//SPI initialisieren
7
// Set MOSI, SCK and SS output, all others input
8
DDR_SPI=(1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_SS);
9
// Enable SPI, Master, set clock rate fck/16 / MSB first
10
SPCR=(1<<SPE)|(1<<MSTR)|(1<<SPR0);
11
12
SPCR&=~(1<<CPOL);
13
SPCR&=~(1<<CPHA);
14
//ADC deaktivieren
15
PORT_SPI|=(1<<DD_SS);
16
17
}
In der main rufe ich am Anfang ADC_Init() auf.
Wenn ich das Programm auf den Controller per ICE mk2 übertrage kann ich
mit dem Oszi einen kurzen Clock-Block (8 Perioden) sehen.
Ist die Übertragung beendet, liefert der SCK-Pin kein Clocksignal mehr?
Hat jemand eine Idee wo der Fehler liegen könnten.
Schon mal vielen Dank!
Gruss
Walter
Walter Reuther schrieb:> Ist die Übertragung beendet, liefert der SCK-Pin kein Clocksignal mehr?>> Hat jemand eine Idee wo der Fehler liegen könnten.
Welcher Fehler?
Bei SPI ist immer nur während einer Übertragung ein Clocksignal
vorhanden.
Hallo Stefan,
hab ich gerade auch gemerkt.
Die SPI Übertragung läuft gerade. Jedoch passen die Werte nicht.
Ich nutze einen TMP121 - Sensor
http://www.ti.com/general/docs/lit/getliterature.tsp?literatureNumber=sbos273c
Mit folgender Routine lese ich meine SPI aus.
Hat jemand eine Ahnung was da nicht passen könnte?
Deswegen frage ich ja, ob mir jemand helfen könnte.
Ich weis schon, dass der SPI(Atmel) nur ein 8-bit langes Register
besitzt und der Sensor 16-bit (2 zeros 1 sign 15 daten) rüberschiebt.
Nur wie kann ich es in meinem Programm umsetzen. Zudem muss ich nach
einem CS 16 Clk-Takte ausgeben und nicht wie jetzt 8.
Kann mir jemand bei der Codeumsetzung helfen.
Ich bin leider im Bereich uC nicht sehr bewandert (Komme aus der
Schaltungstechnik).
Vielen Dank!
Gruss
Walter Reuther schrieb:> Ich weis schon, dass der SPI(Atmel) nur ein 8-bit langes Register> besitzt und der Sensor 16-bit (2 zeros 1 sign 15 daten) rüberschiebt.>> Nur wie kann ich es in meinem Programm umsetzen. Zudem muss ich nach> einem CS 16 Clk-Takte ausgeben und nicht wie jetzt 8.
Indem du den Code einfach zweimal ausführst:
Walter Reuther schrieb:> Vielen Dank für die Antwort,>> wie kann ich dann die beiden 8-bit zusammenfügen und als float-Wert> (Temperaturwert) an den USART übergeben?
Zahlensysteme- und Darstellung hast du also auch nicht verstanden.
Egal was du wie umwandelst, du sendest Bytes durch deinen UART. Warum
also nicht die 2 Bytes senden und der Empfänger kümmert sich um das
DARSTELLEN des Wertes?
Alternativ, wenn du Text direkt an ein Terminal(programm) senden willst,
dann musst du den Wert in einen String umwandeln und bekommst 1 Byte pro
Buchstabe Text. Das geht dann mit itoa oder sprintf.
gruß cyblord
hallo cyblord.
ich hab alles mal wie folgt umgesetzt.
SPI.c
1
#define F_CPU 16000000 // clock frequency in Hz
2
#include<avr/io.h>
3
#include<util/delay.h>
4
#include<stdio.h>
5
6
#define DD_MOSI PINB2
7
#define DD_MISO PINB3
8
#define DD_SCK PINB1
9
#define DD_SS PINB0
10
#define DDR_SPI DDRB
11
#define PORT_SPI PORTB
12
13
14
15
/* ADC initialisieren */
16
voidADC_Init(void)
17
{
18
/* Set MOSI and SCK output, all others input */
19
DDR_SPI=(1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_SS);
20
/* Enable SPI, Master, set clock rate fck/16 */
21
SPCR=(1<<SPE)|(1<<MSTR)|(1<<SPR0);
22
}
23
24
25
//ADC Einzelmessung
26
intADC_Read(void)
27
{
28
volatileintdata;
29
data=0;
30
31
//ADC aktivieren
32
PORT_SPI&=~(1<<DD_SS);
33
34
// Start transmission
35
SPDR=0xFF;
36
while(!(SPSR&(1<<SPIF)));
37
data=SPDR;
38
39
// Start transmission
40
SPDR=0xFF;
41
while(!(SPSR&(1<<SPIF)));
42
data=SPDR;
43
44
//ADC deaktivieren
45
PORT_SPI|=(1<<DD_SS);
46
_delay_ms(1000);
47
48
49
returndata;
50
51
}
main.c
1
#include<avr/io.h>
2
#include<stdlib.h>
3
#include"UART.h"
4
#include"SPI.h"
5
6
#define F_CPU 16000000 // clock frequency in Hz
7
#include<avr/interrupt.h> // include interrupt-routine
8
#include<util/delay.h>
9
10
11
12
13
intmain(void)
14
{
15
16
charx[8];
17
floattest;
18
19
init_uart0();
20
ADC_Init();
21
22
23
24
while(1)
25
{
26
27
_delay_ms(3000);
28
29
test=(float)ADC_Read();
30
dtostrf(test,6,3,x);
31
32
33
uart_transmitt_frame(x);
34
uart_transmitt_frame("\r\n");
35
}
36
37
38
39
return0;// never reached
40
41
}
Leider funktioniert das so nicht.
Muss ich nicht erst die beiden 8-bit Register zu einem long int -
Register zusammenfügen und dann nach float - casten um den Wert danach
an den UART mittels dtostrf zu übergeben?
Ich werde noch wahnsinnig.
Kann mir jemand eine genaue Hilfestellung geben?
Vielen Dank!
Gruss
Anstatt haufenweise Code zu posten, könntest du mal auf meine Frage
eingehen, was du jetzt eigentlich genau Übertragen willst? Vielleicht
solltest du dir das selber erstmal klarmachen?
Wenn du einen String via UART übertragen willst (was du nicht sagst,
weil du gar nichts dazu sagst WAS DU TUN WILLST), solltest du dir als
erstes eine Funktion machen die das tut. Dazu gibt man ihr einen Pointer
auf ein char und die durchläuft das Array und sendet jedes Byte raus.
Bis zur 0 dann ist Ende. So eine Funktion findest du überall im Netz.
Das ist mal Schritt 1.
Dann Schritt 2, wie bekommst du deinen String aus deinem Messwert.
Mit uint16_t x=ADC liest du den Wert erstmal in eine geeignete Variable
ein.
Jetzt musst du Rechnen, je nach Anschaltung deiner Spannung und der
Formel aus dem Datenblatt (ADC=(V*1024)/Vref) rechnest du jetzt den ADC
Wert in eine Spannung Volt um. Das kannst du mit Float machen. Oder als
Festkommawert z.B. Spannung in mV, dann bleibts eine Ganzzahl.
So und Schritt 3, wie wandelst du dein Ergebniss (float oder Ganzzahl)
jetzt in einen String um. Dazu nimmt man bei ganzzahlen itoa (bzw. utoa,
ultoa) oder wenn du nen Float hast, dann am bestne mit sprintf.
Und diesen String kannst du jetzt mit deiner neuen sende_String Funktion
schicken.
So und jetzt würde ich an deiner Stelle Schritt für Schritt vorgehen und
erstmal Zwischenschritte testen.
gruß cyblord
Hallo!
Also das Senden float-Wertes funktioniert (wurde mittels
Terminalprogramm überprüft) bereits. (Diese Funktion ist mittels
dtostrf( test, 6, 3, x); gelöst.)
Nun zu meiner SPI:
Es handelt sich um einen Digitalen-Temperatursensor (CS, SDO, CLK)
dieser liefert laut Datenblatt 2 zeros, 1 sign-bit, 15 data-bits.
Diesen "Digitalen-Temperaturwert" möchte ich mir vom Sensor holen in
einen float-Wert umsetzen und dann an die UART-Sendefunktion übergeben.
Wie gesagt, die UART-Kommunikation mit dem Terminal funktioniert schon
so wie sie soll, nur die SPI bereitet noch Schwierigkeiten.
Im AT90CAN128 ist das SPI-Register nur 8-bit lang ich muss jedoch wie
oben beschrieben 16 - bit abholen.
Daher meine Frage wie die Lösung in der Programmierung aussehen könnte.
Ich bin leider kein "großer Programmierer" aber vll. kann mir jemand von
euch Codehilfestellungen geben!
Vielen DANK!
Walter Reuther schrieb:> Im AT90CAN128 ist das SPI-Register nur 8-bit lang ich muss jedoch wie> oben beschrieben 16 - bit abholen.
Das löst man einfach so, dass man den Lesevorgang 2 mal hintereinander
macht. CS muss man sowieso manuell steuern und somit lässt man es auf Lo
bis beide Bytes empfangen wurden.
Also:
cs_lo();
uint8_t b1=readSPI();
uint8_t b2=readSPI();
cs_hi();
Dann die beiden Bytes zu einem Int16 zusammenbasteln und weiter gehts.
Dachte bei ADC_Read sofort an den internen ADC und hab vergessen dass du
ja einen externen über SPI hast. Ändert aber an der Vorgehensweise
direkt nichts.
Walter Reuther schrieb:> Kann man dann die Funktion einfach in eine Floatvariable casten?
Schon.
Aber was hast du dauernd mit deinem float?
Das ändert doch an der Zahl selber nichts, ob du die jetzt als INteger
oder als Float in Textform zum Terminal schickst. Alles was du tust,
ist dem µCV Mehrarbeit aufbürden. Aber ob der jetzt aus den 258, die er
vom ADC bekommt, jetzt erst mal 258.0 macht, nur um das dann in einen
Text zu überführen und zum Terminal zu geben, ist doch gehupft wie
gehatscht. 258 ist 258. Egal ob dann durch den float noch ein
Nachkommaanteil dazu kommt, der sowieso 0 ist.
Also schieb doch den int erst mal so rüber. Damit du mal siehst, was da
überhaupt rauskommt.
Und wenn nicht das richtige rauskommt, dann schiebt man sich die beiden
erhaltenen Bytes data1 und data2 über die UART aufs Terminal (natürlich
als int).
Nicht gleich alles auf einmal wollen und sich dann wundern, dass nichts
funktioniert! Erst mal müssen die einfachen Sachen funktionieren. Dann
kann man darauf aufbauen und die komplizierteren Sachen machen. Und
float ist nun mal komplizierter zu verarbeiten als int.