Forum: Mikrocontroller und Digitale Elektronik SPI- Schnittstelle Byte senden


von Micha (Gast)


Lesenswert?

Hallo liebes Forum,

da ich mich erst mit dem Thema Mikrocontroller am einarbeiten bin, bitte 
ich schon mal um Nachsicht wegen evtl "einfacher" Fragen.

Ich haben einen Atmega 8515L (auf dem STK500), welchen ich nutzen will 
um einen IC ltc6802-2 zu konfigurieren und später auch auszulesen.

Zunächst will ich einige Bytes vom Master (Atmega) zum Slave senden. 
Gleichzeitig will ich die gesendeten Bytes auf dem UART am Rechner zur 
Kontrolle (über uart_puts(comData);) ausgeben.

Die Initialisierung des Uart sollte stimmen, da ich einen "Hello World" 
String normal ausgeben kann.

Die LED on/off dienen lediglich zur eigenen Kontrolle, wo ich mich 
gerade befinde.

Momentan werden die Bytes nicht sauber gesendet. Auch an der Uart 
Schnittstelle sehe ich ein anderes Ergebnis als erwartet.
Wäre toll, wenn mir jemand weiterhelfen könnte.

Hier ist mein verwendeter Code:


#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>


#ifndef F_CPU

#define F_CPU 1000000L // Systemtakt in Hz
#endif
#define BAUD 4800L // Baudrate
// Berechnungen
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1) // clever runden
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1))) // Reale Baudrate
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD-1000) // Fehler in Promille
#if ((BAUD_ERROR>10) || (BAUD_ERROR<-10))
#error Systematischer Fehler der Baudrate grösser 1% und damit zu hoch!
#endif

#include <util/delay.h> /* in der aktuellen Version in util/ */



// UART Interface

void uart_init(void)      //Init Uart
{
  //UCSRB |= (1<<RXEN) | (1<<TXEN); // UART TX einschalten
  UCSRB |= (1<<TXEN); // UART TX einschalten
  UCSRC = (1<<URSEL)| (1<<UCSZ1) | (1<<UCSZ0);  // 8 Datenb , 1Stb
  UBRRH = UBRR_VAL >> 8;
  UBRRL = UBRR_VAL & 0xFF;
}

void uart_putch(char c) {
   while(!(UCSRA & (1<<UDRE)));
   UDR = c;
}

void uart_puts(char * str) {
   while (*str) {
      uart_putch(*str++);
   }
}


//////////// Test LED 3 on off ////////////

void led3_on(void)
{
DDRB  |= (1 << PB3);     //Port 3 Out
PORTB |= (1 << PB3);     //LED on
_delay_ms(1000);
}

void led3_off(void)
{
DDRB  |= (1 << PB3);     //Port 3 Out
PORTB &= ~(1 << PB3);    //LED off
_delay_ms(1000);
}


// SPI Interface
void spi_init (void)          //Init SPI
{
  DDRB |= (1<<PB4)|(1<<PB5)|(1<<PB7);   // MOSI,SCK,SS als Output
  PORTB |= (1<<PB4);           //SS auf High
  SPCR |= (1<<SPE)|(1<<MSTR);       // SPI enable, Master Mode
}

void spi_senden (unsigned comData, unsigned CFGR0, unsigned CFGR1, 
unsigned CFGR2, unsigned CFGR3, unsigned CFGR4, unsigned CFGR5)
{

  PORTB &= ~(1 << PB4);         //START SENDEN SS auf Low

  SPDR = comData;              //Command Byte
  while (!(SPSR & (1 << SPIF)));     //warten bis gesendet


  while (!(UCSRA & (1<<UDRE)))  //ist die Sendestufe bereit?
      {
    }
  uart_puts(comData);
    led3_on();

  SPDR = CFGR0;
  while (!(SPSR & (1 << SPIF)));     //warten bis gesendet
  SPDR = CFGR1;
  while (!(SPSR & (1 << SPIF)));     //warten bis gesendet
  SPDR = CFGR2;
  while (!(SPSR & (1 << SPIF)));     //warten bis gesendet
  SPDR = CFGR3;
  while (!(SPSR & (1 << SPIF)));     //warten bis gesendet
  SPDR = CFGR4;
  while (!(SPSR & (1 << SPIF)));     //warten bis gesendet
  SPDR = CFGR5;
  while (!(SPSR & (1 << SPIF)));     //warten bis gesendet


while (!(UCSRA & (1<<UDRE)))  //ist die Sendestufe bereit?
      {
    }
   uart_puts(CFGR5);
  //led3_off();

  PORTB |= (1 << PB4);           //ENDE SS auf high

}



int main(void)
{
     uart_init();

    spi_init();


  spi_senden(0x01, 0xE1, 0x04, 0x00, 0xFF, 0x73, 0xAF); // Write Config



  while(1)
   {

  led3_off();


   }

return 0;
}

von holger (Gast)


Lesenswert?

>Momentan werden die Bytes nicht sauber gesendet.

Woher weisst du das? Auf dem Osci nachgesehen?
Dann liegt es an deiner Schaltung.

> Auch an der Uart
>Schnittstelle sehe ich ein anderes Ergebnis als erwartet.

Das ist so weil du nicht weisst was ein String ist.
Ich rate dir dringend zu einem C-Buch oder Lehrgang.

von Stefan E. (sternst)


Lesenswert?

1
uart_puts(comData);
Das ist Unsinn und sendet daher auch Unsinn. comData ist nun mal kein 
Pointer auf einen String.

Du solltest dir gleich von Anfang an angewöhnen, alle Warnungen des 
Compilers ernst zu nehmen.

PS: Für "uart_puts(CFGR5);" gilt natürlich das gleiche. ;-)

PPS: Und verwende bitte beim nächsten Mal die vom Forum angebotene 
Möglichkeit der Source-Code-Formatierung.

von Micha (Gast)


Lesenswert?

Danke ,
mit
1
 uart_putch[comData);
stimmt auch die Ausgabe im Terminal.

Die Daten werden laut Oszi verschickt.
Aber eigentlich will ich den Befehl nur einmal senden. Momentan habe ich 
bei SPI_Senden() eine Endlos-Schleife und ich sehe nicht warum?
In die While(1) Schleife komme ich gar nicht hinein.

von holger (Gast)


Lesenswert?

Watchdog Fuse aus? Richtigen uC eingestellt?

von Micha (Gast)


Lesenswert?

WDTON Haken ist nicht gesetzt und Atmega8515 ist eingestellt.

Wenn ich die Funktion innerhalb von main() aufrufe, dann wird die 
Schleife genau einmal durchlaufen und geht weiter zur while(1).

von holger (Gast)


Lesenswert?

>>Aber eigentlich will ich den Befehl nur einmal senden. Momentan habe ich
>>bei SPI_Senden() eine Endlos-Schleife und ich sehe nicht warum?
>>In die While(1) Schleife komme ich gar nicht hinein.

>Wenn ich die Funktion innerhalb von main() aufrufe, dann wird die
>Schleife genau einmal durchlaufen und geht weiter zur while(1).

Fällt dir auf das sich deine Aussagen widersprechen?

von Micha (Gast)


Lesenswert?

Hmm vielleicht habe ich mich ja falsch ausgedrückt.

Ich will die Byte-folge einmal senden. Wenn ich die Funktion zum senden 
der Bytes spi_senden() außerhalb von main verwende, dann wiederholt sich 
diese Funktion immer wieder. Wenn ich die Funktion innerhalb von main() 
setze und überhalb der while(1) Schleife, dann wird die Byte-Folge genau 
einmal gesendet.

von Johannes (Gast)


Lesenswert?

Gibt es eigentlich eine fertige Funktion,um per SPI Strings zu senden? 
oder müsste man sich die aus der Bytesenden-Routine selber zaubern und 
die Routine mehrmals aufrufen, solange das zeichen != '\0' ist?

Danke und Gruß
jo

von Micha (Gast)


Lesenswert?

Ich kenne keine fertige Funktion, da ja auch jede SPI Kommunikation von 
Datenblatt abhängt.

von Elektrolyt (Gast)


Lesenswert?

Hey Micha,

was genau machst du denn mit dem Balancer ?
Laden und samplen und balancen? oder nur als ADC benutzen?
ich hab das teil auch mal eingesetzt, allerdings habe ich keine Ahnung 
wo der Quellcode ist...


gruß Elko

von Tobias T. (thelaughingman)


Lesenswert?

füg mal ein
1
#include <avr/wdt.h>
ein und ruf direkt als erstes in der main
1
wdt_disable();
auf.

Der 8515L hat keine Fuse für den WatchDogTimer (aus), da du ihn nicht 
deaktiviert startet der Mikrocontroller permanent neu.
WDTON mach ihn nur permanent an. Ausschalten muss du den WDT trotzdem.

Für später um die Initialisierungen immer ein
1
cli();
2
//Initialisierungen ...
3
sei();
packen.

Die DDRX Register für die Pins muss du auch nur einmal einstellen. 
Braucht nicht vor jeden ändern der LED nochmal stehen.

von Tobias T. (thelaughingman)


Lesenswert?

Zu deiner Frage (String per SPI senden):
Schau dir doch den Code zu senden von String über UART, an der greift 
auch auf das Senden einzelner Zeichen zurück. Dasselbe muss du mit SPI 
machen (-> Copy&Paste).

von Stefan E. (sternst)


Lesenswert?

Micha schrieb:

> Ich will die Byte-folge einmal senden. Wenn ich die Funktion zum senden
> der Bytes spi_senden() außerhalb von main verwende, dann wiederholt sich
> diese Funktion immer wieder.

Dann zeige uns den Code zu diesem "außerhalb von main verwende", denn in 
dem Code oben wird die Funktion in main aufgerufen. Wie sollen wir dir 
sagen, was dort schief läuft, wenn wir den Code dazu nicht kennen?

von Micha (Gast)


Angehängte Dateien:

Lesenswert?

Dieser Code macht zumindest das, was ich will.
Einmalig eine Bytefolge aussenden und dauern eine kürzere Byte-folge 
aussenden.
Der Quellcode ist als Anhang beigefügt

@Elko
ich will zunächst die Spannung über ADC auslesen und ausgeben.
Wäre toll, wenn Du den Quellcode nochmal findest (?) und mal posten 
kannst.

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.