const int dataPin = 2; /* Data I/O */ 
const int numBit = 40; /* numero data bit */ 
volatile uint32_t m1; // m1 per lettura sequenza 
volatile int8_t stato, bit_count; 
volatile uint8_t rby[5], cksum, olds; 
#define FLOW 50 
#define ZERO 26 
#define UNO 70 
#define INIZIO 80 
#define SREAD 18 
#define OKREAD 6 
#define FERR -1 
void setup() 
{ 
	Serial.begin(9600); 
	char tString[ 10 ]; 
	// Inseriamo un controllo dei tempi 
	Serial.print( "F_CPU: " ) ; 
	Serial.println( ltoa( F_CPU, tString, 10 )) ; 
	Serial.print("CyclesMillis = "); 
	Serial.println(microsecondsToClockCycles(1000)); // cicli per mS 
	pinMode(dataPin, OUTPUT); // default Output 
	digitalWrite(dataPin, HIGH); // Stato riposo 
	for(uint8_t i = 0; i< 5; i++) rby[i]=0; 
	delay(1000); // Un secondo di salvaguardia 
	digitalWrite(dataPin,LOW); // Invio impulso di lettura 
	delay(SREAD); // Durata = SREAD mS 
	digitalWrite(dataPin,HIGH); 
	pinMode(dataPin, INPUT_PULLUP); // Switch dataPin come INPUT 
	stato=bit_count=m1=0; // Aspetto il bit_change 
	olds=HIGH; 
	
attachInterrupt(digitalPinToInterrupt(dataPin), dh11in, CHANGE); 


} 

void loop() 
{ 
	if(stato < 0) Serial.println("Framing Error"); 
	else if(stato == OKREAD || Serial.available( )) 
	{ 
		uint8_t cksum=0; 
		for(uint8_t i = 0 ; i< 4; i++) cksum +=rby[i]; 
		if(cksum == rby [4]) 
		{ 
			Serial.print("Umidità: ");
			Serial.print(rby[0]); 
			Serial.print(","); 
			Serial.print(rby[1]); 
			Serial.print(" Temperatura: "); 
			Serial.print(rby[2]); 
			Serial.print(","); 
			Serial.println(rby[3]); 
		} 
		else Serial.println("CheckSum Error"); 
		stato = 0; 
		while (Serial.available()) Serial.read(); 
	} 
} 


void dh11in() { 
	uint32_t mx = micros(); 
	uint8_t news = digitalRead(dataPin); 
	//uint8_t news = PIND & _BV(dataPin);
	if(news == olds) stato = FERR; 
	else 
	{ 
		m1 = mx-m1; 
		switch(stato) 
		{ 
			case 0: // Attendo sequenza di L, non conto il tempo 
				if(news == LOW) stato++; 
			break; 
			case 1: // Attendo sequenza LH, verifico tempo 
				if(news == HIGH) WaitFor(INIZIO, m1); 
			break; 
			case 2: // Attendo sequenza HL, verifco tempo 
				if(news == LOW) WaitFor(INIZIO, m1); 
			break; 
			case 3: // Attendo sequenza LH, verifco tempo
				if(news == HIGH) WaitFor(FLOW, m1); 
			break; 
			case 4: // Misuro durata H 
				if(news == LOW) ZeroUno(ZERO, UNO, m1); 
			break; 
			case 5: // Attendo sequenza LH, verifco tempo 
				if(news == HIGH) 
				{ 
					WaitFor(FLOW, m1); 
					detachInterrupt(digitalPinToInterrupt(dataPin)); 
				} 
			break; 
		} 
		m1=mx; 
		olds=news; 
	} 
} 

void ZeroUno(uint8_t t0, uint8_t t1, uint8_t t)
{ 
	uint8_t i = bit_count/8; 
	uint8_t by = rby[i]; 
	by <<=1; 
	bit_count++; 
	if(t < (t0+t0/2)); 
	else if(t < (t1+t1/2)) by |=1; 
	else stato = FERR; 
	rby[i] = by; 
	if(bit_count >= numBit) stato = 5 ; 
	else stato = 3; 
} 

void WaitFor(uint8_t tx, uint8_t t)
{ 
	if(t < (tx+tx/2) && t > (tx-tx/2)) stato++; 
	else stato = FERR; 
}