Forum: Mikrocontroller und Digitale Elektronik USART >> Array vom PC zum mC


von Michael A. (ammannm)


Angehängte Dateien:

Lesenswert?

Guten Tag miteinander!

Ich weiss dass dieses Thema schon mehrmals hier behandelt wurde und ich 
habe schon einiges gelernt beim durchstöbern.
Mein erstes USART Programm findet ihr im Anhang!

Beschreibung:

Die Daten die ich vom PC sende sind Binär und 35 Bit lang.Immer 8 bit's 
werden zu einem byte und diese werden zum ansteuern der Ports verwendet 
(35 Bit = ca. 5 Ports). Die empfangenen Daten möchte ich in ein Array 
packen und auslesen können.
PORTA = zeichen[1];
PORTB = zeichen[2]; usw.

Das Array sollte ein zweisimensionales (array[5][200]) sein und würde 
max. 200(zeilen) auf 5(spalten) sein. Beim ausschalten und wieder 
einschalten sollten die Daten noch vorhanden sein!

Nun meine Fragen:

-Funktioiert dieses Programm so wie es im Anhang ist überhaupt(soll nur 
daten auslesen)?
- wie bringe ich die Daten in ein Array?
- Wie speichere ich die Daten ab?

Vielen dank für die Hilfe!!

MfG Michael

von Jean P. (fubu1000)


Lesenswert?

> Ich weiss dass dieses Thema schon mehrmals hier behandelt wurde und ich
> habe schon einiges gelernt beim durchstöbern.
> Mein erstes USART Programm findet ihr im Anhang!
Naja, ich sag lieber nix.

> Die Daten die ich vom PC sende sind Binär und 35 Bit lang.Immer 8 bit's
> werden zu einem byte und diese werden zum ansteuern der Ports verwendet
> (35 Bit = ca. 5 Ports). Die empfangenen Daten möchte ich in ein Array
> packen und auslesen können.
> PORTA = zeichen[1];
> PORTB = zeichen[2]; usw.
Also byte empfangen und z.B. ne Variable hochzählen welcher Port gerade 
dran ist.

> Das Array sollte ein zweisimensionales (array[5][200]) sein und würde
> max. 200(zeilen) auf 5(spalten) sein. Beim ausschalten und wieder
> einschalten sollten die Daten noch vorhanden sein!
Dann brauchste nen µC mit mehr als 1kB RAM, sowie EEPROM zum speichern 
der Daten, welche du bei Reset dir wieder holst.

> -Funktioiert dieses Programm so wie es im Anhang ist überhaupt(soll nur
> daten auslesen)?
Nein.

> - wie bringe ich die Daten in ein Array?
> - Wie speichere ich die Daten ab?
In dem du die Daten ins array speicherst ;-)
Und vorm ausmachen ins EEPROM verschiebst.


Hier mal nen Ausschnitt für die USART.c:
1.)SendSign sendet nen einzelnes Byte
2.)GetSign schltet Uart Empfang Interrupt frei
3.)init und DeInit sind selbst erklrärend
1
#include "USART.h"
2
3
#define CLOCK 16000000UL
4
#define BAUD 38400UL
5
#define UBRRVAL (CLOCK/(BAUD*16)-1)
6
7
8
void USARTSendSign(unsigned char byte)
9
{
10
  while (!(UCSRA & (1<<UDRE))) 
11
  ;
12
  UDR = byte;
13
}
14
15
16
unsigned char USARTGetSign()
17
{
18
  UCSRB |= (1 << RXCIE);
19
  sei();
20
  return 0;  
21
}
22
23
24
void USART_init()
25
{
26
  UBRRH = (unsigned char) UBRRVAL >> 8;    
27
    UBRRL = (unsigned char) UBRRVAL;      
28
29
  UCSRC |= (1<<URSEL)|(3<<UCSZ0);
30
  UCSRB |= (1<<TXEN) | (1 << RXEN);
31
}
32
33
34
void USART_DeInit()
35
{
36
  UCSRB &= ~(1 << TXEN);
37
  UCSRB &= ~(1 << RXEN);
38
  UCSRB &= ~(1 << RXCIE);
39
}

von Jean P. (fubu1000)


Lesenswert?

So, dann würde ich im USART.h ne struct deklarieren, z.B. so:
1
struct MyStruct
2
{
3
  char puffer[5][200];
4
  unsigned char port;
5
}UsartRam;

Jetzt musst du nur noch den Spalten, welche vermutlich für die Ports 
stehen, die bytes zuweisen. Dafür würde ich Pc seitig nen byte voraus 
schicken, um zu wissen, welcher Port es ist. Z.B. A = PORTA, B = 
PORTB.....; 0 bedeutet kein Empfang. Anfangs Zustand der Variablen port 
im struct muss natürlich irgend ein Zeichen sein was du nit brauchst. 
Und nach Ende der Übertragung muss die Variable wieder zurück gesetzt 
werden.
Nachteil dabei wäre das ein Steuerzeichen für deine Ports weg fällt.

Andere Möglichkeit wäre nen byte voraus zu schicken und die Länge des 
folgenden Arrays anzugeben, dann füllst du solange das Array[0][x], bis 
die Länge des ersten bytes(Länge) erreicht ist. Dann schickste wieder 
nen byte für die Länge Array[1][x] und so weiter. Gibt noch jede Menge 
andere quick and dirty Methoden das zu machen.....
Die ISR würde ich so gestalten:
1
ISR(USART_RXC_vect)
2
{  
3
  unsigned char byte = UDR;
4
  
5
  //Speicher dein ARRAY, irgendwie ab!
6
  //DIESE STELLE probierst du erstmal selbst.
7
  //falls du es nit schaffst deine Ergebnnisse zeigen
8
  //um guten Willen zu zeigen und dir wird geholfen ;-)
9
}

von Michael A. (ammannm)


Lesenswert?

Vielen Dank erstmal!
Setze mich nun dahinter und versuche mal es hinzubekommen!

von Michael A. (ammannm)


Lesenswert?

Habe nun nach ca. 3 stunden etwas geschrieben, nur funktioniert es nicht 
wie ich will. Es ist nicht viel aber meiner Meinung nach müste es 
gehen?!
Habe herausgefunden dass ich mich mit der ANSI-C Programmiersprache noch 
viel beschäftigen muss!

Nun zu meinem Progrämchen.
1
#include <stdio.h>
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
#include "usart.h"
5
#include <usart.c>
6
7
int pos = 0;
8
9
int main(void){
10
11
  while(1){
12
    //Ram auslesen und PORT's ansteuern
13
  }
14
}
15
16
17
ISR(USART_RXC_vect)
18
{  
19
20
    unsigned char byte;
21
  byte = UDR;    //daten auslesen und an byte übergeben
22
23
  if (pos ==6){
24
  
25
    pos = 0;
26
  
27
  }else{
28
29
    UsartRam.port[pos] = byte;
30
    pos++;
31
32
  }
33
34
}


Und die USART.H datei die ich abgeändert habe.
1
struct datenarray
2
{
3
  char port1[200];
4
  char port2[200];
5
  char port3[200];
6
  char port4[200];
7
  char port5[200];
8
  
9
}UsartRam;

Die Daten möchte ich ins Flash speichern da ich einen atmega64 verwende 
und mein Programm höchstens 10k braucht von 64k.

Michael

von Jean P. (fubu1000)


Lesenswert?

Michael Ammann schrieb:
> Habe nun nach ca. 3 stunden etwas geschrieben, nur funktioniert es nicht
> wie ich will. Es ist nicht viel aber meiner Meinung nach müste es
> gehen?!
Mal im Ernst, was soll das Programm denn machen. Du hast ja nit mal den 
Interrupt aktiviertl geschweige denn den Uart initialisiert.

> Habe herausgefunden dass ich mich mit der ANSI-C Programmiersprache noch
> viel beschäftigen muss!
Mag sein.

Ich habe mir mal erlaubt dein Proggi zu verändern, mit den von mir oben 
geposteten Code, allerdings musste die Usart_init und so selber 
auslagern. Habe jetzt mal alles in eine datei sozusagen geschrieben:
OHNR GEWÄHR ALLES AUSM KOPF, ABER DENKE DAS PASST, TESTE ALSO MAL IN 
DEINER WHILE(1), OB ÜBERHAUPT WAS ANKOMMT !
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
#define CLOCK 16000000UL
5
#define BAUD 38400UL
6
#define UBRRVAL (CLOCK/(BAUD*16)-1)
7
 
8
struct datenarray
9
 {
10
   char port1[200];
11
   char port2[200];
12
   char port3[200];
13
   char port4[200];
14
   char port5[200];
15
 }UsartRam;
16
 
17
volatile int pos; 
18
19
int main(void)
20
{
21
  pos = 0;
22
23
  //Usart_init();
24
  UBRR0H = (unsigned char) UBRRVAL >> 8;    
25
  UBRR0L = (unsigned char) UBRRVAL;      
26
  UCSR0C |= (3<<UCSZ00);
27
  UCSR0B |= (1<<TXEN0) | (1 << RXEN0);
28
29
  //UsartGetSign();
30
  UCSR0B |= (1 << RXCIE0);
31
  sei();
32
 
33
   while(1)
34
   {
35
     //Ram auslesen und PORT's ansteuern
36
     //darauf achten das überhaupt was im UsartRam.portX[y] steht,
37
     //also prüfen
38
   }
39
 }
40
 
41
 
42
 ISR(USART_RXC_vect)
43
 {
44
 
45
   unsigned char byte;
46
   byte = UDR;    //daten auslesen und an byte übergeben
47
 
48
   if (pos ==6){
49
 
50
    pos = 0;
51
 
52
   }else{
53
 
54
     UsartRam.port1[pos++] = byte;  //ich schreibe erstmal nur port1,        //denn Rest machst du schon ;-) 
55
   }
56
 
57
 }
>




>Die Daten möchte ich ins Flash speichern da ich einen atmega64 verwende
>und mein Programm höchstens 10k braucht von 64k.
Glaube ich nit.

Gruß

von Michael A. (ammannm)


Lesenswert?

Also, ich glaube so könnte es funktionieren aber habe noch irgendwo 
einen schreibfehler drin da es fehlermeldungen beim compilieren gibt.
1
#include <stdio.h>
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
#include <avr/pgmspace.h>
5
#include <usart.h>
6
7
#define CLOCK 16000000UL
8
#define BAUD 38400UL
9
#define UBRRVAL (CLOCK/(BAUD*16)-1)
10
#define arrayimflash;
11
 
12
volatile int pos; 
13
volatile int portnr;
14
15
int main(void)
16
{
17
  int i;
18
  char a;
19
    
20
  DDRB = 0b00000000;
21
22
  pos = 0;
23
24
    //Usart_init();
25
    UBRRH = (unsigned char) UBRRVAL >> 8;    
26
    UBRRL = (unsigned char) UBRRVAL;      
27
    UCSRC |= (3<<UCSZ2);
28
    UCSRB |= (1<<TXEN) | (1 << RXEN);
29
30
    //UsartGetSign();
31
    UCSRB |= (1 << RXCIE);
32
    sei();
33
34
 //----------------------------------------
35
36
 while(1)
37
  {
38
  
39
  if (UsartRam.port1[1] == 0) {    //Daten im Array?
40
  
41
  }else{
42
43
    for (i=0;i<200;i++) {    Daten aus array auslesen
44
         a = pgm_read_float (&arrayimflash[i]); // entspr. "a = arrayimflash[i];"
45
      PORTB = a;    //hjPort ansteuern
46
       }
47
  }
48
 }
49
}
50
 
51
 
52
ISR(USART_RXC_vect)
53
{
54
 
55
   unsigned char byte;
56
   byte = UDR;    //daten auslesen und an byte übergeben
57
 
58
   if (pos ==201){    // 200 mal 8bit Daten
59
 
60
    pos = 0;
61
 
62
   }else{
63
 
64
     UsartRam.port1[pos++] = byte;  //erstmal nur port1 auslesen (routine schreiben um Port zu wechseln!) 
65
 
66
   }
67
 
68
  const uint8_t *arrayimflash PROGMEM = {UsartRam.port1};  //datenarray in flash speichern mit zeiger "arrayimflash"
69
70
}

Es ist recht schwierig! Muss mir die Infos zusammensuchen. Bis jetzt 
haben meine C (grund)kenntnisse ausgereicht aber bei diesem Projekt 
nicht mehr....

MfG Michael

von Karl H. (kbuchegg)


Lesenswert?

Michael Ammann schrieb:

> ISR(USART_RXC_vect)
> {
>
>    unsigned char byte;
>    byte = UDR;    //daten auslesen und an byte übergeben
>
>    if (pos ==201){    // 200 mal 8bit Daten
>

Das sieht nicht richtig aus.
Dein Array ist 200 Bytes gross. D.h. die Indizes laufen von 0 bis 199. 
Wenn pos den Wert 200 hat, darfst du schon nichts mehr in UsartRam.port1 
speichern, weil UsartRam.port1[200] schon nicht existiert.

>     pos = 0;
>
>    }else{
>
>      UsartRam.port1[pos++] = byte;  //erstmal nur port1 auslesen
> (routine schreiben um Port zu wechseln!)
>
>    }

Ausserdem: warum wirfst du das empfangene Byte weg, wenn du pos auf 0 
setzen musstest?

>
>   const uint8_t *arrayimflash PROGMEM = {UsartRam.port1};  //datenarray
> in flash speichern mit zeiger "arrayimflash"

Das wird so nichts.
Daten im Flash ablegen ist nicht so simpel, dein normaler Programmcode 
kann das gar nicht, sondern mann muss den Umweg über Programmcode in der 
Bootloader-Sektion gehen. Du suchst dir hier eine Problemstellung aus, 
die (zumindest momentan) mit an Sicherheit grenzender Wahrscheinlichkeit 
zum Scheitern verurteilt ist.
>
> Es ist recht schwierig! Muss mir die Infos zusammensuchen. Bis jetzt
> haben meine C (grund)kenntnisse ausgereicht aber bei diesem Projekt
> nicht mehr....

Mach Vorübungen auf dem PC!
Dort kannst du besser Debuggen.
Du UART ersetzt du durch ein char-Array aus dem du Byte für Byte Werte 
holst und verarbeitest. Du kannst auf dem PC die ganze Verarbeitung, mit 
all den Buffern und dergl. wunderbar entwickeln und durchspielen.

> Bis jetzt
> haben meine C (grund)kenntnisse ausgereicht

Mit Verlaub, bei allem nötigen Respekt und ohne dich kränken zu wollen: 
Aber das was ich da sehe, sind noch nicht einmal Grundkenntnisse.

von Michael A. (ammannm)


Lesenswert?

Vielen Dank für die erlichen Worte.
Somit ist mein Projekt wirklich gescheitert.

Nun werde ich wie vorgeschlagen hinter die Bücher gehen und Lernen.

Fertige Programmcodes findet man ja nur schwer.

Danke für die Hilfe.

MfG Michael

von Michael A. (ammannm)


Lesenswert?

Es lässt mir keine Ruhe!

Habe nochmals nach Beispielen im internet gesucht. Auf folgender Seite 
sieht es so einfach aus.

Nur mal das auslesen des USART angeschaut, nichts von ins Flash 
speichern und so!

Warum siehts hier so einfach aus?

http://www.rn-wissen.de/index.php/Sourcevergleich
1
#include <avr/io.h> 
2
3
#define F_CPU       8000000 
4
#define USART_BAUD_RATE   9600 
5
#define USART_BAUD_SELECT   (F_CPU/(USART_BAUD_RATE*16L)-1) 
6
7
//-----------------------------------------------------
8
int main(void)
9
{
10
  char bZeichen;
11
  
12
  UCSRB = (1 << RXEN) | (1 << TXEN); 
13
  UCSRC = (1 << URSEL) | (1 << UCSZ1) | (1 << UCSZ0); 
14
  UBRRL = (unsigned char) USART_BAUD_SELECT; 
15
  
16
  while (1) 
17
  { 
18
    while ( !(UCSRA & (1 << RXC)) ) 
19
    {}
20
    bZeichen = UDR; 
21
  }
22
}

Bin noch eine Antwort schuldig: Es sollte eine Anzeige werden welche 35 
LED in einer Reihe hat. Diese werden nach einem bestimmten Muster 
angesteuert. Davon wird ein Foto gemacht, danach kommt ein anderes 
Muster und wieder ein Foto, dies immer weiter und am Schluss werden die 
Fotos aneinander gefügt und es entsteht ein Schriftzug. Der Schriftzug 
oder auch ein Bild wird via usb einprogrammiert (EEPROM oder Flash wobei 
eher EEPROM). Die zu sendenden Daten sind lauter einsen und nullen 35 
pro Zeile und 200 Zeilen lang.

mfg

von Karl H. (kbuchegg)


Lesenswert?

Michael Ammann schrieb:

> Warum siehts hier so einfach aus?

Weil das kein praxistaugliches Programm ist, sondern nur die 
prinzipielle Funktionsweise der Registerzugriffe im AVR zeigt.

Im Grunde ist es wie der Unterschied zwischen einer halben Stunde 
Fahrpraxis eines Autofahr-Anfängers auf dem nächstgelegenen 
Kaufhausparkplatz und dem Fahren um 5 in der Rushhour einer Grossstadt. 
Fahren auf einem leeren Parkplatz ist einfach im Vergleich zum Fahren in 
der Stosszeit. Und doch ist beides nur Autofahren.

von Karl H. (kbuchegg)


Lesenswert?

Michael Ammann schrieb:

> Bin noch eine Antwort schuldig: Es sollte eine Anzeige werden welche 35
> LED in einer Reihe hat. Diese werden nach einem bestimmten Muster
> angesteuert. Davon wird ein Foto gemacht, danach kommt ein anderes
> Muster und wieder ein Foto, dies immer weiter und am Schluss werden die
> Fotos aneinander gefügt und es entsteht ein Schriftzug. Der Schriftzug
> oder auch ein Bild wird via usb einprogrammiert (EEPROM oder Flash wobei
> eher EEPROM). Die zu sendenden Daten sind lauter einsen und nullen 35
> pro Zeile und 200 Zeilen lang.

Dann ist eine Speicherung in einem Array[35][200] aber sehr 
speicherintensiv!

Das kann man im µC auch bitweise speichern. Dann benötigt man 5*200 = 
1000 Bytes.

Wie auch immer:
Der Ansatz mit der Interrupt Routine war ja im Grunde schon in Ordnung. 
Aber die Aufgabenstellung als Ganzes ist noch zu schwer für dich. 
Vergiss fürs erste deine LED. Fang nochmal an und lass deinen AVR einen 
Text empfangen, den du ihm von einem Terminalprogramm aus schickst. Der 
AVR soll den Text zwischenspeichern und wenn eine Zeiele vollständig 
ist, den Text zurückschicken. Aber nicht in der ISR zurückschicken! Das 
muss die Hauptschleife erledigen können. Die ISR soll einfach nur das 
empfangene abspeichern und mitteilen (in einer Variablen) wann eine 
Zeile vollständig ist. Nicht mehr!

von Michael A. (ammannm)


Lesenswert?

Gute Idee! Werde ich versuchen!

Karl heinz Buchegger schrieb:

> Dann ist eine Speicherung in einem Array[35][200] aber sehr
> speicherintensiv!

Von dieser Seite habe ich es noch nicht betrachtet! Habe mich noch 
umgesehen wegen dem abspeichern der Daten. Zwei dinge habe ich gefunden: 
speichern in EEPROM, gibt es fertige Bibliotheken. Oder die Lösung mit 
einer SD-Karte. Die SD-Karte wäre auch nicht schlecht, da grössere 
Datenmengen gepeichert werden können und sogar mehrere Dateien 
aufgerufen werden könnten(?!).

Welches würde wohl besser zu meinem Projekt passen?

Aber erstmal eins nach dem anderen! Zuerst UART lesen und auswerten 
danach antworten!

von Michael A. (ammannm)


Lesenswert?

Guten Morgen!

Nach etwas längerem grübeln habe ich mir nun volgendes überlegt:
Da es für mich noch schwierig ist ein Programm zu schreiben welches die 
ankommenden Signale (ein aus zustände der LED) ZUSAMMENZUHÄNGEN (bit 1 + 
bit 2...) mache ich es mir leichter.

Wenn ich ein zeichen wie den Buchstaben (ascii) ä  sende, sieht ein byte 
so aus 11100100. Dieses kann ich nun in einem Array ablegen und das 
nächste byte empfangen und wieder alblegen usw. Nun kann ich den PORT's 
direckt das array zuweisen ohne irgendetwas umzurechnen sprich PORTA = 
array[1].

Das Problem dabei ist, einige Binärcodes wie 10001111 sind Leerzeichen 
und wenn ich mehrere davon habe weiss der mC nicht was ich damit meine!?

wie funktionirt das Hypertherminal?
Wenn ich bei einem Hypertherminal ein Zeichen sende wird das in Binär 
umgewandelt und gesendet? Buchstabe für Buchstabe?

Kann ich da auch Hex code senden sprich C3 und der mC empfängt im UDR 
Register 11000011 ?


Das Problem mit dem empfangen von Daten habe ich gelöst. Sie kommen an.


Hoffe ihr könnt meinem Gedankengang verstehen und mir helfen.

MfG Ammann Michael

PS: Habe ein Programm geschrieben welches mir Binärdaten in verschiedene 
andere umschreibt (Hex, Dez, ASCII)

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.