PIC16F877 + DHT22

Zdravím všechny a přeji úspěšný rok 2016,
rok se s rokem sešel a já jsem vytáhnul opět na Vánoce nějáký projekt.
Snažím se rozchodit jednoduchý program s PIC16F877, GLCD a snímačem teploty a vlhkosti DHT22. Bohužel se mi nedaří a nemohu přijít na to, kde dělám chybu, snímač DHT data posílá, ale mě se je nedaří přečíst a když už něco přečtu, tak to nedává smysl. Mám to nějak slepený z netu, ale pro Atmela myslím a něco jsem tam předělával. Mohl by se na to prosím někdo znalý podívat. Děkuju


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
	}
}

char ReadData()
{
 	char i, j;
 	for(j = 0; j < 8; j++)
	{
 		while(RA0 == 0); //Čeká dokud je RA0 v 0
 		__delay_us(30);//30 hranice mezi log 0 a log 1
 		if(RA0 == 0) //Zkouší, zda je RA0 po uplynulé době v 1 čí 0
       		i&= ~(1<<(7 - j));  //Znuluje bit
 		else 
		{
			i|= (1 << (7 - j));  //Nastaví bit do 1
 			while(RA0 == 1); //Čeká dokud je RA0 v 1
			break;
		}
 	}
 	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();

	unsigned int i = 0;
	char text1[16];
	char text2[16];

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

	TRISA = 0b00000000;    //RA0 jako vstup
	TRISC = 0b00000000;
	__delay_ms(1000);

	while(1)
  	{
		GLCD_ClrScr();
		StartSignal();
		CheckResponse();

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

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

		sprintf(text1,"Teplota: %d^C            ",teplota/10);
		GLCD_text(0, 4,text1 );
		sprintf(text2,"Vlhkost: %d `            ",vlhkost/10);
		GLCD_text(0, 6,text2 );

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

		RH_byte1 = 0;
		RH_byte2 = 0;
		T_byte1 = 0;
		T_byte2 = 0;
		teplota = 0;
		vlhkost = 0;

	}//end while(1)
}//end main

Bez logického analyzéru nebo křišťálový koule asi těžko.

Tady jde třeba, jestli by jste nepoužili jiné datové typy, atd.
Data ze snímače lezou, to už jsem kontroloval.

Nejde o to jestli lezou, ale jaká a jak přesně lezou… Sry, ale prinscreen z analyzéru je prostě víc, než „Data ze snímače lezou, to už jsem kontroloval.”, pak až můžem navázat se čtením a odpovídat na dotazy (a taky až uvedeš co to máš za kompilátor - SDCC, XC8 nebo něco jiného?). Obecně první prostě musí být z čeho vyjít, aby to nebyla ztráta času pro všechny strany, jen tvrzení nestačí.

Ok, omlouvám se. V příloze je prinscreen, jenom teda z PICkit2. Další kdyžtak udělám. Kompiler používám HI-TEC C PRO.

200us/dílek, to asi opravdu budeš muset přidat lepší. Jinak v datasheetu toho „zázraku” píšou že je to DS18B20 + přidanej senzor vlhkosti, takže 1-wire, takže by ti asi dost pomohl datasheet přímo od toho DS18B20 (pokud se ho číňani drželi aspoň trochu), tam je popsaný jak má vypadat 1-wire (možná tak vypadá, ale podle toho co jsi přiložil to fakt nepoznám).

Jinak teda říkám narovinu dopředu že nejsem céčkač, takže odchytávání vstupu v Cčku bude výzva trochu víc než v ASM (ale analyzér bude potřeba tak či onak, bez něj se sériové komunikace ladí hodně těžko, takže do budoucna si určitě pořiď od soudruhů saleae klon pokud nemáš, stojí to dvě stovky a práce to za ty prachy nadělá až až).

A na tuhle ptákovinu jsi přišel jak ? Datasheet od DHT11 tu mám před sebou a nic takového tam není. Je tam ale celkem dobře popsáno, jak spustit přenos, jak dlouhý má pulz být a jak vypadají bity, které DHT11 vrací a jak data intepretovat. Je to tam popsáno dost detailně.

Odpověď se skrývá pod heslem „On ale nemá DHT-11” a googlovským výsledkem hledání „k čínskýmu pajcu čínskej datasheet” (a navíc to nic nemění na tom, že si to navzorkoval s malým rozlišením :wink: )

Je to děláný PICkit2kou, ale objednám z eBay lepší a budou lepší snímky :slight_smile:

Nebo si z práce půjčím oscilo, to bude nejrychlejší :slight_smile:

B0sc0: Logický analyzátor se Ti hodí (osciloskop je v tomhle případě poněkud těžkopádný, pokud nemáš k dispozici paměťový), nicméně tentokrát bych řekl, že Tvůj PICkit2 to zvládnul. Trochu jsem pohledal a DHT22 posílá data sice stejným způsobem jako DHT11, ale rozkódovat je musíš trošku jinak. Pokud jsem dobře počítal a simulační software nekecá, tak jsi z čidla dostal 02 01 00 E4 E7 (kontrolní součet tam sice nemáš zachycený celý, ale je to nižších 8 bitů součtu bytů na pozicích 0-3). První 2 byty jsou 10xvlhkost, druhé 2 byty jsou 10xteplota. 0x0201 je 513 => 513/10 = 51,3%, teplota je 0x00E4 = 228 => 228/10 = 22,8°C.

Záporná hodnota není kódovaná “klasicky”, ale hodnota je doplněná jedničkou na bitu 15 :
0x00E4 = 228 => 22,8°C
0x80E4 = -228 => -22,8°C

Díky Balů, ten saleae analzátor jsem již objednal. Ty hodnoty sedí, ale nevím proč mi je nechce stonožka načíst a zobrazit. :-/

A nemůže být chyba tady ?

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

Jestli se nepletu, tak unsigned char má 8 bitů. Neměl bys tam mít unsigned int místo unsigned char ?

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

To je přesně to, k čemu jsem myslel, že se vyjádříte. Až příjdu z práce, tak se na to mrknu. Díky
Ten princip toho přenosu je celkem jednoduchej, tak nechápu, že to nechodí :slight_smile:

To je tak, když si neprojdu pořádně program a hledám problém tam, kde evidentně není … Jsem zvědavý, jestli je to ono.

A navíc by, jestli se dobře dívám, měly být ty proměnné volatile , nebo ne?

Tak jsem zkusil dát

unsigned int teplota;
unsigned int vlhkost;

a pokaždé mi to vyčte něco jiného, udělal jsem x opakování a vyčtlo mi to:
Teplota: 4112;-32704;32704;20496;3084;-28664;12296;-32704;-12272
Vlhkost: 8224;8192;4096;1154;4240;4112;128;4176

Nevím, proč je u teploty sem tam záporná hodnota, když by to mělo být unsigned. Hodnoty nejsou děleny 10.

Se mi zdá, že to čte jak se mu chce, zkusím si pohrát se zpožděním u rozpoznávání 0 a 1.

Pak ještě zkusim

volatile

Upravil jsem si program, aby mi vypisoval i číslo měření, protože sem tam se mi to sekne a nedostane se to ani do while(1) a kolikrát to přestane i měřit.

Když tam dám u teploty a vlhkosti

volatile unsigned int

tak mi to vypíše hned při prvním měření u hodnot měření, teploty a vlhkosti 8224 a tu to vypíše vždycky při dalších měřeních.

Můj program teď vypadá takto

[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
}
}

char ReadData()
{
char i, j;
for(j = 0; j < 8; j++)
{
while(RA0 == 0); //Čeká dokud je RA0 v 0
__delay_us(40);//30 hranice mezi log 0 a log 1
if(RA0 == 0) //Zkouší, zda je RA0 po uplynulé době v 1 čí 0
i&= ~(1<<(7 - j)); //Znuluje bit
else
{
i|= (1 << (7 - j)); //Nastaví bit do 1
while(RA0 == 1); //Čeká dokud je RA0 v 1
break;
}
}
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(); 

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

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

   TRISA = 0b00000000;    //RA0 jako vstup 
   TRISC = 0b00000000; 
	int a =0;
   __delay_ms(1000); 

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

  sprintf(text3,"Mereni: %d                ",a); 
  GLCD_text(0, 2,text3 ); 
  sprintf(text1,"Teplota: %d^C            ",teplota); 
  GLCD_text(0, 4,text1 ); 
  sprintf(text2,"Vlhkost: %d `            ",vlhkost); 
  GLCD_text(0, 6,text2 ); 

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

while(1) 
{ 
	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(text3,"Mereni: %d                ",a); 
  GLCD_text(0, 2,text3 ); 
  sprintf(text1,"Teplota: %d^C            ",teplota); 
  GLCD_text(0, 4,text1 ); 
  sprintf(text2,"Vlhkost: %d `            ",vlhkost); 
  GLCD_text(0, 6,text2 ); 
	a++;

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

  RH_byte1 = 0; 
  RH_byte2 = 0; 
  T_byte1 = 0; 
  T_byte2 = 0; 
  teplota = 0; 
  vlhkost = 0; 

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

Tak mě napadá, jestli v tý funkci ReadData :

  1. Není ten break v cyklu for tak nějak navíc ? Jakmile se break provede, ukončí se cyklus for bez ohledu na j - vyhoď ho.
  2. Když před cyklem for dáš i=0, tak Ti stačí podmínka

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 }

mozna je chyba nekde v prevodu ale zameril bych se nejdrive na vycteni konstantni hodnoty z cidla,takze bych to hodil na LA , pripojit tam jeste vystup z picu a ten bych togloval pri cteni toho cidla aby bylo jasny kdy se cte stav toho cidla…

Tak teď mi to z nějákýho důvodu nechce nic načíst.

Ten break; je tak fakt asi navíc, když se ne to teď dívám, tak by to mělo být asi takto

int ReadData() { int i, j; for(j = 0; j < 8; j++) { while(RA0 == 0); //Čeká dokud je RA0 v 0 __delay_us(30);//30 hranice mezi log 0 a log 1 if(RA0 == 0) //Zkouší, zda je RA0 po uplynulé době v 1 čí 0 i&= ~(1<<(7 - j)); //Znuluje bit else i|= (1 << (7 - j)); //Nastaví bit do 1 while(RA0 == 1); //Čeká dokud je RA0 v 1 } return i; }

Togloval nevíc co znamená, ale tipnul bych si, že to má hodit puls, když to načte něco. Je to tak