The last step of preparation for some serious PIC programming is to learn how to use the serial interface of the PIC for reading (Rx) and writing (Tx). So I decided to enhance the 3-Digit 7-segment display to read the input value over the serial connection. To test it I wrote a simple serial transmitter that sends the numbers from 1 to 255 first counting upwards (1 to 255) and then downwards (255 to 1) over and over again. The 3-digit display shows these numbers that it reads from its serial port.
The transmitter
First some definitions for the direction of counting
#define UP 1
#define DOWN 2
Then the timer 0 counter
int timer0count;
The ISR simply increments the timer 0 counter every time Timer0 rolls over
void interrupt ISR()
{
if (INTCONbits.TMR0IF) {
timer0count++;
INTCONbits.TMR0IF = 0;
TMR0 = 0;
}
}
This is the main() function
void main()
{
unsigned int value = 1;
char direction = UP;
OSCCON = 0xF0; // set internal osc to 32Mhz
OPTION_REG = 0x08; // Prescaler not assigned to timer 0
TRISA0 = 0;
The next line sets the TX function on pin A0. This is important because the default is to use A4 for Tx.
// TX function on pin A0
TXCKSEL = 1;
Baud rate configuration. The data sheet contains tables with the settings for common values.
// configure EUSART BAUD rate: Fosc / 64(n+1)
BRG16 = 0;
BRGH = 0;
The following lines configure the EUSART (extended universal serial asynchronous receiver transmitter) for Tx
// configure the EUSART receiver
TXEN = 1;
SYNC = 0;
SPEN = 1;
Clearing the analog output bit for pin A0 that we will use for Tx
// The analog bit must be cleared for RX to function
ANSELAbits.ANSA0 = 0;
timer0count = 0;
Enabling the interrupts – needed for Timer 0
INTCON = 0xC0 | 0xE0;
INTCONbits.GIE = 1;
while(1) {
We wait for 2000 overruns for transmitting a number. This comes out around 16 times a second.
if (timer0count < 2000)
continue;
timer0count = 0;
The TRMT bit indicates whether we can write a character to the transmit register. We can write if it is set.
if (TRMT == 0)
continue;
Transmitting a character is done by writing it to TXREG
TXREG = value;
Then we increase of decrease the value.
if (direction == UP)
value += 1;
else
value -= 1;
if (value == 254)
direction = DOWN;
if (value == 1)
direction = UP;
}
}
The receiver
We will not copy the 3-digit controller again, but only point out the differences.
First the updated ISR with the new section highlighted in bold. The new section reads a character from RCREG when the RCIF flag is raised.
void interrupt ISR()
{
if (INTCONbits.TMR0IF) {
timer0count++;
INTCONbits.TMR0IF = 0;
TMR0 = 0;
}
if (PIR1bits.RCIF == 1) {
if (FERR == 0)
adcvalue = RCREG;
if (OERR == 1) {
overrun = 1;
}
}
}
Next is a new function to indicate that there is an overrun error. An overrun error occurs when a character is received before all the characters have been read from the 2 character input buffer. I decided to indicate this condition by lighting one segment on each digit. This is done by the following function:
void show_overrun_error()
{
LATC0 = 1;
LATC1 = 0;
LATC2 = 0;
LATC3 = 0;
LATC4 = 0;
LATC5 = 0;
LATA4 = 0;
}
There are some changes in the main function. First we enable the EUSART receive interrupt and enable the EUSART:
// enabling EUSART rx interrupt
PIE1bits.RCIE = 1;
INTCONbits.PEIE = 1;
INTCONbits.GIE = 1;
// configure EUSART BAUD rate: Fosc / 64(n+1)
BRG16 = 0;
BRGH = 0;
// configure the EUSART receiver
CREN = 1;
SYNC = 0;
SPEN = 1;
// The analog bit must be cleared for RX to function
ANSELAbits.ANSA1 = 0;
The last change is in the switch statement that shows the digit. Here we check for an overrun and display the overrun error or the digit:
if (overrun == 1)
show_overrun_error();
else
show_number(digits[digit1index]);
Demo
This is how it work. The 3-digit controller is not perfect yet and the digit (especially to left most one) are flickering. But it does show the numbers correctly and will be very helpful in debugging my applications.
Discover more from Eli's Blog
Subscribe to get the latest posts sent to your email.
