PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : RS232 Verbindung zum PC in C



ciruz
13.04.2006, 15:20
Hi!
Ich habe verzweifelt versucht mit meinem RN-Control mit Atmega32 über RS232 zu kommunizieren. Ich habe viele Möglichkeiten ausprobiert, Tutorials gelesen, aber nix zu laufen gebracht.
wichtig ist mir, dasss das ganze in C/C++ programmiert ist. hat mir da vielleicht wer was?
Gruß und thx
ciruz

13.04.2006, 20:36
Versuchs mal in Bascom mit Print und Input

izaseba
13.04.2006, 20:59
Tolle Antwort Gast....

@ciruz, was hast Du bis jetzt versucht?
schick mal irgendein Code, dann können wir gucken, was da Faul ist.

Gruß Sebastian

ciruz
18.04.2006, 08:09
Hi!
Leider lag das Wekzeug brach übers lange Wochenende...
Hier ist einer der Codes mit denen ichs versucht hab:



/************************************************** **************************
UART.c
------
Übungsprojekt zum Empfang von Daten mit dem UART.
Eine LED an Pin 0 von Port C soll gesteuert werden beim Empfang folgender
Zeichen:
'1' - LED ein.
'0' - LED aus.


Autor: Christian Schifferle
Datum: November 2002
Software: AVR-GCC
needed
************************************************** **************************/

#include <io.h> // Wir brauchen Zugriff auf die I/O's des Controllers

#define F_CPU 8000000 /* 8Mhz */
#define UART_BAUD_RATE 9600 /* 9600 baud */

// Berechnung des Inhalts des UBBR-Registers
#define UART_BAUD_SELECT (F_CPU/(UART_BAUD_RATE*16l)-1)

// Datentypdefinitionen
typedef unsigned char BYTE;
typedef unsigned short WORD;



int main (void)
/************************************************** **************************
Hier ist der Programmeinstiegspunkt.
*/
{
/* UART Control Register laden. Wir verwenden (noch)
keine Interrupts. Hier wollen wir nur empfangen, also wird
nur das Receiver Enable Flag gesetzt. */
outp ((1 << RXEN), UCSRB);

/* Baudrate einstellen */
outp ((BYTE) 0x00, UBRRH);
outp ((BYTE) UART_BAUD_SELECT, UBRRL);


// Port B als Ausgang konfigurieren
outp (0xff, DDRC);
PORTC=0xff;

// Hier machen wir einmal etwas anderes zur Realisierung der
// Endlosschleife. Wir setzen zu Beginn der Schleife ein Label.
// Am Schleifenende springen wir direkt zu diesem Label.
// Nicht schön, aber unheimlich schnell.
LOOP:
// Prüfen, ob ein Zeichen empfangen wurde.

if (inp (UCSRA) & (1 << RXC)) { // Bit RXC im USR gesetzt ?
switch (inp (UDR)) { // Datenregister auslesen
case '0': // LED einschalten
sbi (PORTC, PINC0);
break;
case '1': // LED ausschalten
cbi (PORTC, PINC0);
break;
default: // Bei allen anderen Zeichen nichts tun
break;
}
}

goto LOOP;

} /* end of main */


Ich bin mir nicht sicher ob die Register alle korrekt benannt sind. Ansonsten hab ich kein Plan warums net läuft...
thx schonmal
gruz ciruz

Kaiser-F
18.04.2006, 08:56
Hi,

Hier Codes für den Mega32 UART:

hier drei Funktionen (uart.c):


void UART_init(void){
UBRRL |= (uint8_t) UART_BAUD_SELECT;
UCSRB = (1<<RXCIE)|(1<<RXEN)|(1<<TXEN);
UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
}

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

void UART_transmit_string(uint8_t *string){
while(!(UCSRA & (1<<UDRE)));
while( *string){ UART_transmit (*string++); }
}

UART_init(); Den UART Einschalten, hier wird auch der Empfangsinterrupt aktiviert. Dein Hauptprogramm muss dann so aussehen:




// AVR-Includes
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>

// Programm-Includes
#include <uart.c> // Oder die obigen Funktionen hinschreiben...

SIGNAL( SIG_UART_RECV ) { /*hier was beim Enpfang geschehen soll*/ }

int main (void){

sei(); // Interrups global aktivieren
UART_init(); // Uart init funktion ausführen


while(1){
/*HAUPTSCHLEIFE*/

}
}

18.04.2006, 09:30
Vielen Dank schonmal, aber leier kriege ich auch das nich zum laufen... :-(

SprinterSB
18.04.2006, 10:52
Wo setzt du denn das Dateformat? Üblich ist 8N1, das wird nirgends eingestellt.

ciruz
19.04.2006, 08:03
ok, und wie stelle ich das ein?

Kaiser-F
19.04.2006, 11:01
http://www.atmel.com/dyn/resources/prod_documents/doc2503.pdf


Seite 140 bis 168 befasst sich mit dem USART (~UART);

Auf Seite 162 und 163 ist CONTROL/STATUS Register C beschrieben.

ciruz
19.04.2006, 12:14
Dank auch an dich, aber mit dem Datenblatt hatte ich michauch bereits beschäftigt.
Hat denn keiner ein in C geschriebenes Prog für rn-control das einfach läuft?
Ich habe auch schon mehr als den oben geposteten Code probiert, ich kriegs aber einfach nicht auf die Reihe in C. In Bascom hab ichs zwar hinbekommen, allerdings wär mir C halt schon lieber...
Gruß

Kaiser-F
19.04.2006, 12:33
Probiers mal einfach so:

main.c:



// AVR-Includes
#include <avr/io.h>

// Defines
#define F_CPU 7372800 // Hier die Taktfrequenz in Hz eingeben
#define UART_BAUD_RATE 115200 // Hier die gewünschte Baudrate
#define UART_BAUD_SELECT (F_CPU/(UART_BAUD_RATE*16L)-1)


// Funktionen
// -=> UART initialisieren <=-
void UART_init(void){
UBRRL |= (uint8_t) UART_BAUD_SELECT;
UCSRB = (1<<RXEN)|(1<<TXEN);
UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
}

// -=> Byte Transmit <=-
void UART_transmit(uint8_t c){
while(!(UCSRA & (1<<UDRE)));
UDR = c;
}

// -=> String Transmit <=-
void UART_transmit_string(uint8_t *string){
while(!(UCSRA & (1<<UDRE)));
while( *string){ UART_transmit (*string++); }
}



int main (void)
{


UART_init(); // UART-Init Funktion ausführen

UART_transmit_string("Hurra, es funktioniert!!!");


while(1){


}
}



Stelle sicher, dass du die richtige Taktfrequenz eingibst. Und dass auch das Verwendete quarz in den Fuses eingestellt ist....

Kaiser-F
19.04.2006, 12:35
Stell auch sicher, dass in deinem Terminal-Programm 8N1 eingestellt ist. Also 8 Datenbits und 1 Stop-Bit. Sowie die passende baudrate,

Wenns nicht funkt, dann sag uns genau was er macht, oder wo es hackt usw....

ciruz
24.04.2006, 15:14
Hurra, es funktioniert!!! ;-)
Das ist echt schonmal super, vielen dank.
Jetzt bräuchte ich noch was zum empfangen.
Weiterhin würde mich noch interessieren wie es mit Wartezeiten in C aussieht. Gibts da nen Befehl oder muss man Schleifen machen wie in Assembler?
gruz ciruz

Kaiser-F
24.04.2006, 16:57
Hoi,

Ich hätte ein gepuffertes System zusammenprogrammiert.

Evtl schaust dir das Schema mal an:

-----------------------------------------------------------------------
Ausschnitt aus dem Thema:
https://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=9090&highlight=


Hallo,

Zum Thema USART Befehle Empfangen habe ich mir Folgendes Ausgedacht:

Man überlegt sich zunächst wie man seine Befehle Sendet.
Also eine art Protokoll.

Bei mir ist das Folgendermaßen:

1. Ein Zeichen, welches für den Beginn eines neuen Befehlspaketes symbolisiert
2. die länge der Nachfolgenden Bytes
4. X-Bytes

Als Startzeichen habe ich mit ESC ausgesucht. Hat den ASCII-Code 0x1B.



Allgemein ist bekannt, dass es nicht so hinhaut die einkommenden Befehle direkt zu bearbeiten. also schreibe ich die empfangenen Zeichen in einen Puffer.
Da das Befehlspaket ein Startzeichen hat ( ESC hier ), und mir dann gleich die Länge übermittelt ist das ja ein Kinderspiel, die Daten in einen Puffer zu schreiben.

Hier der Code. Ich verwende 5 Puffer:



uint8_t UART_buffer0[8];
uint8_t UART_buffer1[8];
uint8_t UART_buffer2[8];
uint8_t UART_buffer3[8];
uint8_t UART_buffer4[8];

uint8_t *UART_pointer;



void UART_receive( uint8_t data ){
if ( data == ESC ){
uint8_t gotone = 0;
UART_buffer0[1] = 0; // Unvollständige verwerfen
UART_buffer1[1] = 0; // Unvollständige verwerfen
UART_buffer2[1] = 0; // Unvollständige verwerfen
UART_buffer3[1] = 0; // Unvollständige verwerfen
UART_buffer4[1] = 0; // Unvollständige verwerfen

if( ! UART_buffer4[0] ){ UART_pointer = UART_buffer4; gotone = 1; } // Nimm Puffer 4 wenn er frei ist
if( ! UART_buffer3[0] ){ UART_pointer = UART_buffer3; gotone = 1; } // Nimm Puffer 3 wenn er frei ist
if( ! UART_buffer2[0] ){ UART_pointer = UART_buffer2; gotone = 1; } // Nimm Puffer 2 wenn er frei ist
if( ! UART_buffer1[0] ){ UART_pointer = UART_buffer1; gotone = 1; } // Nimm Puffer 1 wenn er frei ist
if( ! UART_buffer0[0] ){ UART_pointer = UART_buffer0; gotone = 1; } // Nimm Puffer 0 wenn er frei ist

if( gotone ){
UART_pointer[1] = 1; // Markiere den gewählten Puffer
UART_pointer[2] = 0; // Leeren
UART_pointer[3] = 0; // Leeren
UART_pointer[4] = 0; // Leeren
UART_pointer[5] = 0; // Leeren
UART_pointer[6] = 0; // Leeren
UART_pointer[7] = 0; // Leeren
}
} else {
if( UART_pointer[1] ){ // Nur in Puffer schreiben, wenn er in Bearbeitung ist!

UART_pointer[ UART_pointer[2] + 3 ] = data;

UART_pointer[2]++; // Füllzähler hochaddieren
if( UART_pointer[3] && (UART_pointer[2] > (UART_pointer[3]+1)) ){
UART_pointer[1] = 0; // Puffer aus Bearbeitung entfernen
UART_pointer[0] = 1; // Puffer als VOLL markieren
}
}
}
}


[0] = Puffer ist Volol
[1] = Puffer in Arbeit
[2] = Selbstgezählte
[3] = Empfangene Längenangabe
[4] = Databyte 1
[5] = Databyte 2
[6] = Databyte 3
[7] = Databyte 4


Die routine wird mit UART-Interrupt ausgeführt.

Als erstes wird nach einem Freien bzw. schon gelesenen Puffer gesucht
( schaun ob BufferXXX[0] = 0 ist. )

Wurde einer gefunden, dann wird einen zeiger Drauf!

Dann wird dieser als "in Bearbeitung markiert." und eventuell vorher fehlerhafte IN BEARBEITUNG werden verworfen.
demnach gibt es immer nur EINEN Puffer, der in bearbeitung ist.


sind so viele Bytes empfangen wie es das Längenbyte angab, so wird der pufer aus der Bearbeitung entfernt BufferXX[1]=0 und als VOLL markiert: BuufferXX[0] = 1.




Dieser kann dann bequem von einer anderen Funktion Verarbeitet werden. Das ganze verschafft mehr zeit zum verarbeiten!
Funktioniert bei mir einwandfrei. Hab diesen code ein wenig zugeschnitten, da ich selbst ein bisschen ein anderes "Protokoll"habe, aber dieses ist das beste meiner meinung nach.

Ich hoffe jemand findet Gebrauch dafür!

Kaiser-F
24.04.2006, 17:04
Achja, inzwischen habe ich noch eine Prüfsumme eingebaut.

Also das Datenpaket schaut dann so aus:

(Startzeichen) (Anzahl der Datenbytes) (n Datenbytes) (Prüfsumme)

Der Sender zählt alle Datenbytes in eine 1Byte Zahl zusammen.
Egal ob die zahl größer als 255 wäre...

Diese wird als "Prüfsumme" mitgeschickt.

Der Empfänger rechnet auch die Prüfsumme aus den Empfangenen Bytes aus und vergleicht sie. Stimmen sie überein, dann wurde Fehlerfrei übertragen. Man kann dies dann mit einem Aknowledge dem Sender zurückbestätigen.... Oder ein Nope wenns nicht geklappt hat...

Guck dir mal das SMART-Protokoll an beim EDIP Grafikmodul von
http://www.lcd-module.de



EDIT:
Man könnte auch noch die Länge mit prüfen in der Prüfsumme.
Nur darauf achten dass Sender und Empfänger das Gleiche machen.

ciruz
25.04.2006, 15:12
Vielen Dank erstmal...
Ich werde wohl noch ein bischen brauchen bis ich dazu komme, das alles umzusetzen, werde dann aber auf jeden fall nochmal feedback geben.
gruz ciruz

ciruz
15.05.2006, 15:59
Komme mit dem Code nicht wirklich zurecht.
Ich bräuchte eine Funktion, die mir einen vom Twerminalprogramm gesendeten String ausliest. Dieser ist 4 Zeichen lang. Geht sowas nicht auch einfacher?

P.S. Wie kann ich einzelne Portpins auf H oder L setzten?

Gruß

manu_f
29.03.2007, 20:30
hallo zusammen,

muss das thema noch mal aufwärmen.
leider habe ich auch probleme mit dem rn-control 1.4 daten über uart zu senden.
beim rn-control ist ja der externe quarz 16Mhz default eingestellt.
habe den code oben compiliert und übertragen.

leider tut sich am hyperterminal nichts! und soweit ich mit meinem multimeter messen konnte ändert sich der pegel (-9,3V) am tx auch nicht.

hat jemand noch ideen für mich, bekomms einfach nicht zum laufen! :(

Vielen Dank!
Manu