# ATMEL mikrokontrolleri >  Atmelis un C

## Jurkins

Šovakar jau vēls, bet tomēr uzrakstīšu tēmējot uz rītdienu.
Tātad rakstam kodu iekš C. Ir VirtualWire bibliotēka priekš Arduino, bet gribu bez Arduino (nu gribu ::  un viss). Viss jau darbojas - 328P ar raidītāju galā un uztvērējs ar otru 328P galā. Kods ir vienā c failā bez dažām konstantēm, kuras ir h failā. Šī jebstiņa laikā radās jautājums.
1. Ir fails "bibiliotēka.h", kurā ir bez visādām konstantēm ir definētas funkcijas, kuru rumpji ir failā "bibliotēka.c".
2. Failā "bibliotēka.c" ir rinda "#include <bibiliotēka.h>"
3. Ja es savā projektā ielieku rindu "#include <bibiliotēka.h>", tad viss notiekās.
Bet, ja es:
1. Uztaisu failu "fēcas.h", kur definēju funkcijas, kuru rumpji ir citā uztaisītā failā "fēcas.c"
2. Failā "fēcas.c" ir rinda "#include <fēcas.h>"
3. Ielieku savā projektā "#include <fēcas.h>" un izmantoju tur definētās funkcijas un dabūju "undefined reference to ...manas funkcijas".
Nu it kā jau veselais saprāts saka, ka, kā lai nabaga kompilators zina, ka viņam jāmeklē to funkciju rumpji failā "fēcas.c", jo iekš h nav nekādas norādes. Protams, ja ielieku "<include <fēcas.c>" arī, tad viss aiziet. Bet, velns parāvis, iekš "bibliotēka.h" arī nav norādes, bet Arduino visu atrod! Kur tas dzivnieks ir aprakts?

----------


## Texx

*.C failus paarsti neincludo. Tas nav labais stils. Ātrumā izskatās, ka kompilators nevar atrast ceļu pie taviem include failiem. Liec to "fēcas.h" (intersants faila nosaukums  ::  pēdiņās nevis trīsstūriekavās.
P.S. Un lieto #ifndef #define #endif savos header failos

----------


## Jurkins

Ja ielieku trīsstūriekavās visu ceļu, tad h failu atrod. Ja to h ielieku blakus citām bibliotēkām, tad viss ir cmuki. Un, ja funkciju rumpji ir failā h, tad viss ir ok. Bet, ja funkciju rumpji ir failā c (kurš atrodas tajā pašā vietā, kur h), tad neatrod. Bet standarta virtualwire.h virtualwire.c gadījumā atrod.
Paldies par norādi uz to #ifndef #define #endif vakarā izmēģināšu. Jāpalasa kāda grāmata par c.

----------


## Texx

Nu tad papēti vēl. Parasti šādas problēmas ir paša programmētāja neuzmanības dēļ. Include ceļā drīkst norādīt arī mapi, netikai pašu failu. Kaut kā tā "mape\heder.h". Tāpat arī IDE compilator uzstādījumos vajag pārbaudīt un uzlikt, kādos folderos šie include faili tiek meklēti.

----------


## SnacK

Include norādes uz lokāliem header failiem parasti liek pēdiņās. Trīsstūriekavās liek norādes uz iebūvētajām bibliotēkām, piem., <stdio.h>

Parasti visos IDE *.c faili jāsaliek "Project explorer" (kā nu kur to sauc) mapēs, lai kompilators zin ko kompilēt. *.c faili netiek meklēti pa mapēm, kā *.h faili.

Protams, projekta opcijās jābūt norādēm uz visām mapēm, kur ir *.h faili.

----------


## Jurkins

Bet tad man savā *.h failā jāliek arī visu funkciju rumpji? Pēc analoģijas ar to virtualwire bibliotēku - tās *.h failā neatrodu nekādu norādi, ka funkciju rumpji jāmeklē blakus esošajā *.cpp failā, bet kompilators funkcijas atrod. Savukārt, ja es definēju funkcijas *.h failā, bet pašas funkcijas uzrakstu blakus esošajā *.c failā, tad manas funkcijas kompilators neatrod.

p.s. muldu laikam bišķi nesakarīgi, tik daudz jaunas informācijas ienācās :: , kopš ar to c sāku ņemties.

----------


## Delfins

.h ir headeris - instrukcija izsaukšanai.
.c/.cpp - izsaukšanas realizācija
IDE kompilējot jāuztaisa no. cpp "obj.kods", ko beigās salinko veselā vienumā

.h nekas nav jāzin par .cpp. tikpat labi var būt pliks gatavs .DLL (ielādēts no hakeru saita) un tīrs .h, ko izmantot jau savā projektā (slēgtā realizācija/draiveris/plugins un etc)

----------


## Jurkins

Sorry par neattapību, bet, ja virtualwire.h ir definētas funkcijas, kuras ir uzrakstītas virtualwire.cpp, tad tur viss notiekās, bet, ja es no sava strādājošā projekta .c faila aiznesu funkciju definīcijas uz mansvirtualwire.h un pašas funkcijas uz mansvirtualwire.c un mana projekta .c failā (un pēc tam citiem raidītājiem/uztvērējiem domātajiem kodiem) inklūdoju to mansvirtualwire.h, tad dabūju kļūdu. Ja daru nesmuki un inklūdoju arī mansvirtualwire.c, tad viss strādā. 
Gan jau problēma ir tik stulba un vienkārša, ka tas, kurš ar c uz TU, nesaprot, kur problēma  :: .

edit: tfu, ieciklējos uz sīkumiem. Viss atrisinājies.

----------


## JDat

> edit: tfu, ieciklējos uz sīkumiem. Viss atrisinājies.


 Kā? Man, kā C dundukam, liekas interesanti. Varbūt vari parādīt "nepareizos" un "pareizos" .h un .c failus. Kā arī fīča kur arškirība.

----------


## Jurkins

Problēma nebija pareizajos un nepareizajos .c un .h failos, bet tur, ka iekš IDEs (šajā gadījumā Atmel Studio) vajadzēja salikt projektā ceļus, kur meklēt tos failus. Līdzko tas tika izdarīts, viss notikās. Galīgi neesmu speciālists, bet pieņemu, ka, ja ir zināms ceļš, tad, ja .c un .h ir ar vienādiem nosaukumiem, kompilators pats sajēdz, ka iekš .h definēto funkciju "rumpji" jāmeklē blakus esošajā .c /.cpp failā. Galvenajā failā pietiek ar to, ka inklūdo .h.

Vakar "uzmetās" nākamā c nespeciālista problēma. Galīgi sa...su prātu ar pointeriem. Problēma, ka vajag nodefinēt portu, kuru iebarot funkcijai kā mainīgo. Kamēr viss bija vienā failā izlīdzējos ar #define izteiksmi, bet, kad funkcijas aiznesu prom uz inklūdojamo failu, tā vairs nesanāk (jeb nemāku pareizi izdarīt). Iebarot funkcijai portu iemanījos, bet pirms tam dabūt, lai cita funkcija to iebarojamo portu atgriež kā vērtību... ai, karoče, jāņem pārtraukums  :: ...

edit:
velns, ar to c var triperi dabūt... :Roll Eyes (Sarcastic): ... Kāpēc jātaisa šāda konstrukcija?

#define __COMB(a,b,c) (a##b##c)
#define _COMB(a,b,c) __COMB(a,b,c)

Ar ko tās divas apakšsvītras atšķiras no vienas apakšstrīpas?

----------


## Texx

Tās apakšvītras ir daļa no funkciju nosaukuma. Ja nepatīk apakšvītras aizvieto ar kaut ko citu. Bet vispār tās ir prekompilatora direktīvas funkcijas, kas apvieno a,b,c stringus. Izskatās, ka abas ir nodefinētas tā, ka var lietot izsaukumā abus pierakstus ar vienu apakšvītru vai divām. Palasi google par preprocessor macros.

----------


## Jurkins

ēē, paldies, tad sanāk vienkārši, ka var lietot abas. To es sapratu, ka šīs apvieno stringus, tikai nesapratu, kāpēc divos piegājienos.

edit:
nu bet sekss ar to c ir labs  :: ! Varu iedomāties, kāds ir ar cpp  :: . 
Bet interesanti  ::

----------


## Jurkins

Šodien piebāzu pie Nano 6 DS18... termometrus. Viens 1820 no Argusa un pieci 18B20 no suņhujčajiem. Iemaucu šiem visiem pieciem skračpadā konfigurācijas baitā 1F - mērījumi ar 12 bitu precizitāti. Spriežot pēc nolasītā skračpada viss ir ierakstījies, bet ha-ha-ha. Trīs jaunākie biti nulles. Nu cita rubiļņika takš šiem nav, ar kuru pārsēgt.
 
Vot i tagad nesaprotu, ko tie suņhujčaji tur dara. Family Code pareizs, izmantotie un rezervētie biti skračpadā arī pareizie. Piem 18S20 nemaz nevar ierakstīt konfigurācijas bitu, šim tāda nav. Tā kā pārmarķēšana atkrīt.

No otras puses - suns zina, ko ēdis :: . Dļa seļskoj mestnosķi ... Farnelī viens štuks maksā gandrīz trīs eiro + PVN, suņhujčaji 10 gab. pa ~5 USD. Kas zin, kā šiem ar precizitāti, be lietošanai ārpus atomelektrostacijām būs jau labi.

----------


## Jurkins

Šodien piemetu vienu metāla puļķī ieintegrētu termometru no cita pārdevēja. Family code 0x28, skračpada baiti pareizi, defaultā konfigurācijas baits 0x7F. Ierakstu 0x1F... un sūkā bračkiņ! Trīs jaunākie temperatūras biti kā nulles bija tā nulles arī palika. Nē, nu man jau it kā pietiek ar pusgrāda precizitāti, bet interesanti, ko tie suņhujčaji dara. Jebšu netaisnīgi apvainoju suņhujčajus, jo pats kaut kur nolohojos?

Jā, un varbūt kādam noder sekojošais grābeklis.
Sametu visas funkcijas OneWire.c un OneWire.h failos, uzkāpu uz dažiem citiem grābekļiem un beigās "undefined reference to" uz visām manām funkcijām. 3.14sos kā mazais ezītis... un tad pamainīju faila paplašinājumu uz *.cpp. Tas ir par Arduino IDE.
Un vēl. Arduino IDE neredz globālos mainīgos,kuri ir definēti bibliotēkas failā.

----------


## Jurkins

Sveiciens sestdienā!
Uzmetās kārtējā c iesācēja problēma. 
Uzrakstīju visas nepieciešamās darbības manipulācijām ar LCD 2*16 displeju. Tik tālu ir labi. Vienā failā viss strādā. Aiznesu visus #define un funkciju definīcijas uz *.h failu. Aiznesu visas funkcijas uz *.c failu. Galvenajā *.c failā ierakstu:

#define F_CPU 8000000 
#include "LCD.h"
...bla, bla, bla...

Un dabūju brīdinājumu, ka F_CPU nav definēts. To F_CPU vajag util/delay.h bibliotēkai, kura ir inklūdota manā LCD.h failā. Vai tiešām man jāraksta #define F_CPU 8000000 iekš LCD.h faila? Tas nav visai ērti. Bibliotēku (kaut paša taisītu) it kā vajadzētu atstāt tādu kā ir. Biju iedomājies, ka kompilators nolasīs šo galvenajā failā un sapratīs...

----------


## sasasa

Es uz Arduino ide biki vienkāršāk to daru - nekādu .cpp failu, bet visu raxtu .h failā un lieku "somiņā" pie pārējā koda. Tad arī viegli rediģēt pie vajadzības, jo viss vienuviet un atverot uzreiz redz visus manus .h failus. Man tur ir savi faili pinout.h, configuration.h, functions.h, hardware.h. Viss smuki pa plauktiņiem, ērti pārskatāms un rediģējams. Pat no citām  bibliotekām cenšos tikai paņemt nepieciešamās funkcijas un salikt pie sevis lai būtu pārskatāmāk, jo citādi optimizējot kodu katru reizi jāpārrok visas svešās bibliotēkas, kamēr atrodi vajadzīgo.

----------


## Jurkins

Nu jā, ja F_CPU nodefinē iekš tās LCD.h, tad nav problēmu. 
A par to .c un .h es neesmu nemaz interesējies, kāpēc tā dara - kāpēc jādala divos failos. C sāku mācīties laikam jau no nepareizā gala  ::  
Bet nu delay.h jau nebūtu vajadzības rediģēt. Tās funkcijas ir pietiekoši labas. Vajadzētu varēt tomēr kaut kā to F_CPU nodefinēt projekta galvenajā failā un nemaz neinteresēties par to, kas notiek iekšā bibliotēkās. Vismaz tā es to saprotu.

edit: Problēma atrisināta. Bļin, vot tā iet, kad nemācās no pareizā gala :: . Biju sākumā nodefinējis (kaut kur noskatījies). Vot tā ir - nevajag visu tupa kopēt.
#define F_CPU 8000000UL
Laikam jau tie burti galā nozīmē U(nsigned)L(ong). Vot i šitā copy/paste iekšā. Kamēr viss bija vienā failā, tikmēr gāja. A bet tagad noņēmu to UL nost un viss štokos.

----------


## Delfins

gan jau ka šādi vajag


```
include config.h

include lib1.h
include lib2.h
include libN.h

main()
{
 // trollolo
}
```

 attiecīgi ja ir fukkcijas no device/app atkarīgas
piem.    mana_super_liba.c, tad tad sākumā  include config.h un viss notiekās (global level)

libām attiecīgi ir klasiskās definicījas


```
if not defined _mana_super_liba
define _mana_super_liba
...
endif
```

----------


## Jurkins

Esmu galīgi sapinies. Pirmo reizi kompilējot izmet, ka F_CPU nav definēts. Nospiežu otrreiz kompilēt, un viss ok. Kontrolieris strādā. 
Rakstu tā.
Iekš main.c sākumā definēju F_CPU un tad inklūdoju bibliotēku:

#define F_CPU 8000000
#include <LCD.h>

savukārt iekš LCD.h ir rinda:

#include <util/delay.h> 

Šis delay.h izmanto F_CPU. Netieku gudrs vai kaut kur ir feileris vai nē. Jo otro (u.t.t.) reizi kompilējot ne tikai kļūdas, bet arī warningi nerādās. Un kontrolieris strādā. Nu jā, un par to F_CPU met warningu nevis kļūdu.
Un vēl netieku gudrs, kāpēc piem. iekš LCD.h raksta:

#ifndef _LCD_H_
#define _LCD_H_
...blabla...bla...
#endif

Kāpēc tās apakšējās svītras? Jebšu kaut kur ir jau nodefinēts, ka "_blablabla_H_" ir "blablabla.h"?

----------


## Delfins

Tapec ari nekompilejas ja definicijas ir ieks .cpp. Visas def. Vajag ieks headeriem. Headeri nav domati programesanai un tie inkludojas pec nepieciesamibas,bet cpp kompilejas seciigi par .obj

Apaksvitras ir domatas smukumam ieksejai lietosanai "tipa lai nejauktu ar global define"

----------


## Jurkins

Pag, tad man tas F_CPU jāliek iekš speciāli šādiem mērķiem (un varbūt arī citiem mērķiem) veidota main.h un iekš main.c/cpp jāraksta #include <main.h>? Un vispār visus  #define , kas man pašlaik ir  main.c/cpp jānes uz main.h?

----------


## Delfins

Jā, ja mainīgais ir "konfigurācija" programmai.
Vēl ir tāda nianse, ka Makefile un t.t. kompilatoram var padot defines no konfigurātora   compile-with-debug, compile-release un t.t.
https://gcc.gnu.org/onlinedocs/gcc/P...r-Options.html


To pašu F_CPU var padot kā parametru  


```
gcc -DF_CPU=0x000....
```

 attiecīgi var uztaisīt kompilēšanas profilus:
"compile 16Mhz atmel graphics LCD"
"compile 8Mhz atmel 16*2 LCD"
"compile 8Mhz atmel 16*4 LCD"

tālāk ar defines iekš koda jau būs darbs ar predefinētām konstantēm un kods strādās zibenīgi.


Ja ir makefile, tad ar make --configure var visādus pigorus nodefinēt nemainot kodu
include + define + makefile ir spēks. Viss liels open-source uz tā dzīvo.

----------


## Jurkins

Paldies! Nu tagad viss ir daudz skaidrāks. Forums tomēr rullē. 
Tas makefile un visas citas gudrības man vēl priekšā, bet nu mācīties nekad nav par vēlu.

edit: yesss!!! viss rullē bez warningiem.


Priecīgus Ziemassvētkus!
Lai spēks ir ar Jums :: !

----------


## JDat

Cik saparatu, tad makefile aizvieto visu arduino ide un avr studio kopā ņemtu. Vajadzīga tā figņa (nezinu kā saucās), kura māk izpildīt makefile, C kompilators, linkeris (laikam winavr komplekts) un avrdude. Tālāk rakstam C kaut ar notepac (neērti) un dev sistēma gatava. Ka'dreiz pamēģināšu copy/paste no arduino un sakomplektēt savu uzparikti vienā folderī ar kuru kompilēt C priekš AVR. Tīri sporta pēc. Dzīvē noderēs.

Kas attiecas uz "skeletu" Delfīnu. Skelets tāpēc Delfīns savulaik pazuda no foruma un tagad reinkarnējās. Ļoti vērtīgus padomus par C. Lasu un mācos. Gandīz tik pat labi kā Jurkins. Teorētiski. Vēlreiz liels paldies par mini lekcijām, svarīgu, trāpīgu un interesantu info par C.

----------


## Jurkins

Tā, mož kādam noder:
Atkal daru "TO" - izdomāju, ka vajag iemācīties iemest c/cpp projektā asmu, tikai nevis inline, bet gan atsevišķā failā.

Ierakstu savā main.c failā:


```
extern void asm_us_delay(uint16_t us);
```

 Ierakstu assmblera failā:


```
.global asm_us_delay
.section .text
asm_us_delay:
    sbiw R25:R24, 1
    brne asm_us_delay
ret
```

 Izrādās, ka gcc manu mainīgo us met uz reģistru pāri R25, R24. Nu un rakstu kā ierasts sbiw R25:R24, 1. A bet šis (maita) raksta angliski rupjības un neiet.
Izrādās, ka jāraksta sbiw R24, 1, bet šis skaita nost no reģistra pāra. Bet, ja rakstītu visu projektu asmā, tad būtu jāraksta kā pirmajā variantā. Nu sviesc! :: 


```
.global asm_us_delay
.section .text
asm_us_delay:
    sbiw R24, 1
    brne asm_us_delay
ret
```

 Un viss ok.

----------


## M_J

Izrādās, ka arī asmā nav obligāti rakstīt reģistru pāri, pietiek ar jaunāko reģistru. Pirms kāda laika ar zināmu pārsteigumu šādu lietu konstatēju. C un asm veiksmīga apvienošana ir lieta, kas arī mani stipri interesē. Ir diezgan muļķīgi visu darīt asmā, kā to pašreiz daru, bet īsti nezinu kā to, ko tagad taisu asmā, izdarīt C, nepazaudējot kontroli pār atmiņas sadalījumu un reģistru izmantošanu.

----------


## Jurkins

O, velns! Vajadzēs pamēģināt. Es jau gan esmu iesācējs gan vienā, gan otrā, bet nu, domāju(ceru :: ), ka tas netraucēs.

----------


## Jurkins

Nu ko, veiksmīgu un ražīgu visiem Jauno 2016-to.
A bet es jau pirmajā dienā uzprasījos uz problēmas.
Divas vienkāršas funkcijas. 


```
void set_adc_channel(uint8_t channel)
{
    ADMUX &=~((1<<MUX0)|(1<<MUX1)|(1<<MUX2)|(1<<MUX3));
    ADMUX |= channel;
}
uint8_t get_adc_channel(void)
{
    return ADMUX&((1<<MUX0)|(1<<MUX1)|(1<<MUX2)|(1<<MUX3));
}
```

 ADC kanālu uzstāda ok, bet, kad es gribu dabūt, kurš ADC kanāls dotajā brīdī ir aktīvs:


```
#define ADC1 1
...
...
if (get_adc_channel==ADC1)
{
...
```

 met brīdinājumu "comparison between pointer and integer"  un, saprotams, ka neko nesalīdzina.
Kur ir pointeris? ADMUX takš ir lasāms reģistrs, izmēģināju arduino IDE. 


```
Serial.println(ADMUX&((1<<MUX0)|(1<<MUX1)|(1<<MUX2)|(1<<MUX3)),BIN)
```

 Skaisti parāda, kurš MUX bits kād ir.

edit:  Pats lohs esmu  :: . Azmirsu mazas, mazītiņas iekaviņas.


```
#define ADC1 1
...
...
if (get_adc_channel()==ADC1)
{
...
```

----------


## Jurkins

Labs vakars!
Es jau saprotu, ka man nav nekādas sajēgas, kā tiek realizēts 'float' un noteikti iziešu cauri šai tēmai arī, bet varbūt var tā uz pirkstiem:


```
float a = 52.96;
uint8_t temp1 = (uint8_t) a;
a = 100*a - 100*((float)temp1);
```

 dod 96, bet


```
float a = 52.96;
uint8_t temp1 = (uint8_t) a;
a = 100*(a - ((float)temp1));
```

 dod 95.99...

----------


## karloslv

Tik daudz grābekļu, uz kuriem uzkāpj gandrīz katrs, kurš sāk apgūt C. Daudz ko no tā varētu novērst, lasot C "tēvu" grāmatu (Kernighan & Ritchie, kuri ir arī piedalījušies Unix izveidē).

Mēģināšu izskaidrot mistēriju par .h failiem:

1) C kompilatoram ir pavisam pie kājas .h faili. Patiešām. Kompilators strādā tikai un vienīgi ar .c failiem. Tehniski .h faili ir tikai *ērta vienošanās*, kas atvieglo dzīvi. Nav nekādu noteikumu par to, kā .h faili būtu jāsauc un vai tiem vispār ir jāeksistē.
2) _#include_ direktīva gluži vienkārši tās vietā ievieto norādīto failu. Nav nekādas īpašas maģijas ar .h failiem, tikpat labi var rakstīt:



```
#include <vecmaminas_pensija.txt>
#include <cits_c_fails.c>

void funkcija() {
#include "funkcijas_kods"
}
```

 3) Pirms *katra* jauna funkcijas izsaukuma C kompilators grib redzēt šīs funkcijas *deklarāciju* (jebkur kompilētajā tekstā, bet *pirms* izsaukuma):



```
void deklaracija();   // šī ir funkcijas deklarācija, kas pasaka tikai to, kā šo funkciju izsaukt

// bla bla bla, kaut vai miljons rindiņu 

void izsaukums() {
  deklaracija();
}
```

 4) sekas no 1-3 punkta ir tādas, ka ir loģiski funkciju deklarācijas salikt .h failos un tad tos iekļaut .c failos. Piemēram, iekļaujot "stdio.h" failu, attiecīgais .c fails "uzzina" par daudzām jaunām funkcijām.

5) no katra C faila kompilators izveido .obj (.o) failu, kurš satur definēto funkciju mašīnkodu. Šos OBJ failus pēc vēlmes var apvienot .lib vai .a failos, kas vienkārši satur daudzus OBJ failus (vienkāršoti).

6) liekot programmu kopā (linkeris) tiek apvienoti norādītie OBJ un LIB faili (kas satur mašīnkodu). Šajā brīdī kompilators sāk meklēt, vai visas funkcijas, kas tiek izsauktas, ir sameklējamas, un tai skaitā pēc noklusējuma meklē main() funkciju. Ja kāda funkcija ar tādu pašu nosaukumu ir realizēta vairākos OBJ failos, rodas konflikts. Ja kāda funkcija, kas tiek izsaukta (pēc tās deklarācijas), nav atrodama nevienā no norādītā failu komplekta, tad arī rodas linkera kļūda un programmu nevar uzbūvēt.

Tāpēc viss, ko jūs lasāt par to, kas kurā failā ir jāliek, ir blēņas - nav tādu noteikumu, ir vienkārši rīcība un tās sekas. Ir gadījumi, kad C failā vajag iekļaut C failu. Vai ASM failu. Vai citur automātiski ģenerētu koda gabalu. Iesaku iziet cauri kompilatora loģikai, un viss kļūs skaidrs, kurā failā kas ir jāliek!

----------


## Powerons

Nu pēc tik gara apraksta rodās jautājums.

AVR nav X86
Vi avr prot izpildīt programmu no jebkuras vietas, kur to ielādē atmiņā, vai ielādes vieta tiek notaikta jau programmu kompilējot.

----------


## karloslv

Ja programmas gabaliņš būvēts, par to padomājot un izmantojot relatīvos lēcienus un izsaukumus (rjmp un rcall), tad principā tas (kā konkrēts nemainīgs mašīnkoda gabals) ir relocējams uz jebkuru adresi. Pat, ja izsaukumi ir absolūti, zinot, kuras pozīcijas jāmodificē, to var relocēt uz jebkuru adresi. Tikai nianse, ka AVR programmas izpilda no FLASH, tāpēc parasti jautājums par "ielādi" īpaši nav aktuāls - protams, to var darīt un dara, piemēram, bootloader, bet 99% gadījumu tas vienkārši izdzēš visu FLASH un ieraksta saņemto programmu no 0 adreses. Parasti par "ielādē atmiņā" runā operētājsistēmu kontekstā, kuras programmas lādē operatīvajā atmiņā. FLASH pēc tādas izvirtības ātri vien aizies pie dieviem.

AVR C kompilators normālā režīmā neparedz tādas izvirtības  :: 

Vēl ir aspekts, ka AVR arhitektūra pirmās FLASH adreses uztver īpaši, jo tur glabājas pārtraukumu izsaukumu adreses, turklāt RESET vektors tipiski ir 0. adresē - AVR to nolasa un aizlec uz norādīto adresi.

----------


## Delfins

pag pag, a kā ar iespēju pieslēgt S(D)RAM?
atmega 8/16/32/128 nebūs aktuāli, bet "jaudīgākiem" tā būtu norma.

https://www.alvidi.de/products/EN/AV..._xavrb_v20.php

----------


## Kodolskiltava

Protams, ka var pieslēgt, bet tā kā AVR nav nekāda dzelziskā "suporta" priekš SDRAMa, Tev būs pašam jāraksta RAMa cikliskā "refrešošana", lai RAMā ierakstītie dati nepazustu un tas Tev aizņems CPU resursus. Arī rakstīšana šajā RAMā nebūs viens mašīnkods kā rakstot iebūvētajā RAMā, bet gan vesela funkcija, kura nodarbosies ar datu apmaiņu ar RAMu.
Tev ir kāda reāla nepieciešamība priekš tik liela RAMa projektā ar mikrokontrolieri?

----------


## JDat

Karloslv! Labs skaidrojums priekš nezinīšiem un sliņķiem kā es. Paldies!
External S(D)Ram uz AVR ir realizējams, lai arī liels mazohims.

Tad labāk izvēlēties kontrolieri, kurš ir paredzēts tādiem mēr'jiem 8051 raritāte nav atcelta, tāpat kā HiEnd ARM platformas.

----------


## Jurkins

Paldies, Karloslv! Precizējošs jautājums. Ja man funkcijas ir definētas <kaut_kaads_fails.h>, tad taču pašām funkcijām jābūt failā <kaut_kaads_fails.c>? Nevar būt <kaads_fails.c>? Un šim failam jāatrodas blakus hederim?

----------


## karloslv

Atbildot par hederu nosaukumiem - nav nepieciešams, bet tā bieži vien dara. Tikai te labāk uzreiz nošķirt, kas ir deklarācija un kas ir definīcija. Deklarācija, gluži kā neatkarības deklarācija, ir tikai vēlmes izpaušana, t.i.



```
int funkcija(int parametrs);
```

 Ar to pietiek, lai kompilators zinātu, kā funkciju izsaukt jebkurā citā koda vietā. Kompilējot kodu, viņam nav jāzina, ko tieši funkcija darīs, ka tikai var izsaukt. 

Funkcijas definīcija turpretī ir pašas funkcijas satura apraksts:



```
int funkcija(int parametrs) {
  return 2 * parametrs;
}
```

 Tad lūk, definīcijas gan neliek .h failos, jo tos mēdz iekļaut vairāk nekā viens .c fails, un rezultātā rodas vairākas identiskas viena nosaukuma funkcijas implementācijas. 

Padomā par visu procesu tīri no .c failu viedokļa - kompilators apstrādā TIKAI tos. Tas, kas ir rakstīts #include šajos failos, vienkārši tiek iekļauts .c failā 1:1. Ja iekļautajā .h failā ir vēl #include, arī tie faili tiek iekļauti un tā, līdz kompilatoram atmiņā ir milzīgs fails, kuru tad kompilēt.

----------


## Jurkins

Nu jā, es ar terminiem jaucos. 
Bet daru jau laikam pareizi. Funkciju deklarācijas ir *.h failā, definīcijas ir *.c failā. Un tajā *.c failā ir #include <*.h>. Tik tālu ir skaidrs, ka kompilators to *.h failu iekļaus *.c failā.
Ja "galvenajā" .c failā (nu kaut main.c) būs ieraksts #include <*.h>. Nu ok, kompilators iekļaus šo .h failu ar funkciju deklarācijām tajā main.c. Bet kā viņš zinās, kur meklēt funkciju definīcijas, jo .h failā nav nekādas norādes, ka šās jāmeklē tajā un tajā .c failā. Kaut kā biju iedomājies, ka, ja šim .c būs tāds pats nosaukums kā .h, tad viss notiksies.
Jeb sāls ir tur, ka kompilators vienkārši saliks kopā visus .c failus, kas ir "projektā" un tad jau tur būs arī funkciju definīcijas?

p.s. studēju Kernighan-Ritchie grāmatu, bet līdz kompilatoram vēl neesmu ticis.

----------


## karloslv

> Ja "galvenajā" .c failā (nu kaut main.c) būs ieraksts #include <*.h>. Nu ok, kompilators iekļaus šo .h failu ar funkciju deklarācijām tajā main.c. Bet kā viņš zinās, kur meklēt funkciju definīcijas, jo .h failā nav nekādas norādes, ka šās jāmeklē tajā un tajā .c failā. Kaut kā biju iedomājies, ka, ja šim .c būs tāds pats nosaukums kā .h, tad viss notiksies.
> Jeb sāls ir tur, ka kompilators vienkārši saliks kopā visus .c failus, kas ir "projektā" un tad jau tur būs arī funkciju definīcijas?


 Jautājums ļoti pareizs  ::  Lieta tāda, ka no c failiem līdz gatavai programmai ir 2 soļi:
1) kompilators, kurš .c failus pārvērš .obj failos (mašīnkoda fragmentos)
2) linkeris, kurš .obj failus salasa kopā vienā programmā (veselā, pašpietiekamā, izpildāmā mašīnkodā)

Tad lūk, linkeris nekādi nezina, kur meklēt funkcijas, un par .h failiem arī neko negrib zināt. Nav tāda eleganta automātiska veida, kā viņš no .h faila zinātu atbilstošo .c failu. Tad, lai viss notiktos, programmēšanas vidē (vai Makefile, ja tādu izmanto) norāda VISUS .c failus, kas nepieciešami, lai salasītu kopā veselu programmu, plus ārējās (gatavi nokompilētās) bibliotēkas .lib vai .a formātā (vai .obj, ja ir tāda perversa vēlme). Pats kompilators parasti nesaliek kopā visus .c failus projektā, bet jā, tuvu tam, to parasti nodrošina kaut kāda IDE, ja tādu izmanto.

----------


## Jurkins

Ak nu ja. Protams, ka IDE salasa failus projektā. 
Paldies, nu jau daudz skaidrāk viss palika. 
Laikam mani samulcināja arduino IDE. Atmel studio man jāpievieno projektam gan savs OneWire.h gan OneWire.c, bet iekš arduino kodā ierakstu #include <OneWire.h>, un abiem failiem jābūt vienā mapē pie lietotāja bibliotēkām.  Un tad gan jau, ka šis uztaisa "projektu" pats.

----------


## Delfins

C/C++ .H un deklarācijas ir ieviestas tikai viena iemesla pēc - lai funkcijas varētu izsaukt jebkuru citu funkciju neatkarīgi no pozīcijas nokompilētajā "atmiņā (programmā)".

1) Deklarācija ir pointeris uz izsaukumu
2) izsaucot funkciju pasaka izpildīt instrukciju X adresē ar parametriem Y
3) funkcijai var padot citas funkcijas adresi
4) funkciju var nodefinēt ar dažādiem tipiem
5) .H failos deklarē struktūras un konstantes

Deklarēšanu (likumus) atrisina .H  (saeima[komp]+prezidents[linkeris])
Izpildi atrisina .C (valsts iedz.[funkcijas] + iestādes[sys bibliotēkas] )
Mainīgie ir [maciņi], [kustamie īpašumi], [nekustamie īpašumi]


Tāpēc bieži kompilējot sarežģītus projektus uz linksa  (open-source pakotnes salasīšana PHP, piemēram), bieži vien viena "iestāde" pabļauj, ka neesi aizgājis uz citu "iestādi" un paņēmis tur papīru (resp. uzinstalējis).

----------


## M_J

Lasu un apbrīnoju Karloslv elegantos skaidrojumus. Es joprojām priekš AVR rakstu visu ASMā, vienlaicīgi apzinoties, cik tas ir neracionāli. Savukārt to daļu, kas atrodas uz PC rakstīju Delphi7, tagad Javā, lai programma darbotos ne tikai zem Windows. Tieši C nerakstu, bet, nedomāju, ka pāriet uz to būtu problēma. Es runāju par programmu, kas darbojas uz PC. Jo tur man galīgi neinteresē, kā dators fiziskajā līmenī izmanto atmiņu. Ar AVR ir savādāk. Tur man ir ļoti svarīga ātrdarbība, un ļoti svarīgi lai dažas lietas notiktu PRECĪZI NOTEIKTAJĀ MOMENTĀ. Tāpēc vietās, kur tas ir kritiski svarīgi, un tās vietas ir pārtraukumos, es, zinot cik ciklus aizņem katras komandas izpilde, skaitu ciklus, un, lai NOTIKUMS notiktu precīzi paredzētajā momentā, piemeklēju komandas (vienu un to pašu lietu var izdarīt ar dažādām komandu kombinācijām), sliktākajā gadījumā pa vidu ielieku "tukšās" komandas un daru visādas citādas viltības. Labi, C tādas lietas nav darāmas, tas vienalga jādara ASM iespraudumos. Bet ir vēl cita lieta. Kā zināms, lai kaut ko ar datiem izdarītu, tos vispirms no SRAMa ir jādabū reģistros. Un tās ir komandas lds/sts, ld/st, ldd/std kas aizņem daudz laika, vai, pasarg die's visi tie pusch un pop pārtraukumu sākumā un beigās, kas vispār aizņem veselu jūru laika, bet tāda laika man nav. Tāpēc ir virkne reģistru, kurus izmantoju tikai konkrētos pārtraukumos, konkrētām vajadzībām, un kuros visu laiku glabāju lietas, kuras, šajos pārtraukumos arī izmantoju. Izmantot citur šos reģistrus ir "tabu". Otrkārt - SRAMā esošo datu adresācijai tiek izmantoti divi baiti. Tātad, ja SRAMā glabājas kaut kāds masīvs, un ar to gribu kaut ko darīt, visā tajā darīšanā ar adresāciju jādarās ar diviem baitiem. Kas ir lēnāk, nekā, ja darītos ar vienu baitu. Var darīties arī tikai ar vienu baitu, ja masīvs nav lielāks par 256, bet tad masīvam jābūt novietotam tā, lai vecākais baits kaut kur masīva vidū nemainītos. Bet tad masīvu nevar nomest, kur kompilatoram ienāk prātā, bet gan pilnīgi konkrētā vietā, kur es to gribu. Tātad man ir svarīgi lai es C kompilatoram kaut kādā veidā varētu iestāstīt: "Lūdzu aizmirsti, ka AVR ir tādi reģistri, teiksim no r10 līdz r21. Tie ir paredzēti man, izmantošanai ASM iespraudumos, bet tu tos nedrīksti izmantot nekādā gadījumā". Ja es to izdarīt nevaru, tad C izmantot nevaru. Un to pašu par SRAMu. Ar SRAMu, šķiet problēmu nevarētu būt, bet kā ar reģistriem?

----------


## Jurkins

Tas c ir kā cīņa ar vējdzirnavām :: .  LCD 2*16 displejs. Uzrakstīju savu fukciju, kas float skaitli konvertē  uz ascii simbolu rindu. Viss ok, bet atklāju, ka ir tāda sprintf  funkcija. 
 6738
Dod ārā vienu jautājuma zīmi. It kā viss pēc parauga. Tagad nav miera. ::

----------


## karloslv

Kas attiecas uz reģistriem, tad parasti jau C kompilators cenšas izmantot tos visus, lai maksimāli varētu optimizēt programmu. 
Pēc noklusējuma tiešām tā ir: http://www.atmel.com/webdoc/AVRLibcR...reg_usage.html
Taču, izskatās, ka var rezervēt reģistrus un piesiet pat tos pie C mainīgajiem: http://www.atmel.com/webdoc/AVRLibcR...q_regbind.html

Attiecībā uz float, iesaku tos neizmantot, ja vien nelieto resnu MCU un programmas ātrumam nav nozīmes. Float un sprintf izmantošana pamatīgi palielina programmas izmēru (taču tas ir ērti un to var darīt, ja tas der). Kritiskākos uzdevumos es izmantoju fixed point, t.i. komatu binārajā sistēmā, kad konkrēti N jaunākie biti ir rezervēti skaitļa "neveselajai" daļai. Tos var saskaitīt, atņemt un reizināt un dalīt, parūpējoties par pareizu komata pozīciju. Tādiem skaitļiem var arī ērti uzrakstīt pats savu konvertoru uz decimālo pierakstu, jo ir zināma skaitļa maksimālā vērtība un zīmīgo ciparu skaits aiz komata.

----------


## Jurkins

Jā, par to, ka float un sprintf izmanto lērumu resursu, es jau sapratu. Mani tikai nemiers  :: , ka tas sprintf no float met ārā jautājuma zīmi. Paldies par norādi uz fixed point, par to nemaz nezināju. Lai gan man patiesībā konkrētajam uzdevumam laikam nemaz nevajag to float.

----------


## M_J

Paldies, Karlos! Izskatās, ka tā lieta varētu strādāt. Būs iemesls vēlreiz pamēģināt sākt lietot C.

----------


## next

Cik es kaadreiz prieksh mcu softu taisiiju - vienmeer iztiku ar fixed point.
Es pat nespeeju iedomaaties uzdevumu kur tas nebuutu iespeejams.

----------


## Jurkins

Nu es skatījos piemērus. Konkrēti temperatūras dabūšanu no DS18B20, un tur netā visi piemēri ar float. Un tā kā c neesmu programmējis vispār, pirmā iepazīšanās ar c bija iekš Arduino, tad par tādiem fixes point nemaz nezināju līdz šim brīdim. 
Jā, nu skaidrs, ka "mācīties, mācīties un vēlreiz mācīties, kā teici lielais Ļeņins"  :: .

----------


## karloslv

Pareizi par mācīšanos  :: 

Par "?" drukāšanu neizzīlēšu pēc fotogrāfijām, bet, iespējams, kaut kur tu norādi ne to atmiņas apgabalu vai arī neesi rezervējis tam vietu.

Vēl aspekts ir pareizi izvēlēties kompilatora opcijas - lietojot Arduino, par to nav jādomā īpaši, taču, ja projekts ir specifisks (piemēram, kaut kas uz ATTiny, ar daļēju asemblera izmantošanu, ar advancētu struktūru vai tamlīdzīgi), tad nākas vien izmantot kādu nopietnāku IDE vai pašam veidot _make_ failus. Tad bieži vien vislabākie ir šādi parametri:
1) kompilatoram -Os -fdata-sections -ffunction-sections -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -fno-inline-small-functions 
2) linkerim -Wl,--relax,--gc-sections 

Šie nodrošina mazu koda izmēru un pietiekami labu ātrdarbību.

----------


## Jurkins

Paldies, karloslv. Es lietoju gan Arduino, gan AtmelStudio, bet vēl laikam nebūšu nonācis līdz kompilatora un linkera parametriem. Tā kā man šis nav maizes darbs bet hobijs, tad pagaidām pats jūtu, ka taustos kā ezītis miglā  :: . Velns nerāvis to jautājuma zīmi, tieši tāds kods "parastajā" c strādā, un, ja float vietā ir jebkas cits, tad arī dod ārā pareizi. Bet viss notiek ar pašrakstītu funkciju, vienkārši ņeporjadoks, ka kaut kas neiet :: .

----------


## Delfins

Jāredz tak kods. un nav skaidrs, kur īsti "drukā"... uz LCD vai debug modē, vai EEPROM stringu skaties?...
Ar VMLAB var nosimulēt rezultātu  ::

----------


## Jurkins

```
#include <stdio.h>
#include <avr/io.h>

//void lcd_print_float(float f_val);
char buf[30];
int main(void)
{
    float pi = 3.14;
    
    sprintf(buf,"%f\n", pi);
    //lcd_print_float(pi);
    while(1);
    
}
```

 Kods ir šāds. AtmelStudio7.0 un skatos watch logā mainīgo buf. Ja atkomentēju tās rindas, tad mana funkcija lcd_print_float(pi) ieraksta iekš buf visu kā vajag, un watch logā es to varu apskatīt. Mana funkcija tikai visu rajsta no otra gala, pēc tam uzreiz uz LCD sūta, šeit tā rinad ir aizkomentēta.


```
void lcd_print_float(float f_val) //f_val = xxx.xx
{
    uint8_t neg = 1;
    (f_val >= 0)?(neg = 0):(f_val = -f_val);
    uint8_t temp1 = (uint8_t) f_val;
    f_val = 100 * f_val - 100 * ((float)temp1);
    uint8_t temp2 = (uint8_t) f_val;
    uint8_t i = 0;
    while (temp2)
    {
        buf[i++] = temp2 % 10 + 48;
        temp2 /= 10;
    }
    buf[i++] = '.';
    while (temp1)
    {
        buf[i++] = temp1 % 10 + 48;
        temp1 /= 10;
    }
    (neg)?(buf[i++] = '-'):(1);
    //while (i--) {lcd_print(buf[i]);}
}
```

  Tieši tas pats arduino vidē:


```
#include <stdio.h>
#include <avr/io.h>

char buf[30];
int main(void)
{
  Serial.begin(9600);
  float pi = 3.14;
  
  sprintf(buf,"%f\n", pi);
  Serial.print(buf[0]);
  Serial.print(buf[1]);
  Serial.print(buf[2]);
  Serial.print(buf[3]);
  while(1);   
}
```

 Viena jautājuma zīme. Bet piem integer gan studijā gan arduino viss kā pēc tutoriāļa - gan ar nullēm priekšā, gan ar zīmi u.t.t., kā vajag, tā var izvadīt.

edit:  Ja ieraksta piem . "PI = %f\n", tad rezultāts ir PI = ?.

----------


## Delfins

kompilatoram/linkerim vajag padot lai apstrādā floatus. kamēr neieslēdzu tikmēr pat VMLAB neko nejēdza attēlot




> In case that link ever disappears, what you have to do is ensure that your gcc command has "-Wl,-u,vfprintf -lprintf_flt -lm". This translates to:
> force vfprintf to be initially undefined (so that the linker has to resolve it).
> specify the floating point printf() library for searching.
> specify the math library for searching.


 priekš ardu: http://forum.arduino.cc/index.php?topic=124809.0

----------


## Jurkins

OK, paldies. Režīms <ņeporjadok> atcelts :: . Vispār jau tāda ideja pavīdēja, ka tas ir defaultā nahrenizēts dēļ resursu patēriņa vai, bet padomāju, ka ideja muļķīga. Par tām kompilatora/linkera komandām es vēl esmu galīgs losis.

edit: vo vellos, strādā! Un kodam nāk klāt 1600 baiti  :: . Skaidrs, kāpēc tas nafig nav vajadzīgs.

edit: vēl viens jautājums karājas gaisā:
temp3 ir f_val cipari aiz komata (man ir tikai līdz 99, tāpēc pietiek ar "mazo" int).


```
float f_val;
uint8_t temp1 = (uint8_t) f_val;
 uint8_t temp3 = (uint8_t)(100 * f_val - 100 * ((float)temp1));
```

 sākumā pēdējorindu rakstīju tā:


```
uint8_t temp3 = (uint8_t)(100 * (f_val -  ((float)temp1)));
```

 un pēdējais cipars par 1 mazāks, pie tam ne vienmēr. Tad sanāk, ka 100*float-100*float nav tas pats, ka 100*(float-float)?

----------


## karloslv

Jā, tā tas var nebūt. Viens niķis slēpjas tajā, ka float ir peldošais punkts *binārā* sistēmā, kamēr mēs esam pieraduši domāt decimālajā, līdz ar to, piemēram, skaitlis 0.1 tiek pārveidots par 1.6 * (2^-4), taču 1.6 ir jāuzdod kā binārs skaitlis, un tas pārveidojas kā 1.10011001100110011... un tā tālāk. Float ir tikai galīga precizitāte, līdz ar to mantisa tiek apcirpta. Piemēram, kad printf to pārveido atpakaļ uz mūsu pierasto decimālo, pēkšņi sanāk jau kaut kas cits. Vēl pavisam jauna jautrība sākas, kad tiek saskaitīti vai atņemti 2 float skaitļi, jo tiem ir jāizlīdzina eksponentes, tikai tad mantisas var saskaitīt. 

Te var papētīt: http://www.h-schmidt.net/FloatConverter/IEEE754.html

Vēl ir jautājums, vai tu labi zini, ko tu dari ar pēdējo decimāldaļas ciparu? Vai tu to gribi noapaļotu uz "vidu" vai uz leju? Tur arī ir āķis. Ja kaut kādu iemeslu dēļ float, kuru tu konvertē uz int, ir kaut nedaudz mazāks par veselo skaitli, t.i. 2.9999999, rezultāts būs pliks 2. Lai noapaļotu float uz int, es parasti rakstu tā: (int)(x + 0.5f)

----------


## Delfins

diezgan loģiski, ka nav, jo tas ir floats ar dažādu formulu pietām.

Mēģini internetā sagūglēt korektu decimal apstrādi.  Nodefinē struct, funkcijas, kas darbojās ap tām un miers mājās.
Pirmais kas no guugles: http://sourceforge.net/projects/avrf...e=typ_redirect

----------


## karloslv

> diezgan loģiski, ka nav, jo tas ir floats ar dažādu formulu pietām.


 Nu paga, jautājums bija korekts - kā 100*(a-b) atšķiras no 100*a-100*b, kas matemātiski ir tas pats. Tur nav nekādu dažādu formulu.

----------


## Delfins

matemātiski... bet reāli nav tas pats  :: 

Ieraksti kaut vai Javascript debugerī iekš Chrome developera konsoles, dabūsi to pašu:



> x = 0.53
> 0.53
> y = 0.17
> 0.17
> x + y
> 0.7000000000000001

----------


## Jurkins

Paldies par skaidrojumiem un linkiem. Jāmācās.

----------


## Delfins

Citiem vārdiem - aizmirsti par float, kamēr tev to tiešām nevajadzēs  :: 
Jāmācās laicīgi izmantot AVR resursus taupīgi. To es sapratu, kad rakstīju kaut kādus demo-izvēlnes + pogas + LCD.

----------


## Jurkins

Tieši tā, kad ieraudzīju tos 1600 baitus... :: .

----------


## next

Es atkal par savu.
Paraadiet man kaadu piemeeru kad float neizbeegami vajadziigs mcu programeeshanaa.
Nu netaisa tak neviens universaalu skaitljotaaju (kam tas protams buutu vajadziigs) uz AVR.
Visi skaitlju diapazoni un nepiecieshamaa precizitaate no saakta gala zinaami.

----------


## Jurkins

Da nav jau vajadzīgs. Ņēmos ar DS18B20. Netā piemērs temperatūras iegūšanai - saliek abus temperatūras baitus un sareizina ar 0.0625 un ar kaut kādu funkciju ftoa() (float uz ascii), kuras pie tam minētajā bibliotēkā nevarēju atrast dzen uz LCD. Skaidrs, ka tā nevajag darīt. Nu tagad ir skaidrs :: . Paldies biedriem par skaidrojumiem.

----------


## karloslv

Fiksais piemērs, kā to visu varētu realizēt ar fiksēto punktu, pārveidojot DS rādījumu uz decimālu pierakstu ar vienu zīmi aiz komata:



```
#define FLOAT_TO_FIX(f)  (uint16_t)(f * (1 << 6) + 0.5f)   // pārveido float par fixed 10.6 formātu

uint16_t ds_raw = read_ds();     // skaitlis ir nosacīti 16.0 fixed point formātā, t.i. veselos skaitļos
uint16_t temp_fixed = ds_raw * FLOAT_TO_FIX(0.0625f);  // sareizina ar 10.6 formātu, rezultāts ir 10.6 formātā
uint16_t temp_f10 = (temp_fixed * 10);  // sareizina ar 10, lai dabūjam vienu decimālo ciparu aiz komata
uint16_t temp_d10 = (temp_f10 >> 6);      // paņemam veselo daļu

// tālāk jau izprintējam temp_d10 pa _decimāliem_ cipariem, respektīvi 234 printējam kā "23.4"
```

 Protams, visu laiku jāseko līdzi katrai operācijai, lai saprastu, kādi ir pieļaujamie skaitļu limiti, lai, piemēram, uint16_t nepārplūstu. Ja pārplūst, lieto jau uint32_t. Jāatceras, ka, piemēram, sareizinot divus 10.6 skaitļus, rodas 20.12 skaitlis, līdz ar to tas jābāž jau 32 bitos un, lai atgrieztos uz 10.6, jāpabīda pa labi par 6 bitiem, pēc kā var nocirpt augšējos bitus, ja limiti ļauj.

----------


## Jurkins

Paldies, karloslv, pašlaik jau galva kūp no peldošā punkta :: . To peldošā punkta "uzbūvi" nekad neesmu papētījis, kaut kas laikam bija >20 gadus atpakaļ, bet sen jau viss no galvas izkritis.
Par to piemēru: 
f * (1<<6) skaidrs - skaitlis tiek pabīdīts tā, ka uint16_t 10 vecākajos bitos ir veselā daļa, bet kas ir 0.5f? Vai domāts 0.5*f, tas ir  2-1*f? Un tas ir dēļ iepriekš minētajām noapaļošanas problēmām?
ufff, šitie float jāsagremo...

----------


## karloslv

Tā loģika jau ir tieši tāda, kā aprakstīji, skaitlis tiek "pabīdīts", pareizinot to ar 64. 

Hm, jā ar 0.5f sanāca mulsinoši, jo tas ir vienkārši float pieraksts C valodā. Ja raksti 0.5, tas automātiski nozīmē double, kas teorētiski šur tur var nozīmēt kaut kādu lieku konvertēšanu. To 0.5 pieskaitu, lai notiktu apaļošana. Sanāca mulsinoši, jo arguments arī ir f, varbūt tad patiesībā makross apjuktu. Tad labāk rakstīt 



```
#define FLOAT_TO_FIX(x)  (uint16_t)(x * (1 << 6) + 0.5f)
```

----------


## Jurkins

ok, paldies! Tas tagad ir skaidrs.

----------


## Jurkins

Vispār uznāca viena apskaidrība. Nezinu vai pareiza... Ir jāmet malā tieksme pēc universālisma. Atmelis nav darbstacija. Jāraksta programma attiecīgam gadījumam(aparātam). Piemēram ar manu termometru. Nafig vispār man float, double vai fiksētais punkts. Aiz komata iespējamas 16 vērtības, katra 4 char, ja grib uzzīmēt visas 4 zīmes aiz komata, normāli pilnīgi pietiek ar 2, kuras jau ierakstam noapaļotas. Masīvs atmiņā, un sūtam uz LCD attiecīgos 4 čārus (vai 3, vai 2). Jeb es domāju galīgi nepareizi?

----------


## karloslv

Pirmo daļu, ka nav darbstacija un jāraksta katram gadījumam, piekrītu, lai gan daļu var universalizēt.

Taču otro daļu galīgi neuzķēru  ::

----------


## Jurkins

Nu jā, izskaidrošana nav mana spēcīgā puse. :: . Aiz komata tam DS18B20 ir 4 biti, tas ir 16 iespējamās vērtības   xx.0000, xx.0625, xx.1250, ... xx.9375. 
char decimal[] = {0,0,0,0,
                        0,6,2,5,
                        1,2,5,0,
                        ...
                        9,3,7,5}
un tad vienkārši aizsūtam uz LCD to "tetrādi", kuru vajag. Nu jā, aizņem 64 vārdus (laikam vārdus nevis baitus) flash atmiņā, bet vai to var uzskatīt par trūkumu? Ja izdomājam, ka vajag divus ciparus aiz komata, tad
char dec2[] = {0,0, 0,6, 1,3, ..., 9,4} un 32 vārdi atmiņā.

----------


## Kodolskiltava

Mnu, fiksētais punkts, manuprāt, šados gadījumos ir pilnīgi piemērots uzdevuma risināšanai. Tādus masīvus, protams, var taisīt lai, piemēram, vienu skaitli pārvērstu citā skaitlī, starp kuriem ir kāda pilnīgi neloģiska saistība. Bet Tavā gadījumā saistība ir pilnīgi loģiska. Nu, nez, brutāls risinājums:

unsigned int bin=[binaaraa veertiiba aiz komata];
unsigned int decimal=0;
decimal=625*bin;
//izvadi temperatūras veselos skaitļus, komatu un mainīgo decimal neaizmirstot nokontrolēt sākuma nulles, lai 0,0625 neizvada kā 0,625.

Un masīva gadījumā tie aizņemtie baiti būs RAMā, ne flashā. Vispār jau abos, jo tas masīvs pie startēšanās būs jāinicializē.

----------


## sasasa

> Piemēram ar manu termometru. Nafig vispār man float, double vai fiksētais punkts. Aiz komata iespējamas 16 vērtības,


 Ja man būtu jātaupa resursi, tad termometram, ja vien tas nav super puper krutais un precīzais,  es tikai ar veseliem skatļiem darbotos. Lai dabūtu 1 zīmi aiz komata rādītu 10x lielāku vērtību un komatu ar marķieri uz displeja uzzīmētu. piem 36.6 = 366
Kam vajadzīgi 0.0625 ja viņi ir greizi? 
Specenē rakstīts:

• ±0.5°C Accuracy from -10°C to +85°C

----------


## next

Precizitaate jau tikai liidz veselai daljai sanaak.
Bet izskjirtspeeja arii kaadreiz noder - piemeeram var veerot izmainjas tendenci.
Es taisiitu 16 baitu masiivu ar noapaljotaam desmitdaljaam (0,1,1,2......8,9,9).

----------


## karloslv

Idejas par masīviem ir ok, bet es tomēr taisītu ar aritmētiku. Ja lasījums no termometra ir 8.4 formātā (4 biti aiz komata), tad uz decimālo konvertētu šādi:



```
// ieejā x

uint8_t vesela_dala = (x >> 4);
uint8_t aiz_komata = (x & 0x000F);
uint8_t cipars_aiz_komata = ((aiz_komata*10 + 8) >> 4);    // "+8" nozīmē apaļošanu, t.i. pieskaitām 0.5

print(vesela_dala, ".", cipars_aiz_komata);
```

 To viegli varētu modificēt citam bitu skaitam aiz komata un citam decimālo ciparu skaitam aiz komata.

Cita starpā, 4 biti aiz komata translējas tikai par 1 *zīmīgu* decimālo ciparu aiz komata. Tas nozīmē, ka nav lielas jēgas pierakstam 36.1875, ja patiesībā ir 36.2 kļūdas (izšķirtspējas) robežās. _Īkšķa_ likums — katri 3-4 biti ir 1 decimālais cipars.

----------


## Jurkins

Es jau šoreiz vairāk par to principu nevis par precizitāti. "Projektā" jau ieliku tieši 16 baitu masīvu ar noapaļotām desmitdaļām.
Paldies, karloslv, man vēl tie pārveidojumi nav asinīs  :: .

----------


## Zalic

Sveiki! Mēģinu ko saprast arduino programēšanā. Visa koda sākumā ir #include ( biblotekas ja pareizi saprotu ). Nesaprotu ka pareizi jasaglaba vinu prohejkti, jo taosot vertify man izmet šo -> QTRSensors.h: No such file or directory. Visiem vailiem kas saistiti ar vienu projektu tak butu jaglabajas viena mape?

----------


## sasasa

Saglabāt var dažādi - gan kopā, gan atsevišķi. Kā pats gribi. Tev iespējams ka nepareizas zīmes <> nevis "" pēc #include, ja šie faili kopā ar *.ino. Palasi googlē par Arduino bibliotekām, tur viss izstāstīts. Gan kā instalēt (visvieglāk uzreiz no zip arhīva), gan pārējais.

----------


## Jurkins

https://www.pololu.com/docs/0J19/2
Izdarīji visu šo?
Sevišķi to, kas tajā treknajā taisnstūrī lapas augšā?

----------


## Zalic

paldies, šaja lapa nemaz nebiju  ::  vismaz kaut kas skaidrāks kļuva  ::

----------


## sasasa

> Izdarīji visu šo?
> Sevišķi to, kas tajā treknajā taisnstūrī lapas augšā?


 Domā šo:
_Download the archive from GitHub, decompress it, and drag the “QTRSensors” folder to your arduino-1.0/libraries directory.
_
Nevajag nekādu decompress, ja gribi kopējā library folderī.  Pa taisno no Arduino norādi zip failu un viņš pats viņu attaisa un noliek kur vajag. 
.. un vispar nav man kāda tur vēl biblioteka vajadzīga, lai nolasītu sensoru? Ieraksti analogRead(x) un priecājies. To ko var dažās rindiņās uzraxtīt, tur pa 2 lapām saskricelēts. . Bet nu var arī tā.
.
sorry aizmirsu ka ir šamējiem sensoriem arī "digitālā" versija, kur analogRead() nestrādā   ::

----------


## Jurkins

Nu jā, toč, nebiju ievērojis, ka Arduino izvēlnē ir "Iekļaut bibliotēku -> Pievienot .zip bibliotēku". Darīju pa vecam - nesu .c un .h ".../Documents/Arduino/libraries" folderī.

Tā bibliotēka laikam ir domāta kaut kādiem optiskajiem sensoriem, tipa melno līniju atšķirt. Tur visādas kalibrācijas, neesmu ne ar ko tādu darbojies, bet nezi vai ar pliku analodRead pietiks.

----------


## Jurkins

```
if  ( vw_rx_enabled && vw_tx_sample++ == 0) {...}
```

 Šādā konstrukcijā vw_tx_sample tiek  palielināts par "1" jebkurā gadījumā PĒC TAM kad ir veikta pārbaude NEATKARĪGI no pārbaudes rezultāta?

----------


## Texx

Vispirms notiek vw_tx_sample salīdzināšana ar nulli, tad notiek vw_rx_enabled un vw_tx_sample UN salidzināšana, tad notiek vw_tx_sample palielināšana. Palieināšana notiek jebkurā gadījumā un to izdara operators ++

----------


## Jurkins

Paldies, it kā nosimulēju ar arduino, bet gribējās pārliecināties, ka esmu pareizi sapratis.

----------


## karloslv

> Vispirms notiek vw_tx_sample salīdzināšana ar nulli, tad notiek vw_rx_enabled un vw_tx_sample UN salidzināšana, tad notiek vw_tx_sample palielināšana. Palieināšana notiek jebkurā gadījumā un to izdara operators ++


 Nebūs taisnība. C un C++ loģiskās izteiksmes rēķina slinki pēc t.s. short-circuit metodes, kad rēķināšana apstājas, tiklīdz ir zināms izteiksmes rezultāts. https://en.wikipedia.org/wiki/Short-circuit_evaluation

Līdz ar to atbilde uz Jurkina jautājumu ir tāda: ja vw_rx_enabled ir 0, tad netiks palielināts vw_tx_sample. Pretējā gadījumā tas vw_tx_sample vispirms tiks salīdzināts ar nulli un palielināts neatkarīgi no salīdzināšanas rezultāta.

Respektīvi, tas ir analoģisks kodam



```
if  ( vw_rx_enabled ) { 
  if (vw_tx_sample == 0) {...}
  vw_tx_sample++;
}
```

----------


## Jurkins

Vo velns, tātad tomēr nepareizi. Vakarā skatīšos, ko tur esmu sarakstījis. Paldies, karloslv. It kā pat biju lasījis jau par šo, bet, kad ar pirkstu iebaksta, tomēr pielec labāk un ātrāk :: .

----------


## Texx

he, he karloslv pat linku piemeklējis uz wikipēdiju. Principā varētu šim apgalvojumam piekrist, bet to jau viegli pārbaudīt kodu izpildot vai simulējot. Man slinkums. Izteicu ātro minējumu balstoties uz C izteiksmju izpildes kārtību. Principā aptuveno koda mērķi var izsecināt jau skatoties uz mainīgo nosaukumiem. 
Bet tas, ko var no šī piemēra mācīties, ka iespējams nav vērts rakstīt īsāku kodu ietaupot pāris rindiņas (nu labi arī dažas nesmukas figūriekavas  :: , toties tiek zudēta skaidrība (mazāk pierdzējušiem programmētājiem) un kā jau mēs te redzam rodas nevajadzīga galvas lauzīšana.

----------


## Jurkins

Tomēr par to alternatīvo kodu. Ja abi nosacījumi izpildās, tad 


```
if  ( vw_tx_enabled && vw_tx_sample++ == 0) {...šeit vw_tx_sample ir jaunā vērtība...}
```

 Bet


```
if ( vw_tx_enabled ){  
if (vw_tx_sample == 0) {...šeit vw_tx_sample ir vecā vērtība ...}  
vw_tx_sample++;
}

```

 Sanāk, ja to mainīgo vw_tx_sample izmanto nosacījuma "rumpī", tad kodi nav identiski. Būtu jāraksta šādi (laikam):


```
if ( vw_tx_enabled ){  
if (vw_tx_sample == 0){vw_tx_sample++;...šeit vw_tx_sample ir jaunā vērtība ...}  
else
{vw_tx_sample++;}
}

```

 p.s. Jā, nu iesācējam šitos vikrutasus ir grūti saprast. Šitas kods nav mans. Es cenšos iebraukt VirtualWire bibliotēkā...uzrakstīt to pašu asmā, lai varētu iedzīt mazajā attiny13 (nu tāds es esmu dīvainis :: ). Un tikko raidītāja gals sāka strādāt. Principā jau ar to pietiktu, bet laikam jau uztvērēju arī nelikšu mierā.

----------


## Texx

Īsti neiebraucu ko gribi panākt, un tas pēdējais kods ir neloģisks. Kādēļ lietot if, ja abos gadījumos vw_tx_sample tiek palielināts par viens?
Otrajā koda piemērā atkal pamaini vietām divas priekšpēdējas rindiņas un viss notiks, nu kas nu tur ir vajdzīgs.

----------


## Jurkins

Vairs neko negribu panākt  :: , bet ņeporjadoks.
Ja otrajā kodā pamaina rindiņas vietām, tad jau pirms pārbaudes mainīgais jau ir palielināts par 1. Tad otrais noteikums ir jāraksta if(vw_tx_sample++==0) un tā atsevišķā mainīgā palielināšanas rindiņa jāizmet.
Trešais kods izsktās neloģisks, bet ir pilnīgs analogs pirmajam.
Tāpēc laikam vajadzīgi šie skaistie samudžinātie kodi :: .

----------


## karloslv

Jurkin, tev ir taisnība, tas, ko rakstīju kā "ekvivalento" kodu, tiešām nav vis tik ekvivalents, ja grib izmantot vw_tx_sample vērtību. Pareizi esi pamanījis  ::  Jebkurā gadījumā, evaluējot "a++" a finālā tiks palielināts par vienu vienību. Tas ir postfix operators. Ja raksta ++a, tad otrādi, ar prefix operatoru vispirms tiks palielināts par 1.

----------


## Jurkins

Labs vakars! 
It kā vienkāršs kods. Kontrolierī šuvis neesmu, jo viss ir sākuma stadijā. Tātad tikai debagerī.
Kāpēc pirmo reizi ejot caur bezgalīgo ciklu debageris pārlec pāri otrajam ciklam. Pēc tam viss ir kārtībā. Kamēr skaitītājs aizskaita līdz 150, notiek ņemšanās iekš while, tad uzmetas OCF0A bits un process aizlec tālāk? Vai tas varbūt kaut kā saistīts ar kaut kādām kompilēšanas optimizācijām?   



```
#include <avr/io.h>
#include <avr/interrupt.h>

int main(void)
{
    
    DDRB = (1<<PB0);
    
    TCCR0A = (1<<WGM01);
    TCCR0B = (1<<CS02)|(0<<CS01);
    OCR0A = 150;
    
    while(1)
    {
        while(!(TIFR0&(1<<OCF0A)))
        { }
        
        PORTB ^= (1<<PB0);
        
        TIFR0 |= (1<<OCF0A);
    }
}
```

 edit: upsss! viss kārtībā. Gāju debagerī pa soļiem un nepaskatījos uz pašu portu. Šis uzlec virsū rindai, bet porta vērtība nenomainās.  Laikam vienkārši procesa vizualizācija kaut kāda greiza.

----------

