#include #include #include #define F_CPU 20000000UL //20 MHz #include /* 7-Segment display: */ #define NUM_DIGITS 3U //3 Digits #define DIGIT_TENS 2U //left #define DIGIT_ONES 1U //middle #define DIGIT_UNIT 0U //right #define SELECT_DIGIT(digit) (1U << digit) /* DHT22 peripherals: */ #define DDR_SENSOR DDRC #define PORT_SENSOR PORTC #define PIN_SENSOR PINC #define SENSOR PINC3 /* DHT22 commands: */ #define SENSOR_sda_out DDR_SENSOR |= (1 << SENSOR) #define SENSOR_sda_in DDR_SENSOR &= ~(1 << SENSOR) // release sda => hi in consequence of pullup #define SENSOR_sda_low PORT_SENSOR &= ~(1 << SENSOR) #define SENSOR_is_hi PIN_SENSOR & (1 << SENSOR) #define SENSOR_is_low !(PIN_SENSOR & (1 << SENSOR)) #define MODE_MEASURE 0U #define MODE_ANIMATION_1 1U #define MODE_ANIMATION_2 2U #define ANIMATION_DELAY_MS 70U #define ANIMATION_START_DELAY_MS 70U #define BUTTON_THRESHOLD 50 //software debounce /* Symbol indexes: */ #define SYM_n 10U #define SYM_o 11U #define SYM_E 12U #define SYM_R 13U #define SYM_DEG_CELCIUS 14U #define SYM_P_P 15U #define SYM_OFF 16U #define SYM_DASH 17U #define SYM_I 18U #define SYM_SEG_A 19U #define SYM_SEG_B 20U #define SYM_SEG_C 21U #define SYM_SEG_D 22U #define SYM_SEG_E 23U #define SYM_SEG_F 24U #define SYM_SEG_AB 25U #define SYM_SEG_BCD 26U #define SYM_SEG_CD 27U #define SYM_SEG_DE 28U #define SYM_SEG_DEF 29U #define SYM_SEG_AEF 30U #define SYM_SEG_AF 31U /* 7-Segment Layout: A F B G E C D P Pin 7 6 5 4 3 2 1 0 Segment A F B E D C G P */ static uint8_t g_au8Symbols[32U] = { /* 00 */ 0b11111100U, //0 (ABCDEF) /* 01 */ 0b00100100U, //1 (BC) /* 02 */ 0b10111010U, //2 (ABDEG) /* 03 */ 0b10101110U, //3 (ABCDG) /* 04 */ 0b01100110U, //4 (BCFG) /* 05 */ 0b11001110U, //5 (ACDFG) /* 06 */ 0b11011110U, //6 (ACDEFG) /* 07 */ 0b10100100U, //7 (ABC) /* 08 */ 0b11111110U, //8 (ABCDEFG) /* 09 */ 0b11101110U, //9 (ABCDFG) /* 10 */ 0b00010110U, //n (CEG) SYM_n /* 11 */ 0b00011110U, //o (CDEG) SYM_o /* 12 */ 0b11011010U, //E (ADEFG) SYM_E /* 13 */ 0b00010010U, //r (EG) SYM_r /* 14 */ 0b10101101U, //degC (ABCDP) SYM_DEG_CELCIUS /* 15 */ 0b11110011U, //P. (ABEFGP) SYM_P_P /* 16 */ 0b00000000U, //OFF SYM_OFF /* 17 */ 0b00000010U, //- (G) SYM_DASH /* 18 */ 0b01010000U, //I (EF) SYM_I /* 19 */ 0b10000000U, //SegA SYM_SEG_A /* 20 */ 0b00100000U, //SegB SYM_SEG_B /* 21 */ 0b00000100U, //SegC SYM_SEG_C /* 22 */ 0b00001000U, //SegD SYM_SEG_D /* 23 */ 0b00010000U, //SegE SYM_SEG_E /* 24 */ 0b01000000U, //SegF SYM_SEG_F /* 25 */ 0b10100000U, //SegAB SYM_SEG_AB /* 26 */ 0b00101100U, //SegBCD SYM_SEG_BCD /* 27 */ 0b00001100U, //SegCD SYM_SEG_CD /* 28 */ 0b00011000U, //SegDE SYM_SEG_DE /* 29 */ 0b01011000U, //SegDEF SYM_SEG_DEF /* 30 */ 0b11010000U, //SegAEF SYM_SEG_AEF /* 31 */ 0b11000000U //SegAF SYM_SEG_AF }; static uint8_t g_u8ButtonCountTop = 0U; //upper button counter static uint8_t g_u8ButtonCountBot = 0U; //lower button counter static uint8_t g_u8Mode = MODE_MEASURE; //Current display mode uint16_t g_u16Humidity = 0U; uint16_t g_u16Temperature = 0U; uint8_t g_u8ISRDigitSelect = 0U; uint8_t g_au8Digits[3U] = { SYM_OFF, //unit SYM_OFF, //ones SYM_OFF //tens }; void s_vInit( void ); void s_vSetValue( uint8_t u8Value, uint8_t u8Unit ); void s_vSetDisplayDigits( uint8_t u8Tens, uint8_t u8Ones, uint8_t u8Unit ); void s_vReadButtons( void ); void s_vShowAnim( uint8_t u8Select ); uint8_t s_u8ReadSensor( void ); /************************************************************************/ /* Timer1 ISR - show values on display */ /************************************************************************/ ISR ( TIMER1_COMPA_vect ) { PORTB = 0; PORTD = 0; _delay_us(2); PORTB = SELECT_DIGIT(g_u8ISRDigitSelect); PORTD = g_au8Symbols[g_au8Digits[g_u8ISRDigitSelect]]; g_u8ISRDigitSelect++; if (g_u8ISRDigitSelect > 2U) { g_u8ISRDigitSelect = 0U; } /* Read and evaluate button status */ s_vReadButtons(); } /************************************************************************/ /* main() */ /************************************************************************/ int main(void) { uint8_t u8ErrorCode = 0U; uint8_t u8Loop = 0U; s_vInit(); s_vSetDisplayDigits( SYM_OFF, SYM_OFF, SYM_OFF ); _delay_ms(10); s_vSetDisplayDigits( SYM_SEG_A, SYM_OFF, SYM_OFF ); _delay_ms(300); s_vSetDisplayDigits( SYM_SEG_A, SYM_SEG_A, SYM_OFF ); _delay_ms(300); s_vSetDisplayDigits( SYM_SEG_A, SYM_SEG_A, SYM_SEG_A ); _delay_ms(300); while ( u8Loop < 5U ) { s_vSetDisplayDigits( SYM_OFF, SYM_SEG_A, SYM_SEG_AB ); _delay_ms(ANIMATION_START_DELAY_MS); s_vSetDisplayDigits( SYM_OFF, SYM_OFF, 7U ); _delay_ms(ANIMATION_START_DELAY_MS); s_vSetDisplayDigits( SYM_OFF, SYM_OFF, SYM_SEG_BCD ); _delay_ms(ANIMATION_START_DELAY_MS); s_vSetDisplayDigits( SYM_OFF, SYM_SEG_D, SYM_SEG_CD ); _delay_ms(ANIMATION_START_DELAY_MS); s_vSetDisplayDigits( SYM_SEG_D, SYM_SEG_D, SYM_SEG_D ); _delay_ms(ANIMATION_START_DELAY_MS); s_vSetDisplayDigits( SYM_SEG_DE, SYM_SEG_D, SYM_OFF ); _delay_ms(ANIMATION_START_DELAY_MS); s_vSetDisplayDigits( SYM_SEG_DEF, SYM_OFF, SYM_OFF ); _delay_ms(ANIMATION_START_DELAY_MS); s_vSetDisplayDigits( SYM_SEG_AEF, SYM_OFF, SYM_OFF ); _delay_ms(ANIMATION_START_DELAY_MS); s_vSetDisplayDigits( SYM_SEG_AF, SYM_SEG_A, SYM_OFF ); _delay_ms(ANIMATION_START_DELAY_MS); s_vSetDisplayDigits( SYM_SEG_A, SYM_SEG_A, SYM_SEG_A ); _delay_ms(ANIMATION_START_DELAY_MS); u8Loop++; } /* Set default value: */ //s_vSetDisplayDigits( SYM_DASH, SYM_DASH, SYM_DASH ); /* wait 3 seconds for humity sensor */ //_delay_ms(3000); /* Set default value: */ s_vSetDisplayDigits( SYM_OFF, SYM_OFF, SYM_OFF ); _delay_ms(600); while ( 1 ) { switch ( g_u8Mode ) { case MODE_MEASURE: if ( SENSOR_is_hi ) { SENSOR_sda_out; SENSOR_sda_low; _delay_ms(20); u8ErrorCode = s_u8ReadSensor(); if ( 0U == u8ErrorCode ) { s_vSetValue( g_u16Humidity / 10, SYM_P_P ); //vSetDisplayValues( g_u16Temperature / 10, SYM_DEG_CELCIUS ); } else { s_vSetDisplayDigits( SYM_E, u8ErrorCode, SYM_OFF ); } } if ( g_u8Mode == MODE_MEASURE ) { _delay_ms(500); } break; case MODE_ANIMATION_1: s_vShowAnim(g_u8Mode); g_u8Mode = MODE_MEASURE; _delay_ms(200); break; case MODE_ANIMATION_2: s_vShowAnim(g_u8Mode); g_u8Mode = MODE_MEASURE; _delay_ms(200); break; default: break; } //end switch // _delay_ms(3000); //wait 3 seconds for new measurement } //end while(1) return 0; } /************************************************************************/ /* Initialize inputs and outputs */ /************************************************************************/ void s_vInit( void ) { /* Port D - Pins 0-7: Outputs */ DDRD = 0b11111111U; /* Port B - Pins 0-2: Outputs */ DDRB = 0b00000111U; /* Port C - Pins 4-5: Inputs with internal Pull-up */ PORTC = 0b00110000U; /* Sensor init: */ DDR_SENSOR &= ~(1 << SENSOR); // define as input PORT_SENSOR &= ~(1 << SENSOR); // disable pullup /* 16-bit TIMER1 in CTC mode * prescaler = 8 * 20 MHz / 8 = 2.5 MHz * Compare value = 2500 => 1 ms IRQ */ TCCR1A = 0U; TCCR1B = (1< BUTTON_THRESHOLD ) { g_u8ButtonCountTop = 0U; //reset top counter g_u8Mode = MODE_ANIMATION_1; } else if ( g_u8ButtonCountBot > BUTTON_THRESHOLD ) { g_u8ButtonCountBot = 0U; //reset bottom counter g_u8Mode = MODE_ANIMATION_2; } return; //void } /************************************************************************/ /* */ /************************************************************************/ void s_vShowAnim( uint8_t u8Select ) { s_vSetDisplayDigits( SYM_OFF, SYM_OFF, SYM_OFF ); _delay_ms(ANIMATION_DELAY_MS); switch ( u8Select ) { case MODE_ANIMATION_1: //fade from left to right and from right to left s_vSetDisplayDigits( SYM_I, SYM_OFF, SYM_OFF ); _delay_ms(ANIMATION_DELAY_MS); s_vSetDisplayDigits( SYM_E, SYM_OFF, SYM_OFF ); _delay_ms(ANIMATION_DELAY_MS); s_vSetDisplayDigits( 8U, SYM_OFF, SYM_OFF ); _delay_ms(ANIMATION_DELAY_MS); s_vSetDisplayDigits( 8U, SYM_I, SYM_OFF ); _delay_ms(ANIMATION_DELAY_MS); s_vSetDisplayDigits( 8U, SYM_E, SYM_OFF ); _delay_ms(ANIMATION_DELAY_MS); s_vSetDisplayDigits( 8U, 8U, SYM_OFF ); _delay_ms(ANIMATION_DELAY_MS); s_vSetDisplayDigits( 8U, 8U, 1U ); _delay_ms(ANIMATION_DELAY_MS); s_vSetDisplayDigits( 8U, 8U, 3U ); _delay_ms(ANIMATION_DELAY_MS); s_vSetDisplayDigits( 8U, 8U, 8U ); _delay_ms(ANIMATION_DELAY_MS); s_vSetDisplayDigits( 8U, 8U, 8U ); _delay_ms(ANIMATION_DELAY_MS); s_vSetDisplayDigits( 8U, 8U, 3U ); _delay_ms(ANIMATION_DELAY_MS); s_vSetDisplayDigits( 8U, 8U, 1U ); _delay_ms(ANIMATION_DELAY_MS); s_vSetDisplayDigits( 8U, 8U, SYM_OFF ); _delay_ms(ANIMATION_DELAY_MS); s_vSetDisplayDigits( 8U, SYM_E, SYM_OFF ); _delay_ms(ANIMATION_DELAY_MS); s_vSetDisplayDigits( 8U, SYM_I, SYM_OFF ); _delay_ms(ANIMATION_DELAY_MS); s_vSetDisplayDigits( 8U, SYM_OFF, SYM_OFF ); _delay_ms(ANIMATION_DELAY_MS); s_vSetDisplayDigits( SYM_E, SYM_OFF, SYM_OFF ); _delay_ms(ANIMATION_DELAY_MS); s_vSetDisplayDigits( SYM_I, SYM_OFF, SYM_OFF ); _delay_ms(ANIMATION_DELAY_MS); break; case MODE_ANIMATION_2: //fade from left to right and clear s_vSetDisplayDigits( SYM_I, SYM_OFF, SYM_OFF ); _delay_ms(ANIMATION_DELAY_MS); s_vSetDisplayDigits( SYM_E, SYM_OFF, SYM_OFF ); _delay_ms(ANIMATION_DELAY_MS); s_vSetDisplayDigits( 8U, SYM_OFF, SYM_OFF ); _delay_ms(ANIMATION_DELAY_MS); s_vSetDisplayDigits( 8U, SYM_I, SYM_OFF ); _delay_ms(ANIMATION_DELAY_MS); s_vSetDisplayDigits( 8U, SYM_E, SYM_OFF ); _delay_ms(ANIMATION_DELAY_MS); s_vSetDisplayDigits( 8U, 8U, SYM_OFF ); _delay_ms(ANIMATION_DELAY_MS); s_vSetDisplayDigits( 8U, 8U, 1U ); _delay_ms(ANIMATION_DELAY_MS); s_vSetDisplayDigits( 8U, 8U, 3U ); _delay_ms(ANIMATION_DELAY_MS); s_vSetDisplayDigits( 8U, 8U, 8U ); _delay_ms(ANIMATION_DELAY_MS); s_vSetDisplayDigits( 3U, 8U, 8U ); _delay_ms(ANIMATION_DELAY_MS); s_vSetDisplayDigits( 1U, 8U, 8U ); _delay_ms(ANIMATION_DELAY_MS); s_vSetDisplayDigits( SYM_OFF, 8U, 8U ); _delay_ms(ANIMATION_DELAY_MS); s_vSetDisplayDigits( SYM_OFF, 3U, 8U ); _delay_ms(ANIMATION_DELAY_MS); s_vSetDisplayDigits( SYM_OFF, 1U, 8U ); _delay_ms(ANIMATION_DELAY_MS); s_vSetDisplayDigits( SYM_OFF, SYM_OFF, 8U ); _delay_ms(ANIMATION_DELAY_MS); s_vSetDisplayDigits( SYM_OFF, SYM_OFF, SYM_E ); _delay_ms(ANIMATION_DELAY_MS); s_vSetDisplayDigits( SYM_OFF, SYM_OFF, SYM_I ); _delay_ms(ANIMATION_DELAY_MS); s_vSetDisplayDigits( SYM_OFF, SYM_OFF, SYM_OFF ); _delay_ms(ANIMATION_DELAY_MS); break; default: break; } //end switch s_vSetDisplayDigits( SYM_OFF, SYM_OFF, SYM_OFF ); _delay_ms(ANIMATION_DELAY_MS); return; //void } /************************************************************************/ /* Read humidity and temperature from DHT22 */ /************************************************************************/ uint8_t s_u8ReadSensor( void ) { uint8_t timeout = 200; SENSOR_sda_in; // Bus master has released time min: 20us, typ: 30us, max: 200us while ( SENSOR_is_hi ) { _delay_us(1); if ( !timeout-- ) { return 2; } } // AM2302 response signal min: 75us typ:80us max:85us timeout = 85; while(SENSOR_is_low) { _delay_us(1); if (!timeout--) { return 3; } } // response to low time timeout = 85; while(SENSOR_is_hi) { _delay_us(1); if (!timeout--) { return 4; } } // response to high time /* * time in us: min typ max * signal 0 high time: 22 26 30 (bit=0) * signal 1 high time: 68 70 75 (bit=1) * signal 0,1 down time: 48 50 55 */ uint8_t sensor_data[5]={0}; for(uint8_t i = 0; i < 5; i++) { uint8_t sensor_byte = 0; // get 8 bits from sensor for(uint8_t j = 1; j <= 8; j++) { // wait for sensor response timeout = 55; while(SENSOR_is_low) { _delay_us(1); // if timeout == 0 => sensor do not response if (!timeout--) { return 5; } } // wait 30 us to check if bit is logical "1" or "0" _delay_us(30); sensor_byte <<= 1; // add new lower bit // If sda ist high after 30 us then bit is logical "1" else it was a logical "0" // For a logical "1" sda have to be low after 75 us. if (SENSOR_is_hi) { sensor_byte |= 1; // add logical "1" timeout = 45; // 30us - 75us = 45us while(SENSOR_is_hi) { _delay_us(1); if (!timeout--) { return 6; } } } } sensor_data[i] = sensor_byte; } // checksum if ( ((sensor_data[0] + sensor_data[1] + sensor_data[2] + sensor_data[3]) & 0xff ) != sensor_data[4]) { // debug output //printf("%b %b %b %b %b %b" CR, sensor_data[0], sensor_data[1], sensor_data[2], sensor_data[3], sensor_data[4], ((sensor_data[0]+sensor_data[1]+sensor_data[2]+sensor_data[3]) & 0xff )); return 7; } g_u16Humidity = (sensor_data[0] << 8) + sensor_data[1]; g_u16Temperature = (sensor_data[2] << 8) + sensor_data[3]; return 0; }