Forum: Compiler & IDEs ctoi funktion winavr ?


von Peter M. (tanger)


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;
}

von Karl heinz B. (kbucheg)


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?

von Peter M. (tanger)


Lesenswert?

jap vieln dank (= dahcte man müssete das erst mit chartoint umwandeln

von Karl heinz B. (kbucheg)


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.

von Stefan (Gast)


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
}

von Peter M. (tanger)


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 ( =

von Dirk (Gast)


Lesenswert?

Beitrag "Auswertung RS232-Befehle"

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


Gruß,
Dirk

von Stefan (Gast)


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.

von Peter M. (tanger)


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
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <avr/signal.h>
4
//#include "uart.h"
5
6
#define SYSCLK    16000000
7
#define BAUD    38400UL
8
#define UBRR_BAUD  ((SYSCLK/(16*BAUD))-1)
9
10
#define BUFLEN  20
11
12
#define COMMAND0 1
13
#define COMMAND1 2
14
#define COMMAND2 3
15
#define COMMAND3 4
16
17
#define READY   0
18
19
20
21
typedef unsigned char  u8;
22
typedef unsigned short u16;
23
typedef unsigned long  u32;
24
 
25
typedef struct commands 
26
{
27
  u8  cmd;
28
  u8  data0;
29
  u8  data1;
30
  u8  data2;
31
  u8  data3;
32
}commands;
33
34
volatile unsigned char rx_buffer[BUFLEN];              // Receive Buffer
35
volatile unsigned char rx_ptr;                      // uchar pointer
36
volatile unsigned char wrx_ptr;                      // uchar pointer
37
volatile unsigned char status_byte;                      // uchar pointer
38
39
enum states {byte0=0, byte1, byte2, byte3, byte4}state;
40
41
42
 struct commands rs232data,*p;
43
44
void uart_init(void);
45
46
47
SIGNAL(SIG_UART_RECV)
48
{
49
  rx_buffer[wrx_ptr] = UDR;            // put new byte to buffer
50
  if (++wrx_ptr >= BUFLEN) {          // erhoehe den lese Buffer
51
    wrx_ptr = 0;          
52
  }
53
}
54
55
56
void get_data(void)
57
{
58
  if(wrx_ptr != rx_ptr){                      
59
    switch (state)
60
    {
61
      case byte0:  p->cmd = rx_buffer[rx_ptr];
62
                  break;
63
                  
64
      case byte1:  p->data0 = rx_buffer[rx_ptr];
65
                  break;
66
      
67
      case byte2:  p->data1 = rx_buffer[rx_ptr];
68
                  break;
69
                  
70
      case byte3:  p->data2 = rx_buffer[rx_ptr];
71
                  break;
72
                  
73
      case byte4:  p->data3 = rx_buffer[rx_ptr];
74
                  status_byte |= (1<<READY);
75
                  break;
76
                  
77
    }
78
    state++;
79
    if (++rx_ptr>=BUFLEN){
80
          rx_ptr = 0;
81
    }
82
  }
83
}  
84
85
void auswertung (void)
86
{
87
    if (status_byte & (1<<READY)){
88
    switch (p->cmd)            
89
    {
90
  
91
    case COMMAND0:  // do anything
92
        while ( !( UCSRA & (1<<UDRE)) )
93
        ;
94
        UDR = 0;
95
                    break;
96
                      
97
    case COMMAND1:  // do anything
98
                    break;
99
                      
100
    case COMMAND3:  // do anything
101
                    break;
102
                      
103
    }
104
    status_byte &= ~(1<<READY);
105
   state=0;
106
  }
107
}
108
109
110
111
int main (void)
112
{
113
114
  p = &rs232data;  
115
  
116
  get_data();
117
  auswertung();
118
  
119
return 0;
120
}
121
122
void uart_init(void)
123
{
124
  /* Baudrate einstellen ( Normaler Modus ) */
125
  UBRRH = (unsigned char) (UBRR_BAUD>>8);
126
  UBRRL = (unsigned char) UBRR_BAUD;
127
128
  /* Aktivieren des Empfängers, des Senders und des "Daten empfangen"-Interrupts */
129
  UCSRB = (1<<RXCIE)|(1<<RXEN)|(1<<TXEN);
130
131
  /* Einstellen des Datenformats: 8 Datenbits, 1 Stoppbit */
132
  UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
133
}

von Stefan (Gast)


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
...

von Dirk (Gast)


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.
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <avr/signal.h>
4
//#include "uart.h"
5
6
#define SYSCLK    16000000
7
#define BAUD    38400UL
8
#define UBRR_BAUD  ((SYSCLK/(16*BAUD))-1)
9
10
#define BUFLEN  20
11
 
12
#define RUN  0
13
#define STOP 1
14
#define BOOM 2
15
16
typedef unsigned char  u8;
17
typedef unsigned short u16;
18
typedef unsigned long  u32;
19
20
volatile unsigned char rx_buffer[BUFLEN];              // Receive Buffer
21
volatile unsigned char rx_ptr;                      // uchar pointer
22
volatile unsigned char wrx_ptr;                      // uchar pointer
23
24
void uart_init(void);
25
26
27
SIGNAL(SIG_UART_RECV)
28
{
29
  rx_buffer[wrx_ptr] = UDR;            // put new byte to buffer
30
  if (++wrx_ptr >= BUFLEN) {          // erhoehe den lese Buffer
31
    wrx_ptr = 0;
32
  }
33
}
34
35
36
void check_data(void)
37
{
38
  if(wrx_ptr != rx_ptr){
39
    switch (rx_buffer[rx_ptr])
40
    {
41
      case RUN:   //starte
42
                  break;
43
44
      case STOP:  //halte an
45
                  break;
46
47
      case BOOM:  //explodiere
48
                  break;
49
50
    }
51
    if (++rx_ptr>=BUFLEN){
52
          rx_ptr = 0;
53
    }
54
}
55
56
int main (void)
57
{
58
  uart_init();
59
  for(;;){
60
  check_data();
61
  }
62
}   
63
  
64
void uart_init(void)
65
{
66
  /* Baudrate einstellen ( Normaler Modus ) */
67
  UBRRH = (unsigned char) (UBRR_BAUD>>8);
68
  UBRRL = (unsigned char) UBRR_BAUD;
69
70
  /* Aktivieren des Empfängers, des Senders und des "Daten
71
empfangen"-Interrupts */
72
  UCSRB = (1<<RXCIE)|(1<<RXEN)|(1<<TXEN);
73
74
  /* Einstellen des Datenformats: 8 Datenbits, 1 Stoppbit */
75
  UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
76
}

Gruß,
Dirk

von Peter M. (tanger)


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);
}

von Stefan (Gast)


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.


von Peter M. (tanger)


Lesenswert?

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

von Dirk (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

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

Gruß,
Dirk

von Stefan (Gast)


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.

von Dirk (Gast)


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.







von Peter Moor (Gast)


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

von Peter Moor (Gast)


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 ...

von Dirk (Gast)


Angehängte Dateien:

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).


von Dirk (Gast)


Lesenswert?

@Peter Moore hast du deinen Fehler gefunden oder aufgegeben?




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.