PIC16F877 + DHT22

MiloPS3:
Vzorkování mám 250 kHz, 4 ms okno.
Simulátor žádnej nepoužívám.
Kdystal 2 MHz a nastaneno taky 2 MHz.

Tak z toho zdrojáku pro Arduino nejsem vůbec chytrej. Je to úplně neco jinýho než Cčko pro HI-TECH

Ať se synchronizujeme, tak tady je aktuální vezde kódu. Už pomale přestávám vnímat co ej co :-/

[code]unsigned char Check;

void StartSignal()
{
TRISA = 0b00000000; //PORTA je výstup
RA0 = 0; //RA0 jde do 0 = startovacísignál
__delay_ms(18);//18
RA0 = 1; //RA0 se vrací do 1
__delay_us(30);
TRISA = 0b11111111; //PORTA je vstupní
}

void CheckResponse()
{
Check = 0;
__delay_us(40);
if (RA0 == 0)
{
__delay_us(80);//80
if (RA0 == 1)
Check = 1;
__delay_us(40);//40
}
}
int ReadData()
{
int i=0, j;
for(j = 0; j < 8; j++)
{
RC6 = ~RC6;
i = 0;
/ while(RA0 == 0); //Čeká dokud je RA0 v 0
__delay_us(35);//30 hranice mezi log 0 a log 1
if(RA0 == 1) //Zkouší, zda je RA0 po uplynulé době v 1 čí 0
{
i|= (1 << (7 - j)); //Nastaví bit do 1
while(RA0 == 1); //Čeká dokud je RA0 v 1
}
}
return i;
}
void main(void)
{
PSPIE = 0;
PSPMODE = 0;
ADCON1 = 7;
TRISA = 0b00000000;
TRISB = 0b00000000;
TRISC = 0b00000000;
TRISD = 0b00000000;

   GLCD_Init(); 
   __delay_ms(100); 
   GLCD_ClrScr(); 

   int i = 0; 
   char text1[16]; 
   char text2[16];
   char text3[16]; 
   char text4[16]; 
   char text5[16]; 

   GLCD_ClrScr(); 
       
     int T_byte1, T_byte2, RH_byte1, RH_byte2; 
 int Temp, RH, Sum ; 

   TRISA = 0b00000000;    //RA0 jako vstup 
   TRISC = 0b00000000; 
	int a = 0; 

  unsigned int teplota =  0;
  unsigned int vlhkost =  0;

  sprintf(text5,"Mereni: %d                ",a); 
  GLCD_text(0, 2,text5 ); 
  sprintf(text1,"Byte 1: %d               ",teplota); 
  GLCD_text(0, 4,text1 ); 
  sprintf(text5,"Byte 2: %d               ",teplota); 
  GLCD_text(0, 5,text5 ); 
  sprintf(text3,"Byte 3: %d               ",teplota); 
  GLCD_text(0, 6,text3 ); 
  sprintf(text4,"Byte 4: %d               ",teplota); //^C
  GLCD_text(0, 7,text4 ); 

  RC7 = 1; __delay_ms(100); RC7 = 0; __delay_ms(500); 

while(1) 
{     
  RH_byte1 = 0; 
  RH_byte2 = 0; 
  T_byte1 = 0; 
  T_byte2 = 0; 
  teplota = 0; 
  vlhkost = 0;       



	StartSignal(); 
	CheckResponse();

	RH_byte1 = ReadData(); 
	RH_byte2 = ReadData(); 
    T_byte1 = ReadData(); 
    T_byte2 = ReadData(); 
    //Sum = ReadData(); 


//	teplota = (T_byte1  << 8 )| T_byte2; 
//	vlhkost = (RH_byte1 << 8 )| RH_byte2; 

	GLCD_ClrScr(); 

  sprintf(text5,"Mereni: %d                ",a); 
  GLCD_text(0, 2,text5 ); 
  sprintf(text1,"Byte 1: %d               ",RH_byte1); 
  GLCD_text(0, 4,text1 ); 
  sprintf(text2,"Byte 2: %d               ",RH_byte2); 
  GLCD_text(0, 5,text2 ); 
  sprintf(text3,"Byte 3: %d               ",T_byte1); 
  GLCD_text(0, 6,text3 ); 
  sprintf(text4,"Byte 4: %d              ",T_byte2); 
  GLCD_text(0, 7,text4 );  
	a++;

  RC7 = 1; 
  __delay_ms(500); 
  RC7 = 0; 
  __delay_ms(500); 

}//end while(1)
}//end main[/code]

Tak tady to máš ještě pro mbed, je to v podstatě ta samá knihovna, ale v C a líp okomentovaná. To podstatný je spíš v druhý půlce toho kódu, řeší se tam věci jako čekání na začátek a konec ACKu, délka pulzu apod. Taky z toho plyne, že DHT-22 posílá 16bitový hodnoty.

developer.mbed.org/users/hwkit/ … ource.html

Asi bych nad tím nemudroval a vzal si to celý, když už to někdo napsal.

Díky Anonyme, podívám se na to.

No to nemáš zač, hlavně když to nějak rozjedeš (nezapomeň nám to sem pak napsat; pokud bys neuspěl, budem pokračovat)

Já mám trošku obavu, aby to jen při 2 MHz nebylo nad výkonnostní možnosti PICu, protože (pokud si správně pamatuju), tak PICy mají 4 takty hodin na instrukci. Mezi dvěma nulama máš (po odečtení 35us pauzy pro čtení bitu) k dispozici jen asi 20 instrukcí mcu na to, aby ses dostal před další náběžnou hranu. Během jednoho bytu to asi stihnout jde, ale mezi bytama už to asi bude problém - je tam návrat z funkce, uložení hodnoty do proměnné a zavolání funkce znovu. Tam si myslím, že bude největší časový problém… A to počítám s tím, že délka high pulzu bude trvat 30us. Pokud bude pulz kratší (podle datasheetu je minimum 24us), tak se dostáváš na nějakých 18 instrukcí a jakmile Ti uteče nějaký bit, tak Ti funkce zůstane viset na řádku while(RA0 == 0); //Čeká dokud je RA0 v 0 , protože tam nemáš timeout na čekání na náběžnou hranu. Dal bych Ti sem funkční kód pro AVRko, ale nevím, jestli by Ti to pomohlo - je to psaný v assembleru.

Assemble mi nic nedá, jsem rád, že jsem se dostal alespoň trošku do Cčka, mým osobním vrcholem je rozchození GLCD, jsem fakt byl na sebe pyšnej :smiley:

Jinak zkusím doma použít 20 MHz krystal, aby jsme mohli zavrhnout, že to nestíhá

Z čeho vyplynulo že to má na 2MHz, z toho LA záznamu? Přemejšlím nad tím totiž celou dobu na kolika to asi má, nějak nám to nikde nenapsal (a nebo jsem slepej).

20MHz bude dobrých.

Aha už jsem to našel, tak jsem prostě slepej :laughing:

Oprava :

Při ztrátě bitu zůstane funkce viset tady :

          while(RA0 == 1); //Čeká dokud je RA0 v 1

Visí v čekání na RA0 v low, což je ukončení jedničky a začátek dalšího bitu, případně End packetu (což je vlastně jenom 54us dlouhá low mezera a pak už jenom high “ticho” na lince). Ten už ale nepřijde. Výsledek je ale úplně stejný - zůstane to viset. A tím, že výsledky posíláš na displej až po načtení všech bytů (což je samozřejmě logické), tak se Ti zdá, že to nic nenačte …

Tak bohužel jsem našel akorát 20 MHz crystal, ale po upravení programu a záměně kondíků na 22 pF mám rozhašenej GLCD, což nechápu, 20 MHz je maximum. Tak v týdnu se budu muset stavit koupit cca 8 nebo 10 MHz.

V tom případě jsi na ten GLCD moc rychlej. Asi budeš muset upravit obsluhu GLCD - prodloužit prodlevy a délky impulzů, aby ses vešel do časů z datasheetu. Nebo zkontrolovat nastavení. Pokud v Cčku napíšeš Waitms(1), pak musíš mít v překladači správně uvedenou rychlost hodin, aby 1 milisekunda trvala opravdu 1 milisekundu … A pokud máš program Zapni signál Vypni signál

a GLCD nestíhá, tak tady při 20MHz krystalu musíš dát něco mezi :

Zapni signál Počkej pár us Vypni signál

Protože mezi nahozením a shozením máš při 2MHz 2us, při 20MHz je to jenom 0,2us=200ns.

electrosome.com/blinking-led-pic-microcontroller-hi-tech-c/

v tvém případě to bude

#include <htc.h> #define _XTAL_FREQ 20000000

Přesně tak to mám uvedeno v kódu, takže to bude něco s tím, že je to moc rychlé na GLCD a budu to muset tedy někde upravit.

Pokud máš v kódu poslání pulzu stylem

Zapni signál Vypni signál

tak Ti žádné nastavování frekvence krystalu nepomůže - není tam prostě žádné čekání - viz. můj předchozí příspěvek.

Většina displejů vyžaduje délku impulzu minimálně 1us - což je v případě PICu na 20MHz 5x déle, než jednou instrukcí zapnout a hned další instrukcí vypnout. Tam už čekání dát musíš…

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…