mikrocontroller.net

Forum: Compiler & IDEs ctoi funktion winavr ?


Autor: Peter Moor (tanger)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi
ich will mithilfe eines Protokolls daten über usart an meinen mega32 
übermitteln.

aufbau:
{ = start
    comand
    data
} = end

die daten werden immer in bytes übermittelt. ich bäuchte jetz noch eine 
ctoi funktion so das ich bis zu 254 zahlen im data feld übermitteln 
kann.

ich hab mal den code angehangen er ist nicht sehr schön ... für 
verbesserungen und vorschläge semtlicher art bin ich sehr dankbar ( =

grüße


#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>

#define SYSCLK    16000000
#define BAUD    38400UL
#define UBRR_BAUD  ((SYSCLK/(16*BAUD))-1)

/* USART initialisieren */
void uart_init(void);
unsigned char buffer;
int sequ=0;
int speed=0;
int stat=0;
int main(void)
{

  /* USART initialisieren */
  uart_init();
  sei();

  /* Nichts tun. Die Interrupts erledigten den Rest */

  do
  {
  if (speed)
  {


  }
  }
  while (1)
    ;
}

void uart_init(void)
{
  /* Baudrate einstellen ( Normaler Modus ) */
  UBRRH = (unsigned char) (UBRR_BAUD>>8);
  UBRRL = (unsigned char) UBRR_BAUD;

  /* Aktivieren des Empfängers, des Senders und des "Daten 
empfangen"-Interrupts */
  UCSRB = (1<<RXCIE)|(1<<RXEN)|(1<<TXEN);

  /* Einstellen des Datenformats: 8 Datenbits, 1 Stoppbit */
  UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
}

/* Interrupt wird ausgelöst sobald neue Daten im USART-Empfangspuffer 
liegen */
ISR(USART_RXC_vect)
{

  /* Daten aus dem Puffer lesen ... */
  buffer = UDR;

if (buffer == '{')
    sequ=1;
  else
  {
    if(sequ==1)
    {
     if(buffer=='}')
     sequ=0;
     if(buffer=='s')
     stat=1;
     else
    {
    if (stat == 1)
      {
      stat=0;
      speed=buffer;

      while ( !( UCSRA & (1<<UDRE)) )
      ;
      UDR = speed;
      }
    }
    }
   }


  /* ... warten bis der Sendepuffer leer ist ... */
  //while ( !( UCSRA & (1<<UDRE)) )
    ;
  /* ... und gleich wieder zurück schicken */
  //UDR = buffer;
}

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was soll  ctoi() machen?

Du nimmst das Byte, das du ja hoffentlich (habs jetzt
nicht in deinem Code gesucht) in einem unsigned char
empfangen hast und weist das ganz einfach einem int zu.

  unsigned char  data;

  // data kriegt irgendwie seinen Wert von der UART

  int i;

  i = data;

Du kannst auch mit data direkt weiterrechnen. Ein char ist
in C auch nichts anderes als ein kleiner Integer. Mit
dem kann man genauso rechnen wie mit einem int. Nur
spielt sich halt alles im Zahlenbereich 0 bis 255 ab
(wenn du einen unsigned char hast).

Beantwortet das dein Problem?

Autor: Peter Moor (tanger)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
jap vieln dank (= dahcte man müssete das erst mit chartoint umwandeln

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das data:
Ist das ein einzelnes Byte oder ein String.

Die Möglichkeit gibt es auch noch. Im ersten Posting
bin ich davon ausgegangen, dass data nur ein einzelnes
Byte ist, dass den Wert enthält. Das da also eine binäre
Übertragung erfolgt.

Das muss aber nicht so sein. Du kannst ja die Zahl auch
als Stringrepräsentierung rüberschicken. Bei einer
Zahl 123 werden also nacheinander die Zeichen '1', dann
'2' und schlieslich '3' übertragen, sodass du auf der
Empfangsseite jetzt mit einem String "123" da stehst und
daraus wiederrum eine Zahl machen musst. atoi() wäre zb.
dafür geeignet.

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich verstehe nicht, was dein Programm machen soll. Etwas mehr 
Hintergrundinfo wäre hilfreich. Im Moment sieht es so aus:

1/ Das Hauptprogramm initialisiert UART und dreht dann Däumchen. Ein 
Anweisungsrumpf für die Abfrage einer Variable speed ist vorhanden. Soll 
da die Baudrate umgeschaltet werden?

2/ Die Empfangsroutine empfängt Zeichen und setzt unter bestimmten 
Umständen eine Variable speed. Die Umstände werden durch eine state 
machine definiert, die eine 4-Byte Kommandosequenz erwartet.

An Verbesserungen schlage ich vor:

A/ Die state machine aus der Interrupt-Routine rausnehmen. Die ggf. 
zeitraubende Auswertung sollte im Hauptprogramm gemacht werden.

B/ Einen längeren Puffer für die Empfangsroutine einbauen, der 
mindestens so gross ist wie eine Kommandosequenz. Dieser Puffer wird 
gemäß A/ ausgewertet.

C/ Die Zuweisung an UDR aus der Empfangsroutine rausnehmen. Sie hat 
logisch dort nichts zu suchen. Sind das Reste einer Echo-Funktion?

// Globale Definitionen
#define MAXPUFFER 4
char puffer[MAXPUFFER];
unsigned char zeichen_im_puffer = 0;

...
// Auswertung im Hauptprogramm
if ( zeichen_im_puffer == MAXPUFFER
     && puffer[0] == '{'
     && puffer[3] == '}' )
{
    // Kommando?
    switch ( puffer[1] )
    {
        // SPEED
        case 's':
                  speed = puffer[2]; // Nutzdaten
                  // ggf. hier Baudrate umschalten
                  break;
        // Unbekanntes Kommando
        default:
                  break;
    }

    // Kommando abgearbeitet.
    zeichen_im_puffer = 0;
    puffer[0] = 0;
    puffer[1] = 0;
    puffer[2] = 0;
    puffer[3] = 0;
}

...
// Puffer in der Empfangsroutine
ISR(USART_RXC_vect)
{
    unsigned char zeichen = UDR;

    if (zeichen_im_puffer < MAXPUFFER)
        puffer[zeichen_im_puffer++] = zeichen;
    // else = Puffer voll
    // dann z.B. weitere Zeichen verwerfen
}

Autor: Peter Moor (tanger)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
oh vieln dank für die super mühen erstmal ( =

ich hab probiert die state maschine in die main reinzunehem und buffer 
eben global zu deklarieren ... leider ging dies nicht (wieso weiß ich 
nciht)

ich werde deine veränderungen  ausprobieren

...noch mal zu meinem protokoll

ja data ist erstmal nur ein byte

also am controller kommt {f100} für forwärts oder {b100} for backwards 
und eventuell ncoh request um den strom abzufragen aber das wird später 
kommen

baudrate werde ich irgendwann mal umstellen ja ( =

Autor: Dirk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Beitrag "Auswertung RS232-Befehle"

Einfacher geht es sicherlich einfach zum Schluss das Fifo über den 
Memcpy Befehl ins struct zu kopieren.


Gruß,
Dirk

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Peter

Ich weiss es auch nicht. Wenn ich helfen soll, müsstest du 
Fehlermeldungen, eine Problembeschreibung oder den geänderten Sourcecode 
angeben. Am besten alles.

Wenn du meine Codeschnippsel verwendet hast, kennzeichne die beiden 
globalen variablen zusätzlich mit volative.

Autor: Peter Moor (tanger)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

also sowas wie dirk als link beigelegt hat find ich schon sehr gut und 
könnte ich auch sicherlich gut als ausgangasposition verwenden.

ich schrieb einfach mal wie ich das program verstanden habe.

sobalt ich ein zecihen sende wird dies in ein array[0] geschrieben. dann 
wird die funktion get_data ausgeführt sobalt was reingeschrieben wurde 
ist der wrx pointer erhöht und nicht mehr gleich dem rx pointer also 
wird das zeichen in cmd geschrieben sobalt 4 bytes eingelesen worden 
wird statusbyte = ready gesetzt und auswertung() erlaubt die auswertung 
der daten dazu wird eine case angelegt um den cmd zu überprüfen ....

wenn das so stimmt wieso geht mein programm da unten nciht [ =

nochmal danke wusste garnicht das es so ein forum gibt wo soviel mühen 
reingesteckt werden

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
//#include "uart.h"

#define SYSCLK    16000000
#define BAUD    38400UL
#define UBRR_BAUD  ((SYSCLK/(16*BAUD))-1)

#define BUFLEN  20

#define COMMAND0 1
#define COMMAND1 2
#define COMMAND2 3
#define COMMAND3 4

#define READY   0



typedef unsigned char  u8;
typedef unsigned short u16;
typedef unsigned long  u32;
 
typedef struct commands 
{
  u8  cmd;
  u8  data0;
  u8  data1;
  u8  data2;
  u8  data3;
}commands;

volatile unsigned char rx_buffer[BUFLEN];              // Receive Buffer
volatile unsigned char rx_ptr;                      // uchar pointer
volatile unsigned char wrx_ptr;                      // uchar pointer
volatile unsigned char status_byte;                      // uchar pointer

enum states {byte0=0, byte1, byte2, byte3, byte4}state;


 struct commands rs232data,*p;

void uart_init(void);


SIGNAL(SIG_UART_RECV)
{
  rx_buffer[wrx_ptr] = UDR;            // put new byte to buffer
  if (++wrx_ptr >= BUFLEN) {          // erhoehe den lese Buffer
    wrx_ptr = 0;          
  }
}


void get_data(void)
{
  if(wrx_ptr != rx_ptr){                      
    switch (state)
    {
      case byte0:  p->cmd = rx_buffer[rx_ptr];
                  break;
                  
      case byte1:  p->data0 = rx_buffer[rx_ptr];
                  break;
      
      case byte2:  p->data1 = rx_buffer[rx_ptr];
                  break;
                  
      case byte3:  p->data2 = rx_buffer[rx_ptr];
                  break;
                  
      case byte4:  p->data3 = rx_buffer[rx_ptr];
                  status_byte |= (1<<READY);
                  break;
                  
    }
    state++;
    if (++rx_ptr>=BUFLEN){
          rx_ptr = 0;
    }
  }
}  

void auswertung (void)
{
    if (status_byte & (1<<READY)){
    switch (p->cmd)            
    {
  
    case COMMAND0:  // do anything
        while ( !( UCSRA & (1<<UDRE)) )
        ;
        UDR = 0;
                    break;
                      
    case COMMAND1:  // do anything
                    break;
                      
    case COMMAND3:  // do anything
                    break;
                      
    }
    status_byte &= ~(1<<READY);
   state=0;
  }
}



int main (void)
{

  p = &rs232data;  
  
  get_data();
  auswertung();
  
return 0;
}

void uart_init(void)
{
  /* Baudrate einstellen ( Normaler Modus ) */
  UBRRH = (unsigned char) (UBRR_BAUD>>8);
  UBRRL = (unsigned char) UBRR_BAUD;

  /* Aktivieren des Empfängers, des Senders und des "Daten empfangen"-Interrupts */
  UCSRB = (1<<RXCIE)|(1<<RXEN)|(1<<TXEN);

  /* Einstellen des Datenformats: 8 Datenbits, 1 Stoppbit */
  UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
}

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du musst mindestens get_data() und auswertung() in eine Endlosschleife 
einbauen, sonst wird das nix.

Und sehen tust du im Moment auch nix, weil keine Nutzfunktion eingebaut 
ist.

Bau doch mal ein Echo ein (empfangene Zeichen zurückschicken) und 
schalte mit einem Kommando Echo in Grossschreibung an und mit einem 
anderen Kommando Echo in Kleinschreibung. Allerdings sollest du dann 
einfacher eingebare Kommandos benutzen. Also z.B.

#define COMMANDO0 "e" // Echo ein
#define COMMANDO2 "g" // Grossschrift ein
...

Autor: Dirk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo, vielleicht optimiert der Compiler auch das Struct weg, das 
koennte vielleicht weiterhelfen.

volatile struct commands rs232data,*p;

Du möchtest nur ein Byte auswerten und keine komplexen Protokolle 
übertragen ? dann koennte man alles ein bischen verkleinern indem man 
sich das Struct spart.
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
//#include "uart.h"

#define SYSCLK    16000000
#define BAUD    38400UL
#define UBRR_BAUD  ((SYSCLK/(16*BAUD))-1)

#define BUFLEN  20
 
#define RUN  0
#define STOP 1
#define BOOM 2

typedef unsigned char  u8;
typedef unsigned short u16;
typedef unsigned long  u32;

volatile unsigned char rx_buffer[BUFLEN];              // Receive Buffer
volatile unsigned char rx_ptr;                      // uchar pointer
volatile unsigned char wrx_ptr;                      // uchar pointer

void uart_init(void);


SIGNAL(SIG_UART_RECV)
{
  rx_buffer[wrx_ptr] = UDR;            // put new byte to buffer
  if (++wrx_ptr >= BUFLEN) {          // erhoehe den lese Buffer
    wrx_ptr = 0;
  }
}


void check_data(void)
{
  if(wrx_ptr != rx_ptr){
    switch (rx_buffer[rx_ptr])
    {
      case RUN:   //starte
                  break;

      case STOP:  //halte an
                  break;

      case BOOM:  //explodiere
                  break;

    }
    if (++rx_ptr>=BUFLEN){
          rx_ptr = 0;
    }
}

int main (void)
{
  uart_init();
  for(;;){
  check_data();
  }
}   
  
void uart_init(void)
{
  /* Baudrate einstellen ( Normaler Modus ) */
  UBRRH = (unsigned char) (UBRR_BAUD>>8);
  UBRRL = (unsigned char) UBRR_BAUD;

  /* Aktivieren des Empfängers, des Senders und des "Daten
empfangen"-Interrupts */
  UCSRB = (1<<RXCIE)|(1<<RXEN)|(1<<TXEN);

  /* Einstellen des Datenformats: 8 Datenbits, 1 Stoppbit */
  UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
}

Gruß,
Dirk

Autor: Peter Moor (tanger)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
also irgendwie bekomm ich nicht bei jeder 0 etwas zurück sondern nur 
nach einer wilkürlich anzahl ... ich hab noch ne klammer hinzugefühgt 
und ne ausgabe ... was haben die zeiger denn für anfangswerte und was 
macht die if bedingung indem die sie zeiger vergleich ?

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
//#include "uart.h"

#define SYSCLK    16000000
#define BAUD    38400UL
#define UBRR_BAUD  ((SYSCLK/(16*BAUD))-1)

#define BUFLEN  5

#define RUN  0
#define STOP 1
#define BOOM 2


volatile unsigned char rx_buffer[BUFLEN];              // Receive Buffer
volatile unsigned char rx_ptr;                      // uchar pointer
volatile unsigned char wrx_ptr;                      // uchar pointer

void uart_init(void);


SIGNAL(SIG_UART_RECV)
{
  rx_buffer[wrx_ptr] = UDR;            // put new byte to buffer
  if (++wrx_ptr >= BUFLEN) {          // erhoehe den lese Buffer
    wrx_ptr = 0;
  }
}


void check_data(void)
{
  if(wrx_ptr != rx_ptr){
    switch (rx_buffer[rx_ptr])
    {
      case RUN:
    while ( !( UCSRA & (1<<UDRE)) )
        ; //starte
    UDR = 'r';
                  break;

      case STOP:  //halte an
                  break;

      case BOOM:  //explodiere
                  break;

    }
    if (++rx_ptr>=BUFLEN){
          rx_ptr = 0;
    }
}
}

int main (void)
{
  uart_init();
  for(;;){
  check_data();
  }
}

void uart_init(void)
{
  /* Baudrate einstellen ( Normaler Modus ) */
  UBRRH = (unsigned char) (UBRR_BAUD>>8);
  UBRRL = (unsigned char) UBRR_BAUD;

  /* Aktivieren des Empfängers, des Senders und des "Daten
empfangen"-Interrupts */
  UCSRB = (1<<RXCIE)|(1<<RXEN)|(1<<TXEN);

  /* Einstellen des Datenformats: 8 Datenbits, 1 Stoppbit */
  UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
}

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
volatile unsigned char rx_ptr;  // uchar pointer
volatile unsigned char wrx_ptr; // uchar pointer

... sind mistverständlich von der Benennung her oder falsch von der 
Definition her, denn es sind keine Zeiger. Es sind Zähler.

Und die sollten am Programmanfang auf 0 initialisiert werden, wenn man 
sicher gehen will und sich nicht auf den C-Startupcode verlassen will.


Autor: Peter Moor (tanger)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
mh dann müsste ich aber doch beim ersten gesendeten byte (0) schon was 
zurückbekommen

Autor: Dirk (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

anbei eine geteste Version mit ATMEGA16 und 8MHz (externer Quarz).

Gruß,
Dirk

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Angenommen du machst die Initialisierung mit 0

volatile unsigned char rx_ptr = 0;
volatile unsigned char wrx_ptr = 0;

Und das erste Byte kommt über diese Interruptroutine.

SIGNAL(SIG_UART_RECV)
{
  rx_buffer[wrx_ptr] = UDR;            // put new byte to buffer
  if (++wrx_ptr >= BUFLEN) {          // erhoehe den lese Buffer
    wrx_ptr = 0;
  }
}

Dann ist

wrx_ptr == 1
rx_ptr == 0
rx_buffer[0] == 0
Wenn das Byte eine binäre (!!!) 0 ist. Die Ziffer 0 wäre ein '0'. Nur 
zum Verständnis.

In in deinem Programm geht es vielleicht (!) als erstes nach 
check_data(). Vielelicht, weil wir nicht wissen, wo der Interrupt 
aufgetreten ist.

void check_data(void)
{
  if(wrx_ptr != rx_ptr){
    switch (rx_buffer[rx_ptr])
    {
      case RUN:
                  while ( !( UCSRA & (1<<UDRE)) )
                    ; //starte
                  UDR = 'r';
                  break;

      case STOP:  //halte an
                  break;

      case BOOM:  //explodiere
                  break;

    }
    if (++rx_ptr>=BUFLEN){
          rx_ptr = 0;
    }
  }
}

Die aktuellen Werte sind:

wrx_ptr == 1
rx_ptr == 0
rx_buffer[0] == 0

Der if-Fall ist wahr (1 != 0), rx_buffer[0] == 0 == RUN, also geht es in 
den case RUN.

Hier wird gewartet bis der Sendepuffer leer ist und dann wird ein 'r' 
gesendet.

D.h. deine Annahme ist richtig. Empfängt der µC eine binäre 0, sollte 
ein 'r' zurückgeschickt werden.

Wenn nix kommt, könnte es an der Verwechselung von binärer 0 mit Ziffer 
0 liegen. Oder das Senden über UART funktioniert nicht.

Autor: Dirk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

>In in deinem Programm geht es vielleicht (!) als erstes nach
>check_data(). Vielelicht, weil wir nicht wissen, wo der Interrupt
>aufgetreten ist.

Es ist egal wann der Interrupt ausgeloest wird das Fifo Buffer wird 
weiterhin  gefuellt.

In deinen Programm hattest du den Buffer verkleinert auf 5 Bytes, wenn 
deine Mainapplikation zulange braucht um die empfangenden Daten 
auszuwerten werden deine alten Daten überschrieben.

In einigen anderen Mikrocontrollern befinden sich einige Kbyte 
Ringbuffer als Hardware, manchmal kann in dem Fall auf ein Software Fifo 
Buffer verzichtet werden.







Autor: Peter Moor (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
also die hardware funktioniert ich bekomme mit dem programm: 
http://www.kreatives-chaos.com/index.php?seite=c_uart auch die 
buchstaben die ich sende zurück

Autor: Peter Moor (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
also wenn ich dein help.c nehme ... bekomme ich wilkürlich Zeichen 
sobalt ich eine 0 schicke. modifiere ich das programm mit einer anderen 
uart_init() bekomme ich (nicht bei jedem 0 byte was ich sende) start, 
stop ect zurück ...

Autor: Dirk (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

dann liegt es höchstwahrscheinlich an deiner F_CPU (Quarz), CPU 
Einstellung im Makefile. Anbei ein Screenshot, ich sende ein paar Bytes 
jeweils (00) Hexdezimal und bekomme als Rückantwort ein Ascii String 
(RUN).


Autor: Dirk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Peter Moore hast du deinen Fehler gefunden oder aufgegeben?




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.