PIC16F88 USART Test
Date: Nov 2021 Updated: 18 Sep 2023
A good starting point for a Microchip microcontroller project is to test the hardware setup and establish a comms link. Here a twisted pair cable connects to MAX483 pins A and B with the other end going into a RS485 to USB converter plugged into a laptop running CuteCom terminal to send and receive character strings.
http://manpages.ubuntu.com/manpages/trusty/man1/cutecom.1.html CuteCom details
RS485 allows more than two devices to share the bus/cable. A load of about 120 ohms is advised at the ends of the twisted pair to absorb reflections.
https://datasheets.maximintegrated.com/en/ds/MAX1487-MAX491.pdf
The MAX483 could be replaced by an RS232 device like MAX232
see https://github.com/DanMilliken/PIC16F88_UART_Demo/blob/master/Schematic.jpg
and if so the directional control line U1:RB3 is not needed
H8A:5 goes via ZTX300 transistor to drive an LED both on a 5v supply. THE LED is made to flash on power up to verify the PIC is alive and programmed ok.

Above schematic /home/andymc/fotmus/webDesign/niaMondo/hal/zoneController/
zoneControllerPIC16F88wix.png
Dated: 03Nov2021
Main Requirements:
-
MPLAB IDE with 'c' Compiler XC8 v2.32 C99 enabled https://microchipdeveloper.com/xc8:moving-to-xc8-2-0
-
RS485 USB-485 Converter (Ebay about £1.30 in 2021)
-
5v Power supply
-
Laptop with terminal eg CuteCom or Minicom
-
Devices under test as in above schematic
-
Programmer hardware (Used here PICkit3 as supported by MPLAB IDE)
/home/andymc/Ref/halk/PIC16F88supportOld/16F88uartTest2.X/xc8Test16f88uart2.c
Dated 07Nov2021
/******************************************************************************
* PIC16F88 UART Test
* With thanks to Dan Milliken http://www.dmilliken.com/?p=5 2014-12-15
* https://github.com/DanMilliken/PIC16F88_UART_Demo
* and https://simple-circuit.com/mplab-xc8-uart-example-pic-mcu/
* Description: Demonstrates using the PIC16F88 Microcontroller with a MAX483 IC
* to produce RS485 output to a PC with USB.
* 16F88 data sheet/manual https://ww1.microchip.com/downloads/en/DeviceDoc/30487D.pdf
* Compiled under: MPLAB X IDE v5.50 on 03 Nov 2021
* Project and Program Name: 16F88uartTest2
*******************************************************************************/
#include <xc.h> /* XC8 General Include File */
//Note #include <16F88.h> not called directly as it is included by #include <xc.h>
#include <stdio.h> /* C standard IO */
#include <stdint.h> // include stdint header amc added
#include <string.h>
#include <stdbool.h>
#include <stdlib.h> //for itoa see XC8 user guide
#pragma config LVP = OFF // disable low voltage programming
#pragma config FCMEN = OFF // disable fail safe clock monitor
#pragma config IESO = OFF // disable internal/external oscillator switchover
#pragma config BOREN = OFF // disable brown out reset
#pragma config PWRTE = ON // enable power up timer
#pragma config WDTE = OFF // disable watchdog timer
#pragma config FOSC = INTOSCIO // Internal oscillator
#define _XTAL_FREQ 8000000 //8 Mz only needed for delay
#define TXDO PORTBbits.RB3 //PIN_B3 High is TX enable
#define REDLED PORTAbits.RA0 //LED on push switch, red 5v=LED on
void putch(char cDaita) {
// https://microchipdeveloper.com/xc8:console-printing
//This will be called automatically by printf()
TXDO=1; //TX_Enable
__delay_ms(5); // wait
while( ! PIR1bits.TXIF) // wait until the transmitter is ready
continue;
while (TXSTAbits.TRMT == 0); // wait for transmit shift register to be empty
TXREG = cDaita; // send one character
TXDO=0; //TX_Disable
}
//void putch(unsigned char data) {
void myputch(char cDaata) {
//https://microchipdeveloper.com/xc8:console-printing
//printf() calls this customised version of putch
TXDO=1; //TX_Enable
while( ! PIR1bits.TXIF) // wait until the transmitter is ready
continue;
while (TXSTAbits.TRMT == 0); // wait for transmit shift register to be empty
TXREG = cDaata; // send one character
TXDO=0; //TX_Disable
}
void UART_PutC(const char darta)
{
TXDO=1; //TX_Enable
//__delay_ms(20); // wait 20 mS debug
//while (TRMT == 0); // wait for transmit shift register to be empty
while (TXSTAbits.TRMT == 0); // wait for transmit shift register to be empty
TXREG = darta; // update EUSART transmit data register
TXDO=0; //TX_Disable
}
void UART_Print(const char *data)
{
uint8_t i = 0;
while (data[i] != '\0')
UART_PutC (data[i++]);
}
void flashLED(void)
{
int iz;
for (iz = 1; iz < 3; ++iz)
{
REDLED=1;
__delay_ms(1000); // wait 1 second
REDLED=0;
__delay_ms(1000); // wait 1 second
}
}
void UART_Init(void)
{
//OSCCONbits.IRCF = 0b110; // Set internal RC oscillator to 4 MHz
//https://maker.pro/pic/tutorial/getting-started-with-pic-microcontrollers-internal-oscillator-and-io-pins
OSCCONbits.IRCF = 0b111; // Set internal RC oscillator to 8 MHz
while(!OSCCONbits.IOFS); // Wait for frequency to stabilise
TXSTAbits.BRGH = 1; // high baud rate
TXSTAbits.SYNC = 0; // Set Asynchronous Mode, ie UART
TXSTAbits.TX9 = 0; // 8-bit transmission
//SPBRG = 25; // 9600 baud @ 4MHz with BRGH = 1
SPBRG = 51; // 9600 baud @ 8 MHz with BRGH = 1
PIE1bits.RCIE = 1; // AUSART Receive Interrupt Enable bit
//SPEN & CREN set 1 is same as RCSTA = 0x90; // serial port enabled, continues receive enabled
RCSTAbits.SPEN = 1; // Serial port enabled (configures RB2/SDO/RX/DT and RB5/SS/TX/CK pins as serial port pins)
RCSTAbits.CREN = 1; // Continuous Receive Enable bit
TXSTAbits.TXEN = 1; // enable transmitter
return;
}
const char sTestMsg[] = "ex-PIC16F887 UART example" ;
#define LTERM 0x0D //\r=cr=13=LTERM - End of message character
#define LGO '!' // Start of message character
// main function
void main(void)
{
//Set port directions
//RA5/MCLR is i/p only http://ww1.microchip.com/downloads/en/devicedoc/30487d.pdf
char cInp;
unsigned char chh;
char comin_buf[30]; //input data buffer, A string literal in XC8 is a const array of char
int iMsg;
TRISBbits.TRISB3 = 0; // Set B3 as output TXDO controls MAX483 direction
TRISAbits.TRISA0 = 0; // Set A0 as output see REDLED
//OSCCON = 0x70; // set internal oscillator to 8MHz
TRISBbits.TRISB2 = 1; //Input RX for UART
TRISBbits.TRISB5 = 1; //Input TX (as UART has its own driver!)
UART_Init(); // 9600); // initialise UART module with 9600 baud
__delay_ms(2000); // wait 2 seconds
flashLED();
UART_Print("Hello 16F88!\r\n"); // UART print
__delay_ms(1000); // wait 1 second
UART_Print(sTestMsg); // UART print message
__delay_ms(1000); // wait 1 second
UART_Print("\r\n"); // start new line
printf("Done with printf\r\n");
myputch('X');
myputch('Y');
myputch('Z');
for (cInp = 'A' ; cInp <= 'Z' ; cInp++) {
myputch(cInp);
}
putch('!');
putch('h');
while (1)
{
//RCIF == 1 then The AUSART receive buffer is full (cleared by reading RCREG) **
//RCIF bit (register PIR1, bit 5)
iMsg = 0;
while ( RCIF == 1 ) // if 1 character(s) are available
{
//OERR: Overrun Error bit
//1 = Overrun error (can be cleared by clearing bit CREN)
//The USART can receive two characters before it overflows
if (OERR) // if there is overrun error
{ // clear overrun error bit
CREN = 0; //Clear overrun
NOP();
CREN = 1;
}
chh = RCREG; // read from EUSART receive data register, clears receive buffer **
comin_buf[iMsg++] = (char)chh;
}
if (iMsg > 0)
{
comin_buf[iMsg++] = NULL;
for (int ix = 0; ix < iMsg; ix++)
{
putch(comin_buf[ix]);
}
}
}
} //end main
//========================================
Below the test input and echoed output is shown on the laptop terminal.
Character delay is set to 12 mS for this polling example.
CR/LF is appended to each line sent
File /home/andymc/fotmus/webDesign/niaMondo/hal/zoneController/
zoneControllerPIC16F88CuteComwix.png

Manuals
MPLAB® XC8 C Compiler User’s Guide http://ww1.microchip.com/downloads/en/devicedoc/50002053g.pdf
Moving to the v2.0 MPLAB® XC8 C Compiler https://microchipdeveloper.com/xc8:moving-to-xc8-2-0
Micro PIC16F88 https://ww1.microchip.com/downloads/en/DeviceDoc/30487D.pdf
Legacy CCS compiler https://www.engr.mun.ca/~dpeters/6806/postings/CRefManual.pdf