Categories

PIC16F877 and 74HC595 shift register example

Sometimes in your projects you simply do not have enough I/O lines available, take for example a lot of the multiple LED examples, these use 8 outputs to control 8 LEDs via your PIC, that can restrict the amount of outputs you would have available to drive other devices. Instead of this we can use a shift register, in this case a 74HC595 and using 3 I/O pins we can control 8 LED’s, thats a saving of 5 I/O pins for other uses.

You can use it to control 8 outputs at a time while only taking up a few pins on your microcontroller. You can link multiple registers together to extend your output even more. The 74HC595 has an 8 bit storage register and an 8 bit shift register. Data is written to the shift register serially, then latched onto the storage register. The storage register then controls 8 output lines

Lets look at the 74HC595

595 pin diagram

595 pin diagram

PINS 1-7, 15 Q0 to Q7 Output Pins
PIN 8 GND Ground, Vss
PIN 9 Q7″ Serial Out
PIN 10 MR Master Reclear, active low
PIN 11 SH_CP Shift register clock pin
PIN 12 ST_CP Storage register clock pin (latch pin)
PIN 13 OE Output enable, active low
PIN 14 DS Serial data input
PIN 16 Vcc Positive supply voltage usually 5v

This is a link to the 74HC595 datasheet

Schematic

PIC16F877 and 595 shift register_schem

PIC16F877 and 595 shift register_schem

Code

This was written in mikroC PRO for PIC compiler, no libraries were used


#define SHIFT_CLOCK PORTC.F2
#define SHIFT_LATCH PORTC.F1
#define SHIFT_DATA PORTC.F0

void shiftdata595(unsigned char _shiftdata)
{
unsigned int i;
unsigned char temp;
temp = _shiftdata;
i=8;
while (i>0)
{
if (temp.F7==0)
{
SHIFT_DATA = 0;
}
else
{
SHIFT_DATA = 1;
}
temp = temp<<1;
SHIFT_CLOCK = 1;
Delay_us(1);
SHIFT_CLOCK = 0;
i--;
}
}

void latch595()
{
SHIFT_LATCH = 1;
Delay_us(1);
SHIFT_LATCH = 0;
}

void main()
{
PORTC=0;
TRISC=0;
while(1)
{
shiftdata595(1);
latch595();
delay_ms(200);

shiftdata595(0x02);
latch595();
delay_ms(200);

shiftdata595(0b00000100);
latch595();
delay_ms(200);
}
}

Links
10PCS SN74HC595N

30pcs SN74HC595N 8 Bit Shift Register

PIC16F877 and DS1820 temperature sensor example

In this example we connect the ever popular DS18B20 temperature sensor to our PIC, we will then display the temperature on our LCD

We used the DS18S20 in our example this was connected to PORT E pin 2 of our PIC16F877, once again we had a 16×2 LCD connected to PORT B.

Schematic

PIC16F877 and DS1820 example

PIC16F877 and DS1820 example

Code


sbit LCD_RS at RB4_bit;
sbit LCD_EN at RB5_bit;
sbit LCD_D4 at RB0_bit;
sbit LCD_D5 at RB1_bit;
sbit LCD_D6 at RB2_bit;
sbit LCD_D7 at RB3_bit;

sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;

//  Set TEMP_RESOLUTION to the corresponding resolution of used DS18x20 sensor:
//  18S20: 9  (default setting; can be 9,10,11,or 12)
//  18B20: 12
unsigned short TEMP_RESOLUTION = 9;
unsigned temp;
char *text = "000.00";
int i;
int colona;

void Read_Temperature()
{
// Perform temperature reading
Ow_Reset(&PORTE, 2);                         // Onewire reset signal
Ow_Write(&PORTE, 2, 0xCC);                   // Issue command SKIP_ROM
Ow_Write(&PORTE, 2, 0x44);                   // Issue command CONVERT_T
Delay_us(120);
Ow_Reset(&PORTE, 2);
Ow_Write(&PORTE, 2, 0xCC);                   // Issue command SKIP_ROM
Ow_Write(&PORTE, 2, 0xBE);                   // Issue command READ_SCRATCHPAD
temp =  Ow_Read(&PORTE, 2);
temp = (Ow_Read(&PORTE, 2) << 8) + temp;
}

void Display_Temperature()
{
unsigned short RES_SHIFT = TEMP_RESOLUTION - 8;
char temp_whole;
unsigned int temp2write;
unsigned int temp_fraction;

temp2write = temp;
// Check if temperature is negative
if (temp2write & 0x8000)
{
text[0] = '-';
temp2write = ~temp2write + 1;
}
// Extract temp_whole
temp_whole = temp2write >> RES_SHIFT ;
// Convert temp_whole to characters
if (temp_whole/100)
text[0] = temp_whole/100  + 48;

text[1] = (temp_whole/10)%10 + 48;             // Extract tens digit
text[2] =  temp_whole%10     + 48;             // Extract ones digit
text[3] = '.';
// Extract temp_fraction and convert it to unsigned int
temp_fraction  = temp2write << (4-RES_SHIFT);
temp_fraction &= 0x000F;
temp_fraction *= 625;
// Convert temp_fraction to characters
text[4] =  temp_fraction/1000    + 48;         // Extract thousands digit
// Print temperature on LCD
Lcd_Out(1, 1, text);
// Print degree character and'C' for Celsius
Lcd_Chr_CP(0xDF);                             // 223 ASCII for degree symbol on my LCD
Lcd_Chr_CP('C');
}

void main()
{
CMCON |=7;
ADCON1 = 0x0D;
TRISE.B2 = 1;                                  // Configure RE2 pin as input

Lcd_Init();                                    // Initialize LCD
Lcd_Cmd(_LCD_CLEAR);                           // Clear LCD
Lcd_Cmd(_LCD_CURSOR_OFF);                      // Turn cursor off

// Main loop
do
{
Read_Temperature();
Display_Temperature();
Delay_ms(100);
} while (1);
}

Links
DS1820 20pcs

DS1820 Temperature Module

PIC16F877 temperature and humidity example

In this example we will read the temperature and humidity using a DHT11 sensor and display the readings on our LCD. We have linked to the datasheet at the bottom of the page, download it and then you can read a bit more technical information on this sensor.

These sensors whether standalone or in the form of breakouts are relatively inexpensive and for most projects they have an acceptable level of accuracy

I tried a couple of examples on the internet and none of them worked for me. Fortunately these all seemed to use Port A.0, changing this to PORTD.0 fixed the problems for me.

Schematic

I’ve omitted the external crystal and power connections to the PIC micro, concentrated mainly on the connections between the DHT11, LCD and the PIC micro.

PIC16F877 and DHT11 schematic

PIC16F877 and DHT11 schematic

Code

mikroC for PIC code again


sbit LCD_RS at RB4_bit;
sbit LCD_EN at RB5_bit;
sbit LCD_D4 at RB0_bit;
sbit LCD_D5 at RB1_bit;
sbit LCD_D6 at RB2_bit;
sbit LCD_D7 at RB3_bit;

sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;


sbit Data at RD0_bit;
sbit DataDir at TRISD0_bit;
char message1[] = "Temp = 00.0 C";
char message2[] = "RH   = 00.0 %";
unsigned short TOUT = 0, CheckSum, i;
unsigned short T_Byte1, T_Byte2, RH_Byte1, RH_Byte2;

void StartSignal(){
DataDir = 0;     // Data port is output
Data    = 0;
delay_ms(18);
Data    = 1;
delay_us(30);
DataDir = 1;     // Data port is input

}

unsigned short CheckResponse(){
TOUT = 0;
TMR2 = 0;
T2CON.TMR2ON = 1;      // start timer
while(!Data && !TOUT);
if (TOUT) return 0;
else {
TMR2 = 0;
while(Data && !TOUT);
if (TOUT) return 0;
else {
T2CON.TMR2ON = 0;
return 1;
}
}
}

unsigned short ReadByte(){
unsigned short num = 0, t;
DataDir = 1;
for (i=0; i<8; i++){
while(!Data);
TMR2 = 0;
T2CON.TMR2ON = 1;
while(Data);
T2CON.TMR2ON = 0;
if(TMR2 > 40) num |= 1<<(7-i);  // If time > 40us, Data is 1
}
return num;
}

void interrupt(){
if(PIR1.TMR2IF){
TOUT = 1;
T2CON.TMR2ON = 0; // stop timer
PIR1.TMR2IF  = 0; // Clear TMR0 interrupt flag
}
}

void main() {
unsigned short check;
TRISB = 0b00000000;
PORTB = 0;
TRISD = 0b00000001;
CMCON = 7;
INTCON.GIE = 1;    //Enable global interrupt
INTCON.PEIE = 1;   //Enable peripheral interrupt
// Configure Timer2 module
PIE1.TMR2IE = 1;  // Enable Timer2 interrupt
T2CON = 0;        // Prescaler 1:1, and Timer2 is off initially
PIR1.TMR2IF =0;   // Clear TMR INT Flag bit
TMR2 = 0;
Lcd_Init();
Lcd_Cmd(_Lcd_Clear);
Lcd_Cmd(_LCD_CURSOR_OFF);

do {
Delay_ms(1000);
StartSignal();
check = CheckResponse();
if (!check) {
Lcd_Cmd(_Lcd_Clear);
Lcd_Out(1, 1, "No response");
Lcd_Out(2, 1, "from the sensor");
}
else{

RH_Byte1 = ReadByte();
RH_Byte2 = ReadByte();
T_Byte1 = ReadByte();
T_Byte2 = ReadByte();
CheckSum = ReadByte();
// Check for error in Data reception
if (CheckSum == ((RH_Byte1 + RH_Byte2 + T_Byte1 + T_Byte2) & 0xFF))
{
message1[7]  = T_Byte1/10 + 48;
message1[8]  = T_Byte1%10 + 48;
message1[10] = T_Byte2/10 + 48;
message2[7]  = RH_Byte1/10 + 48;
message2[8]  = RH_Byte1%10 + 48;
message2[10] = RH_Byte2/10 + 48;
message1[11] = 223;     // Degree symbol
Lcd_Cmd(_Lcd_Clear);
Lcd_Out(1, 1, message1);
Lcd_Out(2, 1, message2);
}

else{
Lcd_Cmd(_Lcd_Clear);
Lcd_Out(1, 1, "Checksum Error!");
Lcd_Out(2, 1, "Try Again.");
}
}

}while(1);
}


Links

DHT11 datasheet

1x DHT11 DHT-11 Digital Temperature and Humidity Temperature sensor

PIC16F877 and LDR warning example

In this example we will connect an LDR again but this time when the ADC value goes below a certain number we will switch an LED on, in real life this could be an alarm or a night light.

The LCD is more for debug purposes and could be removed

Schematic

 

PIC16F877 LDR and LED

PIC16F877 LDR and LED

Code

The code was witten in mikroC pro for PIC, its fairly simple when the value falls below 100 we switch on the LED connected to PORT C 0



sbit LCD_RS at RB4_bit;
sbit LCD_EN at RB5_bit;
sbit LCD_D4 at RB0_bit;
sbit LCD_D5 at RB1_bit;
sbit LCD_D6 at RB2_bit;
sbit LCD_D7 at RB3_bit;

sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;
unsigned int adcvalue,value,temp_res;
unsigned char car,x,y;
char *voltage = "00.00";
long temp;

// Routine to show the value of the ADC_read
void ShowADC(int x, int y, unsigned int adcvalue)
{
car = adcvalue / 1000;
LCD_Chr(x,y,48+car);
adcvalue=adcvalue-1000*car;
car = (adcvalue / 100);
LCD_Chr_CP(48+car);
adcvalue=adcvalue-100*car;
car = (adcvalue / 10);
LCD_Chr_CP(48+car);
adcvalue=adcvalue-10*car;
car = adcvalue;
LCD_Chr_CP(48+car);
delay_ms(30);
}

void main()
{
TRISA = 0xFF; // PORTA is input
TRISB = 0;
TRISC = 0;
PORTB = 0;
Lcd_Init(); // Initialize LCD
Lcd_Cmd(_LCD_CLEAR); // Clear display
Lcd_Cmd(_LCD_CURSOR_OFF); // Cursor off
Lcd_Out(1, 1, " ADC :");

do {
temp_res = ADC_Read(2); // Get 10-bit results of AD conversion
adcvalue = temp_res;
ShowADC (1,7,adcvalue);

if(adcvalue < 100)
{
PORTC = 0x01;
}
else
{
PORTC = 0x00;
}
Delay_ms(200);
} while(1);

} // end main

 

Links

50 pcs Light Dependent Resistors

250pcs 3MM LED Assortment Kit

QL200 PIC16F877A-I/P PIC16F877 PIC 8-bit Development Board

PIC16F877 and LDR example

In this example we connect an LDR to ADC channel 2 which is PA 2. Once again you will get a value in theory between 0 and 1023. The more light that there is the higher the value.

We will read the value in from the LDR and display this on the LCD

Schematic

 

PIC16F877 LDR

PIC16F877 LDR

Code

The example was written using mikroC pro evaluation version

sbit LCD_RS at RB4_bit;
sbit LCD_EN at RB5_bit;
sbit LCD_D4 at RB0_bit;
sbit LCD_D5 at RB1_bit;
sbit LCD_D6 at RB2_bit;
sbit LCD_D7 at RB3_bit;

sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;
unsigned int adcvalue,value,temp_res;
unsigned char car,x,y;
char *voltage = "00.00";
long temp;

// Routine to show the value of the ADC_read
void ShowADC(int x, int y, unsigned int adcvalue)
{
car = adcvalue / 1000;
LCD_Chr(x,y,48+car);
adcvalue=adcvalue-1000*car;
car = (adcvalue / 100);
LCD_Chr_CP(48+car);
adcvalue=adcvalue-100*car;
car = (adcvalue / 10);
LCD_Chr_CP(48+car);
adcvalue=adcvalue-10*car;
car = adcvalue;
LCD_Chr_CP(48+car);
delay_ms(30);
}

void main()
{
TRISA = 0xFF; // PORTA is input
TRISB = 0;
PORTB = 0;
Lcd_Init(); // Initialize LCD
Lcd_Cmd(_LCD_CLEAR); // Clear display
Lcd_Cmd(_LCD_CURSOR_OFF); // Cursor off
Lcd_Out(1, 1, " ADC :");
do {
temp_res = ADC_Read(2); // Get 10-bit results of AD conversion
adcvalue = temp_res;
ShowADC (1,7,adcvalue);
Delay_ms(300);

} while(1);

} // end main

Links
Microcontroller Programmer Kit Development Board for PIC microcontroller evaluation QL200 PIC

50 pcs Light Dependent Resistors