Používání knihovních funkcí - import knihoven z AVR Studia

pointery raděj ne, takže for cyklus odzadu stringu, dokud nenajde 0 ? Stejně se mi to pořád zdá nějaký složitý a komplikovaný.

A když budu mít teplotu z teploměru (DS18B20) - předpokládám ve float, budu jí chtít porovnávat s další, případně určit průměr - nebyl by ten float přeci jenom vhodnější ?

S těmi pointery to není nic složitého. Jméno pole je vpodstatě pointer na řetězec a ta funkce vrací tak pointer do stejného řetězce. Když tedy odečteš hodnotu vrácenou funkcí a adresu pole, máš index, na kterém je hledaná nula. Je to jednoduché, jen když ti to napíšu, abys věděl o co jde.
Vypadalo by to nějak takto (nemám zatím vyzkoušeno):
index = strchr (tmp, 0) - ((char *)tmp);
tmp[index + 1] = tmp[index];
tmp[index] = tmp[index - 1];
tmp[index - 1] = ‘.’;
Tohle všechno včetně výpisu můžeš zabalit do funkce, kterou pak budeš jen volat jako jmenoFunkce(teplota);

Případný průchod cyklem (musí být od začátku, nikoli od konce) je obvykle srozumitelný i těm, kteří o pointerech vživotě neslyšeli.

Složitý. Mě to přijde jednodušší, než se zabejvat nastavením překladače tak, aby ti přeložil funkčně sprintf s %f a zabere to o několik kB míň flash. Tobě je to s vybraným mcu asi jedno, ovšem já bych ten program dostal bez problému do 2kB tiny. Ty budeš potřebovat určitě víc jak 4kB flash pouze pro printf a float aritmetiku.

Díky
,ale vypisuje mi to warningy - např. implicit declaration of function ´strchr´
Že by to neznalo tu funkci ?

tak nakonec jsem našel na internetu něco v tomhle stylu a funguje to i sloatem :smiley:

[code]char str[100];
float adc_read = 678.01234567;

int d1 = adc_read; // Get the integer part (678).
float f2 = adc_read - d1; // Get fractional part (0.01234567).
int d2 = trunc(f2 * 10000); // Turn into integer (123).
float f3 = f2 * 10000 - d2; // Get next fractional part (0.4567).
int d3 = trunc(f3 * 10000); // Turn into integer (4567).

sprintf (str, “adc_read = %d.%04d%04d\n”, d1, d2, d3);[/code]

Samozřejmě, že to vypisuje warningy pokud jsi nevložil patřičný hlavičkový soubor.

Určitě máš nejmíň 3 varování (chybí přetypování). Jelikož tě zabraná flash netrápí, na rychlosti ti ve tvé situaci taky nesejde (nechtěj vidět výpočetní čas těch 5ti řádků), tak ti to zřejmě dobře poslouží :slight_smile:.

jo warningy jsou - a jaký hlavičkový soubor ? A jak přetypovat ?
A taky jsem našel problém se zápornými čísly, ale ten už ošetřím podmínkou.

Jaký hlavičkový soubor si najdi v manuálu překladače.
Přetypování (změna datového typu) se provádí tak, že před přetypovávaný objek vložíš do závorek nový datový typ.

Co se týká porovnávání teplot - jaký je rozdíl mezi porovnáním dvou intů a dvou floatů? Kromě rychlosti a paměťové náročnosti (ve prospěch intu) tu žádný problém nevidím. Stejně tak v uchovávání hodnot jako int místo float.

Tu máš moji a tvoji upravenou verzi. Tvoje je o nějaký řádek kratší, moje zabere míň flash a je rychlejší. Obě generují stejný výstup a bez varování.

[code]#include <avr/io.h> // knihovna obsahujici definice regstrů procesoru
#include <string.h> // pro funkci strchr()
#include <stdlib.h> // pro funkci itoa()
#include <math.h> // pro funkci trunc()
#include <stdio.h> // pro funkci sprintf()

void main(void)
{
/*
// moje verze (“volatile” u roměnných jen pro simulátor)
volatile char buff[10];
volatile float teplota = 27.325; // pouziti float = 1.5kB kodu navic
volatile int a;
volatile unsigned char index;

a = (int)(teplota * 10);	// 2300 cyklů
itoa(a, (char *)buff, 10);	// 700 cyklů
index = strchr ((char *)buff, '\0') - ((char *)buff);
buff[index + 1] = buff[index]; 
buff[index] = buff[index - 1]; 
buff[index - 1] = '.';
// Flash: 1.8kB, RAM: 8B (tohle z mě neznámýho důvodu kecá)
// celkem 3200 cyklů
*/


// tvoje upravená verze
volatile char str[10]; 
volatile float adc_read = 27.325; 

int d1 = (int)adc_read;
int d2 = (int)trunc((adc_read - d1) * 10);

sprintf ((char *)str, "%d.%01d%", d1, d2);
// Flash: 4.7kB, RAM: 274B
// celkem 8500 cyklů

for(;;)
{

}

}[/code]

piityy:
Jenom malá poznámka.
Všiml jsem si, že důsledně přetypováváš stringy.

itoa(a, (char *)buff, 10);

To je nadbytečné, samo jméno stringu už je proměnná typu char*.
Nebo obecně, jméno pole obsahuje adresu prvního prvku v poli.

dobreho pretypovania nie je nikdy dost :slight_smile:

radsej o 10 pretypovani viac ako by malo jedno nebyt. Ono ak su pretypovania na miestach kde ich netreba tak sa kod nezvacsuje, aspon mam taku skusenost.

V opacnom pripade sa clovek nestaci cudovat, preco sa mu vysledky pri urcitych vhodnych hodnotach premennych zjancia. A hladat chyby tohto druhu je fakt o hubu. Dovolim si nepretypovavat iba ak su vsetky hodonty vo vyraze rovnakeho typu.

Toto je trochu iny pripad ako premenne vo vyraze, ale obzvlast s ukazatelmi na pole char sa mi obcas stava (s AVR-GCC), ze mi prekladac vyhodi warning o nespravnom type ukazatela pre nejaku funkciu z libc. Pritom sa evidentne o rovnaky typ ukazatela jedna. Po vlozeni pretypovania sa prekladac ukludni. Takze moja skusenost je pretypovat, pretypovat, pretypovat aj ked sa to zda byt zbytocne :slight_smile:

AB: o tom vím, taky by to bez toho fungovalo. Stejně tak je to u všech referenčních typů (např. struktury). Ovšem jak píše martin - překladač prudil s varováním, tak jsem mu udělal radost a přetypoval to.
Občas to zlepšuje čitelnost kódu. Třeba konverze z nižšího typu na vyšší je bez keců, ale když to tam dopíšu, tak k tomu pak přijdu a nemusím zkoumat, jesli je to zbytečný nebo nutný - udělal jsem to úmyslně.

EDIT: oprava - struktura není referenční (jako parametr se předává kopie).

Martin:
To co jsem napsal je opravdu jiný případ.
Týká se třeba hromady funkcí v knihovně <string.h>
kde se v deklaraci opakuje “char* str”, “char* dest” a podobně.
Tam se jednoznačně bez přetypování obejdeme.

Máš pravdu, že ve složitých matematických výrazech jsou problémy (pokud všechny proměnné nejsou stejného typu).
Přiznám se, že ani já to vždycky neodhadnu.
Řeším to tak, že sleduju výraz v simulátoru, a hledám jaké přetypování stačí ke správnému výsledku.

Samozřejmě tvoje metoda přetypovat všechno co uvidím musí fungovat také. A bez nárůstu kódu.

De gustibus non est disputandum.

piityy:
Nerozumím, jaké varování vydal překladač když jsi vynechal přetypování (char*).

itoa(a, buff, 10); index = strchr (buff, '\0') - buff;

tak jsem přeci jenom udělal to tvoje, je to opravdu lepší. malinko jsem to přiupravil (není tam teplota*10, teplota bude někde jinde násobena 10 a převedena na int)

void pisdesetine(char buff[10], int teplota)
{
   int a; 
   unsigned char index; 
   a = (int)(teplota);   // 2300 cyklů 
   itoa(a, (char *)buff, 10);   // 700 cyklů 
   index = strchr ((char *)buff, '\0') - ((char *)buff); 
   buff[index + 1] = buff[index]; 
   buff[index] = buff[index - 1]; 
   buff[index - 1] = '.';
}

volám funkci takto:

temp = -152;	  
char buf[33];
pisdesetine(buf, temp);
lcd_puts(buf);

ale dělá mi to chybu u čísel mezi <-1 a +1> -např. číslo -.1 zobrazí jako .1

zkouším dělat něco jako tyto podmínky ale pořád to nejde správně

if (buff[0] == '.')
   {buff[2] = buff[1];
   buff[1] = buff[0];
   buff[0]='0';
   }
   if (buff[0] == '-' && buff[1] == '.')
   {buff[3] = buff[2];
   buff[2] = buff[1];
   buff[1] = '0';
   buff[0]='-';
   }

Funkci máš udělanou skoro dobře. U toho pole nemá bejt rozměr.
Nevím jesli víš, proč můžeš pole předávat jako vstupní parametr, ve funkci ho změnit, nic nevracet a mít nové hodnoty k dispozici, ale je to skutečně tak :slight_smile:.
Nyní už není potřeba proměnná “a” (a ani řádek “a = (int)(teplota);”), protože “teplota” už je int. Můžeš teplotou proměnnou “a” všude nahradit.
Na ty nesprávný převody se mrknu.

Byl tam vopruz, že při jednocifernym čísle před onou cifrou nic není a proto při posunu tedy taky nic nebylo před desetin. tečkou.
Proto je v případě hodnoty “teplota” v <-9, 9> třeba místo o 1 pozici posouvat o 2 a před tečku ještě dopsat tu nulu.

Pokud nepůjdeš s teplotou pod -99.9 nabo nad 999.9, stačí ti buffer velkej 6 znaků.

[code]#include <avr/io.h> // knihovna obsahujici definice regstrů procesoru
#include <string.h> // pro funkci strchr()
#include <stdlib.h> // pro funkci itoa()

void pisDesetine(char buff], int teplota)
{
unsigned char index;

itoa(teplota, (char *)buff, 10);
index = strchr ((char *)buff, '\0') - ((char *)buff);
if(teplota < 10 && teplota > -10)
{
	buff[index + 2] = buff[index]; 
	buff[index + 1] = buff[index - 1]; 
	buff[index] = '.';
	buff[index - 1] = '0';
}
else
{
	buff[index + 1] = buff[index]; 
	buff[index] = buff[index - 1]; 
	buff[index - 1] = '.';
}

}

void main(void)
{
volatile char buff[10];
volatile int temp = -1; // = -0.1°C

pisDesetine((char *)buff, temp); // pokud před buff nevložíš "(char *)", nic se neděje, jen se může vyskytnout varování

// vypsat buff

for(;;)
{

}

}
[/code]

hezké, funguje
Díky moc

a k čemu je to volatile ?

Že by to pole bylo prostě přístupné odkudkoliv a opět se do něj odkudkoliv ukládalo ? Ale je mi to opravdu nějaký divný.

Pole je referenční datový typ narozdíl od obyčejných proměnných (primitivní datové typy).
Primitivní datové typy se předávají tak, že při volání funkce se pro ni zkopírují na určené místo. Funkce s nimi může manipulovat, ovšem po ukončení funkce tyto kopie zaniknou. Původní proměnné v místě, odkud byla funkce zavolána, zůstávají nezměněny.

Naproti tomu pole je referenční typ a pokud je parametrem funkce, předává se pouze reference (tedy odkaz neboli pointer) na data. Při manipulaci např. s polem ve funkci tedy pomocí odkazu pracuješ přímo s původními daty, nikoli s kopiemi. Proto máš po skončení funkce v poli to, co potřebuješ. Pokud bys pro nějakou funkci potřeboval to pole a přitom nesměl změnit původní, musel by sis na začátku takové funkce vytvořit pole nové a to původní (odkazované) si do něho zkopírovat.

“volatile” říká překladači, že nesmí s proměnnou provádět optimalizace. Tento prefix MUSÍ být před každou proměnnou, kterou používáš v přerušení a zároveň mimo něj.
Použití v mém případě pro potřeby simulátoru má ten význam, že proměnná je umístěna v RAM a lze ji tedy sledovat v simulátoru v okně “watch”. Jinak by ji totiž překladač mhl umístit do registrů a pak bys ji ve watch neviděl. Navíc při testování používáme postupy, které by mohly znamenat odstranění části kódu a nic bychom v simulátoru neviděli (např. celé volání funkce by překladač vyhodnotil jako konstantu a vyhodil to).

Máš pravdu, na tento případ jsem zapomněl.
Když je proměnná (zde buff) deklarovaná s kvalifikátorem “volatile” nebo “const”,
tak překladač vydá varování, že tento kvalifikátor se při předání ztratí.
(Takže ve funkci se bude s proměnnou zacházet jako s ne-volatile.)

Toto varování můžeme zanedbat, nebo se ho zbavit tak, že přetypováním sami kvalifikátor odstraníme.

Tak tu je zakopaný pes, dík :slight_smile:.

edit: Nevíte někdo náhodou jak odstranit varování:

a přitom zachovat main jako void? Prototyp před mainem dle manualu gcc nepomáhá. O tom, že by to potřebovalo nějaký header také není zmínka. [code]void main(void) attribute((noreturn));

void main (void)
{…[/code]