PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [ERLEDIGT] Daten Senden Empfangen Ic -> Pc -> Ic



knoddelpusch
22.10.2015, 15:48
Hallo zusammen,

ich habe mir ein VB.Net Programm geschrieben wo ich an einen Ic (Atmega16) warte Zeiten ändern. Die Übertragung von VB zum Ic soll in Ascii code passieren. Die Umwandlung in VB funktioniert
super, lasse es mir in einer Textbox anzeigen.
Wenn ich im Ic die Variable x (als Char oder uint8_t) umwandle und damit z.B. eine warte Zeit einstellen möchte geht das nicht.
Ich habe mir auch schon die Variable x als Ascii wider an den Pc geschickt da kommen immer unterschiedliche Werte an. Selbst wenn ich direkt ein Ascii Variable schicke.
[CODE]
#include <avr/io.h>
#include <stdlib.h>
#include <inttypes.h>
#include <util/delay.h>

#define F_CPU 1000000 /* evtl. bereits via Compilerparameter definiert */
#define BAUD 9600UL // 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) // Fehler in Promille, 1000 = kein Fehler.


static void Rot (void)
{
PORTB = (~(1<<PIN0) & ~(0<<PIN1) & ~(0<<PIN2) & ~(0<<PIN2) & ~(1<<PIN3) & ~(0<<PIN4) & ~(0<<PIN5) & ~(0<<PIN5) & ~(1<<PIN6) & ~(0<<PIN7));
}

//----------------------------------------------------------------------------------------------------

// UART konfig

void uart_init (void)
{
UBRRH = UBRR_VAL >> 8;
UBRRL = UBRR_VAL & 0xFF;

UCSRB |= (1<<TXEN) | (1<<RXEN); //UART TX und RX einschalten
UCSRC = (1<<URSEL) |(1<<UCSZ1) | (1<<UCSZ0); //Asynchron 8N1
}

//----------------------------------------------------------------------------------------------------

//Senden
int uart_putc(uint8_t z)
{
while (!(UCSRA & (1<<UDRE))) /* warten bis Senden moeglich */
{
}
UDR = z; /* sende Zeichen */
return 0;
}

//----------------------------------------------------------------------------------------------------

//Empfanen
uint8_t uart_getc(void)
{
while (!(UCSRA & (1<<RXC)))
;
return UDR;
}

//----------------------------------------------------------------------------------------------------

int main (void)
{


uint8_t x;

uint8_t c; //Ascii kommen

uint8_t z; //Ascii gehen

uint8_t t; //Variable für Zeitwert

//Ausgangs Port Festgelegt
DDRB = 0xFF;
PORTB = 0xFF;

uart_init(); //UART deklarit

while (1)
{

c = uart_getc(); //Variable c mpfange
x = atoi (c); //Ascii variable c in variable x umwandeln

itoa (65, z, 10); //65 in Ascii umwandeln entspricht A zum Testen

uart_putc(z); //variable z (65, A) an Pc senden

t = x * 100; //Auf sekungen umwandeln

PORTB = Rot; //Port B schalten
_delay_ms(t); //WarteZeit t
PORTB =0xFF; //Port B ausschalten
_delay_ms(t); //WarteZeit t
PORTB = Rot; //Port B schalten
_delay_ms(t); //WarteZeit t
PORTB =0xFF; //Port B ausschalten
}

return 0; // never reached

}
[/CO

hans99
23.10.2015, 20:39
Hallo knoddelpusch,

sehr konfus das Ganze, aber ich probiere es.

Zuerst zur Namenskonvention: IC heißt Integrated Circuit -> meist ist der IC ein (dummer) Baustein in einer Schaltung.
Was Du meinst ist ein Mikrokontroller (auch MCU oder µC genannt). Bleiben wir in deinem Fall beim ATmega16.

Also:
Ich gehe jetzt stark davon aus, daß Du keine Ahnung von der internen Verarbeitung von Daten hast.
Ein Computer kann nur binäre Zahlen verarbeiten. Das heisst 0 oder 1. 0 = aus 1 = ein.

Da aber der Mensch mit binären Zahlen nicht sehr viel anfangen kann hat man die hexadezimale Darstellung eingeführt.
Damit aber alle den gleichen binären Wert für jedes Zeichen verwenden wurde (zumindest auf PC und µC) der ASCII Code eingeführt
(es gibt da auch noch den EBCDIC Code).

Also wenn Du ein Zeichen "A" an den Atmega16 schickst dann sendet der PC 10000001 an den µC.
binär 10000001 = hex 41 dezimal 65 = A (der PC malt dir dann ein A auf den Schirm).

Warum willst Du das dann noch einmal in ASCII konvertieren?:confused:

Zum programmieren: ich kenne weder VB noch irgendeine C** Sprache (und werde es auch nicht lernen).

Ich habe mir dein Programm angesehen. was mir fehlt ist die genaue Einstellung der
Übertragungsrate (BAUD) auf beiden Seiten (PC UND Atmega16).

Ich hoffe, ich konnte dich verwirren.;)

P.S. welche Werte willst Du an den µC senden?

knoddelpusch
24.10.2015, 18:56
Hallo,

Ich will Zeitwerte an meine uC senden, wo ich warte Zeiten ändern kann.
Dachte das es in ASCII konvertieren einfacher geht. Ich gebe eine Zahl auf dem PC ein, wandele die dann in den ASCII-Code um
Auf dem uC wieder zurück und nehme die Zahl mal x das ich auf meine Wartezeit komme.
Die Übertragungsrate habe ich auf PC auf 9600 und auf dem uC auch (unter der CPU Definition).

Habe mich jetzt im Internet noch etwas recherchierte habe auch ein paar Fehler gefunden, aber es funktioniert immer noch nicht, ich bin am Verzweifeln.
Hier ist noch mal mein Programm.


#include <avr/io.h>
#include <stdlib.h>
#include <inttypes.h>
#include <util/delay.h>


#define F_CPU 1200000 /* evtl. bereits via Compilerparameter definiert */
#define BAUD 9600UL // 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) // Fehler in Promille, 1000 = kein Fehler.

#include <util/setbaud.h>

//----------------------------------------------------------------------------------------------------

// UART konfig

void uart_init (void)
{
UBRRH = UBRR_VAL >> 8;
UBRRL = UBRR_VAL & 0xFF;

UCSRB |= (1<<TXEN) | (1<<RXEN); //UART TX und RX einschalten
UCSRC = (1<<URSEL) |(1<<UCSZ1) | (1<<UCSZ0); // Einstellen des Datenformats: 8 Datenbits, 1 Stoppbit
}

//----------------------------------------------------------------------------------------------------

//Zeichen Senden
int uart_putc(unsigned char c)
{
while (!(UCSRA & (1<<UDRE)))
{
}
UDR = c;
return 0;
}

//----------------------------------------------------------------------------------------------------

void uart_puts (char *s)
{
while (*s)
{ /* so lange *s != '\0' also ungleich dem "String-Endezeichen(Terminator)" */
uart_putc(*s);
s++;
}
}


//----------------------------------------------------------------------------------------------------

//Zeichen Empfanen
uint8_t uart_getc(void)
{
while (!(UCSRA & (1<<RXC))) //warten bis Zeichen verfügbar
;
return UDR; //Zeichen aus UDR an Aufrufer zurückgeben
}

//----------------------------------------------------------------------------------------------------


void uart_gets( char* Buffer, uint8_t MaxLen )
{
uint8_t NextChar;
uint8_t StringLen = 0;

NextChar = uart_getc(); // Warte auf und empfange das nächste Zeichen

// Sammle solange Zeichen, bis:
// * entweder das String Ende Zeichen kam
// * oder das aufnehmende Array voll ist
while( NextChar != '\n' && StringLen < MaxLen - 1 ) {
*Buffer++ = NextChar;
StringLen++;
NextChar = uart_getc();
}

// Noch ein '\0' anhängen um einen Standard
// C-String daraus zu machen
*Buffer = '\0';
}


//----------------------------------------------------------------------------------------------------

int main (void)
{

DDRB = 0xFF;
PORTB = 0xFF;

int Line [8]; //Array vom Typ int

char Buffer[9]; //String mit maximal 8 zeichen

int a;

uart_init(); // UART einstellen

while (1)
{


if ( (UCSRA & (1<<RXC))) //überprüfen ob neue Zeichen vorhanden sind
{ //Zeichen wurden empfangen, jetzt abholen
uart_gets (Line, sizeof(Line));


a=atoi(Line); //aus Text eine Zahl machen

itoa (Line, Buffer, 10); // Aus der Variablen a ein Text erstellen

uart_puts(Buffer); //Senden Text aus Buffer

}
else
{

PORTB = 0b00000000; //Port B schalten
_delay_ms(1000); //WarteZeit t
PORTB =0b11111111; //Port B ausschalten
_delay_ms(1000); //WarteZeit t
PORTB = 0b00000000; //Port B schalten
_delay_ms(1000); //WarteZeit t
PORTB =0b11111111; //Port B ausschalten
}
}

return 0; // never reached


}

Unregistriert
24.10.2015, 19:51
Hallo,

Wenn Du Zeichen an den Atmega sendest, was kommt dort an?
Bist Du sicher, das Du den richtigen COM-Port eingestellt hast?

Versuche einfach nur Zeichen zu senden z.B. "AAAA". Über die Zahlen sprechen wir später.

Übrigens ist mir im ersten Post ein Fehler unterlaufen: ein "A" hat den Binäwert 01000001 und NICHT 10000001!
Da hat der Calculator eine Null verschluckt und ich habe es auch noch falsch abgeschrieben.

M.f.G.
Hans

knoddelpusch
24.10.2015, 23:20
Hallo,

Mit dem Com-Port bin ich mir sicher, habe nur den einen zur Auswahl und ich bekomme ja schon komisches Zeug zurück.
Ja was kommt dor an, das ist eine gute Frage, wo ich mir definitiv sicher bin ist das bei mir auch der Buchstabe raus geht wo ich will.
Habe zwei Pc's mit einem Nullmodem Kabel verbunde, und habe Buchstaben und Zahlen hin und her geschickt und sind immer die angekommen
wo ich los geschickt habe.
Habe auch schon das HyperTerminal von Win XP benutzt, ist aber immer das selbe, kommt immer unterschiedliche Buchstaben oder Zahlen an.
Habe da auch Porbleme mit dem Auswerten von dem Endzeichen eines Srings (\n) das funktioniert auch nicht.

021aet04
25.10.2015, 08:09
Versuche einmal vom uC etwas fixes zu übertragen. Also z.b. A, B, C, 1, 2, 3,...
Somit kannst du herausfinden ob es an der Wandlung (int»ascii oder ascii»int) liegt oder der Übertragung.

MfG Hannes

oberallgeier
25.10.2015, 09:20
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1) // clever rundenWer hat denn diese Formel erfunden - genauer den offset BAUD*8 ? Bisher dachte ich immer (und bei mir läufts) dass die richtige Formel, z.B. auf Datenblatt mega16A 8154B–AVR–07/09 - Seite 150 Tabelle 19-1 steht.


.. wenn Du ein Zeichen "A" an den Atmega16 schickst dann sendet der PC 10000001 an den µC ..ASCII ist im Ursprung siebenbittig. Daher ist in ASCII ein 'A' (0)100 0001. Die (meisten?) C-Konventionen erlauben aber stattdessen die Syntax 'A' - Buchstabe mit Strichelchen. Wie es Hans schon als Gastredner dargestellt hat.

sternst
25.10.2015, 11:10
Wer hat denn diese Formel erfunden - genauer den offset BAUD*8 ?Das ist das, was im Kommentar steht. Es sorgt dafür, dass bei der Integer-Division eine Rundung stattfindet. Aus X/Y wird (X+Y/2)/Y gemacht, so wird das Ergebnis von (z.B.) 9/5 zu 2 statt 1.

- - - Aktualisiert - - -


itoa (Line, Buffer, 10); // Aus der Variablen a ein Text erstellen
Diese Zeile ist Unsinn.

knoddelpusch
25.10.2015, 11:50
Hallo

Ich habe es mal mit den festen Variablen probiert, aber da kommt alles nur nicht das an wo ich los geschickt habe. Habe das HyperTerminal von Win XP benutzt.
Also kann es an der Umwandlung nicht liegen oder?
Habe auch mal den uC getauscht hätte ja sein könne das der ein defekt hat, hat sich aber nichts geändert.

Warum ist diese Zeile Unsinn?


itoa (Line, Buffer, 10); // Aus der Variablen a ein Text erstellen

Ich muss doch meine Variable in einen Text umwandeln damit ich diesen übertragen kann oder nicht?

sternst
25.10.2015, 12:00
Ich muss doch meine Variable in einen Text umwandeln damit ich diesen übertragen kann oder nicht?Und dir kommt es nicht irgendwie merkwürdig vor, dass der Kommentar sagt, dass etwas mit der Variable a getan werden soll, diese aber gar nicht in der Code-Zeile vorkommt?

021aet04
25.10.2015, 12:10
Wenn du schon nichts Fixes übertragen kannst, liegt es an der Einstellung (unterschiedliche Einstellungen PC-uC) oder einer nicht funktionierenden Verbindung (defekte Lötstelle, RX/TX falsch angeschlossen, ...).

Es gibt noch weitere mögliche Fehler, aber das würde ich als erstes kontrollieren.

MfG Hannes

knoddelpusch
25.10.2015, 12:22
Hallo


mhh defekte Lötstellen kann ich mal kontrollieren, kann ich mir jetzt weniger vorstellen.
Ich benutzt zur Programmierung das STK500 Board.
RX/TX kann ich auch ausschliessen denn wenn ich die zwei Pins drehe kommt nichts mehr an.

Was für einstellung kann es denn noch geben. StopBits = 1, Buad = 9600, Datenbits = 8

Wenn ich jetzt eine feste Variable übertragen will z.B. "j" bekomme ich auf meinem Hyperterminal ein ö angezeigt

@ sternst
ich habe die Variable a zu Testzwecken durch die Line variable ausgetauscht. Aber das hat auch nicht funktioniert. Da steht jetzt wieder a.

sast
26.10.2015, 14:47
Wenn ich jetzt eine feste Variable übertragen will z.B. "j" bekomme ich auf meinem Hyperterminal ein ö angezeigt
Sieht nach Baudrate aus.

Am Anfang hast du 1MHz als F_CPU dann zwischendurch mal 12MHz. Was stimmt denn nun? Denn das ist nicht ganz unwichtig für die korrekte Baudrateneinstellung. Was steht denn im makefile und da 12MHz sicher extern in den Controller gehen, sind die Fuses richtig eingestellt? Wenn das alles stimmt, sollte auch das richtige Zeichen kommen bzw immer das gleiche verkehrte Zeichen.

Wenn mit
// Warteschleife
void delay_ms(unsigned int ms)
{
unsigned int zaehler;
while (ms) {
zaehler = F_CPU / 5000;
while (zaehler) {
__asm volatile("nop");
zaehler--;
}
ms--;
}
}

//und in der main

delay_ms(1000);
LED an;
delay_ms(1000);
LED aus;


die LED ungefähr im Sekundentakt an und dann wieder aus geht, dann stimmt dein F_CPU mit deiner Theorie überein. Sonst musst du da noch einmal drüber schauen.

sast

knoddelpusch
26.10.2015, 16:00
Hallo,

ich habe die F_CPU auf 12MHz stehen und die LED's blinken im Sekundentakt

Hier die Fuses einstellungen
30824

Habe auch schon probiert wenn ich nur den Sende Pin aktiviert ist. Da habe ich dann die uart_puts() zeile in die else schleife geschrieben, kam aber auch nur irgendwelche Buchstaben oder Zeichen an.
Habe es auch mal mit einem anderen PC und uC probiert.

Hier nochmal das Programm


#include <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>

#define F_CPU 1200000 /* evtl. bereits via Compilerparameter definiert */
#define BAUD 9600UL // 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) // Fehler in Promille, 1000 = kein Fehler.

#include <util/setbaud.h>

//------------------------------------------------------------------------------------------

//USART initialisieren
void uart_init(void)
{
UBRRH = UBRR_VAL >> 8;
UBRRL = UBRR_VAL & 0xFF;

UCSRB |= (1<<TXEN) | (1<<RXEN); //UART TX und RX einschalten
UCSRC = (1<<URSEL) |(1<<UCSZ1) | (1<<UCSZ0); // Einstellen des Datenformats: 8 Datenbits, 1 Stoppbit

}

//------------------------------------------------------------------------------------------

//Warteschleife
void delay_ms(unsigned int ms)
{
unsigned int zaehler;
while (ms) {
zaehler = F_CPU / 5000;
while (zaehler) {
__asm volatile("nop");
zaehler--;
}
ms--;
}
}

//------------------------------------------------------------------------------------------

// Zeichen senden
int uart_putc(unsigned char c)
{
while (!(UCSRA & (1<<UDRE)))
{
}
UDR = c;
return 0;
}
//------------------------------------------------------------------------------------------

//String senden
void uart_puts(char *s)
{
while (*s)
{ /* so lange *s != '\0' also ungleich dem "String-Endezeichen(Terminator)" */
uart_putc(*s);
s++;
}
}
//------------------------------------------------------------------------------------------

//Zeichen empfangen
uint8_t uart_getc(void)
{
while (!(UCSRA & (1<<RXC))) //warten bis Zeichen verfügbar
;
return UDR; //Zeichen aus UDR an Aufrufer zurückgeben

}
//------------------------------------------------------------------------------------------

//Sting empfangen
void uart_gets(char *Buffer, uint8_t MaxLen)
{
uint8_t NextChar;
uint8_t StringLen = 0;

NextChar = uart_getc(); // Warte auf und empfange das nächste Zeichen

// Sammle solange Zeichen, bis:
// * entweder das String Ende Zeichen kam
// * oder das aufnehmende Array voll ist
while( NextChar != '\n' && StringLen < MaxLen - 1 ) {
*Buffer++ = NextChar;
StringLen++;
NextChar = uart_getc();
}

// Noch ein '\0' anhängen um einen Standard
// C-String daraus zu machen
*Buffer = '\0';

}
//------------------------------------------------------------------------------------------

//Hauptprogramm
int main(void)
{
int Line[5]; //Array vom Typ int
char Buffer[9]; //String mit maximal 8 zeichen
int a;

DDRB = 0xFF;
PORTB = 0xFF;

uart_init(); // UART einstellen

while (1)
{
if ((UCSRA & (1<<RXC))) //überprüfen ob neue Zeichen vorhanden sind
{
uart_gets(Line, sizeof(Line)); //Zeichen wurden empfangen, jetzt abholen

a=atoi (Line); //aus Text eine Zahl machen

itoa (Line, Buffer, 10); // Aus der Variablen a ein Text erstellen

uart_puts("j"); //Senden festen Buchstaben j
else
{
uart_puts("a"); //Senden festen Buchstaben a

PORTB = 0b00000000;
delay_ms(1000);
PORTB = 0b00001111;
delay_ms(1000);
PORTB = 0b11110000;
delay_ms(1000);
PORTB = 0b11111111;
delay_ms(1000);
}

}

}


Wenn ich die Daten-oder die Stoppbits verstelle, bekomme ich gar nichts mehr angezeigt.
Also müsten diese ja auch stimmen.

sast
26.10.2015, 17:05
Deine Fuses stehen auf 1MHz interner Takt und wenn du wirklich 12 MHz dran hast, fehlt bei F_CPU auch noch eine 0. Durch deine F_CPU von 1,2MHz wirkt das natürlich dann wie 1s.
Hatte mich nämlich vorhin um diese eine 0 vertan.

sast

knoddelpusch
27.10.2015, 11:38
Ich habe meinen internen Takt auf 8MHz 6CK + 64ms gestellt. Die LED's blinken im Sekunden

Wenn ich jetzt auf meinem Realterm den Ansi Code einstelle bekomme ich gar nichts mehr angezeigt.
wenn ich ihn aber auf Ascii einstelle bekomme ich wider irgendwelche zeichen und Buchstaben angezeigt.
takt.

Habe jetzt auch probleme auf mein STK500 zu kommen.

drew
28.10.2015, 12:45
Hallo,
Da gibt es doch den alten Trick bei der RS232, dass man RX und TX verbindet. Dann wird das auf dem Terminal empfangen, was man gerade gesendet hat.
Auf die Weise kann man testen, wie weit die Übertragung noch gut gegangen ist. (Vor dem Pegelwandler, direkt auf der Platine, ...)

Man kann aber nicht erkennen, ob die eingestellte Baudrate auf dem Controller zu der auf dem PC passt. (Komisches Zeug auf der RS232 hört sich irgendwie nach falscher Baudrate an.)

knoddelpusch
28.10.2015, 13:51
Hallo,
danke für den Tipp, hätte man ja auch selbst drauf können.
Habe das auch gleich mal getestet.
Habe die Brücke auch nach dem Pegelwandler gemacht und es funktioniert super, es kommen immer die Buchstaben bzw. Zahlen an wo ich los schicke.
Habe auch schon unterschiedliche Baudrate (auf PC und uC) ausprobiert es kommt aber immer was anderes an.

021aet04
28.10.2015, 16:14
Hast du schon versucht statt der Berechnung der Baudrate es fix einzustellen? Im DB steht für einige übliche Frequenzen die Baudraten mit den Einstellungen.

MfG Hannes

knoddelpusch
28.10.2015, 22:19
Hallo,

habe jezt auch mal die Baudrate fix eingestellt dies hat aber auch nichts gebracht. Immer der selbe "Müll".
Habe meinen externen Quarz mal weggenommen und habe intern den RCOsc. mal auf 8MHz; 6CK+64ms gestellt, und habe meine F_CPU auf 8000000 gestellt
Meine LED's blinken alle noch im sekundentakt.
Wenn ich mir einen festen Wert oder Buchstabe übertragen lassen will, kommt in ANSI nichts mehr an und in Ascii nur noch komische Symbole, ich sehe aber an meinen RXD das irgendwelche daten ankommen.

Hier nochmal mein Programm


#include <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>

#define F_CPU 8000000// 12000000 /* evtl. bereits via Compilerparameter definiert */
#define BAUD 300 // 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) // Fehler in Promille, 1000 = kein Fehler.

#include <util/setbaud.h>

//------------------------------------------------------------------------------------------

//USART initialisieren
void uart_init(void)
{
//Set Baudrate
UBRRH = UBRR_VAL >> 8;
UBRRL = UBRR_VAL & 0xFF;

UCSRB |= (1<<TXEN) | (1<<RXEN); //UART TX und RX einschalten
UCSRC = (1<<URSEL) |(1<<UCSZ1) | (1<<UCSZ0); // Einstellen des Datenformats: 8 Datenbits, 1 Stoppbit
}

//------------------------------------------------------------------------------------------

//Warteschleife
void delay_ms(unsigned int ms)
{
unsigned int zaehler;
while (ms) {
zaehler = F_CPU / 5000;
while (zaehler) {
__asm volatile("nop");
zaehler--;
}
ms--;
}
}

//------------------------------------------------------------------------------------------

// Zeichen senden
int uart_putc(unsigned char c)
{
while (!(UCSRA & (1<<UDRE)))
{
}
UDR = c;
return 0;
}
//------------------------------------------------------------------------------------------

//String senden
void uart_puts(char *s)
{
while (*s)
{ /* so lange *s != '\0' also ungleich dem "String-Endezeichen(Terminator)" */
uart_putc(*s);
s++;
}
}
//------------------------------------------------------------------------------------------

//Zeichen empfangen
uint8_t uart_getc(void)
{
while (!(UCSRA & (1<<RXC))) //warten bis Zeichen verfügbar
;
return UDR; //Zeichen aus UDR an Aufrufer zurückgeben

}
//------------------------------------------------------------------------------------------

//Sting empfangen
void uart_gets(char *Buffer, uint8_t MaxLen)
{
uint8_t NextChar;
uint8_t StringLen = 0;

NextChar = uart_getc(); // Warte auf und empfange das nächste Zeichen

// Sammle solange Zeichen, bis:
// * entweder das String Ende Zeichen kam
// * oder das aufnehmende Array voll ist
while( NextChar != '\n' && StringLen < MaxLen - 1 ) {
*Buffer++ = NextChar;
StringLen++;
NextChar = uart_getc();
}

// Noch ein '\0' anhängen um einen Standard
// C-String daraus zu machen
*Buffer = '\0';

}
//------------------------------------------------------------------------------------------

//Hauptprogramm
int main(void)
{
int Line[2]; //Array vom Typ int
char Buffer[3]; //String mit maximal 8 zeichen
int a;

DDRB = 0xFF;
PORTB = 0xFF;
a=12;
uart_init(); // UART einstellen

while (1)
{
if ((UCSRA & (1<<RXC))) //überprüfen ob neue Zeichen vorhanden sind
{
uart_gets(Line, sizeof(Line)); //Zeichen wurden empfangen, jetzt abholen

a=atoi (Line); //aus Text eine Zahl machen

itoa (Line, Buffer, 10); // Aus der Variablen a ein Text erstellen

uart_puts("j"); //Senden festen Buchstaben j
}
else
{
uart_puts(a); //Variable a senden Testzwecke
PORTB = 0b00000000;
uart_puts(a); //Variable a senden Testzwecke
delay_ms(1000);
uart_puts(a); //Variable a senden Testzwecke
PORTB = 0b00001111;
uart_puts(a); //Variable a senden Testzwecke
delay_ms(1000);
PORTB = 0b11110000;
delay_ms(1000);
PORTB = 0b11111111;
delay_ms(1000);
}

}

}


Kann das wirklich nur an der CPU-Frequenz liegen?

Habe eben mal noch Versucht eine feste Variable zu Übertragen das heißt ich habe


uart_puts("12")

geschrieben und es kommt auch die 12 an auch wenn ich buchstaben übertrage funktioniert das.

Wenn ich jetzt aber eine Variabel deklariere zum Beispiel


char a;
a = 65;

Aber hier kommt dann nur wirres zeug an.

Peter(TOO)
29.10.2015, 02:25
Hallo,

Versuchs mal mit
uart_putc(a);
an Stelle von
uart_puts(a);

"a" ist ein int und kein String, da ist kein '/0' am Ende!

"12" ist ein String und wird im Speicher als
0x32, 0x32, 0x00
abgelegt.

12 ist eine dezimale Zahl und wird als
0x0C
im Speicher abgelegt. 0x0C ist übrigens das Steuerzeichen FF (Form Feed). Auf einem Drucker würde dies einen Seitenvorschub auslösen.

Mit a=65 würdest du ein "a" senden, dahinter kommt dann aber irgendwelcher Schott bis uart_puts(a); irgend wo auf 0x00 im Speicher stösst.
Wenn du Pech hast, ergeben sich aber auch Steuerzeichen, welche das "a" oder die ganze Zeile in deiner Terminalemulation wieder löschen.

Das ist auch der Unterschied zwischen ANSI- und ASCII-Darstellung.

Im ANSI-Mode werden Steuer-Zeichen und -Sequenzen interpretiert und ausgeführt. Alle Zeichen < 0x20 sind Steuerzeichen und werden nicht angezeigt, lösen aber meistens eine Funktion aus, sofern auf dem Terminal umsetzbar. 0x07 sollte einen Beeb erzeugen, 0x0A ist eine Zeilenvorschub und 0x0D ein Wagenrücklauf (der Cursor wird nach ganz links gestellt). 0x0C macht auf dem Terminal keinen Sinn und wird meistens ignoriert. Dann gibt es noch Befehle mit Parametern, wie z.B. das Positionieren des Cursors an einer beliebigen Stelle auf dem Terminal. Diese beginnen, bei ANSI, mit 0x1B (ESC). Die folgenden Bytes sind dann der Befehl und die Parameter.

Im ASCII-Mode wird jedes Zeichen angezeigt und nicht als Steuerbefehl interpretiert.

Grundsätzlich kennt ein Prozessor nur Zahlen, Buchstaben gibt es für ihn gar nicht!
Buchstaben sind eine Art Verschlüsselung. In einer Tabelle werden den Zahlen Buchstaben zugeordnet.
Die bekannteste Codierung ist ASCII, welche aber nur für die ersten für die Werte 0...127 Zeichen gilt.
https://de.wikipedia.org/wiki/American_Standard_Code_for_Information_Interchange #ASCII-Tabelle

Besonders IBM bevorzugte aber eine andere Codierung Namens EBCDIC:
http://www.astrodigital.org/digital/ebcdic.html

Dummerweise kennen die AMIs aber keine Umlaute und andere Sonderzeichen!
Ein Problem durch die ASCII-Norm, war noch, dass vor allem bei der Datenübertragung nur oft 7 Bit übertragen wurden (Teilweise wurde Bit-8 als Parity-Bit verwendet und beim Empfang dann auf 0 gesetzt).
Der erste Ansatz war dann z.B. die deutschen Umlaute auf normalerweise wenig benutzte Zeichen zu legen.
Ein weiteres Problem war dadurch, dass man so keine Binärdaten Übertragen konnte, weshalb man die 8 Bit in ein Format mit 6 Bit umpacken musste.
Deshalb werden heute noch Binärdaten in E-Mails als MIME-64 codiert:
https://de.wikipedia.org/wiki/Multipurpose_Internet_Mail_Extensions

Man hat dann z.B. Umlaute auf die Zeichen "[" und "]" gelegt. Als Programmierer bekam man dann aber lustige Listings ausgedruckt :-(

Da ein Byte aber die Werte 0...255 annehmen kann und in ASCII z.B. keine Umlaute vorgesehen sind, haben die Hersteller dann den Erweiterten-ASCII-Code, welcher den Werten 128...255 Zeichen zuordnet. Entwickelt. Allerdings waren diese Erweiterungen für jede Sprache unterschiedlich und die meisten Hersteller kochten ein eigenes Süppchen.
Mit dem IBM-PC und DOS hat dann IBM eine Defaktostandard geschaffen. Allerdings waren auch hier die Zuordnungen je nach eingestellter Code-Page unterschiedlich.

Eine genormte Vereinheitlichung entstand dann erst vor etwa 25 Jahren mit dem Unicode:
https://de.wikipedia.org/wiki/Unicode#Versionen
Windows unterstützt Unicode seit NT 4.0 (1996) bzw. Windows 2000 (2000).

MfG Peter(TOO)

sast
29.10.2015, 07:43
Viel Text von Peter. Aber genau so sehe ich das auch. Du überträgst ein einzelnes Byte mit einer Funktion, die auf ein \0 wartet. Das geht schief. wenn du puts verwenden willst, musst du ein char array verwenden und nach den eigentlichen zu übertragenden Zeichen in einer weiteren Arraystelle mit einem \0 abschließen.

char s[11];
int a;
a = 65;
sprintf(s, "%d,%c\n", a, a);
uart_puts(s);

überträgt dir den Wert von a erst als 65 und dann als A. sprintf fügt das \0 selbständig an. Musst also immer eine Speicherstelle mehr planen als du füllen willst im Array.

Ansonsten hast du ja die richtige Baudrate, sonst würde deine Stringfolge "12" nicht übertragen. Jedenfalls habe ich das so verstanden, dass das geht.
Dann liegts nur noch an den Programmierfähigkeiten.

sast

sternst
29.10.2015, 09:01
Mit a=65 würdest du ein "a" senden,Nö, er würde das senden, was im Speicher an Adresse 65 steht.

knoddelpusch
29.10.2015, 16:14
Hallo,

habe das Problem mit dem Übertragen gelöst.
Das habe ich noch nicht ganz verstanden
sprintf(s, "%d,%c\n", a, a);
es wird ein Array s erstellt von den Zeichn a, aber was beudet jetzt das %d und das %c.
Ich vermute mal das das c wird für char steht.

Wie kann ich am besten ein Array in teile aufteilen. Die Trennstellen sind durch ein komma getrennt.
Das heist ich bekomme eine Zeichen folge von 12,345,6.
Dies wandle ich dann in eine Integer Zahl um, aber wie teile ich die dann in z.B, x=12, y=345 und z=6 auf.
Ich habe da auch schon viel von strtok, sscanf oder strsep gelesen aber so richtig schau bin ich da nicht draus geworden.

knoddelpusch
30.10.2015, 13:45
Hallo,

so habe die Probleme gelöst es funktioniert alles. Naja fast alles, muss jezt noch mein Kommunikation mit VB.Net hinbekommen (auch schon fast am verzweifeln).

Ich möchte mich mal bei allen beteiligten bedanken, für die groß Hilfe, viel Dank!

Das Hauptproblem lag wahrscheinlich darin das mein 12MHz Quarz einen defekt hatte bzw hat, habe das jetzt alles auf dem intern 8MHz laufen und funktioniert alles,
es waren aber auch noch genug kleine fehler dabei.

Ich habe mein Aufteilung mit der "strtok" und "strcpy" funktionen erledigt.
Mit der strtok habe ich auf meine String auf Trennzeichen untersucht
und mit der strcpy in die entsprechenden Variablen gespeichert.

Wenn ich jetzt über das RealTerm eine 1,2,3,4\n sende veränderen sich auch die Blink Zeiten entsprechend.

Hier mal mein Programm


#include <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>
#include <string.h>

#define F_CPU 8000000 /* evtl. bereits via Compilerparameter definiert */
#define BAUD 300 // 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) // Fehler in Promille, 1000 = kein Fehler.

#include <util/setbaud.h>


struct _S_DATA S_DATA;
int Line[9]; //Array vom Typ int

//------------------------------------------------------------------------------------------

//USART initialisieren
void uart_init(void)
{
//Set Baudrate
UBRRH = UBRR_VAL >> 8;
UBRRL = UBRR_VAL & 0xFF;

UCSRB |= (1<<TXEN) | (1<<RXEN); //UART TX und RX einschalten
UCSRC = (1<<URSEL) |(1<<UCSZ1) | (1<<UCSZ0); // Einstellen des Datenformats: 8 Datenbits, 1 Stoppbit
}

//------------------------------------------------------------------------------------------

struct _S_DATA
{
char Rot[2];
char RG [2];
char GR [2];
char GE [2];
};
//------------------------------------------------------------------------------------------

//Warteschleife
void delay_ms(unsigned int ms)
{
unsigned int zaehler;
while (ms) {
zaehler = F_CPU / 5000;
while (zaehler) {
__asm volatile("nop");
zaehler--;
}
ms--;
}
}
//------------------------------------------------------------------------------------------

// Zeichen senden
int uart_putc(unsigned char c)
{
while (!(UCSRA & (1<<UDRE)))
{
}
UDR = c;
return 0;
}
//------------------------------------------------------------------------------------------

//String senden
void uart_puts(char *s)
{
while (*s)
{ /* so lange *s != '\0' also ungleich dem "String-Endezeichen(Terminator)" */
uart_putc(*s);
s++;
}
}
//------------------------------------------------------------------------------------------

//Zeichen empfangen
uint8_t uart_getc(void)
{
while (!(UCSRA & (1<<RXC))) //warten bis Zeichen verfügbar
;
return UDR; //Zeichen aus UDR an Aufrufer zurückgeben

}
//------------------------------------------------------------------------------------------

//Sting empfangen
void uart_gets(char *Buffer, uint8_t MaxLen)
{
uint8_t NextChar;
uint8_t StringLen = 0;

NextChar = uart_getc(); // Warte auf und empfange das nächste Zeichen

// Sammle solange Zeichen, bis:
// * entweder das String Ende Zeichen kam
// * oder das aufnehmende Array voll ist
while( NextChar != '\n' && StringLen < MaxLen - 1 ) {
*Buffer++ = NextChar;
StringLen++;
NextChar = uart_getc();
}

// Noch ein '\0' anhängen um einen Standard
// C-String daraus zu machen
*Buffer = '\0';

}
//------------------------------------------------------------------------------------------

//String Zerlegung
void string_zer(void)
{

unsigned char i; //Case Hochzählung
char Trennzeichen[]=","; //Trennungszeichen
char *ptr; //Variable zum zwischenspeichern

i = 2; //Variable i auf 2 setzten

ptr=strtok(Line, Trennzeichen); // Line durchsuchen bis zum Trennzeichen und in ptr zwischen speichern
strcpy (S_DATA.Rot, ptr); // Erster Teil in Rot kopiern wo in der Struct _S_DATA liegt
while (ptr != NULL) //weiter durchsuchen bis das nächste Trennzeichen oder Ende kommt
{
ptr = strtok (NULL, Trennzeichen); // Line durchsuchen bis zum Trennzeichen oder Ende und in ptr zwischen speichern
switch (i) //Um in Unterschiedlichen Variablen zu speichern
{
case 2: strcpy(S_DATA.RG,ptr); break;
case 3: strcpy(S_DATA.GR,ptr); break;
case 4: strcpy(S_DATA.GE,ptr); break;
}
i++; //Variable i um eins hochzählen
}
}

//------------------------------------------------------------------------------------------

//Hauptprogramm
int main(void)
{
//Variablen Deklartion
int time = 1000;
int time1 = 1000;

char Buffer[9]; //String mit maximal 8 zeichen
int a; //Umwandlung ascii zu integer

DDRB = 0xFF;
PORTB = 0xFF;

uart_init(); // UART einstellen

while (1)
{
//---------------------------------------------------------------------------------------------
if ((UCSRA & (1<<RXC))) //überprüfen ob neue Zeichen vorhanden sind
{
uart_gets(Line, sizeof(Line)); //Zeichen wurden empfangen, jetzt abholen

string_zer(); //String in seine Teile zerlegen

uart_puts(S_DATA.Rot);
uart_puts(S_DATA.GE);

a = atoi (S_DATA.Rot); //Rot in integer wandeln
time = a *1000; // mal 1000 um auf sekunden zu kommen

itoa (time, Buffer, 10); //time in char umwandeln

uart_puts(Buffer); //Buffer senden
}
//---------------------------------------------------------------------------------------------
else
{

PORTB = 0b00000000;
delay_ms(time1);
PORTB = 0b00001111;
delay_ms(time);
PORTB = 0b11110000;
delay_ms(time1);
PORTB = 0b11111111;
delay_ms(time);
}

}

}