We will explore the methods of using the built in SPI module in PIC16F887 Microcontroller. According to the datasheet of the microcontroller there is built in SPI module available in the microcontroller which could make life lot of easier when it comes to the SPI Master Slave communication. There is Master Synchronous Serial Port (MSSP) module which support all 4 modes. All of these modes are explained in the following diagram taken from this official SPI getting started guide.
CD4094 Shift Registers
4094 is one of the most popular shift register after the 74HC595 Shift registers. The communication protocol is same in both of the shift registers which is SPI protocol. We already demonstrated software based shift register 7 segment example with Arduino in one of our previous articles. Here is internal structure of the shift register from the datasheet.
PIC SPI example C Code PIC CCS Compiler
Let’s first of all see a very basic example of using the MSSP module in PIC CCS Compiler and create a very basic SPI example c code. This example will just write a counter on the SPI module and increment that counter.
According to the PIC CCS compiler documentation this is what they says under the SPI Section of the PIC microcontrollers.
SPI™ is a fluid standard for 3 or 4 wire, full duplex communications named by Motorola. Most PIC devices support most common SPI™ modes. CCS provides a support library for taking advantage of both hardware and software based SPI™ functionality. For software support, see #USE SPI.
PIC CCS Compiler Documentation
#include<16F887.h>
#device *=16
#fuses HS,WDT,NOPROTECT,NOLVP
#use delay(clock=8000000)
#define _4094_ENABLE PIN_C0
void main(){
unsigned int8 counter, temp;
setup_comparator(NC_NC_NC_NC);
setup_ADC(ADC_off);
setup_ADC_ports(no_analogs);
setup_CCP1(CCP_off);
setup_CCP2(CCP_off);
setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_16);
counter = 0;
output_high(_4094_ENABLE);
//_4094_ENABLE = 1;
while(True){
output_low(_4094_ENABLE);
counter++;
if(counter>99)counter=0;
spi_write(counter);
delay_us(50);
output_high(_4094_ENABLE);
output_low(_4094_ENABLE);
delay_ms(200);
}
}
Code language: Arduino (arduino)
Here is the proteus simulation results of the above c code.
PIC SPI 4094 Shift Register 7 segment interfacing C Code
Here is the further extended version of the above code where we interfaced three 7 segments and drive a up counter with it. Which is pretty simple once we created a seperate function to update the 4094 shift registers. Also we created a constant array of seven segment codes.
#include<16F887.h>
#device *=16
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=8000000)
#define _4094_Strobe PIN_C0
#define strobe PIN_C0
const unsigned int8 segChar[]={
0b00111111, //0
0b00000110, //1
0b01011011, //2
0b01001111, //3
0b01100110, //4
0b01101101, //5
0b01111101, //6
0b00000111, //7
0b01111111, //8
0b01101111, //9
0b00000000, //10
0b01011000, //11,-c
};
void sendTo4094(int16 value, int8 num_of_digits){
int8 i;
unsigned char digit1=0;
// Iterate through digits in reverse order (least significant first)
for (i=0;i<num_of_digits;i++) {
// Extract the current digit using modulo and division
digit1=value%10;
output_bit(strobe,0);
// Send the segment pattern to the corresponding shift register
spi_write(segChar[digit1]);
delay_us(5);
output_bit(strobe,1);
output_bit(strobe,0);
delay_us(5);
value /=10;
}
}
unsigned int8 counter;
void main(){
setup_comparator(NC_NC_NC_NC);
setup_ADC(ADC_off);
setup_ADC_ports(no_analogs);
setup_CCP1(CCP_off);
setup_CCP2(CCP_off);
setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_16);
counter = 0;
output_high(_4094_Strobe);
//_4094_ENABLE = 1;
while(True){
output_low(_4094_Strobe);
counter++;
if(counter>99)counter=0;
sendTo4094(counter,3);
output_b(counter);
delay_ms(500);
}
}
Code language: Arduino (arduino)