SPI- Schnittstelle Byte senden

Gast #1406180
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;
}
Gast #1406212
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.
#1406268
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.
Gast #1406556
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.
Gast #1406697
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?
Gast #1406755
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.
Gast #1406800
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
Gast #1407021
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
#1407048
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.
#1407090
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?
Gast #1407183
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.
Angehängte Dateien:

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