Here is the main.c file of my software serial project
/*
* File: Main.c
* Author: David J S Briscoe
* PIC: 16F819 with INTERNAL RC OSC @ 8MHz, 5v
* Program: 03_RS232
* Compiler: XC8 (v2.40, MPLABX X v6.00)
* Program Version: 1.0
*
* Program Description: This Program Allows PIC16F819 to write to/from RS232.
* .
*
* Hardware Description:
*
* Notes:
*
*
*
* Created May 30th 2023, 11:32 AM
* Last Updated:31st May 2023
*/
/*******************************************************************************
Change History:
Revision Description
31st May 2023 Added calls to SUART_Init()routine and SUART_Write_Text("Hello") to main().
1st to 2nd June 2023
*******************************************************************************/
/*******************************************************************************
TO DO:
Task Details
Check header file/s Make sure calls in main() are same as in sw_uart.h and sw_uart.c.
*******************************************************************************/
/*******************************************************************************
*Includes and defines
******************************************************************************/
#include "16F819_Internal.h" // Include header which sets config fuses and oscillator frequency (set @ 8MHz) if using a XTAL.
#include "sw_uart.h"
#include <string.h>
/*******************************************************************************
* Function: void initMain()
*
* Returns: Nothing
*
* Description: Contains initializations for main
*
* Usage: initMain()
******************************************************************************/
void initMain()
{
OSCCONbits.IRCF = 0b0111; //Set the Clock to 8MHz when using internal oscillator.
/*
111 = 8 MHz (8 MHz source drives clock directly)
110 = 4 MHz
101 = 2 MHz
100 = 1 MHz
011 = 500 kHz
010 = 250 kHz
001 = 125 kHz
000 = 31.25 kHz (INTRC source drives clock directly)
Page 38 of the PIC16F819 data sheet.
*/
ADCON1bits.PCFG = 0b0110; //See page 82 of data sheet..
///////////////////////
// Setup SW UART
//////////////////////
PORTA = 0x00; //Clear Port A.
PORTB = 0x00; //Clear Port B.
}
/*******************************************************************************
* Function: Main
*
* Returns: Nothing
*
* Description: Program entry point
******************************************************************************/
int main(void)
{
char letter;
int n,i,j;
initMain();
// Initialize SW UART
SUART_Init();
__delay_ms(1000);
// Do forever.
while(1)
{
for ( n = 65; n < 91; n++)
{
letter = n;
__delay_ms(1000);
SUART_Write_Text(letter);// SPACE for testing. Measure bit time on a scope.
__delay_ms(1000);
}
}
for ( i = 97; i < 123; i++)
{
letter = i;
__delay_ms(1000);
SUART_Write_Text(letter);// SPACE for testing. Measure bit time on a scope.
__delay_ms(1000);
}
for ( j = 48; j < 58; j++)
{
letter = n;
__delay_ms(1000);
SUART_Write_Text(letter);// SPACE for testing. Measure bit time on a scope.
__delay_ms(1000);
}
}
Here is the sw_uart.c code
/*
* File: sw_uart.c
* Author: Armstrong Subero modified by David Briscoe
* PIC: 16F819 w/Int OSC @ 8MHz, 5v
* Program: Library file for Software UART
* Compiler: XC8 (v1.41, MPLAX X v3.55)
* Program Version: 1.0
*
* Program Description: This Library allows you to use a software UART with
* the PIC microcontroller
*
* Created on June 1st, 2023
*/
#include "sw_uart.h"
/*******************************************************************************
* Function: SUART_Init(void)
*
* Returns: Nothing
*
* Description: Initializes UART pins
*
******************************************************************************/
void SUART_Init(void)
{
UART_TX = 1; // TX pin is high in idle state
UART_RX_DIR = 1; // Input
UART_TX_DIR = 0; // Output
}
/*******************************************************************************
* Function: unsigned char SUART_Receive(void)
*
* Returns: Nothing
*
* Description: recieves via soft UART
*
******************************************************************************/
unsigned char SUART_Receive(void)
{
// Initial at 0
unsigned char DataValue = 0;
//wait for start bit
while(UART_RX==1);
__delay_us(OneBitDelay);
__delay_us(OneBitDelay/2); // Take sample value in the mid of bit duration
for ( unsigned char i = 0; i < DataBitCount; i++ )
{
if ( UART_RX == 1 ) //if received bit is high
{
DataValue += (1<<i);
}
__delay_us(OneBitDelay);
}
// Check for stop bit
if ( UART_RX == 1 ) //Stop bit should be high
{
__delay_us(OneBitDelay/2);
return DataValue;
}
else //some error occurred !
{
__delay_us(OneBitDelay/2);
return 0x000;
}
}
/*******************************************************************************
* Function: void SUART_Transmit(const char DataValue)
*
* Returns: Nothing
*
* Description: transmits via soft UART
*
******************************************************************************/
void SUART_Transmit(const char DataValue)
{
/* Basic Logic
TX pin is usually high. A high to low bit is the starting bit and
a low to high bit is the ending bit. No parity bit. No flow control.
BitCount is the number of bits to transmit. Data is transmitted LSB first.
*/
// Send Start Bit
UART_TX = 0;
__delay_us(OneBitDelay);
for ( unsigned char i = 0; i < DataBitCount; i++ )
{
//Set Data pin according to the DataValue
if(((DataValue>>i)&0x1) == 0x1 ) //if Bit is high
{
UART_TX = 1;
}
else //if Bit is low
{
UART_TX = 0;
}
__delay_us(OneBitDelay);
}
//Send Stop Bit
UART_TX = 1;
__delay_us(OneBitDelay);
}
/*******************************************************************************
* Function: void SUART_Write_Text(char *text)
*
* Returns: Nothing
*
* Description: writes text via soft UART
*
******************************************************************************/
void SUART_Write_Text(char *text)
{
int i;
for(i=0;text[i]!='\0';i++)
SUART_Transmit(text[i]);
}
/*******************************************************************************
* Function: void SUART_Read_Text(char *Output, unsigned int length)
*
* Returns: Nothing
*
* Description: reads text via soft UART
*
******************************************************************************/
void SUART_Read_Text(char *Output, unsigned int length)
{
int i;
for(int i=0;i<length;i++)
Output[i] = SUART_Receive();
}
/*******************************************************************************
* Function: void SUART_Write_Char(char a)
*
* Returns: Nothing
*
* Description: writes a character to SOFT UART
*
******************************************************************************/
void SUART_Write_Char(char a)
{
SUART_Transmit(a - 128);
}
Here is the sw_uart.h header file
/*
* File: sw_uart.h
* Author: Armstrong Subero modified by David Briscoe
* PIC: 16F819 w/X OSC @ 8MHz, 5v
* Program: Header file to setup PIC16F819 software UART
* Compiler: XC8 (v1.41, MPLAX X v3.55)
* Program Version 1.0
*
* Program Description: This program header allows PIC to use a software UART
*
* Created on April 15th, 2017, 12:57 PM
* Modified 1st June 2023.
*/
#include "16F819_Internal.h"
// bits per second
#define Baudrate 9600
// delay for UART
#define OneBitDelay (1000000/Baudrate)
// no parity no flow control
#define DataBitCount 8
// SW UART RX
#define UART_RX PORTBbits.RB4 //Wherever the compiler sees SW1_PORTB4 it substitutes PORTBbits.RB4
// SW UART TX
#define UART_TX PORTBbits.RB2 //Wherever the compiler sees LED_PORTB2 it substitutes PORTBbits.RB2
// RX pin direction register
#define UART_RX_DIR TRISBbits.TRISB4 //Ensure RB4 is an input pin (RX). Make same pins as in course material.
// TX pin direction register
#define UART_TX_DIR TRISBbits.TRISB2 //Ensure RB2 is an output pin (TX).
//Function Declarations
void SUART_Init(void);
unsigned char SUART_Receive(void);
void SUART_Transmit(const char);
void SUART_Write_Text(char *text);
void SUART_Write_Char(char a);
void SUART_Read_Text(char *Output, unsigned int length);
And here is the 16F819_Internal.h file.
/*
* File: 16F819_Internal.h
* Author: David J S Briscoe
* PIC: 16F819 with INTERNAL OSC @ 8MHz, 5v
* Program: Header file to setup PIC16F819
* Compiler: XC8 (v2.40, MPLAX X v6.00)
* Program Version 1.0
*
* *Changed comments and layout
*
* Program Description: This program header will allows setup of configuration
* bits and provides routines for setting up internal
* oscillator and includes all devices and MCU modules
*
* Created on February 24th, 2023
******************************************************************************/
/*******************************************************************************
*Includes and defines
******************************************************************************/
// PIC16F819 Configuration Bit Settings
/*
Fuses: NOWDT,WDT,PUT,NOPUT,LP,XT,HS,EC_IO,INTRC_IO,INTRC,RC_IO,RC
//////// Fuses: NOMCLR,MCLR,NOBROWNOUT,BROWNOUT,NOLVP,LVP,CPD,NOCPD,WRT_600
//////// Fuses: WRT_400,WRT_200,NOWRT,DEBUG,NODEBUG,CCPB3,CCPB2,PROTECT
//////// Fuses: NOPROTECT
*/
// PIC16F819 Configuration Bit Settings
// 'C' source line config statements
// CONFIG
#pragma config FOSC = INTOSCIO // Oscillator Selection bits (INTRC oscillator; port I/O function on both RA6/OSC2/CLKO pin and RA7/OSC1/CLKI pin)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON // Power-up Timer Enable bit (PWRT enabled)
#pragma config MCLRE = ON // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is MCLR)
#pragma config BOREN = ON // Brown-out Reset Enable bit (BOR enabled)
#pragma config LVP = OFF // Low-Voltage Programming Enable bit (RB3/PGM pin has digital I/O function, HV on MCLR must be used for programming)
#pragma config CPD = OFF // Data EE Memory Code Protection bit (Code protection off)
#pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off)
#pragma config CCPMX = RB2 // CCP1 Pin Selection bit (CCP1 function on RB2)
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
//XC8 Standard Include
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
//Other Includes
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <math.h>
//For delay routines WHEN USING A CRYSTAL OSCILLATOR ONLY
#define _XTAL_FREQ 8000000
//MCU Modules Includes
When I compile this using MPLABX and XC8 I get a few warnings but no errors. However all I get from PUTTY is garbage. I can also see the bursts of data on the R&S RTO1024 scope at work. I'm still learning how to use the scope and I havent figured out how to freeze and zoom into the waveform of the serial data and measure the timing yet. I have attached a zip file of the project below. Can anyone see any obvious mistakes (apart from in the comments which need review and updating in parts) or any ways to get the code working? How can I use a hardware timer in this code to make the timing more accurate? Thanks.
PS Ive been asked to use a 16F819 initially but I'll be writing code for a 16f1827/47 with a hardware EUART later on.