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 :)
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.
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
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).
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!
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.
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...
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
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
voidu16_to_string(char*str,uint16_tn)
7
{
8
staticconstuint16_tpows10[]=
9
{
10
10000,1000,100,10
11
};
12
13
constuint16_t*p=pows10;
14
uint16_tpow10;
15
uint8_tnot0=0;
16
17
do
18
{
19
charc='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.