Temperature and Light Level Monitor With Displaying on LCD NOKIA 5110

About: Welcome to FOG channel! "Hobby" "DIY" "Electronics" "Programming" "Video Games" "Media Design" "Digital Art" and more... https://www.y...

Hello everyone!

In this section we make simple electronic device to monitor the temperature and light level. Measurements of these parameters are displayed on LCD NOKIA 5110. The device is based on the microcontroller AVR ATMEGA328P. The monitoring device is equipped DS18B20 digital thermometer and photoresistor to measure light level.

Teacher Notes

Teachers! Did you use this instructable in your classroom?
Add a Teacher Note to share how you incorporated it into your lesson.

Step 1: Description Components

Basic components of the monitoring device:

  • Microcontroller AVR «ATMEGA328P»
  • Monochrome Graphic LCD «NOKIA 5110»
  • Programmable Resolution 1-Wire Digital Thermometer «DS18B20»
  • Light dependent resistor
  • Wires

Microcontroller AVR «ATMEGA328P»

Monitoring device uses the following peripheral features of microcontroller:

  1. 16-bit Timer/Counter interrupt
  2. 8-channel 10-bit ADC
  3. Master/slave SPI serial interface

Monochrome Graphic LCD «NOKIA 5110»

Specifications:

  1. 48 x 84 Dot LCD Display
  2. Serial Bus Interface with maximum high speed 4 Mbits/S
  3. Internal Controller/Driver «PCD8544»
  4. LED Back-Light
  5. Run at Voltage 2.7-5 Volt
  6. Low power consumption; it is suitable for battery applications
  7. Temperature range from -25˚C to +70˚C
  8. Support Signal CMOS Input

Handling of LCD Address (Addressing):

The address arrangement of memory that is shown on LCD Display (DDRAM) is Matrix that consists of 6 rows (Y Address) from Y-Address 0 to Y-Address 5 and 84 columns (X Address) from X-Address 0 to X-Address 83. If user wants to access to the position of displaying result on LCD Display, must refer to the relationship between X-Address and Y-Address.

Data that will be sent to display is 8 bit (1 Byte) and it will be arranged as vertical line; in this case, Bit MSB will be lower and Bit LSB will be upper as shown in the picture.

Programmable Resolution 1-Wire Digital Thermometer DALLAS «DS18B20»

Features:

  1. Unique 1-Wire® Interface Requires Only One Port Pin for Communication
  2. Reduce Component Count with Integrated Temperature Sensor and EEPROM
  3. Measures Temperatures from -55°C to +125°C (-67°F to +257°F)
  4. ±0.5°C Accuracy from -10°C to +85°C
  5. Programmable Resolution from 9 Bits to 12 Bits
  6. No External Components Required
  7. Parasitic Power Mode Requires Only 2 Pins for Operation (DQ and GND)
  8. Simplifies Distributed Temperature-Sensing Applications with Multidrop Capability
  9. Each Device Has a Unique 64-Bit Serial Code Stored in On-Board ROM
  10. Flexible User-Definable Nonvolatile (NV) Alarm Settings with Alarm Search Command Identifies Devices with Temperatures Outside Programmed Limits

Applications:

  1. Thermostatic Controls
  2. Industrial Systems
  3. Consumer Products
  4. Thermometers
  5. Thermally Sensitive Systems

Light dependent resistor

Light Dependent Resistor (LDR) is a transducer which changes its resistance when light falls on its surface changes.

Typically an LDR will have from one megaOhms to two megaOhms at total darkness, from ten to twenty kiloOhms at ten LUX, from two to five kiloohms at 100 LUX. The resistance between the two contacts of sensor decreases with light intensity or the conductance between two contacts of sensor increases.

Use voltage divider circuit to converting change in resistance to change in voltage.

Step 2: Microcontroller Firmware Code

#ifndef F_CPU
#define F_CPU 16000000UL // telling controller crystal frequency (16 MHz AVR ATMega328P) #endif

// SPI INTERFACE DEFINES
#define MOSI 3 // MOSI it's PORT B, PIN 3 #define MISO 4 // MISO it's PORT B, PIN 4 #define SCK 5 // SCK it's PORT B, PIN 5 #define SS 2 // SS it's PORT B, PIN 2

// RESET THE DISPLAY #define RST 0 // RESET it's PORT B, PIN 0

//DISPLAY MODE SELECT - Input to select either command/address or data input. #define DC 1 // DC it's PORT B, PIN 1

// codes array of negative sign
static const unsigned char neg[4] = {0x30,0x30,0x30,0x30};

// codes array of digits [0..9] static const unsigned char font6x8[10][16] = { { 0xFC, 0xFE, 0xFE, 0x06, 0x06, 0xFE, 0xFE, 0xFC, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01}, // 0 { 0x00, 0x00, 0x18, 0x1C, 0xFE, 0xFE, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x01, 0x00}, // 1 { 0x0C, 0x8E, 0xCE, 0xE6, 0xE6, 0xBE, 0x9E, 0x0C, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01}, // 2 { 0x00, 0x04, 0x06, 0x26, 0x76, 0xFE, 0xDE, 0x8C, 0x00, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01}, // 3 { 0x3C, 0x3E, 0x7C, 0x60, 0x60, 0xFC, 0xFE, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x01}, // 4 { 0x1C, 0x3E, 0x3E, 0x36, 0x36, 0xF6, 0xF6, 0xE4, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01}, // 5 { 0xFC, 0xFE, 0xFE, 0x36, 0x36, 0xF6, 0xF6, 0xE4, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01}, // 6 { 0x04, 0x06, 0x06, 0x86, 0xE6, 0xFE, 0x7E, 0x1C, 0x00, 0x00, 0x00, 0x01, 0x03, 0x01, 0x00, 0x00}, // 7 { 0xCC, 0xFE, 0xFE, 0x36, 0x36, 0xFE, 0xFE, 0xCC, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01}, // 8 { 0x3C, 0x7E, 0x7E, 0x66, 0x66, 0xFE, 0xFE, 0xFC, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01} // 9 };

// codes array of word "TEMP:" static const unsigned char TEMP_1[165] = { 0x02,0x06,0x06,0xFE,0xFE,0xFE,0x06,0x06,0x02,0x00,0xFC,0xFE,0xFE,0x26,0x26,0x24,0x00,0xFC,0xFE,0xFE,0x1C,0x38,0x70,0x38,0x1C,0xFE,0xFE,0xFC, 0x00,0xFC,0xFE,0xFE,0x66,0x66,0x7E,0x7E,0x3C,0x00,0x8C,0x8C,0x00,0x00,0x00,0x01,0x03,0x01,0x00,0x00,0x00,0x00,0x01,0x03,0x03,0x03,0x03,0x01,0x00,0x01,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x01,0x03, 0x01,0x00,0x01,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x0C,0x1E,0x33,0x33,0x1E,0x0C,0x00,0xF8,0xFC,0x0C,0x9C,0x98,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x03,0x03,0x03,0x01, };

// codes array of word "LUX:" const unsigned char TEMP_2[60] = { 0xFC,0xFE,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0xFE,0xFC,0x00,0x00,0xFC,0xFE,0xFC,0x00,0x04,0x8E,0xDE,0xFC,0xF8,0xFC,0xDE,0x8E,0x04,0x00,0x8C,0x8C, 0x01,0x03,0x03,0x03,0x03,0x03,0x03,0x01,0x00,0x01,0x03,0x03,0x03,0x03,0x03,0x03,0x01,0x00,0x01,0x03,0x03,0x01,0x00,0x01,0x03,0x03,0x01,0x00,0x01,0x01 };

#include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h>

// Port Initialization
void Port_Init() { DDRB = (1<<MOSI)|(1<<SCK)|(1<<SS)|(1<<RST)|(1<<DC);// Set MOSI,SCK,SS,RST,DC as output, all others input PORTB |= (1<<RST);// Set RST pin as high PORTB |= (1<<SS);// Set SS pin as high - Display is Disable DDRC=0xFFu; // Set all pins of the PORTC as output. DDRC &= ~(1<<0);//Makes first pin of PORTC as Input PORTC=0x00u; // Set all pins of PORTC low which turns it off. }

// ADC Initialization void ADC_init() { // Enable ADC, sampling freq=osc_freq/128 set prescaler to max value, 128 ADCSRA |= (1<<ADEN) | (1<<ADPS2)| (1<<ADPS1)| (1<<ADPS0); ADMUX = (1<<REFS0); // Select the voltage reference for the ADC // Select channel zero by default using the ADC Multiplexer Select register (ADC0). }

// Function to read the result of analog to digital convert uint16_t get_LightLevel() { _delay_ms(10); // Wait for some time for the channel to get selected ADCSRA |= (1<<ADSC); // Start the ADC conversion by setting ADSC bit. write 1 to ADSC while(ADCSRA & (1<<ADSC)); // wait for conversion to complete // ADSC becomes 0 again till then, run loop continuously _delay_ms(10); return(ADC); // Return the 10-bit result }

// SPI Initialization void SPI_Init() { SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);//Enable SPI, Set as Master, Set Prescaler as Fosc/16 in SPI control register }

// initialize 16 bit Timer1, interrupt and variable void TIMER1_init() { // set up timer with prescaler = 256 and CTC mode TCCR1B |= (1 << WGM12)|(1 << CS12); // initialize counter TCNT1 = 0; // initialize compare value - 1 sec OCR1A = 62500; // enable compare interrupt TIMSK1 |= (1 << OCIE1A); // enable global interrupts sei(); }

//Display Enable void SPI_SS_Enable() { PORTB &= ~(1<<SS); // Enable the SS pin to logic 0 }

//Display Disable void SPI_SS_Disable() { PORTB |= (1<<SS); // Disable the SS pin to logic 1 }

//Function to send data into the display buffer void SPI_Tranceiver (unsigned char data) { SPDR = data; //Load data into the buffer while(!(SPSR & (1<<SPIF) )); //Wait until transmission complete }

// Reset the Display at the beginning of initialization void Display_Reset() { PORTB &= ~(1<<RST); _delay_ms(100); PORTB |= (1<<RST); }

//Command write function void Display_Cmnd(unsigned char data) { PORTB &= ~(1<<DC); // make DC pin to logic 0 for command operation SPI_Tranceiver(data); // send data on data register PORTB |= (1<<DC); // make DC pin to logic high for data operation }

//Initialization of Display void Display_init() { Display_Reset(); // reset the display Display_Cmnd(0x21); // command set in addition mode Display_Cmnd(0xC0); // set the voltage by sending C0 means VOP = 5V Display_Cmnd(0x07); // set the temp. coefficient to 3 Display_Cmnd(0x13); // set value of Voltage Bias System Display_Cmnd(0x20); // command set in basic mode Display_Cmnd(0x0C); // display result in normal mode }

// Clear the Display void Display_Clear() { PORTB |= (1<<DC); // make DC pin to logic high for data operation for (int k=0; k<=503; k++){SPI_Tranceiver(0x00);} PORTB &= ~(1<<DC);// make DC pin to logic zero for command operation }

// set the column and row to the position of displaying result on LCD Display void Display_SetXY(unsigned char x, unsigned char y) { Display_Cmnd(0x80|x); // column (0-83) Display_Cmnd(0x40|y); // row (0-5) }

// Function to display negative sign void Display_Neg(unsigned char neg) { Display_SetXY(41,0); // Set the address of position on display for (int index=0; index<4; index++) { if (neg>0) {SPDR = 0x30;} //Load data into the buffer of display (display negative sign) else {SPDR = 0x00;} //Load data into the buffer of display (clear negative sign) while(!(SPSR & (1<<SPIF) )); //Wait until transmission complete _delay_ms(100); } }

// Function to clear the digital sign void Off_Dig(unsigned char x, unsigned char y) { Display_SetXY(x,y); // Set the address of position on display (top row) for (int index=0; index<8; index++) {SPI_Tranceiver(0);} //Load data into the buffer of display (clear top part of digital sign) y++; Display_SetXY(x,y);// Set the address of position on display (bottom row) for (int index=0; index<8; index++) {SPI_Tranceiver(0);}// Load data into the buffer of display (clear bottom part of digital sign) }

// Function to display digital sign void Display_Dig(int dig, unsigned char x, unsigned char y) { Display_SetXY(x,y);// Set the address of position on display (top row) for (int index=0; index<16; index++) { if (index==8){y++;Display_SetXY(x,y);} // Set the address of position on display (bottom row) SPI_Tranceiver(font6x8[dig][index]); // Load codes array of digits data into the buffer of display _delay_ms(10); } }

// Initialization of DS18B20 unsigned char DS18B20_init() { DDRD |= (1 << 2); // Set PD2 pin of the PORTD as output PORTD &= ~(1 << 2); // Set PD2 pin as low _delay_us(490); // Initialization Timing DDRD &= ~(1 << 2); // Set PD2 pin of the PORTD as input _delay_us(68); // Timing OK_Flag = (PIND & (1 << 2)); // get sensor pulse _delay_us(422); return OK_Flag; // return 0-ok sensor is plug, 1-error sensor is unplug }

// Function to read byte from DS18B20 unsigned char read_18b20() { unsigned char i, data = 0; for(i = 0; i < 8; i++) { DDRD |= (1 << 2); // Set PD2 pin of the PORTD as output _delay_us(2); // Timing DDRD &= ~(1 << 2); // Set PD2 pin of the PORTD as input _delay_us(4); // Timing data = data >> 1; // Next bit if(PIND & (1 << 2)) data |= 0x80; // put bit into byte _delay_us(62); } return data; }

// Function to write byte to DS18B20 void write_18b20(unsigned char data) { unsigned char i; for(i = 0; i < 8; i++) { DDRD |= (1 << 2); // Set PD2 pin of the PORTD as output _delay_us(2); // Timing if(data & 0x01) DDRD &= ~(1 << 2); //if we want to write 1, release the line else DDRD |= (1 << 2); // if not will keep low data = data >> 1; // Next bit _delay_us(62); // Timing DDRD &= ~(1 << 2); // Set PD2 pin of the PORTD as input _delay_us(2); } }

// Function to display light level void Read_Lux() { uint16_t buffer; unsigned int temp_int_1,temp_int_2,temp_int_3,temp_int_0; // single digits, double digits, triple digits, quarter digits buffer = get_LightLevel(); // read the result of analog to digital convert light level temp_int_0 = buffer % 10000 / 1000; // quarter-digit temp_int_1 = buffer % 1000 / 100; // triple-digit temp_int_2 = buffer % 100 / 10; // double-digit temp_int_3 = buffer % 10; // single-digit if(temp_int_0 > 0) // if result is quarter-digit number { Display_Dig(temp_int_0,32,2); // display 1 digit of light level Display_Dig(temp_int_1,41,2); // display 2 digit of light level Display_Dig(temp_int_2,50,2); // display 3 digit of light level Display_Dig(temp_int_3,59,2); // display 4 digit of light level } else { if(temp_int_1 > 0) // if result is triple-digit number { Off_Dig(32,2); // clear 1 sign of number Display_Dig(temp_int_1,41,2); // display 1 digit of light level Display_Dig(temp_int_2,50,2); // display 2 digit of light level Display_Dig(temp_int_3,59,2); // display 3 digit of light level } else { if(temp_int_2 > 0) // if result is double-digit number { Off_Dig(32,2); // clear 1 sign of number Off_Dig(41,2); // clear 2 sign of number Display_Dig(temp_int_2,50,2); // display 1 digit of light level Display_Dig(temp_int_3,59,2); // display 2 digit of light level } else // if result is single-digit number { Off_Dig(32,2); // clear 1 sign of number Off_Dig(41,2); // clear 2 sign of number Off_Dig(50,2); // clear 3 sign of number Display_Dig(temp_int_3,59,2); // display 1 digit of light level } } } }

// Function to display temperature void Read_Temp() { unsigned int buffer; unsigned int temp_int_1,temp_int_2,temp_int_3; // single digits, double digits, triple digits, quarter digits unsigned char Temp_H, Temp_L, OK_Flag, temp_flag; DS18B20_init(); // Initialization of DS18B20 write_18b20(0xCC); // Sensor code check write_18b20(0x44); // Start temperature conversion _delay_ms(1000); // Sensor polling delay DS18B20_init(); // Initialization of DS18B20 write_18b20(0xCC); // Sensor code check write_18b20(0xBE); // Command to read the contents of the Sensor RAM Temp_L = read_18b20(); // Read first two byte Temp_H = read_18b20(); temp_flag = 1; // 1-positive temperature, 0-negative temperature // Get negative temperature if(Temp_H &(1 << 3)) // Sign Bit Check (if bit is set - negative temperature) { signed int temp; temp_flag = 0; // flag is set 0 - negative temperature temp = (Temp_H << 8)|Temp_L; temp = -temp; // Convert the additional code in direct Temp_L = temp; Temp_H = temp >> 8; } buffer = ((Temp_H << 4) & 0x70)|(Temp_L >> 4); temp_int_1 = buffer % 1000 / 100; // triple-digit temp_int_2 = buffer % 100 / 10; // double-digit temp_int_3 = buffer % 10; // single-digit

// If temperature is negative display sign of temperature, else clear if(temp_flag == 0) {Display_Neg(1);} else {Display_Neg(0);} if(temp_int_1 > 0) // if result is triple-digit number { Display_Dig(temp_int_1,45,0); // display 1 digit of temperature Display_Dig(temp_int_2,54,0); // display 2 digit of temperature Display_Dig(temp_int_3,63,0); // display 3 digit of temperature } else { if(temp_int_2 > 0) // if result is double-digit number { Off_Dig(45,0); // clear 1 sign of number Display_Dig(temp_int_2,54,0); // display 1 digit of temperature Display_Dig(temp_int_3,63,0); // display 2 digit of temperature } else // if result is single-digit number { Off_Dig(45,0); // clear 1 sign of number Off_Dig(54,0); // clear 2 sign of number Display_Dig(temp_int_3,63,0); // display 1 digit of temperature } } }

// This ISR is fired whenever a match occurs of timer count with compare value (every 1 second) ISR (TIMER1_COMPA_vect) { // Reading, displaying of temperature and light level Read_Temp(); Read_Lux(); }

// Function to display words "TEMP" and "LUX" void Display_label() { // Word "TEMP" Display_SetXY(0,0); // Set the address of position on display (up row) for (int index=0; index<105; index++) { if (index==40){Display_SetXY(0,1);} // Set the address of position on display (bottom row) if (index==80){Display_SetXY(72,0);} // Set the address of position on display (up row) if (index==92){Display_SetXY(72,1);} // Set the address of position on display (bottom row) SPDR = TEMP_1[index]; // Load codes array data into the buffer of display while(!(SPSR & (1<<SPIF) )); // Wait until transmission complete _delay_ms(10); } // Word "LUX" Display_SetXY(0,2); // Set the address of position on display (up row) for (int index=0; index<60; index++) { if (index==30){Display_SetXY(0,3);} // Set the address of position on display (bottom row) SPDR = TEMP_2[index]; // Load codes array data into the buffer of display while(!(SPSR & (1<<SPIF) )); // Wait until transmission complete _delay_ms(10); } }

int main(void) { Port_Init(); // Port Initialization ADC_init(); // ADC Initialization SPI_Init(); // SPI Initialization SPI_SS_Enable(); // Display Enable DS18B20_init(); // Initialization of DS18B20 Display_init(); // Display initialization Display_Clear(); // Display clear Display_label(); // Display words "TEMP" and "LUX" TIMER1_init(); // Timer1 Initialization. Start monitoring. Getting parameters every one second. // Infinity loop while (1) { } }

Step 3: Flashing Firmware to Microcontroller

Uploading HEX file into the microcontroller flash memory. Watch the video with a detailed description of the microcontroller flash memory burning: Microcontroller flash memory burning...

Step 4: Monitoring Device Circuit Assembly

Connect components in accordance with schematic diagram.

Plug power and it is working!

Arduino Contest 2019

Participated in the
Arduino Contest 2019

Share

    Recommendations

    • Indoor Lighting Contest

      Indoor Lighting Contest
    • Make It Fly Challenge

      Make It Fly Challenge
    • Growing Beyond Earth Maker Contest

      Growing Beyond Earth Maker Contest

    Discussions