www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik kommunikation zwischen uc und pc


Autor: Floyd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hallo zusammen!
ich möchte gerne eine permanente kommunikation zwischen uc (atmega16) 
und pc aufrecht erhalten. datenaustausch über rs232 funktioniert in 
beide richtungen - leider nur unter einschränkungen (es können nur 8 
bits gesendet werden). in abhängigkeit von bestimmten einflüssen, sollen 
zwei mototen mit pwm geregelt werden. jeder motor für sich läuft, doch 
ich weiß nicht wie ich eine unterscheidung der motoren realisieren kann.

beispiel:

pc sagt: motor 1 -> pwm 255
         motor 2 -> pmw 180

wie schaffe ich es, dass der uc beim lesen von udr mehr als 8 bit 
einliest?

hatte gedacht dass ich vom pc aus z.b. 1255 verschicke, wobei die 1 für 
den ersen motor steht.

benutze das avr studio.

würde mich über anregungen oder verbesserungsvorschläge freuen.

gruß
  Floyd

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was du brauchst ist ein Protokoll.

Denk dir was aus: zb.
  1. Byte  Kennung des Motors
  2. Byte  PWM Wert

> wie schaffe ich es, dass der uc beim lesen von udr mehr als 8 bit
> einliest?

Gar nicht. Die Einheit der Übertragung ist ein Byte (8 bit).
Wenn dir das nicht reicht, dann benutz halt mehrere Byte, siehe oben.





Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Alle seriellen Übertragungsarten, die von µCs zur Verfügung gestellt 
werden, sind zunächst 8-Bit-Interfaces. Wenn Du mehr als 8 Bit 
übertragen willst, musst Du ein Protokoll vereinbaren und "Frames" aus 
mehreren Bytes versenden. Das ist eigentlich kein großes Problem. Du 
schickst also z.B. immer 2 Bytes, von denen das erste die "Adresse" 
(also z.B. die Nummer) des Motors enthält und das zweite den gewünschten 
Wert für die Geschwindigkeit.

Autor: Floyd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
könnt ihr mir ein bischen starthilfe für die erstellung eines solchen 
protokolls geben?

Autor: Peter S. (psavr)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du kannst ja mehrere Bytes nacheinader senden.

Ich würde aber keine binären Werte über die RS-232 senden, sondern nur 
ASCII-Characters. Dies vermeidet allfällige Probleme mit Steuerzeichen. 
[Carridge Return] [Line-Feed] [Backspace] [Delete] etc...

Deine Zahl würde dann als "1255/n" bzw. [0x31,0x32,0x35,0x35,0x13] 
übermittelt.

So kannst Du die Werte auch direkt im via ein Terminalprogramm eingeben 
oder anzeigen lassen.

MfG  Peter

Autor: Peter S. (psavr)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oder noch besser: übermittle die Werte in einer besser lesbaren Form, 
z.B. mit Kommandos wie zum Beispiel:

M1-255
M2-180

Autor: Floyd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
vom pc solche kommandos abschicken geht ja, doch ich weiß nicht ganz wie 
es dann im uc weitergeht. um einen sochen string einzulesen, muss ich 
doch mehrmals udr auslesen. wie kann ich das machen ohne daten zu 
verliehren?

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dafür gibts nen Interrupt, der ausgelöst wird, wenn ein Zeichen 
empfangen wurde. Wenn Deine Strings immer gleich lang sind (was zu 
empfehlen ist), dann musst Du nur warten, bis ein String komplett ist 
und ihn dann auswerten. Wenn Du als letztes Zeichen einen Nullterminator 
sendest, kannst Du auch eine Fehlerüberprüfung machen.

Beispiel:
1. Byte: Nummer des Motors
2. bis 4. Byte: Wert für PWM
5. Byte: Nullterminator
Du brauchst also nur einen Puffer mit 5 Bytes, in den nacheinander in 
der Interrupt-Routine die ankommenden Zeichen geschrieben werden und 
dessen aktuelle Schreibposition durch einen Zähler überwacht wird. Wenn 
der Puffer voll ist (also der Zähler z.B. in diesem Beispiel den Wert 4 
erreicht hat), kann der String ausgewertet werden.

Autor: Floyd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hi johnny.m
genau so würde ich das gerne umsetzen wollen! könntest du mir mit 
entsprechendem c-code auf die sprünge helfen? bis jetzt sieht das ganze 
bei mir so aus:

#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <stdlib.h>

#define   F_CPU 3686400
#include <util/delay.h>

unsigned char buffer1;

void uart_init(void)
{
  UBRRH = 0x00;
  UBRRL = 0x17;
  UCSRB = 0x98;
  UCSRC = 0x86;
}

unsigned char USART_RX(void)
{
while(!(UCSRA&(1<<RXC)))
  ;
return UDR;
}


int main(void)
{

PORTD=0x00;
DDRD=0x20;

TCCR1A=0x81;
TCCR1B=0x05;
TCNT1H=0x00;
TCNT1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

uart_init();

while(1)
{
         // will sehen was am uc angekommen ist
  USART_RX();
  buffer1 = UDR;


// Ende vom while
}
// Ende der main
}

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Als erstes würde ich mir mal eine String-Ausgabe machen:
// Sendet ein einzelnes Zeichen
void uart_putc( char c )
{
  // Warte bis die Sendeeinheit bereit ist
  while( !(USR & ( 1<<UDRE) ) )
    ;
  UDR = c;
}

// Sende einen C-String
void uart_puts( const char* str )
{
  while( *str ) {
    uart_putc( *str );
    str++;
  }
}

Damit kannst du schon mal solche Dinge machen:
int main()
{
  while( 1 )
    uart_puts( "Hallo du\n" );
}

oder auch
int main()
{
  char Text[] = "Hallo Welt\n";
  while( 1 )
    uart_puts( Text );
}

Dann gehts weiter: Du brauchst eine Funktion, die nicht
nur ein einzelnes Zeichen empfängt, sondern eine Zeile
davon. Als Zeile definieren wir mal: Alles was bis zum
Return Zeichen geht:
unsigned char USART_RX(void)
{
  while(!(UCSRA&(1<<RXC)))
    ;
  return UDR;
}

void uart_gets( char* Input )
{
  char c = USART_RX();
  uart_putc( c );   // und gleich wieder zurückschicken, damit
                    // der Benutzer auch was sieht

  while( c != '\n' ) {
    *Input = c;
    Input++;
    c = USART_RX();
    uart_putc( c );
  }
  *Input = '\0';
}

Damit kann man dann schon so was machen:
#include <string.h>

.... // hier die uart Funktionen

int main()
{
  char Buffer[20];

  while( 1 ) {
    uart_gets( Buffer );   // Auf eine Zeile vom Benutzer warten

    //
    // Testweise die komplette Zeile zurückschicken, so wie
    // sie vom µC empfangen wurde
    //
    uart_puts( "Ich habe verstanden : " );
    uart_puts( Buffer );
    uart_putc( '\n' );

    // war die Eingabe vom Benutzer der Text 'Floyd'
    if( strcmp( Buffer, "Floyd" ) == 0 ) {
      // Wenn ja, dann begrüsse ihn
      uart_puts( "Hallo Floyd\n" );
      uart_puts( "Wie gehts\n" );
    }
  }
}

Wenn du dich jetzt mit einem Terminalprogramm an den
µC klemmst, muss der brav jede Eingabe wieder zurück-
schicken. Jedesmal wenn du Return drückst, zeigt
er dir die zuletzt gelesene komplette Zeile an.


Und so gehts dann weiter:
Du vereinbarst mit dir, dass das erste Zeichen in der
Übertragung die Motornummer ist, das nächste Zeichen
ignorierst du und daran anschliessend kommt der PWM Wert.

An das erste Zeichen kommst du ganz einfach mit Buffer[0] ran.
Ab Buffer[1] steht dann eine 'Zahl' in ihrer ASCII Form.
Die Funktion atoi() kann diese ganz leicht in eine tatsächliche
Zahl wandeln.
....

   int MotorNr;

   while( 1 ) {

     uart_gets( Buffer );

     // zu testzwecken. Ist immer gut zu kontrollieren
     // was der µC tatsächlich empfängt
     uart_puts( "Ihre Eingabe: " );
     uart_puts( Buffer );
     uart_putc( '\n' );

     MotorNr = Buffer[0] - '0';    // Die Motornummer nummerisch machen
     PWMWert = atoi( &Buffer[2] ); // Den PWM Wert umrechnen lassen

     if( MotorNr == 0 )
       uart_puts( "Setze Motor 0 auf neuen Wert\n" );

     else if( MotorNr == 1 )
       uart_puts( "Setze Motor 1 auf neuen Wert\n" );

     else
       uart_puts( "Diesen Motor gibt es nicht!\n" );
  }
}


Verbinde dich wieder mit dem Terminalprogramm zum µC und
gib ein:
0 200
(und natürlich Return drücken)

Der µC sollte antworten mit:
Ihre Eingabe: 0 200
Setze Motor 0 auf neuen Wert

1 154
Ihre Eingabe: 1 154
Setzte Motor 1 auf neuen Wert
2 300
Diesen Motor gibt es nicht!

Autor: Floyd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hallo Karl Heinz!
vielen dank für deine ausführlichen beschreibungen und code-auszüge. sie 
haben mein problem vollständig gelöst. leider kann ich das ergebnis erst 
in zwei tagen begutachten, da sich mein uc gestern abend verabschiedet 
hat...

vielen dank!

gruß,
  Floyd

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hoffe mal, dassich nicht allzuviele Fehler eingebaut habe.
Ein Fehler ist beim direkten eintippen in da Forum immer
drinnen.

Wenn du noch Probleme hast: gerne wieder.

Autor: Floyd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hab gerade noch einen uc gekauft, da ich neugierig geworden bin.
ist mir jetzt wirklich schon peinlich, aber ich hab da ein kleines 
problem mit dem code. definiere ich buffer im uc läuft die 
identifizierung einwandfrei. lese ich jedoch über den uart den string 
ein, wird nur "uart_gets(Buffer)" aufgerufen und danach ist schluß. 
woran liegt es? hab gerade echt ein brett vorm kopf...

der code:

#include <avr/io.h>
#include <stdio.h>
#include <string.h>


int MotorNr;
char Buffer[20];
//char Buffer[]="1 255\n";

// Sendet ein einzelnes Zeichen
void uart_putc( char c )
{
  // Warte bis die Sendeeinheit bereit ist
  while( !(UCSRA & ( 1<<UDRE) ) )
    ;
  UDR = c;
}

// Sende einen C-String
void uart_puts( const char* str )
{
  while( *str ) {
    uart_putc( *str );
    str++;
  }
}

// Ausgabe mit printf über USART
static int uart_putchar(char c, FILE *stream);
static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL,
                                             _FDEV_SETUP_WRITE);

static int
    uart_putchar(char c, FILE *stream)
    {

      if (c == '\n')
        uart_putchar('\r', stream);
      loop_until_bit_is_set(UCSRA, UDRE);
      UDR = c;
      return 0;
    }

unsigned char USART_RX(void)
{
  while(!(UCSRA&(1<<RXC)))
    ;
  return UDR;
}

void uart_gets( char* Input )
{
  char c = USART_RX();
  uart_putc( c );

  while( c != '\n' )
  {
    *Input = c;
    Input++;
    c = USART_RX();
    uart_putc( c );
  }
  *Input = '\0';
}


void uart_init(void)
{
  UBRRH = 0x00;
  UBRRL = 0x17;
  UCSRA = 0x00;
  UCSRB = 0x18;
  UCSRC = 0x86;
}


int main(void)
{

PORTD=0x00;
DDRD=0xB0;

TCCR1A=0xA1;
TCCR1B=0x0B;
TCNT1H=0x00;
TCNT1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

// USART initialisieren
uart_init();


while(1)
{

uart_gets(Buffer);

uart_puts( "Ihre Eingabe: " );
uart_puts( Buffer );
uart_putc( '\n' );

MotorNr = Buffer[0] - '0';    // Die Motornummer nummerisch machen
OCR1AL = atoi( &Buffer[2] ); // Den PWM Wert umrechnen lassen

if( MotorNr == 0 )
{
uart_puts( "Setze Motor 0 auf neuen Wert\n" );
stdout = &mystdout;
printf(" Dieser ist: %u\n",OCR1AL);
}

else if( MotorNr == 1 )
{
uart_puts( "Setze Motor 1 auf neuen Wert\n" );
stdout = &mystdout;
printf(" Dieser ist: %u\n",OCR1AL);
}

else
uart_puts( "Diesen Motor gibt es nicht!\n" );

// Ende vom while
}
// Ende der main
}


vielen dank im voraus.

Floyd

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dein uart_gets() liest ein bis ein '\n' (=LINEFEED) kommt. Schickt dein 
PC Terminalprogramm überhaupt solche Zeichen oder schickt es beim 
Drücken von RETURN nur '\r' (=CARRIAGE RETURN)?

Autor: Floyd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
jetzt ja. das war die antwort. danke!

gruß,
 Floyd

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.