Blog Entry




Seven Segment Display Thermometer with PIC Microcontroller

March 8, 2009 by , under Microcontroller.




The seven segment display is one of the most popular numeric displays used in many microcontroller applications because it’s cheap, robust and reliable. The seven segments actually consists of 8 LED (Light Emitting Diode) and it’s come with various sizes suitable for various numeric display application such as digital clock, counter, thermometer, humidity, etc. On this project we are going to show you how to drive this type of display and this time we will use the Microchip PIC16F886 microcontroller to display the room’s temperature both in Centigrade and Fahrenheit scale.

The Seven Segments Display

Many years ago before the LCD (Liquid Crystal Display) come into the arena, the seven segments display is the main player; it’s so popular and its use in almost everything not just to display the numeric value but also a character as well, such as my old Multitech Zilog Z80 microprocessor teaching board to run the BASIC language interpreter bellow:

Seven Segment Display Thermometer with PIC Microcontroller  (1)

From the above picture you could see how complex the circuit was on those days; the circuit consists of separate IC such as 8-bit microprocessor (Zilog Z80), counter timer circuit (CTC), 4K EPROM (Erasable Programmable ROM, this ROM type can be erased only by exposing it to the UV lamp) for the firmware (the board basic I/O function and BASIC language interpreter), 2K RAM for the program and the I/O controller. Thanks to today technology this complex circuit is already put into single chip known as the microcontroller and we don’t have to use this UV lamp to erase the program anymore (you must be laugh right know, but on those days that’s the only way to do it) but what remain the same is; we still use this seven segments display, mostly for displaying the numeric value.

There are two types of seven segments available on the market known as common anode (CA) and common cathode (CC):

Displaying the seven segments is just a matter of applying the correct forward bias voltage to each of the LED’s segment in the seven segments package; for example if we want to show the digit “3” than we have to apply the forward bias voltage on each of the A, B, C, D and G LED segments. The segment pins out is vary among the types and the brands, therefore you have to find out the correct pins for each segments and the common pin as well before you can start to use it.

The Room’s Temperature Project

Our room’s temperature project is use 4 seven segments display for displaying the room’s temperature. The heart of this room’s temperature project is the 8-bit 28 pins midrange Microchip PIC16F886 microcontroller (for those with the Atmel AVR background this microcontroller is comparable to the AVR ATMega8 or ATMega88 microcontroller families). The following is the complete schematic design for this project:

The designed I’ve made here not solely to show the room’s temperature with the seven segments, but it serve as the good learning tools as well, as we will explore the PIC 16F886 features such as ADC (Analog to Digital Converter), PWM (Pulse Width Modulation) and the timer counter capabilities in one shoot. Ok now lets fasten your seat belt as we will run through the design concept here.

First is the display, all the common anode seven segments are connected to PIC 16F886 microcontroller’s port RC0 to RC7, because the microcontroller’s port I/O could not sink the 8 LEDs current all together so we use the 2N3906 PNP transistor (T1 to T4) to sink the current; you could read more about sinking and sourcing I/O port in Powering Your Microcontroller Project article posted on this blog. Differ from usual design I put the NPN BC639 transistor (T5) for driving the four PNP transistors (T1 to T4) with the PWM signal in order to control the seven segments display contrast.

The display contrast is controlled by the LDR (light dependent resistor) together with 10K trimpot serve as the voltage divider input to the PIC16F688 microcontroller analog port AN1; by detecting the light intensity captured by the LDR, this room’s temperature circuit will automatically adjust the seven segments display contrast according to the room’s light intensity. The darkest the room’s the brightest the seven segments display and vise verse.

Secondly the temperature sensor, on this circuit we use the National Semiconductor LM35DZ precision centigrade temperature sensor. The LM35DZ will produce linear voltage output of 10 mV for each degree of the temperature increment in centigrade scale. Together with the 1 Volt voltage reference input provided by 10K trimpot (R17) on the PIC16F886 microcontroller’s VRef+ (4) and VRef- (5) pins, we could precisely measure the room’s temperature on the PIC16F886 microcontroller’s analog port AN0.

The last is the S1 switch, this switch is use as the toggle switch to choose the room’s temperature scale: Centigrade or Fahrenheit. The following table shows the Microchip PIC16F886 microcontroller ports used in this project:

The following is the list of hardware and software used in this tutorial:

1. Resistor: 680 Ohm (8), 4K7 (4), 2K7 (1), 10 K (1)
2. Two Trimpot: 10 K
3. One LDR (Light Dependent Resistor)
4. Capacitor: 100nF (1), 10nF (1)
5. One Micro Switch
6. Transistor: NPN BC639 (1), PNP 2N3906 (4)
7. National Semiconductor LM35DZ precision centigrade temperature sensor (TO-92)
8. 4 Common Anode Seven Segments Display
9. Microchip PIC16F886 Microcontroller
10. Microchip PICKit2 Programmer
11. Microchip MPLAB IDE v8.0 or higher
12. HI-TECH C PRO for the PIC10/12/16 MCU family V9.60PL5 (you could not use the HI-TEC PICC Lite version on the Microchip PIC 16F886 microcontroller, but you could use the Hi-TECH C PRO in Lite Mode).

Now let’s take a look at the C code that makes this thing happen:

// ***************************************************************************
//  File Name    : pictemp.c
//  Version      : 1.0
//  Description  : PIC Thermometer
//  Author       : RWB
//  Target       : Microchip PIC16F886 Microcontroller
//  Compiler     : HI-TECH C PRO for the PIC10/12/16 MCU family V9.60PL5
//  IDE          : Microchip MPLAB IDE v8.00
//  Programmer   : PICKit2
//  Last Updated : 28 Feb 2009
// ***************************************************************************
#include <pic.h>
/*   PIC Configuration Bit:
**   INTIO      - Using Internal RC No Clock
**   WDTDIS     - Wacthdog Timer Disable
**   PWRTEN     - Power Up Timer Enable
**   MCLRDIS    - MCLR functions as IO
**   UNPROTECT  - Code Un-Protect
**   DUNPROTECT - Do not read protect EEPROM data
**   BORDIS     - Brown Out Detect Disable
**   IESODIS    - Internal External Switch Over Mode Disable
**   FCMDIS     - Monitor Clock Fail Safe Disable
**   BORV21     - Brown Out Reset 2.1 Volt
*/
__CONFIG(INTIO & WDTDIS & PWRTDIS & MCLRDIS & UNPROTECT & DUNPROTECT & \
  BORDIS & IESOEN & FCMDIS & LVPDIS & DEBUGEN);   // Address 0x2007
__CONFIG(BORV21);                                 // Address 0x2008
// Using Internal Clock of 8 MHz
#define FOSC 8000000L
// Variable Used for Thermometer
#define LDR_THRESHOLD 50
#define MAX_DCYCLE 255
const char SSEG[] = {
  0b11000000,  // 0, LED Segment: A,B,C,D,E,F
  0b11111001,  // 1, LED Segment: B,C
  0b10100100,  // 2, LED Segment: A,B,D,E,G
  0b10110000,  // 3, LED Segment: A,B,C,D,G
  0b10011001,  // 4, LED Segment: B,C,F,G
  0b10010010,  // 5, LED Segment: A,C,D,F,G
  0b10000010,  // 6, LED Segment: A,C,D,E,F,G
  0b11111000,  // 7, LED Segment: A,B,C
  0b10000000,  // 8, LED Segment: A,B,C,D,E,F,G
  0b10010000,  // 9, LED Segment: A,B,C,D,F,G
  0b11000110,  // C, LED Segment: A,D,E,F
  0b10001110   // F, LED Segment: A,E,F,G
};
unsigned char DispDigit[4];
unsigned char DigitCount;
unsigned char TempType;
static void interrupt isr(void)
{
  if(T0IF) {			    // TIMER0 Interrupt Flag
    /* Pull Low the Segment */
    PORTC = DispDigit[DigitCount];
    /* Activate the Digit and Advanced to next Digit */
    PORTB = ~(1 << DigitCount++);     

    /* Reset the Digit Count */
    if (DigitCount > 3)
      DigitCount=0;

    TMR0 = 156;             // Initial Value for 3.2 ms Interrupt
    T0IF = 0;			    // Clear TIMER0 interrupt flag
  }
}
// Delay Function
#define _delay_us(x) { unsigned char us; \
	  	       us = (x)/(12000000/FOSC)|1; \
		       while(--us != 0) continue; }
void _delay_ms(unsigned int ms)
{
  unsigned char i;
  do {
    i = 4;
    do {
      _delay_us(164);
    } while(--i);
  } while(--ms);
}
/* Seven Segment Put Number: Implementing floating value from 0 to 99.9 */
void SSEG_putnum(float number)
{
   unsigned char iDigit,iDigit1,iDecimal;
   if (number > 99.9) return;
   /* Global interrupt disable */
   GIE = 0;		                   

   iDigit=number;                        // Convert float to Integer
   iDecimal=(number - iDigit) * 10;      // Get The Decimal Digit
   DispDigit[1]=SSEG[iDecimal];          // First Decimal Digit
   if (iDigit >= 10) {
     iDigit1=iDigit / 10;
     DispDigit[3]=SSEG[iDigit1];         // Second Digit
     iDigit=iDigit - (iDigit1 * 10);
   } else {
     DispDigit[3]=SSEG[0];               // Zero Sign Second Digit
   }
   DispDigit[2]=SSEG[iDigit] & 0x7F;     // First Digit with Decimal Point
   /* Global interrupt enable */
   GIE = 1;
}
void main(void)
{
  unsigned int iValue,iCTemp;
  unsigned char ldr_value;
  float CentTemp;

  OSCCON=0x70;         /* Select 8 MHz internal clock */

  TRISA = 0xFF;        // Input for RA0 to RA7
  TRISB = 0x00;        // Output for RB0 to RB7
  TRISC = 0x00;        // Output for RC0 to RC7
  ANSEL = 0b00000011;  // Set PORT AN0 and AN1 to analog input AN2 to AN7 digital I/O
  ANSELH = 0b00000000; // Set Other as Digital I/O
  /* Initial Output Port */
  PORTC=0xFF;
  PORTB=0xFF;
  /* Init TIMER0: Period: 1/(Fosc/4) x Prescaler x TMR0
     0.0005 ms x 64 * 100 = 3.2 ms */
  OPTION = 0b00000101; // 1:64 Prescaler
  TMR0=156;            // Interrupt every 3.2 ms
  T0IE = 1;	       // Enable interrupt on TMR0 overflow
  GIE = 1;	       // Global interrupt enable
  /* Init PWM for Single Output */
  CCP1CON=0b00001100;  // Single PWM mode; P1A, P1C active-high; P1B, P1D active-high
  CCPR1L=MAX_DCYCLE;   // Start with Max Duty Cycle
  T2CON=0b00000101;    // Postscaler: 1:1, Timer2=On, Prescaler = 1:4
  PR2=0x65;            // Frequency: 4.90 kHz
  TMR2=0;              // Start with zero Counter
  PSTRCON=0b00001000;  // Enable Pulse Steering on P1D (RB4)
  /* Initial variables used */
  DigitCount=0;
  TempType=0;                // Centigrade Type
  DispDigit[0]=SSEG[10];     // Centigrade Sign
  DispDigit[1]=SSEG[0];      // Zero Digit
  DispDigit[2]=SSEG[0];      // Zero Digit
  DispDigit[3]=SSEG[0];      // Zero Digit
  for(;;) {
    /* Get First Sample */
    ADCON0=0b11000001;       // Select the FRC for 8 MHz. ADC port channel 0, Turn On A2D
    ADCON1=0b10110000;       // Right Justified, Vref: VCFG1 and VCFG0 (1 Volt Reference)
    GODONE=1;	             // initiate conversion on the channel 0
    while(GODONE) continue;  // Wait conversion done
    iValue=ADRESL;           // Get the 8 bit LSB result
    iValue += (ADRESH << 8); // Get the 2 bit MSB result
    iCTemp = iValue;
    _delay_ms(50);
    /* Get Second Sample */
    GODONE=1;	// initiate conversion on the channel 0
    while(GODONE) continue;  // Wait conversion done
    iValue=ADRESL;           // Get the 8 bit LSB result
    iValue += (ADRESH << 8); // Get the 2 bit MSB result
    iCTemp += iValue;
    _delay_ms(50);
    /* Get Third Sample */
    GODONE=1;	// initiate conversion on the channel 0
    while(GODONE) continue;  // Wait conversion done
    iValue=ADRESL;           // Get the 8 bit LSB result
    iValue += (ADRESH << 8); // Get the 2 bit MSB result
    iCTemp += iValue;

    /* Calculate the Average Centigrade Value */
    /* (ADC Value/10.24) / Vref, LM35DZ Out=10mV/C, Vref = 1 Volt */
    CentTemp=(iCTemp/3.0)/ 10.24;
    /* Read the Light Sensor */
    ADCON0=0b11000101;       // Select the FRC for 8 MHz. ADC port channel 1, Turn On A2D
    ADCON1=0b00000000;       // Left Justified, Vref: Vss and Vdd
    GODONE=1;	             // initiate conversion on the channel 0
    while(GODONE) continue;  // Wait conversion done
    ldr_value = ADRESH;        // Get the LDR Value, Ignore the LSB on ADRESL
    if (ldr_value > LDR_THRESHOLD)
     ldr_value = LDR_THRESHOLD;
    CCPR1L=MAX_DCYCLE - (5 * ldr_value);  // Set the PWM Duty Cycle
    /* Read the RA4 Switch */
    if (RA4 == 0) {              // Change the Thermometer Type when pressed
      _delay_ms(1);
      if (RA4 == 0) {            // Read again for Simple De bounce
        TempType=~TempType;      // Change Type Flag
      }
    }
    /* Set the Temperature Type */
    if (TempType) {
      /* Fahrenheit = 9/5 x Centigrade + 32 */
      CentTemp=((9.0/5.0) * CentTemp) + 32;
      DispDigit[0]=SSEG[11];     // Fahrenheit Sign
    } else {
      DispDigit[0]=SSEG[10];     // Centigrade Sign
    }

    /* Now Display The Result */
    SSEG_putnum(CentTemp);
    _delay_ms(200);
  }
}
/* EOF: pictemp.c */

Multiplexing with PIC TIMER0

As you’ve seen from the schematic above, displaying the entire seven segments digits at the same time would be not possible because every digit will have different information to be displayed, in other word every digit will display different LED segment combination; therefore the solution is to display it one at the time. If we display the four seven segment digits in sequence fast enough, it will appear (give an illusion) to our eyes as we display all these segments simultaneously; this method is called multiplexing.

The multiplexing algorithm is best implemented using the PIC timer/counter TIMER0 peripheral; by letting the TMR0 counter register to overflow and generate interrupt every 3.2 ms, we could display each of the seven segments digit every 3.2 ms; the total time to complete displaying the whole digits is about 12.8 ms (4 x 3.2ms) and this time is already sufficient to avoid flicking appear to our eyes (you could read more about PIC TIMER0 peripheral on the Basic Servo Motor Controller with Microchip PIC Microcontroller article posted on this blog).

The following is the C code that implements this algorithm:

const char SSEG[] = {
  0b11000000,  // 0, LED Segment: A,B,C,D,E,F
  0b11111001,  // 1, LED Segment: B,C
  0b10100100,  // 2, LED Segment: A,B,D,E,G
  0b10110000,  // 3, LED Segment: A,B,C,D,G
  0b10011001,  // 4, LED Segment: B,C,F,G
  0b10010010,  // 5, LED Segment: A,C,D,F,G
  0b10000010,  // 6, LED Segment: A,C,D,E,F,G
  0b11111000,  // 7, LED Segment: A,B,C
  0b10000000,  // 8, LED Segment: A,B,C,D,E,F,G
  0b10010000,  // 9, LED Segment: A,B,C,D,F,G
  0b11000110,  // C, LED Segment: A,D,E,F
  0b10001110   // F, LED Segment: A,E,F,G
};
unsigned char DispDigit[4];
unsigned char DigitCount;
if(T0IF) {		      // TIMER0 Interrupt Flag
  /* Pull Low the Segment */
  PORTC = DispDigit[DigitCount];
  /* Activate the Digit and Advanced to next Digit */
  PORTB = ~(1 << DigitCount++);     

  /* Reset the Digit Count */
  if (DigitCount > 3)
    DigitCount=0;

  TMR0 = 156;             // Initial Value for 3.2 ms Interrupt
  T0IF = 0;		  // Clear TIMER0 interrupt flag
}

The seven segments LED display is store in the SSEG[] constant array, therefore by assigning this array to the PIC16F886 microcontroller’s PORT C (RC0 to RC7), the corresponding LED’s segment on the seven segments display will be pulled to the ground (low), and by pulling low the corresponding PNP transistor (T1 to T4) base lead attached to the PORT B, we could make the seven segment to display it’s content.

The TIMER0 is initialized by choosing the 64 prescaler on the OPTION register and preset the TIMER0 counter register TMR0 to 156 will ensure that it will always overflow every 3.2 ms. Using the 8 MHz internal clock frequency, we could calculate the TIMER0 period with this following formula:

TIMER0 Period = 1/(Fosc/4) x Prescale x (256 – TMR0)

TIMER0 Period = 0.0005ms x 64 x (256 – TMR0) = 3.2 ms

Bellow is the complete C code for initializing this PIC TIMER0 peripheral:

/* Init TIMER0: Period: 1/(Fosc/4) x Prescaler x TMR0
     0.0005 ms x 64 * 100 = 3.2 ms */
OPTION = 0b00000101; // 1:64 Prescale
TMR0=156;            // Interrupt every 3.2 ms
T0IE = 1;            // Enable interrupt on TMR0 overflow
GIE = 1;	     // Global interrupt enable

Reading the Temperature

The room’s temperature is base on the voltage level output supplied by the LM35DZ sensor, this precision centigrade temperature sensor from National Semiconductor is connected to the PIC16F886 microcontroller’s analog port AN0.

In order to get the precision ADC result on the PIC16F886 microcontroller, we use the 10 K trimpot (R17) to supply the 1 volt external voltage reference to the microcontroller’s successive approximately circuit. Make sure you adjust this trimpot so the voltage across VRef+ (Pin 5) and VRef- (Pin 4) is measured approximately 1 volt, this is the first important step after you complete building this project. The ADC peripheral on the PIC16F886 in general is similar to the PIC16F690 (you could read more information about the PIC ADC on the PIC Analog to Digital C Programming article posted on this blog); there are only minor different on setting the ADCON0 and ADCON1 registers (for more information please refer to the Microchip PIC16F886 microcontroller datasheet).

Because we are using the internal clock (FRC) of 8 MHz, then we set these ADC clock selection bits to ADCS1 = 1 and ADCS0 = 1. The channel selection bits CHS3, CHS2, CHS1 and CHS0 is used to select the appropriate analog channel input where on this project we use 2 analog inputs, one for the temperature sensor (AN0) and the other for the light intensity sensor (AN1).

The 10-bit analog to digital conversion result format in ADRESH and ADRESL registers is determined by the ADFM bit on the ADCON1 register, by setting this bit to “0” the result will be left justified, this mean the first 8-bit MSB bits will be placed on the ADRESH register while the last 2-bit LSB bits will be placed on the ADRESL register. Assigning ADFM bit to “1” make the 10-bit ADC peripheral to put the first 2-bit MSB result on the ADRESH register and the last 8-bit result will be placed on the ADRESL register (right justified result).

The voltage reference bits VCFG1 and VCFG2 is use to select the voltage reference for the ADC peripheral circuit; when we use the PIC16F886 microcontroller’s ADC peripheral circuit to read the room’s temperature we use the 1 volt external voltage reference, therefore we set the VCFG1 and VCFG0 bits to “1“; and when we use it for reading the light intensity we set these voltage reference bits to “0” (use the Vdd as the voltage reference). The following is the C code for setting the PIC 16F886 microcontroller’s ADC peripheral:

ADCON0=0b11000001;  // Select the FRC for 8 MHz. ADC port channel 0, Turn On A2D
ADCON1=0b10110000;  // Right Justified, Vref: VCFG1 and VCFG0 (1 Volt Reference)

The 10-bit ADC result could be calculated using this following formula:

ADC Result = (Vin x 1024) / VRef

With the 10 mV linear increment for every Centigrade increment of the room temperature starting from zero, than the 100 Centigrade degree room’s temperature with 1 volt external voltage reference could be calculated as follow:

ADC result = (Vin x 1024) / VRef = (100 x 10mV x 1024)/1 = 1024

Dividing the result by 10.24, we could get the exact reading of 100 on Centigrade scale. Using the following Centigrade to Fahrenheit conversion formula bellow we could easily convert the scale from Centigrade to the Fahrenheit scale:

Fahrenheit Scale = 9/5 x Centigrade Scale + 32

The PWM Controlled Display

One of my favorite features on this project is the ability to automatically control the brightness of the seven segments display according to the room’s light intensity; this feature make this circuit to use low power consumption by dimming the seven segment’s LED on the bright light room and brighten the seven segment’s LED on the complete darkness.

The heart of this feature is the PIC16F886 microcontroller single output PWM mode (you could read more about PIC PWM on the H-Bridge Microchip PIC Microcontroller PWM Motor Controller article posted on this blog), the PWM signal is feed to the base lead of T5 transistor (BC639) which supply the current needed by the seven segments driver transistors T1 to T4 (2N3906). By making lower PWM duty cycle the T5 transistor will conduct less, this will make the T1 to T4 transistors supply less current to the seven segments and as the result the LEDs will dim. Bellow is the PIC PWM peripheral initialization C code:

#define MAX_DCYCLE 255
/* Init PWM for Single Output */
CCP1CON=0b00001100;  // Single PWM mode; P1A, P1C active-high; P1B, P1D active-high
CCPR1L=MAX_DCYCLE;   // Start with Max Duty Cycle
T2CON=0b00000101;    // Postscale: 1:1, Timer2=On, Prescale = 1:4
PR2=0x65;            // Frequency: 4.90 kHz
TMR2=0;              // Start with zero Counter
PSTRCON=0b00001000;  // Enable Pulse Steering on P1D (RB4)

The LDR (Light Dependent Resistor) and the trimport circuit is called voltage divider circuit (you could read more about the voltage divider circuit on the Basic Resistor Circuit article posted on this blog), this circuit simply provide the voltage level to the AN1 analog input channel; more light received by the LDR the higher the voltage level input to the AN1 port and vice verse.

Therefore by connecting the ADC result from AN1 channel to the PWM duty cycle, we could achieve this behavior as shown on this C code bellow:

#define LDR_THRESHOLD 50
#define MAX_DCYCLE 255
/* Read the Light Sensor */
ADCON0=0b11000101;     // Select the FRC for 8 Mhz. ADC port channel 1, Turn On A2D
ADCON1=0b00000000;     // Left Justified, Vref: Vss and Vdd
GODONE=1;	         // initiate conversion on the channel 0
while(GODONE) continue;  // Wait conversion done
ldrvalue=ADRESH;         // Get the LDR Value, Ignore the LSB on ADRESL
if (ldr_value > LDR_THRESHOLD)
  ldrvalue=LDR_THRESHOLD;
CCPR1L=MAX_DCYCLE - (5 * ldr_value); // Set the PWM Duty Cycle

As you notice from the code that we are not directly assign the ADC result on the ADRESH register to the CCPR1L register which control the PWM duty cycle output; this is due to the behavior we required; that the more light intensity received by the LDR the more higher the ADC value result we’ve got but on the other hand we have to assign less PWM duty cycle value and vice verse.

Inside the C Code

Differ from the Microchip PICF6F690, the PIC16F886 microcontroller has two configuration bit words; one is located on the address 0×2007 and the other on the address 0×2008. Although we disable the brown out detection on this project (BORDIS) but is a good practice to put these two configuration bits words in your program:

__CONFIG(INTIO & WDTDIS & PWRTDIS & MCLRDIS & UNPROTECT & DUNPROTECT & \
  BORDIS & IESOEN & FCMDIS & LVPDIS & DEBUGEN);   // Address 0x2007
__CONFIG(BORV21);                                 // Address 0x2008

As you see from the statement, there is no configuration bit address specified on the code, but the HITEC-C PRO compiler is smart enough to place the BORV21 (brown out reset at 2.1 volt) configuration bit to the correct address 0×2008.

The program begin by initialized the PIC16F886 microcontroller’s ports needed by this project and continue with the PIC peripheral initialization routine. Next the program entering the infinite loop where inside this loop the program will do these following tasks:

  • First we read the room’s temperature from the analog channel 0 three times and get the average result
  • Secondly we read the room’s light intensity from the analog channel 1 and use the value to properly adjust the PWM duty cycle for the display contrast
  • Third we read the switch and doing the Centigrade to Fahrenheit scale conversion as needed.
  • At last we display the room’s temperature value by calling the SSEG_putnum() function; this function work by separating the numeric value digits and assign each digit to the corresponding DispDigit[] array variable using the appropriate seven segment constant SSEG[] array definition. Next the PIC TIMER0 interrupt function will use the DispDigit[] array variable and DigitCount variable for multiplexing the output through PIC16F886 microcontroller’s PORTC and PORTB.

Downloading the Code

After compiling and simulating your code hook up your PICKit2 programmer to the board ICSP connector (in this project I use the breadboard). From the MPLAB IDE menu select Programmer -> Select Programmer -> Pickit2 it will automatically configure the connection and display it on the PICkit2 tab Output windows:

Now you are ready to down load the code from MPLAB IDE menu select Programmer -> Program; this will down load the HEX code into the Microchip PIC 16F886 Microcontroller:

Seven Segment Display Thermometer with PIC Microcontroller (2)

Now just relax and enjoy your room’s temperature project in action:

The Final Thought

If you build this project using the breadboard (as I did), with your creativity and imagination you could transform this project as the work of art by putting the breadboard inside the nice photo frame and hang it on the wall or perhaps putting on your desk. Share it to your friends and let them enjoy the electronics art as well as the fully functioning room’s temperature with the light sensor, who knows they might be interest to buy this piece of art from you; of course if you willing to sell it. Just to give you a clue to what I mean, take a look on this possible looks of your room’s temperature project:

Seven Segment Display Thermometer with PIC Microcontroller (3)

Bookmarks and Share


bookmark bookmark bookmark bookmark bookmark bookmark bookmark bookmark bookmark bookmark




117 Responses to “Seven Segment Display Thermometer with PIC Microcontroller”

03.10.09#1

Comment by worthyrabbito.

Hello! I’m trying to build your circuit. How about if I use MikroC as my compiler. Can you please help me with the codes. I’m not familiar with MPLAB IDE. Tnx

03.10.09#2

Comment by rwb.

Currently I’ve never used the mikroC PIC Compiler, as I understand this compiler has already come with advanced library build in (e.g. ADC, PWM, etc) therefore you will have two choices when programming with this C compiler, either to use the easy approach (use library) or use your own code as shown on this blog. For the learning purpose, I’ve tend to use a C compiler that only has basic/standard library build in in order to understand how the hardware really work.

04.10.09#3

Comment by worthyrabbito.

I was trying to simulate it first using Proteus encoded with the codes from MikroC. But I couldn’t get it to work =( We were only thought programming in MikroC

04.10.09#4

Comment by worthyrabbito.

I meant taught LOL

04.10.09#5

Comment by rwb.

Actually what you need is to convert the HITEC-PRO C dialect to the MikroC dialect, most of the C syntax I think will be the same/standard, the different between various PIC C compiler is how they implement the INTERRUPT FUNCTION, I/O PORT NAMING, REGISTER NAMING and how they setup the PIC microcontroller INITIAL CONFIGURATION. My suggestion before you code, make sure your hardware is work by using a jumper to debug on each of the seven segment LEDs; this make you absolutely sure that your hardware is working and the error is not caused by the firmware.

06.10.09#6

Comment by ian_april.

Can i replace the PIC16F886 micro controller with PIC18F242.. the required MCU in this project is not available in our area…

What will be the changes in the program?

Please help me…i am not yet familiar in programming MCU…

Thank you..

07.10.09#7

Comment by ian_april.

please reply…. badly needed…

08.10.09#8

Comment by rwb.

Yes you could change the PIC16F886 to PIC18F242; although the PWM feature is slightly different between these two microcontroller. For example you could not use the PB4 for PWM output as PIC16F886, instead you have to use RC2 and this mean you have to change the schematic shown above. Therefore I suggest to read the PIC18F242 datasheet and compare it to the PIC16F886. The other consideration is for the PIC18F microcontroller families there are more C compiler option beside the HITEC PIC18 Compiler, there is also Microchip own C18 compiler, mean you have to choose your prefer C compiler for your project.

08.10.09#9

Comment by worthyrabbito.

I want to be able to measure negative temperature also. what will i add on the circuit? cause supposedly, when the voltage out from LM35 is negative, it considers it as zero right?

08.10.09#10

Comment by rwb.

Yes, using the circuit above you could not measure negative temperature; the best/simple one is to use digital temperature sensor such as DS18B20, but if you want to use the LM35CZ (not LM35DZ) to measure negative temperature you need to add diode to the LM35CZ ground to keep it +0.7 Volt relative to it’s output (for non negative supply, see datasheet) and use Op-Amp to shift the LM35CZ output voltage so it’s swing only on the positive level for the ADC input.

08.10.09#11

Comment by ian_april.

what will be the modification in addresses in the program using PIC18F242?

Thank y0u… =)

08.10.09#12

Comment by ian_april.

what will be the changes in the program (C code) if i will replace the PIC16F886 with PIC18f242?

08.10.09#13

Comment by rwb.

My suggestion when you are learning the microcontroller especially at the first time it’s better just to follow what is already being proven to work, changing the microcontroller type such as PIC16F to PIC18F families actually required more experience knowledge both in hardware and software in order to make it work. Once you gain experience building and understanding this project both in hardware and software, next it will be easier for you to convert or build your own version of this project to any microcontroller type available in the market.

10.10.09#14

Comment by worthyrabbito.

I don’t understand this from your codes,
CentTemp=(iCTemp/3.0)/ 10.24;

You mention that ADCValue/10.24 = Centigrade Value;then why did you divided iCTemp by 3? I thought iCTemp is already equal to ADCValue.

10.10.09#15

Comment by worthyrabbito.

also, i don’t why do you have to get the 8bit LSB and the 2 bit MSB first? Sorry if I’m asking to much questions =)

10.10.09#16

Comment by rwb.

Because the ADC value is read three times (iCTemp += iValue) for accuracy, then this accumulated value is divided by three to get the average value.

Remember the PIC16F886 is the 8-bit class microcontroller; while the ADC peripheral is 10-bit resolution, therefore first we get the LSB (8-bit) in ADRESL register then later added the remaining MSB (2-bit) in ADRESH register. You should read my previous posted blog “PIC Analog to Digital Converter C Programming” to get an idea of how the ADC work.

10.10.09#17

Comment by ian_april.

Sorry but PIC16F886 is not available in any electronic shops in our region… and we don’t have enough time to make an order in Singapore…
i’ve read that PIC16F886 is compatible with PIC16F877A…
the problem is that PIC16F877A has 40 pins….. will there be any changes with the program and the schematic diagram?

10.10.09#18

Comment by rwb.

Most of the Microchip PIC16F families member is compatible one to each other. The closest to PIC16F886 is the PIC16F887 (40 pins) not the PIC16F877A. Even though you use the PIC16F887 you still have to make a minor changes both in schematic and program.

11.10.09#19

Comment by worthyrabbito.

Oh, sorry. But now I get your idea. In MikroC just typing the code ADC_read automatically gives you the 10bit resolution. So I got kinda confused hehe.

11.10.09#20

Comment by worthyrabbito.

To ian_april:
Actually, I’m using PIC16F877 also. Since 886 is not available in my compiler (have no plans of upgrading yet LOL). I’ve made my code, it’s just a typical thermometer, tough (without the LDR). But I’m planning to add it, after I work with having a negative temperature.

13.10.09#21

Comment by ian_april.

To worthyrabbito:

what are the changes y0u’ve done in the schematic diagram for PIC16F877?

Can i have a copy of your code? LOL

Thanks….=)

13.10.09#22

Comment by worthyrabbito.

sure, pls give me your email add. I’ll send it to you

14.10.09#23

Comment by ian_april.

To worthyrabbito:

april_einah15@yahoo.com

thanks a l0t….. :’)

y0u’re a big help…

15.10.09#24

Comment by ian_april.

To worthyrabbito:

Please… share the schematic and code….

badly needed… :(

15.10.09#25

Comment by ian_april.

How to modify this if an external clock for PIC166f877a is used?

// Using Internal Clock of 8 Mhz
#define FOSC 8000000L

15.10.09#26

Comment by rwb.

Just change the number, if you use 16Mhz external clock then the FOSC definition will be 16000000L.

16.10.09#27

Comment by ian_april.

what if 9.6 MHz is used?

what will be the definition of FOSC?

sorry for t00 many questi0ns… :)

16.10.09#28

Comment by rwb.

FOSC mean your Oscillator Frequency in Hz, whether you use the internal or external oscillator. Therefore if you use 9.6 MHz than it will be equal to 9600000 Hz and the definition will be 9600000L (L is use to tell the compiler that this is a LONG type number).

16.10.09#29

Comment by ian_april.

Ah.. i see..
How about this code using PIC16f877A, what will be the changes??

{
if(T0IF) { // TIMER0 Interrupt Flag
/* Pull Low the Segment */
PORTC = DispDigit[DigitCount];

/* Activate the Digit and Advanced to next Digit */
PORTB = ~(1 < 3)
DigitCount=0;

TMR0 = 156; // Initial Value for 3.2 ms Interrupt
T0IF = 0; // Clear TIMER0 interrupt flag
}
}

16.10.09#30

Comment by ian_april.

OSCCON=0×70; /* Select 8 Mhz internal clock */

how about this? what will be the right code for PIC16F877A?

thanks a l0t..

16.10.09#31

Comment by ian_april.

Will it be alright if we will burn your PIC16F886 thermometer program on PIC16F877A without modifying?

will it work?

16.10.09#32

Comment by rwb.

No it won’t work! For example OSCCON register is not available on PIC16F877A, because PIC16F877A doesn’t have internal oscillator. The TIMER0 is compatible so you could use the interrupt routine, The PWM is not compatible so just drop the PWM feature always make RB4 output high. The ADC is compatible so you could use it, but only for the temperature input (RA0), drop the LDR input (RA1) because you don’t use the PWM to control the seven segment intensity.

16.10.09#33

Comment by worthyrabbito.

Hi ian_april! I see we’re both throwing the author too many questions LOL. I’ve already sent the file in your email add. Sorry if it took ages. I haven’t had the time to visit this site lately. Been busy at school.

17.10.09#34

Comment by ian_april.

To worthyrabbito:

Thanx a lot for the file.. :)

Yah right! i hope that rwb is not mad.. LOL

18.10.09#35

Comment by hmagadla.

How does isr function work. It’s not called out anywhere in main. You also have somewhere in your code iDigit=number;
idecimal=(number-iDigit)*10;
idecimal will be zero always, am I wrong? I have many other questions about the code. Here is my e-mail address if you dont mind: hummagadla@aol.com

18.10.09#36

Comment by rwb.

For more explanation about how TIMER0 ISR work please read “Basic Servo Motor Controlling with Microchip PIC Microcontroller”. Yes it will always zero when the number is integer, but when the number is decimal then it will contain the decimal value, here is the example

number = 54.3 -> number is a float
iDigit = number -> iDigit = 54 -> iDigit is an integer

iDecimal = (number – iDigit) * 10
iDecimal = (54.3 – 54) * 10 = 3

This is how you could display the decimal part in
seven segment display.

02.11.09#37

Comment by KyAZ.

iDigit=number; // Convert float to Integer

*My Compiler cannont perform this command, I get an error message saying that it cannot convert a float to an integer. Any suggestions to get around this?

02.11.09#38

Comment by KyAZ.

By the way, this is a fantastic project with code. I am using a PIC16F819, and modifying the code to make it work with what I have. Your project is easy to understand, and follow. Thank you.

02.11.09#39

Comment by rwb.

Thank you, Another way is to use the C language casting operator as shown on this following code:

iDigit=(int)number; // Convert float to Integer

24.11.09#40

Comment by papymasangu.

Hi, I’am a new student with microcontroller . I’am using pic 16f877a ,I please asking for the shematique and codes of the thermometer .Here my email address papymasangu@yahoo.fr
yours input will be much appreciated
thanx

24.11.09#41

Comment by rwb.

Again my suggestion is to use this working schematic and code for your project. Please read my previous comments!

26.11.09#42

Comment by papymasangu.

To worthyrabbito
I’m trying to use the code in my pic 16f877a but always fail .I read previous comment in this web ,is it possible that I might get the right code for my pic and the shematique
please help !
tanx

03.02.10#43

Comment by farhan13.

hi,
sorry for asking this.do you have the assembly code for this project?can u send to me?

03.02.10#44

Comment by rwb.

No, I don’t have.

12.03.10#45

Comment by diya.

Sorry can you send me schematic circuit and code C language for pic C compiler using PIC16F877A please :)

12.03.10#46

Comment by diya.

I really needed it for may final year project

12.03.10#47

Comment by rwb.

Currently this project is designed and tested only with the PIC16F886 microcontroller. For use with PIC16F877A you have to make minor change to schema and the C program, please read my previous comment regarding this issue.

13.03.10#48

Comment by gnimpil.

Hi,
I cant find the 2N9306 in my country. Is there any other transistor that can be use to replace 2N9306? Can you list it for me? thanks!

13.03.10#49

Comment by gnimpil.

erm…there should be a correction in the list of component. The transistor used should be 2N3906 not 2N9306 rite?

13.03.10#50

Comment by rwb.

Thanks, you are right the component list should be 2N3906 instead of 2N9306

18.03.10#51

Comment by gnimpil.

i tried to run the simulation and i got this warning

[PIC16ADC] PC=0×0470 ADC conversion started before” wait “time has expired following previous conversion or channel change

[PIC16ADC] PC=0×0555 ADC conversion started before” wait “time has expired following previous conversion or channel change

Do you have any idea how this occur? and how to fix it?
For you information, i change the BC639 to 2N4401 because there are no BC639 in my Proteus library.

19.03.10#52

Comment by rwb.

I’ve never tested this circuit and use the Proteus simulator. Therefore base on the message I think is nothing to do with the transistor and the warning is about reading the ADC value.

24.03.10#53

Comment by gnimpil.

hi it’s me again.
i still cant get the circuit working. at least not the simulation.
i compile the code using MPLab IDE and Hi Tech C
when i load the hex file into Proteus, all i got was just the seven segment showing 4 zero and there are no response when i increase or decrease the temperature.
is there any mistake in the source code? thanks

24.03.10#54

Comment by rwb.

The Code is Ok, At least the simulation should display the “C” sign on the last digit (assuming the ADC value is zero):

DispDigit[0]=SSEG[10]; // Centigrade Sign
-or-
DispDigit[0]=0b11000110 // C, LED Segment: A,D,E,F

But if it display all zero, than you have to check the simulation circuit again.

09.04.10#55

Comment by reinneguhn.

hi there.
i tried doing your project but its not working right for me in the coding part.
in my project, i dont use PWM features (only want to display the temperature) and im using 2Mhz of external clock and PIC16F77a.

i got confused at the configuration bit word part.

__CONFIG(INTIO & WDTDIS & PWRTDIS & MCLRDIS & UNPROTECT & DUNPROTECT & \
BORDIS & IESOEN & FCMDIS & LVPDIS & DEBUGEN); // Address 0×2007
__CONFIG(BORV21);

will this configuration work if i use it with my PIC16F877a??

09.04.10#56

Comment by rwb.

First of all the PIC16F877A (40 pins) is differ from the PIC16F886 (28 pins) or PIC16F887 (the 40 pins version). The PIC16F877A doesn’t have internal oscillator and the configuration bit only reside on the address 0×2007, while PIC16F886 is on the address 0×2007 and 0×2008. The following is the correct configuration bit for PIC16F877A (assuming you used external crystal clock):

__CONFIG(XT & WDTDIS & PWRTDIS & UNPROTECT & BORDIS & \
LVPDIS & DEBUGEN);

10.04.10#57

Comment by reinneguhn.

since im not using the PWM features and only displaying the temperature in celcius so i dont need to use these right:

// Variable Used for Thermometer
#define LDR_THRESHOLD 50
#define MAX_DCYCLE 255

0b10001110 // F, LED Segment: A,E,F,G

unsigned char TempType;

OSCCON=0×70; /* Select 8 MHz internal clock */

ANSEL = 0b00000011; // Set PORT AN0 and AN1 to analog input AN2 to AN7 digital I/O
ANSELH = 0b00000000; // Set Other as Digital I/O

/* Init PWM for Single Output */

TempType=0;

/* Read the Light Sensor */

/* Read the RA4 Switch */

/* Set the Temperature Type */

10.04.10#58

Comment by rwb.

Yes you right, because the PIC16F877A microcontroller doesn’t have the OSCCON, ANSEL and ANSELH registers.

10.04.10#59

Comment by reinneguhn.

another thing that i want to clarify is about this:

/* Initial Output Port */
PORTC=0xFF;
PORTB=0xFF;

isnt it suppose to be like this, since port B and C are output??:

PORTC=0×00;
PORTB=0×00;

10.04.10#60

Comment by rwb.

The microcontroller port initialization is depend on the electronic hardware design that you are going to use; in this project I use PORTC to drive the common anode seven segment LED where it will ON when we give the logical “0″ and OFF when we give the logical “1″. The PORTB is used to drive the 2N3906 PNP transistors (T1,T2,T3 and T4) and to make them ON is by giving the logical “0″ to the B (base) terminal and OFF is by giving them the logical “1″. Therefore the output port initialization for both PORTB and PORTC is “0xFF”.

11.04.10#61

Comment by reinneguhn.

i got problem when building my program, it say :

“undefined identifier: GODONE”

my setting is something like this:

ADCON0=0b10000001;
ADCON1=0b10001101;
GODONE=1;
while(GODONE) continue;
iValue=ADRESL;
iValue += (ADRESH << 8); // Get the 2 bit MSB result
iCTemp = iValue;
_delay_ms(50);

how can i solve this problem and do we have to include header file in our program??

12.04.10#62

Comment by reinneguhn.

owh nvm rwb, i finally figure out my mistake..
actually we just need to change GODONE to ADGO, then the program run smoothly..

12.04.10#63

Comment by rwb.

One important thing when you port the program to different microcontroller family is to check the included header file and the compiler version. In my HI-TECH C PRO v9.7 compiler both identifier GODONE and ADGO for PIC16F877A (pic1687x.h> is being defined and both pointed to the same address:

/* ADCON0 bits */
volatile bit ADCS1 @ (unsigned)&ADCON0*8+7;
volatile bit ADCS0 @ (unsigned)&ADCON0*8+6;
volatile bit CHS2 @ (unsigned)&ADCON0*8+5;
volatile bit CHS1 @ (unsigned)&ADCON0*8+4;
volatile bit CHS0 @ (unsigned)&ADCON0*8+3;
volatile bit ADGO @ (unsigned)&ADCON0*8+2;
// Alternate definition for compatibility with other devices
volatile bit GODONE @ (unsigned)&ADCON0*8+2;
volatile bit ADON @ (unsigned)&ADCON0*8+0;

12.04.10#64

Comment by reinneguhn.

Ok, so we do need header file for this. Do you mind sending me your header file?? its really urgent for me, i’ll edit the header file later.

my email address is: reinneguhn89@gmail.com

thank you.

12.04.10#65

Comment by rwb.

The header file is #include pic.h

Inside the pic.h file it will automatically determine the correct include file for your microcontroller type base on the selected device in your Microchip MPLAB IDE project; in your case (PIC16F877A) it will be #include pic1687x.h

#if defined(_16F873) || defined(_16F874) ||\
defined(_16F876) || defined(_16F877) ||\
defined(_16F872) || defined(_16F871) ||\
defined(_16F870)

#include pic1687x.h

#endif

Note: add the less sign and greater sign in the include header fle.

12.04.10#66

Comment by reinneguhn.

i compiled the program its has no error. but after i load the program in the pic, all that is displayed on the 7-segment is 8.8.8.8. Do you know what is the problem??

12.04.10#67

Comment by rwb.

It seems all the seven segment and the dot is “ON”, check your circuit and first try to debug the seven segment display routine by putting a number directly to the SSEG_putnum() function. Next after it work, you could continue to debug the ADC routine.

28.04.10#68

Comment by maized.

hey rwb awesome tutorial. i have built a similar circuit and writen code for it but it doesn’t quite work. am i able to email you my schematic and code to see where i’ve gone wrong?

i’ve been trying to get it working for the last week now but with no luck.

cheers

28.04.10#69

Comment by rwb.

Hi Maized, you could sent to my email here http://www.ermicro.com/blog/?page_id=2

29.04.10#70

Comment by maized.

Hey Ronald just wondering if you received my email? cheers

29.04.10#71

Comment by rwb.

Yes I’ve already reply to you; you could send in JPG or PDF format.

07.05.10#72

Comment by cenarius.

Hi, i was trying your program out as i am new to this but when i build it there are errors

Error [844] C:\Program Files\HI-TECH Software\PICC\9.70\include\pic16f887.h; 19. lexical error
Error [876] C:\Program Files\HI-TECH Software\PICC\9.70\include\pic16f887.h; 19. syntax error

and this is the line where error is

// Special function register definitions

-> volatile unsigned char INDF @ 0×000;
volatile unsigned char TMR0 @ 0×001;
volatile unsigned char PCL @ 0×002;
volatile unsigned char STATUS @ 0×003;
unsigned char FSR @ 0×004;
volatile unsigned char PORTA @ 0×005;
volatile unsigned char PORTB @ 0×006;
volatile unsigned char PORTC @ 0×007;

can you help me?? Thanks alot =)

07.05.10#73

Comment by rwb.

Recheck your MPLAB Language Toolsuite setup, the HI-TECH PICC v9.7 compiler installation and your program!

14.05.10#74

Comment by cenarius.

Hi again, I realized that I have been using the ‘asm’ type format file to run your program and consistently having errors. Then I tried using the ‘C’ format file to build and it was successful. Is it ok if I use the ‘C’ format file? What’s the difference if I use the ‘asm’ file?

Thanks a lot =)

14.05.10#75

Comment by rwb.

Yes you have to use “C” format file when you program with C language and “ASM” format file when you program with Assembly language.

21.06.10#76

Comment by celhedo.

I’m new to micro controllers.I’m still find it difficult to understand the multiplexing part.And i want to display integers from 0 to 1000,and i want to measure the value of resistors.how do i modify the multiplexing part to suit this?I’m using PIC16f690.

21.06.10#77

Comment by rwb.

The principal is the same, just try to display the integer from 0 to 99.0 first, try to follow and understand the programing logic step by step. Next modify the SSEG_putnum()function to display 0 to 9999 and the multiplexer part in the interrupt isr() function.

05.07.10#78

Comment by riverdan.

Will the “The Room’s Temperature Project” work on its own or just in debugging mode? If so I would like to move it to a PCB and monitor two sensors and control two set points. Like in a refrigerator I need to get it cold and then defrost it. Maybe there is a different setup?
Any suggestions I would be thanking You

05.07.10#79

Comment by rwb.

Yes this room temperature work on its own, although I just made it on the breadboard. If you want to have two temperature threshold point than you have to add the simple controller (e.g. bang-bang) either for upper and lower temperature; you could read more about this type of controller on my previous posted blog Basic Servo Motor Controlling with Microchip PIC Microcontroller

06.07.10#80

Comment by riverdan.

Great! Thanks a Big Bunch rwb, I’ll get started

13.07.10#81

Comment by riverdan.

thanks for the password reset
with a pic16f877 chip 4MHz crystal, this program runs in debug, but will not run on its own. i can simulate a sensor on an0 with a pot to a 7 seg display RD0…RD7 not all the numbers are readable. i need help on making it run on its own and then run another 7 seg to read temperature and control the setting. I don’t c programing.

LIST p=16f877
; Include file, change directory if needed
INCLUDE “p16f877.inc”
; Start at the reset vector
ORG 0×000
nop
clrf PORTD ;Clear PORTD
movlw B’01000001′ ;Fosc/8, A/D enabled, Sample Channel 0
movwf ADCON0
BANKSEL OPTION_REG
movlw B’10000111′ ;TMR0 prescaler, 1:256
movwf OPTION_REG
clrf TRISD ;PORTD all outputs
movlw B’00001110′ ;Left justify, 1 analog channel
movwf ADCON1 ;VDD and VSS references
BANKSEL PORTD
Main bcf INTCON,T0IF
Loop btfss INTCON,T0IF ;Wait for Timer0 to timeout
goto Loop
bsf ADCON0,GO ;Start A/D conversion for channel 0
Wait btfss PIR1,ADIF ;Wait for conversion to complete
goto Wait
movf ADRESH,W ;Write A/D result to PORTD
movwf PORTD ;LEDs
bcf PIR1,ADIF ;Clear the completion flag
goto Loop ;Do it again
END

13.07.10#82

Comment by rwb.

When you activate the TIMER0 and polled the T01F flag make sure you know exactly the start value of TMR0 register, otherwise it would be start at any unpredictable value. When using the A/D peripheral with A/D interrupt disable use the btfss ADCON0,GO to check the A/D conversion completion status. You could read similar principal in PIC assembler on Building your own Simple Laser Projector using the Microchip PIC12F683 Microcontroller

22.07.10#83

Comment by riverdan.

Does anyone have a simple asm to check a 2×16 LCD i bought, i have pic16f877,88,84,870 a lot of chips. i just can’t seem to get any program to work i find on line. Maybe with an AN0 sensor RTD,POT…. Anything

riverdan@riverdan.com
Thank You Much

22.07.10#84

Comment by rwb.

Driving the LCD is simply putting the right value on its input and control pins. You could learn the principal of driving the LCD on these following blog articles:

AVR LCD Thermometer Using ADC and PWM Project

PIC18 Pulse Width Modulation (PWM) DC Motor Speed Controller with the RPM Counter Project

Once you understand the principal it would be straight forward to convert the C code to the Assembler.

23.07.10#85

Comment by riverdan.

What would be the most common pin setup for a
NHD-0216XZ-FSW-GBW 2×16 LCD and a PIC16F88
I have a test program but no pin setup and i can’t tell from the progrm which pins to use.

Thank You Much

24.07.10#86

Comment by rwb.

According to the datasheet this NHD-0216XZ-FSW-GBW 2×16 LCD has the standard HITACHI HD44780U compatible controller, therefore you could use either 8-bit or 4-bit data transfer to/from the LCD. The datasheet also provide the pseudo code of how to initialize for both 8-bit and 4-bit data mode. For PIC16F88 better to use the 4-bit data mode, again the same principle could be applied on this LCD using the code that could be found on the blog’s project mentioned on my previous comment.

24.07.10#87

Comment by riverdan.

Thanks for your help but i can not get the exanple in the data sheet to compile and i don’t understand .c i’ll give it up for not untill i understand more.

27.07.10#88

Comment by riverdan.

I missed this one, I have a temperature setup that I program with a pickit2, hex, it works fine on a LCD as long as i leave the power on. I remove the pickit2, turn the power off then back on and nothing but a blank LCD. This is on a bread board.

Thanks again i have resolved the above problems.

28.07.10#89

Comment by rwb.

Check the power supply on your breadboard circuit! Remember the PICKit2 capable of supplying the power through its Vcc and GND pins. The LCD also has a separate power for the logic (VSS and VDD) and the backlight LED (A(+) and K(-)).

28.07.10#90

Comment by riverdan.

My Man,My Man: You are correct— solution was a 10K pull-up on MCLR/vpp, next I will try a 9vdc battery through a lm7805. I thank I can get down to 3.3 before brown out.

Go get em tiger!

28.07.10#91

Comment by riverdan.

This is great: what I would like to do now is set the temp to turn something on and off with a reset button at, between 0-deg and 100-deg. Can I snip a code and insert it some where in this one.

Thanks

28.07.10#92

Comment by rwb.

Sure you can.

28.07.10#93

Comment by riverdan.

The code I am using is a straight cut and paste from http://www.micro-examples.com/public/microex-navig/doc/086-mcp9700a-thermometer.html because I wanted an LCD display. The 9VDC battery worked fine, it would be good for a back up. Think I might switch from a Pic16f877a to a pic16f887 to use the internal clock insted of a 8 MHz crystal. What do you thunk?

Thanks

28.07.10#94

Comment by rwb.

Yes you should use the new one as the Microchip PIC16F887 is recommended to be used in new design instead of the old PIC16F877A microcontroller

29.07.10#95

Comment by riverdan.

This is Great, I am down to the Pic16f887, 2×16 LCD, the sensor and back light trimmer, replaced with a resistor. Any ideas on where I can snip a temperature control code?

Many Thanks

29.07.10#96

Comment by rwb.

Its depend on the hardware you’ve implemented from this project e.g. PWM, ADC (temperature and light) and seven segment

29.07.10#97

Comment by riverdan.

Sir you are correct, looks like port B is wide open. Let us say for now I want to press button 1 to display a setting, Press that or another button are another and set an led to stay on until it gets to let’s say 40deg F then off and back on above 40deg. Or say off at 35deg and back on above 35deg. really I am learning more from changing a working code than trying my own. I am using a 2×16 with a message on line 1 and centigrade and Fahrenheit side by side on line 2.

Thanks Again

15.08.10#98

Comment by riverdan.

Hi
I am using a 2×16 New Haven on a Pic16F877A and it works just fine. Now when I try to use another display with the same pin setting (2×8 2×24) I get nothing. I have been over all the settings for 2 days, no change. Please Help.

15.08.10#99

Comment by rwb.

If you used the New Haven LCD, then both 2×8 and 2×24 LCD use similar controller (SPLC780D) with the 2×16 LCD. Therefore the command for both 8/4-bit data mode will be the same as the 2×16 LCD. Make sure you re-examine the LCD pins, because these LCD (2×8,2×24) use different pins compared to the 2×16 LCD.

10.09.10#100

Comment by bns2003.

Hi
i liked this project and is explained well and thanks for this wonderful c code. i have a situation in which the display to be shown as 9.999 that is 3 decimal points to be displayed instead of 99.9C.Any logic ??

10.09.10#101

Comment by rwb.

Because you use the same 4 seven segment digit for displaying 3 decimal point then you need to modify the SSEG_putnum() function algorithm so it will assigned 0.000 to 9.999 instead of 00.0C to 99.9C to the DispDigit[4] array variables

05.02.11#102

Comment by pichaha.

Hi,
If I am using servo motor and I want to multiplex seven segment displays as well…how am I going to allocate the timer0?? I am thinking of using timer0 and timer1 simultaneously but I think this will trigger contradiction…or I just assign everthing in the timer0 routine is that possible…thanks a lot.

05.02.11#103

Comment by rwb.

Yes you could use both Microchip PIC16F886 microcontroller TIMER0 (8-bit) and TIMER1 (16-bit) and even TIMER2 (8-bit) peripherals at the same time.

23.02.11#104

Comment by pichaha.

Hi,
I would like to ask, beside using timer0 for displaying seven segment…what other type of technique can i use?…actually I have tried to display them by normal codes in the main function…it works, but not clear and unstable…thanks a lot.

23.02.11#105

Comment by rwb.

Basically you could use any of the Microchip PIC TIMER peripherals to do the Seven Segment multiplexing.

24.02.11#106

Comment by pichaha.

Yes, I have tested it using other timer interrupt and it works very well, thanks a lot…I have another question here…actually I want to optimize the usage of every single pin in pic16f690…and if I am not using the dot pin in the seven segment, from the seven segment array in your source codes (SSEG[]), how am I going to use that particular pin (the pin that suppose to connect to the dot pin) for other output purpose?

24.02.11#107

Comment by rwb.

Sure you can do it. As a rules of thumb when designing the microcontroller circuit you need to consider the efficiency of the C code for driving this circuit as well. Sometimes we have to change the circuit design in order to get more efficient C code. In your case it is depend of how you will use the RC7 output (the seven segment DOT pin in this project) e.g. blink LED, driving motor, activating relay, servo, etc; as this will change this following C statement in the interrupt service routine:

PORTC = DispDigit[DigitCount];

25.02.11#108

Comment by pichaha.

I am using that for buzzer…from your reply you mean I need to change the structure of the array or I can just apply some coding technique to modify it…I am only using RC0 to RC6

25.02.11#109

Comment by pichaha.

Sorry I still haven’t finished…I am only using RC0 to RC6 for seven segments…but in the array, I have to assigned value for RC7 as well…I mean what is the approach as we cannot assign only 7 numbers for PORTC, like PORTC = 0b0001111, the 8th bit just ignore it, impossible right?
Please help thanks a lot

25.02.11#110

Comment by rwb.

You could simply use a C mask operator to the PIC microcontroller PORTC as follow:

BUZZER=0x7F; // Turn Off Buzzer
PORTC = DispDigit[DigitCount] & BUZZER;

and

BUZZER=0xFF; // Turn On Buzzer
PORTC = DispDigit[DigitCount] & BUZZER;

25.02.11#111

Comment by pichaha.

Hi, your method is really great..i never think that before haha…btw I am curious how are you going to drive servo using that pin?

25.02.11#112

Comment by pichaha.

Sorry I mean not using your method in your servo article…I mean use the pwm feature in the mcu…thanks a lot…

25.02.11#113

Comment by rwb.

You could not use the Microchip PIC16F690 PWM peripheral on RC7! First, not all the Microchip PIC16F690 pins could be assigned as PWM peripheral output, for more information please read “H-Bridge Microchip PIC Microcontroller PWM Motor Controller” article on this blog. Secondly if we use the PWM peripheral to drive the servo motor it means we have to lower the PIC16F690 operating frequency please read “Basic Servo Motor Controlling with Microchip PIC Microcontroller” article.

26.02.11#114

Comment by pichaha.

Yes, I know…I mean how to utilize different port pins to multiplex seven segment…because I need P1A pin to drive servo, but I have solved the problem using your idea(using logical operators), and it worked for multiplexing seven segments for different port pins…I have tried your method to drive servo as well and it worked but I would like to try with the pwm feature in the mcu…I have tried to drive the servo (only servo in my circuit), it can turn clockwise and counter clockwise. I can turn it in small degree as well by gradually increase the bit in CCPR1L&CCP1CON automatically in a FOR loop, but when it comes to control the degree increment using push button, it becomes very unstable, the voltage from my voltage regulator will suddenly drop down to unusual level…can I know the problem please…if possible can I send you my source codes?? Please help thanks a lot.

26.02.11#115

Comment by rwb.

There is no relation between the PIC microcontroller C code and the sudden voltage drop of the voltage regulator when you press the push button which effecting the servo motor operation. The voltage regulator should maintain a constant voltage output as long as the operating load is still within its specification limit, that’s why it being called the voltage regulator. You should recheck your circuit.

26.02.11#116

Comment by pichaha.

OK, thanks a lot…so is it recommended to drive a servo using a 9V battery (maybe energizer)?

27.02.11#117

Comment by rwb.

Its depend on your application, for remote operation, sure you need a battery such as 9 volt (PP3) to operate your circuit but for permanent location where the electricity is available is cheaper to use the power adapter to provide DC supply to your circuit.