Forum: Mikrocontroller und Digitale Elektronik Atmel Studio 7 itoa


von Josef_89 (Gast)


Lesenswert?

Halle zusammen,

ich habe begonnen den Attiny 104 auf dem Xplained Nano Board zu 
programmieren (Atmelstudio 7).

Ich möchte über den virtuellen COM-Port Daten bzw. Inhalte einer 
Variable übertragen.

Meine Variable beinhaltet einen 8 bit Integer. Diesen möchte ich über 
itoa
in ASCII umwandeln.

#include <stdlib.h>
#include <stddef.h>

int main(void)
{
  char s[20];
  int8_t i = 1;

  while (1) {
    USART_Transmit( itoa( i, s, 10 ));
  }

  return 0; // never reached
}

Leider bekomme ich beim kompilieren folgende Fehlermeldung:

undefined reference to '__itoa_ncheck'

Ich habe bereits mehrere Lösungsansätze probiert, verstehe leider nicht 
weshalb es nicht funktioniert.

Gebe ich den gleichen code in DEVC++ ein, funktioniert es einwandfrei.

Um in meinem Projekt weiter zu kommen, habe ich nun meine eigene 
Funktion erstellt, mit welcher es auch funktioniert.

Trotzdem würde es mich brennend interessieren was mein Fehler mit der 
itoa Funktion ist.

Könnte mir bitte jemand weiterhelfen? Vergesse ich eine header Datei?

Vielen Dank für eure Hilfe :)

von Chris F. (chfreund) Benutzerseite


Lesenswert?

Was passiert wenn Du die includes auf


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



änderst?

von Peter D. (peda)


Lesenswert?

Der Attiny104 ist definitiv nicht Anfänger geeignet.
Er hat kaum Ressourcen (nur 512 words Flash, 32Byte RAM, 16 Register).
Kann gut sein, daß die itoa-Lib nicht auf den halbierten Registersatz 
portiert wurde.

Nimm einen Standard-AVR, z.B. ATmega328 oder ATmega1284.

von Josef_89 (Gast)


Lesenswert?

Danke für eure Antworten.

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

habe ich schon probiert, funktioniert leider nicht.

von Chris F. (chfreund) Benutzerseite


Lesenswert?

Peter hat recht, es liegt an der Plattform. Bei mir war gerade noch auf 
644P eingestellt als ich es probiert hatte.

Beim Attiny104 musst Du das itoa woanders hernehmen.

Das ist aber echt nicht einfach. Schon wenn du den buffer auf 32 Zeichen 
setzt ist der RAM vom Tiny voll. Hier mal ein Beispiel für itoa mit 
Basis 10
1
#include <avr/io.h>
2
3
char* itoa(int val){
4
  static char buf[8] = {0};
5
  int i = 30;
6
  for(; val && i ; --i, val /= 10)
7
  buf[i] = "0123456789"[val % 10];
8
  return &buf[i+1];
9
}
10
11
int main(void)
12
{
13
  int8_t i = 1;
14
  char * s = itoa( i);
15
  return 0; 
16
}

von Peter D. (peda)


Lesenswert?

Ich glaub, am AVR-GCC wird schon viele Jahre nicht mehr nennenswert 
entwickelt.
Wer wirklich die wenigen AVRs mit kastriertem Registersatz programmieren 
will, wird wohl nur mit einem kommerziellen Compiler (IAR) glücklich.

Zaubern kann der natürlich auch nicht. Für Stringverarbeitung würde ich 
wenigstens nen ATtiny84 mit 512 Byte RAM empfehlen.

32 Byte RAM reichen nur für einfache kleine Steuerungen (Statemaschine, 
Bits setzen, Timer).

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Peter D. schrieb:
> Der Attiny104 ist definitiv nicht Anfänger geeignet.
> Er hat kaum Ressourcen (nur 512 words Flash, 32Byte RAM, 16 Register).
> Kann gut sein, daß die itoa-Lib nicht auf den halbierten Registersatz
> portiert wurde.

So ist es, und das gleiche gilt für viele andere Funktionen.

Peter D. schrieb:
> Ich glaub, am AVR-GCC wird schon viele Jahre nicht mehr nennenswert
> entwickelt.

Kommt drauf an was "nennenswert" ist :-)

Im o.g. Fall ist es Sache, der avr-libc, wo die entsprechenden 
Funktionen wegen fleißig verteilter
1
#ifndef __AVR_TINY__
nicht implementiert sind.  Für utoa und itoa geschieht die entsprechende 
Unterstützung also am einfachsten durch Entfernen der entsprechenden 
#ifndef nebst Auflösung von SBIW an einigen wenigen Stellen.

Aber Projekte wie avr-libc leben eben auch davon, dass Leute Interesse 
an der Weiterentwicklung des Projekts haben, was für avr_tiny eher 
weniger der Fall zu sein scheint...

Eines der Hauptprobleme bei dem Support ist auch nicht, ihn zu 
implementieren, sondern vielmehr vernünftig zu testen.  Wenn man z.B. 
die GCC Testsuite für so einen ATtiny durchnudeln lässt, sind die Anzahl 
der FAILs schon ziemlich ernüchternd, und die wirklichen FAILs zu 
finden, welche nicht aufgrund verkrüppelter Hardware sondern durch 
Fehler der Software produziert wurden, ist eine endlose Sisyphosarbeit!

von Peter D. (peda)


Lesenswert?

Johann L. schrieb:
> dass Leute Interesse
> an der Weiterentwicklung des Projekts haben, was für avr_tiny eher
> weniger der Fall zu sein scheint...

Das ist auch mein Eindruck.
Sehr verwirrend ist allerdings für Anfänger, daß die reduzierten ATtiny 
den gleichen Namen haben, wie die klassischen ATtiny mit 32 Registern.
Da hätte man ihnen doch besser einen unterscheidbaren Namen geben 
sollen, z.B. ATleanly (kümmerlich).
Nichtmal im Product Selector kann man den Unterschied sehen. Man muß 
wirklich erst jedes einzelne Datenblatt öffnen.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

AVR_TINY-Support für itoa und utoa gibt's hier als Patch auf die 
AVR-LibC:

https://savannah.nongnu.org/patch/download.php?file_id=39183

Allerdings ist im offiziellen avr-gcc ATtiny104 nicht unterstützt, und 
es gibt noch nicht einmal den entsprechenden Core-Support:

Während AVR_TINY wie ATtiny4 oder ATtiny4

* kein SBIW, ADIW, MOVW

* keine Z+q, Y+q Adressierung

unterstützen, ist dies für ATtiny102 der Fall.  Ein "normaler" AVR ist's 
aber auch nicht da nur 16 GPRs.

Echt prima gemacht, Atmel schein alle Kombinationen von unterstützten 
Instruktionen und GPR-Layout durchexerzieren zu wollen...

: Bearbeitet durch User
von Josef_89 (Gast)


Lesenswert?

Entschuldigung für die späte Rückmeldung.

Vielen Dank für eure Anregungen.

Wie zu Beginn erklärt habe ich meine eigene int to ascii Funktion 
geschrieben. Mit dieser funktioniert es super.

Für den Einstieg war es nicht die beste Idee.

Ich verwende ihn, da ich eine Attiny104 Xplained Test-board habe.

Ich möchte damit einen one-wire Sensor auslesen und über den virtuellen 
Com-Port Visualisieren.

Wenn ich meine ITOA Funktion aufrufe, verringert sich der Übertragbare 
string Zeichensatz erheblich. Denke dies ist auf den geringen RAM 
zurückzuführen.

Sehe ich dies richtig?

Danke

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Josef_89 schrieb:
> Wenn ich meine ITOA Funktion aufrufe, verringert sich der Übertragbare
> string Zeichensatz erheblich. Denke dies ist auf den geringen RAM
> zurückzuführen.
>
> Sehe ich dies richtig?

Nö.  Wenn du zu wenig RAM hast, schmiert dein Programm einfach ab :-)

Wenn es langsam ist, dann weil die Umwandlung langsam ist.  Das ist z.B. 
der Fall, wenn du wie oben vorgeschlagen "normale" Division und Modulo 
verwendest.

Eine einigermaßen Platzsparende Methode, die schneller arbeitet und ohne 
MUL auskommt, ist einfach Zehnerpotenzen von der zu wandelnden Zahl 
abzuziehen:
 
1
#include <stdint.h>
2
3
// Wandelt N in eine ASCII-Dezimalzahl um. Die Darstellung wird
4
// mit abschliessender '\0' als Stringende nach STR geschrieben.
5
6
void u16_to_string (char *str, uint16_t n)
7
{
8
    static const uint16_t pows10[] = 
9
    {
10
        10000, 1000, 100, 10
11
    };
12
13
    const uint16_t *p = pows10;
14
    uint16_t pow10;
15
    uint8_t not0 = 0;
16
17
    do
18
    {
19
        char c = '0';
20
        
21
        pow10 = *p++;
22
23
        while (n >= pow10)
24
            not0 = 1, n -= pow10, c++;
25
            
26
        if (not0)
27
            *str++ = c;
28
            
29
    } while (! (pow10 & 2)); // pow10 != 10
30
    
31
    // Einer
32
    *str++ = n + '0';
33
    *str   = '\0';
34
}
 
Oder wenn du noch ein paar Ticks rausquetschen willst kannst was 
entsprechendes in Assembler nachklöppeln.

Oder die Version der AVR-LibC übernehmen; die ist zwar langsamer als der 
Code oben, aber allemal schneller als das div 10 und mod 10 von oben.

von Josef_89 (Gast)


Lesenswert?

#define F_CPU 1000000

#include <avr/io.h>
#include <stdlib.h>
#include <util/delay.h>
#include <string.h>
#include <stdint.h>



#define BAUD 1200
#define MYUBRR F_CPU/16/BAUD-1


void USART_Init( unsigned int ubrr)
{
  /*Set baud rate */
  UBRRH = (unsigned char)(ubrr>>8);
  UBRRL = (unsigned char)ubrr;
  /*Enable transmitter */
  UCSRB = (1<<TXEN);
  /* Set frame format: 8data, 1stop bit */
  UCSRC =(3<<UCSZ0);
  }

void USART_Transmit( char data )
{
  /* Wait for empty transmit buffer */
  while ( !( UCSRA & (1<<UDRE)) )
  ;
  _delay_ms(100);
  /* Put data into buffer, sends the data */
  UDR = data & 0xFF;
}
void INT_TO_ASCII (int16_t data)
{
  char buffer[7] ;
  int i = 1, j = 0,change = 0, temp = 0;


  buffer[0]= '\0';

  if (data >= 0)
  {
    do
    {

      buffer[i++] = data % 10 + 48;
      data = data / 10;


    } while (data != 0);

    i = i -1;


  }
  else
  {
    data = data * -1;

    do
    {

      buffer[i++] = data % 10 + 48;
      data = data / 10;


    } while (data != 0);




    buffer [i] = '-';


  }



  while (change < i)
  {
    temp = buffer[change];
    buffer[change] = buffer[i];
    buffer[i] = temp;
    change++;
    i--;

  }



    while (buffer[j] != '\0')
    {
      USART_Transmit(buffer[j]);
      j++;
    }

    //send_string(buffer);

}

void send_string (unsigned char s[100] )
{
  int i = 0;

  while (s[i] != '\0')
  {   /* so lange *s != '\0' also ungleich dem 
"String-Endezeichen(Terminator)" */


    USART_Transmit(s[i]);
    i++;
    //USART_Transmit(i+48);
  }

  for (int i = 100; i<=0; i--)
  {
    s[i]='\0';
  }

}
while (1)
  {
x = 12;
  int y=13;
  int len;

  send_string("Temperatur:");
  //INT_TO_ASCII(x);
  USART_Transmit('C');
  USART_Transmit('\n');
  USART_Transmit('\r');
  _delay_ms(1000);

  send_string("Humidity:");
  //INT_TO_ASCII(y);
  USART_Transmit('%');
  USART_Transmit('\n');
  USART_Transmit('\r');
  _delay_ms(1000);





  }







}

Das ist mein code zur Werteausgabe. Sobald ich meine INT_TO_ASCII 
Funktion aktiviere, erhalte ich folgende Antwort:

Temperatur:12C

13%

Liegt dies wirklich an der geringen "Leistung" des Tiny's?
Einen programmier Fehler kann ich leider nicht erkennen.

Hat jemand einen Tipp?

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.