PIC16F877 + DHT22

Aspoň kdyby napsal co má za přesně GLCD, a taky hlavně když bude kupovat krystaly, tak ať si vezme sadu různých. Já třeba s oblibou používám krystal s frekvencí 4.1943MHz, protože pak mi stačí při časování jen počítat přetečení časovače a nemusím vkládat žádné další instrukce navíc nebo odchytávat nějaká čísla, ale to je jednak známá finta, a druhak nevím, jestli ho tohle v C nějak zajímá (ale možná by to mohlo trochu zmenšit velikost kódu, protože jestli je ten C kompilátor jen trochu chytrej, tak to tak bude překládat taky).

To jsem se blbě vyjádřil. Je mi to jasné Balů, tím upravováním jsem myslel, že tam dám nějáké zpoždění v tý komunikaci s GLCD.
Krystali jsem si vzal opravdu různé, 4, 6, 8, 10, 12 a 16 MHz.
Škoda s tím 4,1943 MHz až budu mít cestu okolo GM, tak se pro něj stavím.

Zkusil jsem si to hodit do kalkulačky na eng-serve.com/pic/pic_timer.html , ale nic kloudného mi nevylezlo. Jsem byl v očekávání, že vyleze nějáké pěkné číslo aniž bych musel používat TMR0, např.: 0,0001s apod. Jak jsi to přesně myslel? Dík

Nepotřebuješ nic počítat - na krátké časy použij Waitus a neřeš to. Pokud Ti to na 2 MHz psalo správně, mezi dvěma instrukcemi byl čas 4/2000000=2us. Pokud máš krystal 20MHz a displej nestíhá, je čas mezi dvěma instrukcemi 4/20000000=0,2us=200ns, a musíš délku pulzu prodloužit, stačí Ti na to pár NOP instrukcí. Maximálně jich bude 9, aby ses dostal na stejnou délku impulzu jako při 2 MHz. Čistší v tomto případě je vložit třeba Waitus(1) případně Waitus(2). Timer používej na delší časy. Pokud potřebuješ třeba 10ms, pak je lepší nastavit timer tak, aby třeba každou 1 ms přetekl a vyvolal přerušení. Proveď první část úkolu, pak si nastav nějakou proměnnou na 10 a cyklicky jí kontroluj, jestli není nula. Jakmile bude 0, uplynul čas a vykonej, zbytek (nebo třeba jenom další část a opět nastavíš proměnnou na nějaké čekání). V přerušení kontroluješ tuto proměnnou a pokud je větší, než 0, tak odečteš jedničku. Dostaneš čas 9-10 ms (podle toho, jak často k přerušení bude docházet). Pokud nastavíš timer na přerušení každých 0,1ms=100us, pak dostaneš čas 9,9-10ms. Tímto způsobem de-facto rozfázuješ to, co potřebuješ udělat, nevytížíš procesor čekáním a můžeš dělat i další věci, které potřebuješ.
Pokud procesor nedělá nic jinýho, můžeš použít i Waitms. Pokud ale třeba reaguješ na tlačítka apod., měl bys používat Waitms tak maximálně do 1-2 ms.

Zkus porovnat chování :

[code]Preruseni_1ms:
{
if (CekaniNaLedku>0) --CekaniNaLedku;
}

Hlavni_smycka:
{
if (CekaniNaLedku==0)
{
PrepniLedku();
CekaniNaLedku=500;
}
VstupniPin=Rxy; // Načti pin Rxy do proměnné
if ((VstupniPin==0)&&(MinulePin==1))
{
if (ReleOutPin==0)
{
ZapniRele();
}
else
{
VypniRele();
}
}
MinulePin=VstupniPin;
}[/code]

Hlavni_smycka: { Waitms(500); PrepniLedku(); VstupniPin=Rxy; // Načti pin Rxy do proměnné if ((VstupniPin==0)&&(MinulePin==1)) { if (ReleOutPin==0) { ZapniRele(); } else { VypniRele(); } } MinulePin=VstupniPin; }

Na první pohled se oba programy chovají stejně - oba blikají LEDkou frekvencí 1 Hz, oba zapínají/vypínají relé při stisku tlačítka. JENŽE … Zatímco v prvním případě reaguje relé na tlačítko vždy prakticky okamžitě, ve druhém reaguje relé někdy hned a někdy až za 0,5 sekundy. Tohle asi bude princip, který se Ti Anonym naznačoval. Pro časy v délce několika mikrosekund je to postup vcelku zbytečný.

Malá poznámka - Příklad neřeší zákmity tlačítek…

Ano, samozřejmě že jsem si je opět popletl :laughing: Ta druhá oblíbená frekvence je 3.2768MHz, TMR musíš použít vždycky, ale jinak ano, přesně o to jde:

V datasheetu se píše:

[code]bit 2-0 PS2:PS0: Prescaler Rate Select bits

Bit Value TMR0 Rate
000 1:2
001 1:4
010 1:8
011 1:16
100 1:32
101 1:64
110 1:128
111 1:256[/code]

3.2768MHz = 3276800Hz, tedy 8bit předdělička nastavená třeba na 1:32 (100) + 8bit TMR0 = 1:8192. (3276800 / 4) / 8192 = 100Hz, tedy krásných 0,01s. Stačí už jen sčítat.

Další takovej podobnej krystal by byl třeba 6.5536MHz

Anonym: Já tedy nevím, ale ten výpočet mi nějak nesedí :
3 276 800 / 32 = 102 400
8-bitový timer je 256 => 102 400 /256 = 400 Hz => 0,0025 s = 2,5ms

Ledaže by jeden tik timeru přišel až po 4 taktech systemových hodin.

Pokud je jeden tik timeru = 1 tik systémových hodin, pak předděličku 110 => 1:128
3 276 800 / 128 = 25 600
25 600/256 = 100 Hz.

Ale tak to přesně je, v těchto malých PICech je všechno fosc/4, i pro časovač

Aha - tak to pak jo.

Jinak teda když už jsme nakousli časomíru, tak to ještě doplním: S tou původní frekvencí co jsem psal prve by to šlo taky, ale muselo by se to vydělit až na jedničku, což je (fosc/4) / 2^20, takže by na to nestačil TMR0 s předděličkou (a nebo stačil, ale dostali bychom 16Hz který bysme si museli ještě podělit sami v rutině přerušení, tj. započítat jen každou 16. obsluhu). Jinak pak je ještě vhodná frekvence krystalu např. 4.096MHz, kde by stačilo stejně jako u těch 3.2768MHz a 6.5536 MHz krystalu jen podělit 1x nějakou vhodnou mocninou 2 a pak už jsme na desítkových počtech, protože to po tom prvním dělení tou mocninou vychází už kulatý.

S klasickýma frekvencema jako 4MHz apod to nikdy nevychází pořádně a musí se připočítávat korekce, protože to nejde bezezbytku dělit dvěma. Teď jsou tedy Cčkaři chytřejší v tom jak to vlastně funguje (a jak to dělají assembleristi) a můžou to klidně dělat stejně a na DelayNěco se vykašlat, když budou chtít (možná tím ušetří nějaký místo v paměti programu).

Myslel jsem samozřejmě mocniny dvou, ne dvojku jako takovou.

Omlouvám se, tento týden na to nemám moc času, stihl jsem jenom zkusit koupené krystaly a funguje to do 8 MHz a pak to začíná blbnou, vynechává to každej druhej byte na displeji. Ale vypadá to, že ten problém byl v tom, že to nestíhalo, už to čte častěji, jen se mi zdá, že v blbejch místech, viz příloha.
333.rar (8.09 KB)

Jestli tam máš kód, který jsi naposled označil jako aktuální, pak čte v pořádku. LEDku invertuješ jenom před čekáním na náběžnou hranu, takže takhle jak to máš je to OK. Okamžik čtení bitu tam “označený” nemáš, to bys musel LEDku invertovat ještě jednou hned po __delay_us(35), abys viděl, ve kterém místě to fyzicky bit čte, ale podle toho, co jsem viděl, tak to už stíhá bez problémů. Před náběžnou hranu se dostane včas a s dostatečnou rezervou…

Nevím jak to myslíš že to má OK, ale vzhledem k tomu že ten sensor má významy těch bitů definovaný trochu jinak než jsme zvyklí z DS18B20, tak by ten kód asi měl ještě upravit.

Jde o to, že bude muset měřit délky pulsů toho signálu z čidla, protože jednak jsou významy dle datasheetu takové, že krátká log.1 = významově „databit je v nule” a dlouhá log.1 = „databit je v jedničce”, a druhak každý to čidlo může mít v rámci nějakých výrobních odchylek tu komunikaci různě rychlou, takže z toho plyne, že nějaký __delay_ms(35); apod napevno v tom kódu v podstatě nemá co dělat, protože i kdyby to náhodou nějak na tomhle čidle rozchodil, tak po jeho výměně se mu ta komunikace stejně zase rozsype. Navíc z toho datagramu jde vidět, že to ani nedočetl do konce (po 16 pulsech mu to přestalo togglovat - dobře, beru, asi ho teplota nezajímá, ale: 1. na konci tý komunikace je nějakej checksum 2. nevím jak čidlo reaguje na přerušení komunikace, podle toho datagramu to vypadá že si vysílá vesele dál, na což je případně potřeba myslet před zahájením dalšího čtení).

Algoritmus čtení z čidla je v mbed knihovně kterou jsem sem už linkoval, a to i včetně měření délky pulsů. Je to v podstatě nejjednodušší způsob jak to udělat (je to jen pár podmínek), nevím proč si to z toho nechce vzít a radši se moří s něčím, co z principu fungovat nebude. Další možnej způsob by byl že by si to pokaždý odměřil např. čítačem/časovačem (když píšu „odměřil” tak myslím hardwarově, takže žádný delay), ale to by musel přepojit vstupy a použít CCP modul.

Tomu měření délky pulzů bych se chcel zatím vyhnot a vrátit se k tomu až třeba později.
Ano, nedočetl jsem to dokonce, vyčítal jsem jenom první dva byte, tak proto je to jenom u vlhkosti.

Anonym: Tak to jsi asi nečetl datasheet toho DHT22.

Tam je jasně napsáno, že :
Host start signal min. 0,8ms, max. 200ms
Bus master release min. 20us, max. 200us
Response low je dlouhý min. 75us, max. 85us
Response high je dlouhý min. 75us, max. 85us
0 má pulz dlouhý min. 22us, max. 30us
1 má pulz dlouhý min. 68us, max. 75us.
Odstup mezi bitama (low) min. 48us, max. 55us.
Senzor release (low) min. 48us, max. 55us.

Tudíž po 35us od náběžné hrany je na drátu buď log. 0 = bit 0 nebo log. 1 = bit 1. Nikde jsem nepsal o tom, že je to stejné jako DS18B20 a nevím, kde jsi na tuhle pitomost přišel. Není potřeba nic měřit - prostě najít náběžnou hranu, počkat 35-60us a přečíst pin => mám bit. Pokud je v datasheetu nějaká maximální hodnota, tak jí musí splňovat (toleranci tam má). Pokud ne, je to zmetek a nemá cenu se s ním zabývat. Pokud čidlo nedodrží parametry v čase, není důvod se domnívat, že bude měřit v tolerancích napsaných v datasheetu.

A to, že četl jenom 2 byty jsem si všimnul, nicméně je to celkem jedno - prostě přečetl vlhkost a na zbytek se vykašlal - to ještě neznamená, že mu to nechodí.

B0sc0: Měřit délku pulzu nemusíš. Stačí dát _delay_us(35) … Co bych ale udělal, to jsou timeouty při čekání na nějakou hranu - a to nejenom při čtení dat, ale i při kontrole response pulzu. Může se Ti stát, že ztratíš bit (jak jsi viděl, tak na 2 MHz jsi je ztrácel běžně), zlomí se drátek k čidlu nebo ho odpojíš a pak ti to tu zamrzne. Je potřeba, abys třeba po 1 ms ukončil čekání a vrátit zpátky chybu …

Netvrdil jsem nikde že jsi o něm něco psal (o DS18B20), mluvím o něm a srovnávám s ním proto, že DHT-22 používá něco, co je jakože ‘1-wire’, ovšem to „jakože” je v tomto případě hodně důležité, protože oproti skutečnému 1-wire je tu dost rozdílů (jako např. že u skutečnýho 1-wire to probíhá tak, že shodím úroveň do nuly a přepnu na vstup, a čidlo mi tu nulu buď prodlouží nebo neprodlouží, ale měřím vždy ve stejném místě, protože datasheet přesně definuje kde mám měřit a konunikaci řídím vždy já, kdežto tady to tak nejde).

Je hezký že jsi tu vypsal časová rozmezí jednotlivých impulsů, ale tím jsi jen potvrdil co jsem psal, protože ty rozestupy jsou v různých místech komunikace prostě různý (myslím u různých čidel, nespoléhal bych moc na to že nula bude vždy max. 28µs a víc ani pikosekunda). Jinými slovy, musí ho zajímat vždy náběžná hrana každého pulsu (neříkám že nezajímá) a od ní nejlíp měřit, ale on píše že měřit nechce - „včil babo raď”.

Navíc teda jak jsi psal prve, ať si ten toggling aspoň dá za ten delay, ať teda vidíme kde skutečně testujeme, jinak to tam máme k ničemu.

Nebo ještě jinými slovy - podívej se pořádně na ten datagram: Má testovat jedničky a testuje nuly - jasně, má toggling ještě před delay, ale to by měl být mimo o 35µs cca, ale on je mimo na začátku asi o 120µs a dál se ten rozdíl ještě zvětšuje, tak jak můžeš napsat že to má ok? Ať to togglí po delay a změří to znova, pak můžem mudrovat dál.

Už od rána se těším až to zkusím dát za delay, večer dám vědět :slight_smile:

Jak víš, že testuje nuly ? Myslím, že by ses měl pořádně podívat Ty. První dva dlouhé pulzy jsou 80us dlouhé. Odstup od sestupné hrany k jeho toggle NENÍ 120us, ale nějakých 32-33us. On totiž dílek, tedy těch 50us, je od jedné dlouhé čáry ke druhé. Ty krátké čárky jsou po 10us. V tomhle datagramu se nemůžeš dívat na to, kde je toggle, resp. jak daleko je od té které hrany - tady je to úplně jedno, protože :

  1. udělá toggle
  2. čeká na náběžnou hranu (to je while smyčka, ne přesně daný delay)
  3. počká 35us (to je přesně daný delay)
  4. přečte si stav pinu
  5. případě, že je pin high, tak počká na low (opět while smyčka)

Tím smyčka končí a jde na 1) nebo po 8. bitu vrátí hodnotu. Všimni si, že toggle dělá PŘED ČEKÁNÍM na náběžnou hranu, takže toggle = vstup do smyčky, následuje náběžná hrana a 35us po ní čte pin, jenže ve kterém je to místě nezjistíš, protože tam toggle NENÍ !!!. Místo, kde čte si můžeš jenom odpočítat a říct “tady někde se čte pin”. Ten high impulz pro 0 trvá cca 25us, pro 1 trvá asi 68us. Z toho plyne, že číst by měl cca 1 čárku za sestupnou hranou nuly, v případě jedničky zcela bezpečně cca v polovině pulzu.

Než něco napíšeš, měl by sis především pořádně prohlídnout program, projít datasheet, zkontrolovat, jestli jsi v datagramu pochopil správně dílky a pak to ještě jednou zkontrolovat.

Nech si ty osobní invektivy, jo (myslím tu poslední větu)? Od toho tu nejsme, abysme si nadávali. Už jsem tu jednou psal že z toho záznamu z pseudoanalyzéru nejsem moc chytrej.

Jo, to vím taky že nemá značku tam kde ji má mít. Když se něco ladí, tak se značky (jo, to je ten toggling) dělají proto, abysme viděli, ne proto aby se něco dopočítávalo, dělat značku před čekací smyčkou tedy jaksi postrádá význam.

Počkám až to změní a s čím pak přijde.