#include "wiring_private.h"
// TM1637
#define CLK 3
#define DIO 4
volatile uint8_t dataTM[4] = {0xff, 0xff, 0xff, 0xff};
// DHT22
#define DHT22_PIN 5
volatile uint8_t dataDH[5] = {0, 0, 0, 0, 0};
volatile uint8_t measuresDH[] = {0, 0};
#define RFLAG GPIOR0 //flag binaria
#define FDATA 0
#define MIN_TEMP 0
#define MAX_TEMP 40
#define MIN_UMID 0
#define MAX_UMID 50
volatile bool MEASURETIME = false;
volatile uint8_t interrupt_count = 30;
const uint8_t digitToSegment[] = {
0b00111111, // 0
0b00000110, // 1
0b01011011, // 2
0b01001111, // 3
0b01100110, // 4
0b01101101, // 5
0b01111101, // 6
0b00000111, // 7
0b01111111, // 8
0b01101111, // 9
0b01110111, // A
0b01111100, // B
0b00111001, // C
0b01011110, // D
0b01111001, // E
0b01110001 // F
};
const uint8_t symbolToSegment[] = {
0b01000000, // -
0b11100011, // °
0b01110110, // H
0b00111110, // U
0b00111000 //L
};
void setup() {
cli();
Serial.begin(9600);
TCCR1A = 0; // Imposta l'intero registro TCCR1A a 0
TCCR1B = 0; // Imposta l'intero registro TCCR1B a 0
TCCR1B |= (1 << WGM12); // Modalità CTC
OCR1A = 15624; //genero interrupt ogni 1s
TIMSK1 |= (1 << OCIE1A);
TCCR1B |= (1 << CS12) | (1 << CS10);
sei();
}
ISR(TIMER1_COMPA_vect) {
if (interrupt_count++ == 30) {
interrupt_count = 0;
MEASURETIME = true;
}
}
void loop() {
if (!MEASURETIME) {
sleepMode();
}
if (MEASURETIME) {
MEASURETIME = false;
impostaSensore();
effettuaRilevamento();
if (bit_is_set(RFLAG, FDATA)) {
cbi(RFLAG, FDATA);
impostaDisplay();
controlli();
stampaRilevamento();
setLumDisplay(false);
sleepMode();
}
}
}
void impostaSensore() {
pinMode(DHT22_PIN, OUTPUT); //inizializzo pin dht22 come output,potrà trasmettere
digitalWrite(DHT22_PIN, LOW); //invio segnale al dht22 indicando che sono pronto ad iniziare comunicazione
aspettaInMicros(20000);// aspetta 20millisecondi, devo usare micros, che 20000microsec, corrisp 20 millis, do tempo al DHT22 per accorgersi cambiamento stato
digitalWrite(DHT22_PIN, HIGH); //indico al dht22 che sono pronto e può iniziare a trasmettere
aspettaInMicros(40);//do il tempo al dht22 per iniziare
pinMode(DHT22_PIN, INPUT);//metto pin dht22 come input quindi adesso (microcontrollore) può leggere dati in ingresso rilevati dal sensore
}
void impostaDisplay() {
pinMode(CLK, OUTPUT); //invio tramite CLK segnali clock al display, quindi output
pinMode(DIO, OUTPUT);//invio tramite pin DIO bit al display, quindi output
digitalWrite(CLK, HIGH);//inizializzo in uno stato alto
digitalWrite(DIO, HIGH);//inizializzo in uno stato alto
setLumDisplay(true); //accendo lo schermo e imposto i digit a 0
}
void effettuaRilevamento() {
if (leggiPin(LOW, 80) && leggiPin(HIGH, 80)) {
// è pronto per leggere i 40bit che compongono temp ed umid
for (int i = 0; i < 40; i++) {
leggiPin(LOW, 50);
uint16_t durata = (uint16_t)pulseIn(DHT22_PIN, HIGH); // casting a unsigned int
dataDH[i / 8] <<= 1; // faccio shift sinistra bit e mi calcolo posizione del byte corrente
if (durata > 40) { // (microsecondi)
dataDH[i / 8] |= 1; // imposto ad 1 il bit meno significativo del byte in posizione i/8
}
}
checksum();
}
}
bool leggiPin(int state, uint16_t maxTime) {
// attende lo stato (che gli passiamo) sul pin e verifica se lo raggiunge entro maxTime (millisecondi)
uint16_t start = (uint16_t)micros();
while (digitalRead(DHT22_PIN) != state) {
if ((uint16_t)(micros() - start) > maxTime) {
return false;
}
}
return true;
}
void checksum() {
uint8_t humidity, temperature = 0;
if (dataDH[4] == ((dataDH[0] + dataDH[1] + dataDH[2] + dataDH[3]) & 0xFF)) { //vedo se il 5° byte è dato dalla somma degli altri
// ricavo temperatura ed umidità
humidity = ((dataDH[0] << 8) | dataDH[1]) * 0.1;
temperature = (((dataDH[2] & 0x7F) << 8) | dataDH[3]) * 0.1; //0x7F indica bit di segno che viene tolto
measuresDH[0] = temperature;
measuresDH[1] = humidity;
sbi(RFLAG, FDATA);
} else {
Serial.println("errore checksum!");
}
}
void controlli() {
uint8_t temp = (dataDH[2] & 0x80) ? -measuresDH[0] : measuresDH[0];
uint8_t umid = measuresDH[1];
if (tolleranza(temp, MIN_TEMP, MAX_TEMP, 227)) { //227 -> °
verificaAllertaTemp(temp);
}
if (tolleranza(umid, MIN_UMID, MAX_UMID, 118)) { //118 -> H
verificaAllertaUmid(umid);
}
}
bool tolleranza(uint8_t valore, uint8_t minLimite, uint8_t maxLimite, uint8_t simbolo) {
bool flag = true;
if (valore < minLimite || valore > maxLimite) {
flag = false;
dataTM[0] = codDigitToSegment(12); // C
dataTM[1] = codDigitToSegment(0); // O
dataTM[2] = codDigitToSegment(14); // E
dataTM[3] = codSymbolToSegment(simbolo);
stampa(dataTM);
aspettaInMillis(2000);
}
return flag;
}
void verificaAllertaTemp(uint8_t temp) {
if (temp == MIN_TEMP) {
//ALLERTA FREDDO
dataTM[0] = codDigitToSegment(12);//C
dataTM[1] = codDigitToSegment(0);//O
dataTM[2] = codSymbolToSegment(56);//L
dataTM[3] = codSymbolToSegment(227);//°
stampa(dataTM);
aspettaInMillis(2000);
} else {
if (temp == MAX_TEMP) {
//ALLERTA CALDO
dataTM[0] = codDigitToSegment(12);//C
dataTM[1] = codDigitToSegment(0);//O
dataTM[2] = codSymbolToSegment(118);//H
dataTM[3] = codSymbolToSegment(227);//°
stampa(dataTM);
aspettaInMillis(2000);
}
}
}
void verificaAllertaUmid(uint8_t umid) {
if (umid == MIN_UMID) {
//ALLERTA BASSA UMIDITà
dataTM[0] = codDigitToSegment(12);//C
dataTM[1] = codDigitToSegment(0);//O
dataTM[2] = codSymbolToSegment(56);//L
dataTM[3] = codSymbolToSegment(118);//H
stampa(dataTM);
aspettaInMillis(2000);
} else {
if (umid == MAX_UMID) {
//ALLERTA ALTA UMIDITà
dataTM[0] = codDigitToSegment(12);//C
dataTM[1] = codDigitToSegment(0);//O
dataTM[2] = codSymbolToSegment(118);//H
dataTM[3] = codSymbolToSegment(62);//U
stampa(dataTM);
aspettaInMillis(2000);
}
}
}
void stampaRilevamento() {
stampaTemperatura();
stampaUmidita();
}
void stampaTemperatura() {
if (dataDH[2] & 0x80) { // se il bit più significativo del byte 3 , vuol dire che temp è negativa
dataTM[0] = codSymbolToSegment(64); // -
dataTM[1] = codDigitToSegment(measuresDH[0] / 10); //decine cifra
dataTM[2] = codDigitToSegment(measuresDH[0] % 10); //unità cifra
dataTM[3] = codDigitToSegment(12); //C
} else {
dataTM[0] = codDigitToSegment(measuresDH[0] / 10); //decine cifra
dataTM[1] = codDigitToSegment(measuresDH[0] % 10);//unità cifra
dataTM[2] = codSymbolToSegment(227); //°
dataTM[3] = codDigitToSegment(12); //C
}
stampa(dataTM);
aspettaInMillis(2000);
}
void stampaUmidita() {
dataTM[0] = codDigitToSegment(measuresDH[1] / 10);//decine cifra
dataTM[1] = codDigitToSegment(measuresDH[1] % 10); //unità cifra
dataTM[2] = codSymbolToSegment(118); //H
dataTM[3] = codSymbolToSegment(62); //U
stampa(dataTM);
aspettaInMillis(2000);
}
void aspettaInMillis(uint16_t target) {
uint16_t startTime = (uint16_t)millis();
while ((uint16_t)millis() - startTime < target) {}
}
void aspettaInMicros(uint16_t target) {
uint16_t startTime = (uint16_t) micros();
while ((uint16_t)micros() - startTime < target) {}
}
void stampa(uint8_t dataTM[]) {
start();
writeByte(0x40); //indica che dovrà scrivere più byte consecutivi
stop();
start();
writeByte(0xC0); //inizia a scrivere dal registro di indirizzo 0x00
for (uint8_t k = 0; k < 4; k++) {
writeByte(dataTM[k]);
}
stop();
}
uint8_t codDigitToSegment(uint8_t cifra) {
if (cifra <= 15) {
return digitToSegment[cifra & 0x0f];
}else{
return 0xff; //valore non valido!
}
}
uint8_t codSymbolToSegment(uint8_t symbol) {
if (symbol == 64) { // 0b01000000 -> -
return symbolToSegment[0];
}
if (symbol == 227) { // 0b11100011 -> °
return symbolToSegment[1];
}
if (symbol == 118) { // 0b01110110 -> H
return symbolToSegment[2];
}
if (symbol == 62) { // 0b00111110 -> U
return symbolToSegment[3];
}
if (symbol == 56) { // 0b00111000 -> L
return symbolToSegment[4];
} else {
return 0; // Simbolo non supportato
}
}
void writeByte(uint8_t bite) {
for (uint8_t i = 0; i < 8; i++) {
digitalWrite(CLK, LOW); //inizio ciclo scrittura, sincronizzando la trasmissione
aspettaInMicros(2);
if (bite & 0x01) { //facendo & bit a bit mi ricavo bit meno signifiativo
digitalWrite(DIO, HIGH); //imposto il pin DIO alto/basso in base al bit meno significativo e lo trasmetto
} else {
digitalWrite(DIO, LOW);
}
bite >>= 1; //shift di tutto a destra così da avere pronto bit meno significativo per dopo
digitalWrite(CLK, HIGH); //chiudo ciclo scrittura
aspettaInMicros(2);
}
digitalWrite(CLK, LOW);//indico che sono pronto a ricevere ACK dal ricevente
pinMode(DIO, INPUT); //aspetto segnale ack dal dispositivo ricevente
aspettaInMicros(2);
digitalWrite(CLK, HIGH); //imposto alto per poter leggere valore DIO
aspettaInMicros(2);
bool ack = digitalRead(DIO) == LOW; //se DIO==LOW allora ack ricevuto, cioè il dispositivo ha ricevuto correttamente i dati
pinMode(DIO, OUTPUT); //reimposto pin DIO come output
digitalWrite(CLK, LOW); //reimposto CLK a low per terminare comunicazione ed essere eventual pronto a ritrasmettere
}
void start() {
pinMode(DIO, OUTPUT); //imposto pin DIO output, cioè pronto ad inviare
digitalWrite(DIO, LOW);//indico al dispositivo ricevente che sono pronto ad inviare
aspettaInMicros(2); //aspetto risposta dispositivo ricevente, do il tempo che si accorga stato pin DIO
digitalWrite(CLK, LOW); //sincronizzo la trasmissione seriale
aspettaInMicros(2);//do tempo al dispostivo ricevente per accorgersi dello stato del pin
}
void stop() {
digitalWrite(CLK, LOW); //sincronizzo la trasmissione seriale
aspettaInMicros(2); //do tempo al dispostivo ricevente di accorgersi cambiamento stato clock
digitalWrite(DIO, LOW);//indico al dispositivo ricevente che sono pronto a chiudere la trasmissione dati
aspettaInMicros(2);//do tempo al dispostivo ricevente di accorgersi cambiamento pin DIO
digitalWrite(CLK, HIGH);//termino la sincronizzazione del clock sulla trasmissione
aspettaInMicros(2);//do tempo al dispostivo ricevente di accorgersi cambiamento
digitalWrite(DIO, HIGH); //chiudo bus dati, indicando effettiva chiusura trasmissione
aspettaInMicros(2); //do tempo al dispositivo di rilevare cambiamento
}
void setLumDisplay(bool on) {
uint8_t command = on ? 0x8F : 0x80; // 0x8F display massima luminosità, 0x80 display spento
start();
writeByte(command);
stop();
}
void sleepMode() {
// Configura il microcontrollore per entrare in modalità Power-down
SMCR |= (1 << SM1) | (1 << SM0); // Modalità Power-down
SMCR |= (1 << SE); // Abilita il bit di sleep
asm volatile (
"sleep"
);
}