Report
Report
🙞···☼···🙜
MICRO-CONTROLLER COURSE
CLASS EXERCISE 3
2. PROGRAM
#include <16F877A.h>
#device ADC=16
#FUSES NOWDT // No Watch Dog Timer
#FUSES NOBROWNOUT // No brownout reset
#FUSES NOLVP // No low voltage prgming, B3(PIC16) or B5(PIC18) used
for I/O
#use delay(crystal=20000000)
#include <stdlib.h>
2
char x[10],y[10],pwmValue[10],speedValue[10],inputString[30];
int characterCounter=0,posD=0,posE=0;
int16 tmr1ovrf=0,tmr0ovrf=0;
#byte TRISC=0x87
#byte PORTC=0x07
#bit PINC0=PORTC.0
#bit PINC1=PORTC.1
#byte TXREG=0x19
#byte TXSTA=0x98
#bit TRMT=TXSTA.1
#bit BRGH=TXSTA.2
#bit SYNC=TXSTA.4
#bit TXEN=TXSTA.5
#byte RCSTA=0x18
#bit CREN=RCSTA.4
#bit SPEN=RCSTA.7
#byte SPBRG=0x99
#byte RCREG=0x1A
#byte PIE1=0x8C
#bit RCIE=PIE1.5
#byte INTCON=0x0B
#bit PEIE=INTCON.6
#bit GIE=INTCON.7
#byte T1CON=0x10
#bit TMR1ON=T1CON.0
#byte TMR1L=0x0E
#byte TMR1H=0x0F
#byte T2CON=0x12
#byte TMR2=0x11
3
#byte PR2=0x92
#byte PIR1=0x0C
#byte CCPR1L=0x15
#byte CCPR1H=0x16
#byte CCP1CON=0x17
#byte TMRO=0x01
#byte OPREG=0x81
#int_rda
void interruptUART()
{
switch(RCREG)
{
case 'd': posD=characterCounter;
case 'e': posE=characterCounter;
default:
if((RCREG>=46)&&(RCREG<=101))
{
inputString[characterCounter]=RCREG;
characterCounter+=1;
}
}
if(posE!=0)
{
for(int i=1;i<6;i++)
{
x[i-1]=inputString[i];
}
for(int j=1;j<6;j++)
4
{
y[j-1]=inputString[j+6];
}
for(int k=13;k<posD;k++)
{
pwmValue[k-13]=inputString[k];
}
for(int l=posD+1;l<posE;l++)
{
speedValue[l-1-posD]=inputString[l];
}
}
}
#int_timer1
void interruptTimer1()
{
tmr1ovrf+=1;
TMR1L=0;
TMR1H=0;
}
#int_timer0
void interruptTimer0()
{
tmr0ovrf+=1;
TMRO=0;
}
5
void uart(char data)
{
while(!TRMT);
TXREG=data;
}
void main()
{
TRISC=0b11000001;
OPREG=0b00000111; // Timer0 prescaler 1:256
INTCON=0b11100000; // Enable interrupts
PIE1=0b00000001;
T1CON=0;
PR2=0xff;
CCP1CON=0b00001100;
T2CON=0b00000111; // CCP1 with PWM mode, Timer 2 prescaler 1:16a and
postscale 1:1
TMR2=0;
BRGH=0; // Set UART to low-speed asynchronous mode, Baudrate 9600 bps
SPBRG=31;
SYNC=0;
SPEN=1;
RCIE=1;
PEIE=1;
GIE=1;
CREN=1;
TXEN=1;
CCPR1L=0;
PINC1=0;
int1 hasSent=0;
6
int32 time,sec;
float encoderS,maximumVoltage=12,kp=0,ki=0.2,kd=0; // PID parameters
double
setPoint=0,voltage=0,inputSpeed=0,samplingTime=0.02,integral=0,lastErr=0,err=0,diff=0;
while(TRUE)
{
if(atol(speedValue)!=0)
{
if(hasSent==0) // Send number value to terminal
{
hasSent=1;
for(int i=0;i<5;i++) uart(x[i]);
uart(' ');
for(int j=0;j<5;j++) uart(y[j]);
uart(' ');
for(int k=0;k<posD-13;k++) uart(pwmValue[k]);
uart(' ');
for(int l=0;l<posE-posD-1;l++) uart(speedValue[l]);
setPoint=atol(speedValue);
}
TMRO=0; // Counting sampling time
tmr0ovrf=0;
err=setPoint-inputSpeed;
diff=(err-lastErr)/samplingTime;
integral+=err*samplingTime;
lastErr=err;
voltage=kp*err+ki*integral+kd*diff;
if (voltage<0)
{
7
PINC1=1;
if (voltage<-12) voltage=-maximumVoltage;
voltage=-voltage;
}
else
{
PINC1=0;
if (voltage>12) voltage=maximumVoltage;
} // Direction control and setting limits
CCPR1L=(unsigned int)((255*(voltage/maximumVoltage))+0.5); // Scale to
PWM
TMR1L=0;
TMR1H=0;
while(PINC0==1);
while(PINC0==0);
TMR1ON=1;
while(PINC0==1);
while(PINC0==0);
TMR1ON=0;
time=(((int16)TMR1H<<8)|TMR1L)+(tmr1ovrf*65536);
encoderS=((20000000/4.0)/time)/36*60; // Speed from the encoder
tmr1ovrf=0;
inputSpeed=(unsigned int16)(encoderS+0.5);
sec=TMRO+256*tmr0ovrf;
samplingTime=sec*256*1/(20000000/4.0); // Sampling time
delay_ms(20);
}
}
}
8
3. EXPLANATION
Our group used COM11 for the COM port connected to the PIC16F877 TX/RX pins.
char x[10],y[10],pwmValue[10],speedValue[10],inputString[30];
int characterCounter=0,posD=0,posE=0;
int16 tmr1ovrf=0,tmr0ovrf=0;
int1 hasSent=0;
int32 time,sec;
float encoderS,maximumVoltage=12,kp=0,ki=0.2,kd=0; // PID parameters
double
setPoint=0,voltage=0,inputSpeed=0,samplingTime=0.02,integral=0,lastErr=0,err=0,dif
f=0;
Variables declaration.
9
#int_rda
void interruptUART()
{
switch(RCREG)
{
case 'd': posD=characterCounter;
case 'e': posE=characterCounter;
default:
if((RCREG>=46)&&(RCREG<=101))
{
inputString[characterCounter]=RCREG;
characterCounter+=1;
}
}
if(posE!=0)
{
for(int i=1;i<6;i++)
{
x[i-1]=inputString[i];
}
for(int j=1;j<6;j++)
{
y[j-1]=inputString[j+6];
}
for(int k=13;k<posD;k++)
{
pwmValue[k-13]=inputString[k];
}
10
for(int l=posD+1;l<posE;l++)
{
speedValue[l-1-posD]=inputString[l];
}
}
}
#int_timer1
void interruptTimer1()
{
tmr1ovrf+=1;
TMR1L=0;
TMR1H=0;
}
#int_timer0
void interruptTimer0()
{
tmr0ovrf+=1;
TMRO=0;
}
11
In interruptTimer1()function, the tmr1ovrf variable is incremented to 1 as Timer1
overflows, then Timer1 is reset to 0.
In interruptTimer0()function, the tmr0ovrf variable is incremented to 1 as Timer0
overflows if overflow is allowed, then Timer0 is reset to 0.
TRISC=0b11000001;
OPREG=0b00000111; // Timer0 prescaler 1:256
INTCON=0b11100000; // Enable interrupts
PIE1=0b00000001;
T1CON=0;
PR2=0xff;
CCP1CON=0b00001100;
T2CON=0b00000111; // CCP1 with PWM mode, Timer 2 prescaler 1:16a and
postscale 1:1
TMR2=0;
BRGH=0; // Set UART to low-speed asynchronous mode, Baudrate 9600 bps
SPBRG=31;
SYNC=0;
12
SPEN=1;
RCIE=1;
PEIE=1;
GIE=1;
CREN=1;
TXEN=1;
CCPR1L=0;
PINC1=0;
UART
o BRGH=1: Low speed, asynchronous mode.
o SPBRG=31: Used to generate baudrate 9600 bps.
o CREN=1: Enable data reception.
o TXEN=1: Enable UART transmission.
PWM
o CCP1CON=0b00001100: Set up CCP1 as PWM mode.
o T2CON=0b00000111: Set up timer 2 with prescaler is 16, 1:1 postcale.
Timer1
o INTCON=0b11100000: Enable global, peripheral and TMR0 overflow
interrupts.
Timer0
o OPREG=0b00000111: Select the prescaler 1:256
void main()
{
TRISC=0b11000001;
OPREG=0b00000111; // Timer0 prescaler 1:256
INTCON=0b11100000; // Enable interrupts
PIE1=0b00000001;
13
T1CON=0;
PR2=0xff;
CCP1CON=0b00001100;
T2CON=0b00000111; // CCP1 with PWM mode, Timer 2 prescaler 1:16a and
postscale 1:1
TMR2=0;
BRGH=0; // Set UART to low-speed asynchronous mode, Baudrate 9600 bps
SPBRG=31;
SYNC=0;
SPEN=1;
RCIE=1;
PEIE=1;
GIE=1;
CREN=1;
TXEN=1;
CCPR1L=0;
PINC1=0;
int1 hasSent=0;
int32 time,sec;
float encoderS,maximumVoltage=12,kp=0,ki=0.2,kd=0; // PID parameters
double
setPoint=0,voltage=0,inputSpeed=0,samplingTime=0.02,integral=0,lastErr=0,err=0,diff=0;
while(TRUE)
{
if(atol(speedValue)!=0)
{
if(hasSent==0) // Send number value to terminal
{
hasSent=1;
14
for(int i=0;i<5;i++) uart(x[i]);
uart(' ');
for(int j=0;j<5;j++) uart(y[j]);
uart(' ');
for(int k=0;k<posD-13;k++) uart(pwmValue[k]);
uart(' ');
for(int l=0;l<posE-posD-1;l++) uart(speedValue[l]);
setPoint=atol(speedValue);
}
TMRO=0; // Counting sampling time
tmr0ovrf=0;
err=setPoint-inputSpeed;
diff=(err-lastErr)/samplingTime;
integral+=err*samplingTime;
lastErr=err;
voltage=kp*err+ki*integral+kd*diff;
if (voltage<0)
{
PINC1=1;
if (voltage<-12) voltage=-maximumVoltage;
voltage=-voltage;
}
else
{
PINC1=0;
if (voltage>12) voltage=maximumVoltage;
} // Direction control and setting limits
CCPR1L=(unsigned int)((255*(voltage/maximumVoltage))+0.5); // Scale to
PWM
15
TMR1L=0;
TMR1H=0;
while(PINC0==1);
while(PINC0==0);
TMR1ON=1;
while(PINC0==1);
while(PINC0==0);
TMR1ON=0;
time=(((int16)TMR1H<<8)|TMR1L)+(tmr1ovrf*65536);
encoderS=((20000000/4.0)/time)/36*60; // Speed from the encoder
tmr1ovrf=0;
inputSpeed=(unsigned int16)(encoderS+0.5);
sec=TMRO+256*tmr0ovrf;
samplingTime=sec*256*1/(20000000/4.0); // Sampling time
delay_ms(20);
}
}
}
Within an infinite loop (while(TRUE)), the code checks if a non-zero speed value has
been received. If such a value is present, it proceeds with the control algorithm.
Initially, it checks whether the data has been sent to the terminal. If not, it sends the
received speed value along with other relevant parameters like x, y, pwmValue, etc.,
to the terminal.
Next, the code resets timer variables and calculates the error (err) between the desired
speed (setPoint) and the measured speed (inputSpeed). It then computes the derivative
of the error (diff) and updates the integral of the error (integral). These terms are used
in the PID control equation to determine the control voltage (voltage) applied to the
motor.
The control voltage is then adjusted based on direction control and voltage limits. If
the control voltage is negative, indicating a need for reverse rotation, the direction pin
is set accordingly (PINC1). Otherwise, the direction pin is cleared. Additionally, the
control voltage is constrained within specified maximum and minimum values.
16
The control voltage is then converted to a PWM duty cycle value and applied to the
motor driver. The code then waits for and measures the duration of an encoder pulse
to calculate the speed of the motor.
Finally, it adjusts the calculated speed to account for the sampling time, and the loop
is delayed by 20 milliseconds before restarting.
4. VIDEO SIMULATION
Google Drive link:
https://drive.google.com/file/d/1EWP1I3q9gFBVf-2fO1fNCpQy1pbGVlkP/view?
usp=drive_link
EXERCISE 2
1. WIRING
17
OUTPUT
o I2C Debugger
- This component read the bits sent from one controller to another through the SDA
and SCL lines, to prove that the codes on the controller are for communicating.
o Virtual Terminal
18
- This component read the bits sent to the RXD pins and print the result on the
screen
- This is used to show the communication results on screen.
INPUT
o Control buttons
Two buttons are used to tell the Master MCU to send or receive data from the Slave
MCU
- And the resistors R1 and R4 act as pull-up resistors so that the inputs will initially
be at a HIGH state.
19
2. PROGRAMMING
2.1. Master MCU program
2.1.1. Initial Config
8MHz crystal/resonator on OSC2/CLKOUT and OSC1/CLKIN
#include <xc.h>
b) I2C_Master_Wait
void I2C_Master_Wait()
{
while ((SSPSTAT & 0x04) || (SSPCON2 & 0x1F));
}
c) I2C_Master_Start()
Start the I2C bus
void I2C_Master_Start()
{
I2C_Master_Wait();
SEN = 1;
}
20
d) I2C_Master_Stop()
Stop the I2C bus
void I2C_Master_Stop()
{
I2C_Master_Wait();
PEN = 1;
}
e) I2C_Master_Write
Send a byte “d” through the buffer register
void I2C_Master_Write(unsigned d)
{
I2C_Master_Wait();
SSPBUF = d;
}
f) I2C_Write
Send multiple bytes (int data) with the address (int address) through the buffer
register and then delay 50 ms
g) I2C_Master_Read
Read data from the Slave MCU
21
ACKEN = 1;
return temp;
}
void UART_init(void)
{
BRGH=1;
SPBRG=51;
SYNC=0;
SPEN=1;
TRISC6=1;
TXEN=1;
}
Initialize the UART with a baudrate of 19200 and the I2C with the clock frequency of
1MHz
if (!PORTBbits.RB7){
while(!PORTBbits.RB7);
I2C_Master_Start(); //Start condition
22
I2C_Write(0x10,'1');
I2C_Write(0x10,'2');
I2C_Write(0x10,'.');
I2C_Write(0x10,'5');
I2C_Write(0x10,'9');
I2C_Write(0x10,' ');
}
If button on pin B7 is pushed, start the I2C in data transmit mode and send “12.59”
if (!PORTBbits.RB6){
while(!PORTBbits.RB6);
for (int j=0;j<5;j++){
I2C_Master_Start(); //Start condition
I2C_Master_Write(0x11); //7 bit address + Read
readData = I2C_Master_Read(0);
I2C_Master_Stop();
UART_write_c(readData);}
}
}
}
If button on pin B6 is pushed start the I2C in data reading mode and print the data
received on to the Virtual Terminal
short z;
int count=0;
23
TRISC4 = 1;
GIE = 1;
PEIE = 1;
SSPIF = 0;
SSPIE = 1;
}
b) I2C_Write
o It loads the data into SSPBUF (I2C Buffer Register) and waits until the buffer
is empty (BF flag is cleared) before proceeding.
c) I2C_Read
o This function checks the data on the receive buffer.
o If the address bit is high (D_A == 1), clear the buffer.
o The function will continue to wait until receive buffer is full
(while(SSPIF==0);) and then output the data read.
24
void __interrupt() I2C_Slave_Read()
{
if(SSPIF == 1)
{
SSPCONbits.CKP = 0;
if ((SSPCONbits.SSPOV) || (SSPCONbits.WCOL))
{
z = SSPBUF; // Read the previous value to clear the
buffer
SSPCONbits.SSPOV = 0; // Clear the overflow flag
SSPCONbits.WCOL = 0; // Clear the collision bit
SSPCONbits.CKP = 1;
}
SSPIF = 0;
}
}
if(SSPIF == 1): This checks if the SSP interrupt flag (SSPIF) is set.
SSPCONbits.CKP = 0;: Disables clock stretching
if ((SSPCONbits.SSPOV) || (SSPCONbits.WCOL)):
This checks for overflow
(SSPOV) or collision (WCOL) conditions. If either condition is detected, it reads the
previous value from SSPBUF to clear the buffer and then clears the overflow and
collision flags before enabling the clock again.
SSPSTATbits.D_nA && SSPSTATbits.R_nW: Check Data/Address and Read/Write
Condition:
o If the received byte is data (D_nA bit is 0) and if it's a write operation (R_nW
bit is 0) then read data from I2C and Transmit via UART
25
o If the received byte is data (D_nA bit is 0) and if it's a read operation (R_nW
bit is 1) then write data to I2C.
o SSPIF = 0;: Finally, the SSP interrupt flag (SSPIF) is cleared to acknowledge
and handle the interrupt.
2.2.3. UART functions
a) UART_init
Initialize the UART bus
void UART_init(void)
{
BRGH=1;
SPBRG=51;
SYNC=0;
SPEN=1;
TRISC6=1;
TXEN=1;
}
}
}
26
3. VIDEO SIMULATION
Google Drive Link:
https://drive.google.com/file/d/1D- c9FkZ_eiZFB5yWYTj4jZljEj8TqJLz/view?
usp=drive_link
27
EXERCISE 3
1. REQUIREMENT
Program the transmission from master to slave number 12.XY if you press button B7 on the
Master and receive the transmission value from slave number 15.XY if you press button B7
on the slave. XY is the number after the dot. (2.5 pts)
2. PROGRAMMING
Master:
#pragma config FOSC = XT // Oscillator Selection bits (XT oscillator)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = OFF // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = OFF // Low-Voltage In-Circuit Serial Programming Enable bit
#pragma config CPD = OFF // Data EEPROM Memory Code Protection bit
#pragma config WRT = OFF // Flash Program Memory Write Enable bits
28
#pragma config CP = OFF // Flash Program Memory Code Protection bit
#include <xc.h>
#include <pic16f877a.h>
#define _XTAL_FREQ 20000000
char number[]={0x31,0x32,0x2E,0x36,0x39,0x20};//12.69
void spiInit(char sType, char sDataSample, char sClockIdle, char sTransmitEdge)
{
TRISC5 = 0;
if(sType & 0b00000100) //If Slave Mode
{
SSPSTAT = sTransmitEdge;
TRISC3 = 1;
}
else //If Master Mode
{
SSPSTAT = sDataSample | sTransmitEdge;
TRISC3 = 0;
}
SSPCON = sType | sClockIdle;
}
static void spiReceiveWait()
{
while ( !SSPSTATbits.BF ); // Wait for Data Receipt complete
}
void spiWrite(char dat) //Write data to SPI bus
{
SSPBUF = dat;
}
29
char spiRead() // Read the received data
{
spiReceiveWait(); // Wait until all bits receive
return(SSPBUF); // Read the received data from the buffer
}
void UART_write_char(char data)
{
while(TRMT==0);
TXREG = data;
}
void main()
{
TRISA5=1;
ADCON1=0x07;
BRGH=1;
SPBRG=51;
SYNC=0;
SPEN=1;
TRISC6=1;
TXEN=1;
spiInit(0x20, 0, 0, 0);
unsigned char data=0x30;
__delay_ms(50);
while(1)
{
PORTAbits.RA5=1;
if (PORTBbits.RB7==0){
while(PORTBbits.RB7==0);
for(int j=0; j<=5;j++){
30
spiWrite(number[j]);
data=spiRead();
__delay_ms(10);
}
}
if (!PORTAbits.RA5) {
for(int j=0; j<=5;j++){
__delay_ms(10);
spiWrite(0x31);
data=spiRead();
if (data <=0x5A) UART_write_char(data);
}
UART_write_char(0xD);
}
while(!PORTAbits.RA5);
}
}
Slave:
#pragma config FOSC = XT // Oscillator Selection bits (XT oscillator)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = OFF // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = OFF // Low-Voltage In-Circuit Serial Programming Enable bit
#pragma config CPD = OFF // Data EEPROM Memory Code Protection bit
#pragma config WRT = OFF // Flash Program Memory Write Enable bits
#pragma config CP = OFF // Flash Program Memory Code Protection bit
#include <xc.h>
#include <pic16f877a.h>
31
#define _XTAL_FREQ 20000000
char number[]={0x31,0x35,0x2E,0x36,0x39,0x20};//15.69
void spiInit(char sType, char sDataSample, char sClockIdle, char sTransmitEdge)
{
TRISC5 = 0;
if(sType & 0b00000100)
{
SSPSTAT = sTransmitEdge;
TRISC3 = 1;
}
else
{
SSPSTAT = sDataSample | sTransmitEdge;
TRISC3 = 0;
}
SSPCON = sType | sClockIdle;
}
void spiWrite(char dat)
{
SSPBUF = dat;
}
char spiRead()
{
while ( !SSPSTATbits.BF );
return(SSPBUF);
}
void UART_write_char(char data)
{
while(TRMT==0);
32
TXREG = data;
}
int count=0;
int index=0;
void __interrupt() SPI_Slave_Read()
{
if(SSPIF == 1)
{
unsigned char readData = 0;
if (count==0){
readData=spiRead();
if (readData!=0x3A)
UART_write_char(readData);
}
if (count==1){
while(index<=5){
readData=spiRead();
spiWrite(number[index]);
index++;
}
index=0;
}
SSPIF = 0;
}
}
void main()
{
GIE = 1;
33
PEIE = 1;
SSPIF = 0;
SSPIE = 1;
ADCON1 = 0x07;
TRISA5 = 1;
BRGH=1;
SPBRG=51;
SYNC=0;
SPEN=1;
TRISC6=1;
TXEN=1;
spiInit(0x25, 0, 0, 0);
TRISA0=0;
char data=0;
while(1)
{ PORTAbits.RA0=PORTBbits.RB7;
if (PORTBbits.RB7==0){
count=1;
PORTAbits.RA0=PORTBbits.RB7;
while(PORTBbits.RB7==0);
count=0;
}
}
}
2. PROGRAMMING EXPLANATION
Master
Configuration Bits
#pragma config FOSC = XT: Selects the XT oscillator (crystal/resonator) for the system
34
clock.
#pragma config WDTE = OFF: Disables the Watchdog Timer.
#pragma config PWRTE = OFF: Disables the Power-up Timer.
#pragma config BOREN = OFF: Disables Brown-out Reset.
#pragma config LVP = OFF: Disables Low-Voltage In-Circuit Serial Programming.
#pragma config CPD = OFF: Disables Data EEPROM Memory Code Protection.
#pragma config WRT = OFF: Disables Flash Program Memory Write Enable bits.
#pragma config CP = OFF: Disables Flash Program Memory Code Protection.
35
SSPCON = sType | sClockIdle;
}
This function initializes SPI communication with specific parameters, setting up whether the
SPI module is in master or slave mode, the data sampling point, the clock idle state, and the
transmission edge.
TRISC5 = 0;: Configures pin RC5 (SPI data output, SDO) as an output.
if (sType & 0b00000100): Checks whether the SPI type indicates slave mode.
If it is in slave mode:
SSPSTAT = sTransmitEdge;: Sets the SPI status register with the specified transmit
edge.
TRISC3 = 1;: Configures pin RC3 (SPI clock, SCK) as an input (common for slave
mode).
If it is in master mode:
SSPSTAT = sDataSample | sTransmitEdge;: Sets the SPI status register with the data
sampling point and transmit edge.
TRISC3 = 0;: Configures pin RC3 as an output (common for master mode).
SSPCON = sType | sClockIdle;: Configures the SPI control register with the specified
type and clock idle state.
36
SSPBUF = dat;: Writes the specified data to the SPI buffer, initiating the SPI
transmission.
The main function initializes the PIC16F877A and performs a basic loop to control SPI and
UART communication:
void main()
{
TRISA5=1;
ADCON1=0x07;
BRGH=1;
SPBRG=51;
37
SYNC=0;
SPEN=1;
TRISC6=1;
TXEN=1;
spiInit(0x20, 0, 0, 0);
unsigned char data=0x30;
__delay_ms(50);
while(1)
{
PORTAbits.RA5=1;
if (PORTBbits.RB7==0){
while(PORTBbits.RB7==0);
for(int j=0; j<=5;j++){
spiWrite(number[j]);
data=spiRead();
__delay_ms(10);
}
}
if (!PORTAbits.RA5) {
for(int j=0; j<=5;j++){
__delay_ms(10);
spiWrite(0x31);
data=spiRead();
if (data <=0x5A) UART_write_char(data);
}
UART_write_char(0xD);
}
while(!PORTAbits.RA5);
}
38
}
Loop Structure
The infinite loop controls SPI communication based on button states and sends data
over UART when certain conditions are met.
PORTAbits.RA5 = 1;: Sets pin RA5 high (indicating an inactive state).
if (PORTBbits.RB7 == 0): If RB7 is low (button pressed):
Waits for the button to be released (while (PORTBbits.RB7 == 0);).
Sends a series of 6 characters over SPI (number[j]).
Slave:
Configuration Bits
#pragma config FOSC = XT: Selects the XT oscillator (crystal/resonator) for the system
clock.
#pragma config WDTE = OFF: Disables the Watchdog Timer.
#pragma config PWRTE = OFF: Disables the Power-up Timer.
#pragma config BOREN = OFF: Disables Brown-out Reset.
#pragma config LVP = OFF: Disables Low-Voltage In-Circuit Serial Programming.
#pragma config CPD = OFF: Disables Data EEPROM Memory Code Protection.
#pragma config WRT = OFF: Disables Flash Program Memory Write Enable bits.
#pragma config CP = OFF: Disables Flash Program Memory Code Protection.
39
char number[]={0x31,0x35,0x2E,0x36,0x39,0x20}: The array includes the ASCII
characters of each number in 15.69.
void spiInit(char sType, char sDataSample, char sClockIdle, char sTransmitEdge)
{
TRISC5 = 0;
if(sType & 0b00000100)
{
SSPSTAT = sTransmitEdge;
TRISC3 = 1;
}
else
{
SSPSTAT = sDataSample | sTransmitEdge;
TRISC3 = 0;
}
SSPCON = sType | sClockIdle;
}
40
{
SSPBUF = dat;
}
Writes data to the SPI buffer.
SSPBUF = dat;: Sets the data to be transmitted over SPI.
char spiRead()
{
while ( !SSPSTATbits.BF );
return(SSPBUF);
}
int count=0;
int index=0;
void __interrupt() SPI_Slave_Read()
{
if(SSPIF == 1)
41
{
unsigned char readData = 0;
if (count==0){
readData=spiRead();
if (readData!=0x3A)
UART_write_char(readData);
}
if (count==1){
while(index<=5){
readData=spiRead();
spiWrite(number[index]);
index++;
}
index=0;
}
SSPIF = 0;
}
}
void main()
42
{
GIE = 1;
PEIE = 1;
SSPIF = 0;
SSPIE = 1;
ADCON1 = 0x07;
TRISA5 = 1;
BRGH=1;
SPBRG=51;
SYNC=0;
SPEN=1;
TRISC6=1;
TXEN=1;
spiInit(0x25, 0, 0, 0);
TRISA0=0;
char data=0;
while(1)
{ PORTAbits.RA0=PORTBbits.RB7;
if (PORTBbits.RB7==0){
count=1;
PORTAbits.RA0=PORTBbits.RB7;
while(PORTBbits.RB7==0);
count=0;
}
}
}
43
spiInit(0x25, 0, 0, 0);: Initializes SPI in slave mode with Slave Select disabled
(SPI_SLAVE_SS_DIS), data sample in the middle
(SPI_DATA_SAMPLE_MIDDLE), clock idle low (SPI_CLOCK_IDLE_LOW), and
idle-to-active transmission edge.
TRISA0 = 0;: Configures RA0 as output.
PORTAbits.RA0 = PORTBbits.RB7;: Mirrors the state of RB7 to RA0.
if (PORTBbits.RB7 == 0): If RB7 is low (button pressed):
Sets count = 1.
Waits until the button is released (while (PORTBbits.RB7 == 0);).
4. RESULT
44
5. VIDEO SIMULATION
Google Drive link
https://drive.google.com/file/d/1_ReS6fP8KHAh-0EAb1MuMopzHznBzfqk/view?
usp=drive_link
45