Wie konvertiert man Bytes in ASCII in C-Sprache

Ich erhalte Bytes von meinem UART als uint8. Wie konvertiere ich diese Bytes in ASCII? Ich verwende Atmel 6.0 und mein Mikrocontroller ist ATMega16L.

BEARBEITEN

Ich verwende ein Android-Telefon, um Informationen von Roving-Netzwerken an ein WLAN-Modul (RN-131) zu senden und zu empfangen. Das WLAN-Modul verbindet sich über UART mit dem Mikrocontroller (atmega16L). Was auch immer das WLAN-Modul vom Telefon empfängt, wird über seinen UART übertragen. In ähnlicher Weise wird alles, was in seinen UART geschrieben wird, über WLAN übertragen.

Jetzt versuche ich, eine Zeichenfolge vom Telefon zu senden, die in Bytes umgewandelt wird. Der Code ist unten dargestellt:

PrintWriter out = new PrintWriter(new BufferedWriter(new outputStreamWriter(socket.getOutputStream())), true);
out.println("Eclipse");

hier der ' BufferedWriter ' - Konstruiert einen neuen BufferedWriter, der einen Puffer von 8192 Bytes bereitstellt. und ' PrintWriter ' - Konstruiert einen neuen PrintWriter mit out als Zielschreiber. Der Parameter autoFlush bestimmt, ob der Druck-Writer seinen Inhalt automatisch an den Ziel-Writer löscht, wenn ein Zeilenumbruch auftritt.

Jetzt zum Programmieren des Mikrocontrollers verwende ich AVR Studio 6.0

uint8_t data;
char arr[32];
data = UDR;
length = strlen(data);
itoa(data, arr, 10);

Aber was ich bekomme, ist "50, 53, 52", selbst wenn ich "Eclipse" sende.

EDIT 20. Juni 2012

Hier ist mein Code bis jetzt. Hinweis: Der Code wurde in AVR Studio 6.0 geschrieben, daher sieht er etwas anders aus als andere Codes, die in AVR Studio 4.18 geschrieben wurden.

/**************************************************
 *  Includes
 */
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
#include "../../../../../../Program Files (x86)/Atmel/Atmel Studio 6.0/extensions/Atmel/AVRGCC/3.4.0.65/AVRToolchain/avr/include/avr/iom16.h"

/**************************************************
 *  Global Variables
 */
int trigger=0, length=0;
int i=0, n=0;
uint8_t data;
char arr[8];

/**************************************************
 *  Defines
 */
#define LED_PORT PORTA
#define RED_ON (PORTA | 0x01)
#define RED_OFF (PORTA & ~0x01)
#define YELLOW_ON (PORTA | 0x02)
#define YELLOW_OFF (PORTA & ~0x02)
#define GREEN_ON (PORTA | 0x04)
#define GREEN_OFF (PORTA & ~0x04)

/**************************************************
 *  Function Prototypes
 */
void initialize(void);                      
void time_display(void);

int main(void){
    initialize();

    while(1){
        //TODO:: Please write your application code

    }
}

void initialize(void){

    DDRA = 0x07; //PORTA pins 0,1,2 set as outputs
//  DDRD = 0x02; //PORTD pin 1 is output (TX) and pin 0 is input (RX)

    //Timer SETUP
    TCCR1A = 0x80; //OCR1A enable in CTC mode
    TCCR1B = 0x0C; //CTC mode, 256 prescale 
    TIMSK = 0x10; //CTC on OCR1A enabled, overflow disabled
    OCR1A = 2000; //OCR value set to get an interrupt every 1 second (15624)

    //USART SETUP
    UCSRA = 0x00; //no Frame Error, no parity error, no Data OverRun
    UCSRB = 0xE0; //receiver enable, transmitter enable (0x18)
    UCSRC = 0x8E; //Asynchronous USART mode, no parity, 1 stop bit, 8-bit character size, Data transmitted on rising edge and received on falling edge of the clock
    UBRRL = 51; //Baud rate of 9600bps
    UBRRH = 0;

    sei(); //Global interrupt enable
}

//timer capture interrupt
ISR(TIMER1_COMPA_vect){

}

ISR(USART_RXC_vect){
    LED_PORT = RED_ON;
    _delay_ms(100);

    for(int x=0; x<5; x++){
        arr[x] = UDR;
    }

    LED_PORT = RED_OFF;
    _delay_ms(100);

    trigger = 1;
}

ISR(USART_UDRE_vect){
    if(trigger >= 1){
        LED_PORT = GREEN_ON;
        _delay_ms(200);
        LED_PORT = GREEN_OFF;
        _delay_ms(200);

        UDR = data; //transmit the data
        trigger = 0;
    }
}
Ähm, uint8 ist bereits eine Ganzzahl von 0 bis 255, was per Definition = char ... wie viel mehr ASCII könnte es sein?
Ich weiß das auch, aber ich erhalte Müll von meinem UART mit uint8
Versuchen Sie, jedes Byte als Zeichen umzuwandeln.
@DavidNorman Es hört sich so an, als würde etwas bei der Übersetzung verloren gehen. Möglicherweise müssen Sie herausfinden, was empfangen wird, um es zu entschlüsseln.
ja das muss ich wohl machen. Ich bekomme kleine Diamanten vom Mikrocontroller, das habe ich noch nie gesehen. Unten ist gezeigt, was ich versuche zu tun. 'data' ist der Datentyp uint16_t. 'tx' ist der Datentyp char[32].data = (uint16_t) tx; length = strlen(data); UDR = data;
Drucken Sie Ihre empfangenen Daten als Hex oder Ganzzahl aus und schlagen Sie sie in einer ASCII-Tabelle nach. Das liefert normalerweise einige Hinweise darauf, was vor sich geht. Die "kleinen Rauten" könnten viele Dinge bedeuten, am wahrscheinlichsten, dass das, was die Zeichen anzeigt, einfach nicht weiß, wie sie sie interpretieren sollen, und das Rautenzeichen ist einfach ein Platzhalter.
Was ist ein „Platzhalter“?
@DavidNorman Von welchem ​​Gerät empfangen Sie UART-Daten? Wohin geht es? (Computer zu uC? uC zu Computer? Irgendein anderes Gerät zu uC?)
Außerdem verwenden Sie strlen() für eine 16-Bit-Ganzzahl. Die strlen()-Funktion erwartet eine Zeichenkette, also zählt sie Stellen im Speicher hinein und findet das Abschluss-ASCII-Zeichen '\0'. Ich denke, Sie sind immer noch verwirrt darüber, wie Ihre Daten noch dargestellt werden. Können Sie vielleicht Ihren Hauptbeitrag erweitern und weitere Details hinzufügen> (Ihr Code, Einrichtung usw.)
alrite mach das schlecht
Warum tust du das? length = strlen(data);Das könnte ziemlich gefährlich werden ... Was dort passiert, ist, dass es sich die Speicheradresse "data" ansieht und versucht, dort eine nullterminierte Zeichenfolge zu finden. Da wir nicht wissen, was da ist, könnte es zählen, bis es abstürzt.
Ich denke, das ist, was passiert. Jedes Mal, wenn ich etwas erhalte, erhalte ich andere Daten. Wie kann ich es beheben? Ich weiß keinen Weg drumherum.
@ DavidNorman, ich bin mir nicht sicher, was Sie erreichen wollen, indem Sie strlendort anrufen. Wenn Sie zum einen die Länge der eingehenden Zeichenfolge erhalten möchten, wird dies nicht so funktionieren, wie Sie es haben. UDRHier befindet sich ein einzelnes Byte, nicht Ihre gesamte Zeichenfolge. Zweitens wird strlenein Zeiger auf den Speicher benötigt, in dem sich die gewünschte Zeichenfolge zum Messen befindet. Sie haben ihm einen Wert übergeben, keinen Zeiger. Dies wird als Speicheradresse interpretiert und beginnt an einem Ort zu zählen, an dem wer weiß, was dort sein wird ...
@ Jon - genau das versuche ich zu tun. Ich dachte daran, die Bytes, die ich aus dem Puffer erhalte, zu loopen und in einem Array zu speichern. Aber ich denke, das ist jetzt nicht möglich. Ich versuche, eine Nachricht vom Telefon an das WLAN-Modul zu senden, um eine LED ein- oder auszuschalten
@DavidNorman, habe meinen Kommentar mit etwas mehr Informationen bearbeitet. Und es ist durchaus möglich, das zu tun, was Sie dort beschrieben haben (Schleifen und Speichern in einem Puffer), aber es sieht so aus, als wäre es noch nicht ganz da ... Ich werde versuchen, meiner Antwort mehr hinzuzufügen, um zu helfen
Sie müssen die Codierung (die CharSetin Java aufgerufen wird) in angeben new OutputStringWriter(stream, charset), da sonst ein Standardwert verwendet wird, der falsch sein könnte. Obwohl es sich höchstwahrscheinlich um UTF-8 handelt, das ASCII als Teilmenge enthält und funktionieren würde. Ich bezweifle also, dass dies die Wurzel Ihres Problems ist.
@starblue - Ich habe das Format und sein UTF8 überprüft. Also ja, du hast recht, das ist nicht die Wurzel des Problems. immer noch versuchen, die Dinge herauszufinden
Nur ein kleiner Ratschlag Verwenden Sie NIEMALS Verzögerungen in einer Interrupt Service Routine, Sie möchten, dass Ihre ISR so schnell wie möglich ist.

Antworten (2)

**BEARBEITEN 19.06.2012******************************************** *****************

Ok, nachdem Sie Ihren Code hinzugefügt haben, habe ich ein paar Änderungen vorgenommen, die Sie ausprobieren (und verstehen!)

Zunächst haben wir unser Zeichenarray als flüchtig deklariert, damit der Compiler weiß, dass es sich unerwartet durch einen Interrupt ändern kann. Ebenso haben wir eine Variable erstellt, um unsere Indexposition im Array zu verfolgen:

/**************************************************
 *  Global Variables
 */
int trigger=0, length=0;
int i=0, n=0;
uint8_t data;
volatile char arr[8];
volatile char arr_idx = 0;

Als nächstes habe ich Ihren UART-Initialisierungscode basierend auf dem ATMega16L-Datenblatt und Ihren Kommentaren bearbeitet:

//USART SETUP
UCSRA = 0x00; //no Frame Error, no parity error, no Data OverRun
UCSRB = 0xD8; //receiver enable, transmitter enable (0x18)
UCSRC = 0x86; //Asynchronous USART mode, no parity, 1 stop bit, 8-bit character size, Data transmitted on rising edge and received on falling edge of the clock
UBRRL = 51; //Baud rate of 9600bps (8MHz clock?)
UBRRH = 0;

Sehen Sie sich das Datenblatt genau an (Seite ~166). Ich glaube, ich habe den UART jetzt basierend auf Ihren Kommentaren richtig konfiguriert. Ich werde nicht jedes Bit durchgehen, aber Sie sollten. Bitte stellen Sie Fragen, wenn Sie glauben, dass ich einen Fehler gemacht habe oder Sie etwas nicht verstanden haben.

Schließlich habe ich Ihre ISR-Routine bearbeitet:

ISR(USART_RXC_vect){
    arr[arr_idx] = UDR;
    arr_idx++;
    arr_idx %= 7; //make sure index stays within array

    trigger = 1;
}

Beachten Sie, dass die ISR jedes Mal ausgeführt wird, wenn ein einzelnes Byte (oder Zeichen) empfangen wird. Das bedeutet, dass wir das einzelne Zeichen verarbeiten (zu unserem Array hinzufügen), unsere Indexposition erhöhen und es schnell verlassen möchten, damit wir für das nächste Zeichen bereit sind.

Sie müssen sich nun den arr[] mit der von Ihnen verwendeten Methode ansehen und sehen, ob er Ihre Zeichen jetzt korrekt empfängt.

**ENDE DER BEARBEITUNG****************************************

Eine Möglichkeit besteht darin, einfach eine der verfügbaren Bibliotheken zu verwenden, die in AVR Studio enthalten sind:

#include <stdlib.h>

und dann irgendwo in deinem Code ...

char num2[5]; //create a buffer for the ascii string
itoa(num1,num2,10); //convert the integer (num1) to an ascii string (num2) in base 10

Wenn Sie dies dann auf einem Zeichen-LCD anzeigen, können Sie das Array num2 an die von Ihnen verwendete LCD-Druckfunktion senden.

Wenn Sie sich Sorgen um den Coderaum machen, können Sie ziemlich einfach Ihre eigene einfache Itoa-Funktion (Integer to Ascii) schreiben. Sie müssen jede "Zehner"-Position aus Ihrer Ganzzahl mit den Operatoren "/" und "%" abrufen und in ASCII konvertieren:

Geben Sie hier die Bildbeschreibung ein
(Quelle: asciitable.com )

Aus der obigen Tabelle können Sie ersehen, dass Sie nach dem Erfassen jedes Ziffernwerts (0-9) einfach 48 hinzufügen müssen, um ihn in die ASCII-Zeichendarstellung umzuwandeln.

BEARBEITEN

Ok, nachdem Sie Ihre Informationen hinzugefügt und angenommen haben:

  • Sie haben die UART-Baudrate usw. auf Ihrem ATMEGA korrekt initialisiert
  • Der Android-Code sendet die ASCII-Bytes erfolgreich über das WiFly und aus seinem UART

Dann sollte der Mikrocontroller diese Zeichen bereits als Ascii empfangen, und die ITOA-Funktion wird hier nicht benötigt und würde tatsächlich Ihre eingehenden String-Daten durcheinander bringen.

Es könnte jedoch immer noch eine Menge verschiedener Dinge sein ... Wie sehen Sie die UART-Daten, die von Ihrem Mikrocontroller empfangen werden?

Nun, ich schaue mir das Überwachungsfenster für eingehende Zeichen an. Ich habe gesehen, dass ich Folgendes erhalte, wenn ich eine Zeichenfolge an den UART des Mikrocontrollers sende, die "Eclipse" ist: {171, 70, 254, 70, 70, 70, 70} in meinem Zeichen-Array. Was bedeutet das? Ich glaube nicht, dass dies die Daten sind, die ich erhalten soll
@DavidNorman Das Problem ist kompliziert genug, dass es immer noch zu erraten ist, was falsch sein könnte. Wenn Sie nach mehreren Versuchen immer noch Probleme haben, sollten Sie Ihren tatsächlichen C-Dateicode (vollständiger Code, nicht nur Ausschnitte) posten, damit wir ihn ordnungsgemäß debuggen können. Sobald wir wissen, dass Sie den UART richtig lesen, können wir das Problem besser eingrenzen.
Sie haben Recht, ich lade jetzt meinen Code hoch
@DavidNorman, Justin sagt hier etwas Wichtiges: Note that, the ISR is executed every time a single byte (or character) is received. Jedes Mal, wenn das passiert, UDRwird es einen neuen Wert haben. Sie müssen die Schleife nicht innerhalb der ISR haben. Hoffentlich gibt Ihnen das genug Einblick, um das Problem zu lösen.
@JonL - dieses Mal habe ich versucht, "123" zu senden, aber was ich erhalte, sind nur zwei Bytes, nämlich 85 und 133. Jedes Mal, wenn ich "123" sende, bekomme ich 85 und 133. Warum passiert das?
@justin - vielen Dank Kumpel, ich habe bemerkt, dass ich einen Fehler in UCSRC hatte, ich hatte versehentlich 2 Stoppbits anstelle von 1 Stoppbit eingestellt. Ich verwende einen 4-MHz-Quarz, was mein zweiter Fehler war. Ich habe UBRRL auf 25 geändert
@DavidNorman Kein Problem. Wenn Sie Ihren UART herausfinden, seien Sie sicher und markieren Sie eine Antwort als richtig. Stellen Sie sicher, dass Sie alle anderen Fragen, die Sie auf dieser Website gepostet haben, zurückgehen und beenden, indem Sie entweder eine Antwort als gut markieren oder Ihre Frage bearbeiten, um besseres Feedback zu erhalten. Die Leute werden dir mehr helfen wollen, wenn du anerkennst, dass sie Zeit investiert haben.
@justin - wird reichen
Ich glaube, eine Sache, die auch Ihr Problem gelöst hat, war das Entfernen von Verzögerungen aus ISR ...
@justin - ich habe meinen Code zum Laufen gebracht, das Problem waren die Verzögerungen in der Interrupt-Funktion, und die Änderungen an Ihrem obigen Code haben geholfen. also ja, vielen dank

Ein ASCII-Zeichen ist einfach eine 8-Bit-Zahl, die als Zeichen angezeigt wird, wenn Sie Funktionen wie "printf" aufrufen, die Zeichen anzeigen sollen.

In C ist ein String ein Array dieser Zeichen (oder 8-Bit-Zahlen), das mit dem Wert 0oder "nullterminiert" abgeschlossen wird.

Wenn Sie also eine Zeichenfolge wie „Eclipse“ senden, senden Sie tatsächlich bereits Zahlen. Tatsächlich sieht es so aus, wenn Sie es senden:

[69, 99, 108, 105, 112, 115, 101, 0]

Wenn Sie dies printfbeispielsweise an übergeben, wird "Eclipse" ausgegeben. Beachten Sie das Null-Terminator. Beachten Sie auch, dass Sie keine Funktion benötigen, um dies zu konvertieren.

itoaist eine Funktion, die verwendet wird, um Zahlen in ihre Zeichenfolgendarstellung umzuwandeln. Zum Beispiel:

 char str[32];
 itoa(223, str, 10);
 printf("%s", str);

Dies würde "223" ausgeben. Die tatsächlichen Zahlenwerte, die sich darin befinden str[], sind uns sicher bekannt: [50, 50, 51, 0]. Nach deiner Beschreibung bin ich mir ziemlich sicher, dass das nicht das ist, was du willst.

Gehen Sie nicht immer von einer ASCII -Codierung aus. Hier ist eine extrem weit verbreitete Zeichencodierung, die auf Anwendungsebene und in der Webentwicklung verwendet wird: UTF-8 - Diese Zeichen sind nicht immer 8-Bit, einige von ihnen sind 16-Bit, um beispielsweise Zeichen in anderen Sprachen darzustellen.

BEARBEITEN:

Es gibt etwas, das Sie über ein typisches UART-Peripheriegerät auf einem AVR wissen müssen (nicht als pauschale Aussage für alle UARTs auf allen uCs gedacht, sondern nur für die Familie, die Sie verwenden). Sie funktionieren wie folgt: Wenn ein Byte hereinkommt, wird es in einen Single-Byte-Speicherort gelegt: UDR- Wenn Sie dieses Register lesen, wird es gelöscht. Wenn neue Daten auf dem UART eingehen und Sie noch nicht aus diesem Register gelesen haben? Es wird mit dem neuen Wert überschrieben. Ganze Saiten werden hier nicht platziert. Nur einzelne Zeichen. All dies ist im Datenblatt für Ihr uC beschrieben, ich empfehle dringend, sich damit vertraut zu machen.

Hoffentlich gibt Ihnen das genügend Informationen, um zu verstehen, warum strlen(data)es nicht funktioniert. Wenn Sie sich immer noch nicht sicher sind, warum, lesen Sie das Datenblatt noch einmal durch, lesen Sie nach, was passiert, wenn Sie diese Zuweisung in C vornehmen, data = UDR;und lesen Sie auch, was strlendie Parameter von sind, und beachten Sie, dass einer von ihnen ein Zeiger auf eine Zeichenfolge ist. Wenn Sie Zeiger nicht gut verstehen, empfehle ich Folgendes: http://www.cplusplus.com/doc/tutorial/pointers/

Wenn Ihnen das alles nach zu viel Arbeit klingt, dann schlage ich vor, stattdessen zu einem Arduino zu greifen. Verstehen Sie mich nicht falsch, es wäre großartig, wenn Sie all dies verstehen und einfaches C auf Ihrem AVR verwenden könnten, aber wenn Ihr Wissen im Moment zu viele Lücken aufweist, kann es ein bisschen überwältigend sein.

Nun zu dem, was Sie erreichen möchten. Sie haben in Ihrem Kommentar erwähnt, dass Sie eine Schleife ausführen wollten, bis Sie eine vollständige Zeichenfolge aus dem UART erhalten und in einem Puffer speichern, wo Sie sie dann als Befehl verarbeiten. Ok. Völlig machbar, in der Tat eine ziemlich verbreitete Technik.

Hier ist etwas Pseudo-Code für Sie:

i = 0;
char str[32];

while(forever) {
   if (data_byte_is_available) {
        if (i == 31)
             i = 0;
        str[i] = UDR;
        i++;
   }
   print(str);
}

Versuchen Sie herauszufinden, was Sie für eine data_byte_is_availableFunktion tun müssen. Das Datenblatt ist dein Freund. Wie zeigen Sie außerdem an, was auf dem UART des uC eingeht? Was auch immer das ist, ersetze das, was printich da oben habe, damit. Ich hoffe, es gibt keine Probleme mit dem, was Sie dort verwenden ...

@DavidNorman, wenn Sie weitere Informationen hinzufügen möchten, bearbeiten Sie bitte Ihren ursprünglichen Beitrag. Wie ich sehe, wollten Sie mir einen ISR zeigen – großartig. Sie können es in Ihrer ursprünglichen Frage posten.
ASCII ist nur 7-Bit. Die von modernen Computern verwendeten Zeichensätze basieren in der Regel auf ASCII, wie z. B. ISO 8859-1 (Latin-1). Weitere Details unter en.wikipedia.org/wiki/ISO/IEC_8859-1 und en.wikipedia.org/wiki/Extended_ASCII