Serial communication RS-485 between Pic16F690/PIC16F18877

Re: Serial communication RS-485 between Pic16F690/PIC16F1887

Postby AussieSusan » Mon Jan 26, 2026 2:54 am

Glad it now works.
But I say again - you don't need the _XTAL_FREQ #define unless you are using the compiler supplied delay macros.
There is a mistaken belief that this #define somehow sets the oscillator frequency - IT DOES NOT. It only reflects what you ultimately set the clock to so the delay macros know what it is.
As for timer0 working correctly, that all depends on how you set up the clock input (which you have now shown us). There are many sources (T0CON1bits.T0CS lists 7 valid ones).
BTW - I've not used that MCU. Everything I'ver suggested is based on my reading of the data sheet. I know that some of these data sheets can be hard to read but learning how to interpret them is an essential skill.
AussieSusan
Verified identity
 
Posts: 183
Joined: Mon Jun 16, 2014 4:45 am
PIC experience: Experienced Hobbyist

Re: Serial communication RS-485 between Pic16F690/PIC16F1887

Postby ciclingman » Mon Jan 26, 2026 12:38 pm

Good morning Susan, I think you're right: the oscillator and or the timer0 are not yet set well because the communication takes place only when the first scan of the firmware is done and after that nothing works, not even the rest of the firmware, I'm talking about the PIC16F18877. I really have to learn to read the datasheet flowchart to be able to make a correct setting of the registers. I am a simple electrician, I am not an engineer.
ciclingman
 
Posts: 18
Joined: Sun Mar 17, 2024 9:11 pm

Re: Serial communication RS-485 between Pic16F690/PIC16F1887

Postby AussieSusan » Tue Jan 27, 2026 3:38 am

Take a step back.
The equivalent of "Hello World" for computer programming is to flash a LED on our MCU. To get that working you need to know how to set the CONFIG settings, how to program the chip (both of which you probably know already) and how to configure the oscillator section.
Also set a GPIO pin as output and connect an LED (and series resistor) to it.
In the main loop, set the GPIO pin high, delay for (say) 500ms (and for that you WILL need to define the _XTAL_FREQ #define), set the GPIO pin log and wait another 500ms.
That will make the LED flash on and off in a 1 second cycle which is easy enough to check by eye (and perhaps the second hand of your watch).
The value in all of this is that you must have the oscillator set correctly to whatever frequency you want before the LED will flash at the correct speed.
You can then try to change the oscillator source, frequency (and also adjust the _XTAL_FREQ value) etc. and still have the LED flash at the correct speed.
Use a multimeter if you don't have an LED but be careful with a digital multimeter to now make the GPIO pin transition too fast or the delays in the multimeter will mess you up.
There is one other option but it is slightly more difficult on your MCU - use the Reference Clock Output module. You will need to read up on how to use the PPS to route the clock signal to a GPIO pin but (and this is based on only a quick read of the datasheet) you should only need to turn the module on and leave everything else set to the power on reset defaults.
Once you know the oscillator is working correctly, then you can get the other modules configured, but still take it one step at a time. That way, if something is not working then it wil be the last step you took which makes debugging much easier.
AussieSusan
Verified identity
 
Posts: 183
Joined: Mon Jun 16, 2014 4:45 am
PIC experience: Experienced Hobbyist

Re: Serial communication RS-485 between Pic16F690/PIC16F1887

Postby ciclingman » Tue Jan 27, 2026 12:27 pm

Thank you for your help... I'll try. The problem is that I know a little bit about PIC16F690 because I have already used it for other projects, but I have never used the PIC16F18877 and it is complicated because it has many possibilities of use
ciclingman
 
Posts: 18
Joined: Sun Mar 17, 2024 9:11 pm

Re: Serial communication RS-485 between Pic16F690/PIC16F1887

Postby ciclingman » Sun Feb 01, 2026 6:46 pm

Hello everyone. I still have communication problems; the PIC16F18877 receives what the PIC16F690 transmits; but the PIC16F690 does not receive what the PIC18877 transmits; I write the setting I wrote for the PIC16F18877:

PIC16F18877

// CONFIG1
#pragma config FEXTOSC = OFF // External Oscillator mode selection bits->Oscillator not enabled
#pragma config RSTOSC = HFINT32 // Power-up default value for COSC bits (HFINTOSC with OSCFRQ= 32 MHz and CDIV = 1:1)
#pragma config CLKOUTEN = OFF // Clock Out Enable bit->CLKOUT function is disabled; i/o or oscillator function on OSC2
#pragma config CSWEN = OFF // Clock Switch Enable bit->Writing to NOSC and NDIV is allowed
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable bit->FSCM timer enabled
// CONFIG2
#pragma config MCLRE = OFF // Master Clear Enable bit (MCLR pin is Master Clear function)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config LPBOREN = OFF // Low-Power BOR enable bit (ULPBOR disabled)
#pragma config BOREN = ON // Brown-out reset enable bits (Brown-out Reset Enabled, SBOREN bit is ignored)
#pragma config BORV = LO // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (VBOR) set to 1.9V on LF, and 2.45V on F Devices)
#pragma config ZCD = OFF // Zero-cross detect disable (Zero-cross detect circuit is disabled at POR.)
#pragma config PPS1WAY = OFF // Peripheral Pin Select one-way control (The PPSLOCK bit can be set and cleared repeatedly by software)
#pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable bit (Stack Overflow or Underflow will cause a reset)
// CONFIG3
#pragma config WDTCPS = WDTCPS_31// WDT Period Select bits (Divider ratio 1:65536; software control of WDTPS)
#pragma config WDTE = OFF // WDT operating mode (WDT Disabled, SWDTEN is ignored)
#pragma config WDTCWS = WDTCWS_7// WDT Window Select bits (window always open (100%); software control; keyed access not required)
#pragma config WDTCCS = SC // WDT input clock selector (Software Control)

// CONFIG4
#pragma config WRT = OFF // UserNVM self-write protection bits (Write protection off)
#pragma config SCANE = available// Scanner Enable bit (Scanner module is available for use)
#pragma config LVP = ON // Low Voltage Programming Enable bit (Low Voltage programming enabled. MCLR/Vpp pin function is MCLR.)

// CONFIG5
#pragma config CP = OFF // UserNVM Program memory code protection bit (Program Memory code protection disabled)
#pragma config CPD = OFF // DataNVM code protection bit (Data EEPROM code protection disabled)

#define _XTAL_FREQ 32000000

#include <xc.h>
#include <stdint.h>
#include <stdbool.h>
#include <pic.h>

void __interrupt() INTERRUPT_Intervallo (void) //Interrupt di TIMER0 settato a 1 ms

{
while (RCIF) {ValoreRicevuto = RCREG;} //Se buffer ricezione pieno
//e assenza di trasmissione passa valore
//Interrupt (verifica ogni millisecondo)-------------------------------------------
if(PIR0bits.TMR0IF)
{
if (tempo != 0) tempo--; //Decremento

TMR0H = 0XF8; //Caricamento nibble H del timer0 a 16 bit
TMR0L = 0XF0; //Caricamento nibble L del timer0 a 16 bit
PIR0bits.TMR0IF = 0; //Reset
}
}

//Funzione di trasmissione dati con tastiera
unsigned char Trasmissione(unsigned char ValTrasmissione)

{
//INIZIO TRASMISSIONE
Routine_Ritardo(100); //Assestamento linea
RCIE = 0; //Disabilitazione interrupt ricezione

TX1STAbits.TXEN = 1; //Abilitazione trasmissione seriale
EnableDati = 1; //Abilitazione trasmissione RS485

Routine_Ritardo(150); //Assestamento linea
while (TXIF)
{
TXREG = ValTrasmissione; //Invio byte fino a quando il flag non si resetta
}
Routine_Ritardo(100); //Assestamento linea

EnableDati = 0; //Abilitazione ricezione RS485
//FINE TRASMISSIONE

//SETTAGGIO RICEZIONE
Routine_Ritardo(100); //Assestamento linea
TX1STAbits.TXEN = 0;//Disabilitazione trasmissione seriale

RCIE = 1; //Abilitazione interrupt ricezione

return 0;
}


void main(void)
{

ADRESL = 0x00; //Esclusione porte analogiche, tutto digitale i/o
ADRESH = 0x00;
ANSELA = 0x00;
ANSELB = 0x00;
ANSELC = 0x00;
ANSELD = 0x00;
ANSELE = 0x00;
ADCON0bits.ADON = 0; //Convertitore analogico digitale spento


//LATx registers

LATE = 0x00;
LATD = 0x00;
LATA = 0x00;
LATB = 0x00;
LATC = 0x00;


//WPUx registers for pull-up

WPUD = 0x00;
WPUE = 0x00;
WPUB = 0x00;
WPUA = 0x00;
WPUC = 0x00;


//ODx registers

ODCONE = 0x00;
ODCONA = 0x00;
ODCONB = 0x00;
ODCONC = 0x00;
ODCOND = 0x00;


//SLRCONx registers

SLRCONA = 0xFF;
SLRCONB = 0xFF;
SLRCONC = 0xFF;
SLRCOND = 0xFF;
SLRCONE = 0x07;


//INLVLx registers

INLVLA = 0xFF;
INLVLB = 0xFF;
INLVLC = 0xFF;
INLVLD = 0xFF;
INLVLE = 0x0F;



// PORT A
TRISA = 0b11011111; //Port A tutto IN tranne bit 5

// PORT B
TRISB = 0b11111111; //Port B tutto IN

// PORT C
TRISC = 0b10001100; //Port C tutto OUT tranne bit 2 3 7

// PORT D
TRISD = 0b00000011; //Port D tutto OUT tranne bit 0 1

// PORT E
TRISE = 0b11101100; //Port D tutto IN tranne bit 0 1 4(per settare la porta D come in e out)

//Abilitazione Interrupt
PIE0bits.TMR0IE = 1;
INTCONbits.GIE = 1;
INTCONbits.PEIE = 0;
// OSCCON1bits.NDIV = 4; //Si divide per 4 per avere un clock di 8 MHz per la comunicazione

//Settaggio timer0 a 1 ms
T0CON1 = 0b01000010;//0b01110000; //0b01110000; 1000 = 2secondi
T0CON0 = 0b10010000;//0b10010000; //0b10010000; 1000 = 2secondi
TMR0H = 0XF8;//Caricamento nibble H del timer0 a 16 bit
TMR0L = 0XF0;//Caricamento nibble L del timer0 a 16 bit

//Settaggio comunicazione e abilitazione ricezione ricordando che il clock source è di 8 MHz

RCIE = 1; //Interrupt ricezione abilitato

TX1STAbits.SYNC = 0;
TX1STAbits.TX9 = 0;

BRGH = 1; BRG16 = 0; //Settaggio per velocità di comunicazione (baud rate)
SPBRG = 207;

RC1STAbits.SPEN = 1; //Settaggi per ricezione
RC1STAbits.CREN = 1;

PORTA = 0X00; PORTB = 0X00; PORTC = 0X00; //Reset delle porte


Routine_Ritardo(30); //Assestamento

while (1)
{

if (Ok == 0) {Routine_Ritardo(50); Trasmissione(21); Sirene = 1;} //prova led rosso acceso
if (Set == 0) {Routine_Ritardo(50); Trasmissione(22); Sirene = 0;}//led verde acceso

if (ValoreRicevuto == 23) {ControlloBatteria = 1;}// Scrittura_Car(ValoreRicevuto); ValoreRicevuto = 0;}
else if (ValoreRicevuto == 21) {Routine_Ritardo(30); ControlloBatteria = 0;}
}
}


PIC16F690

#include <pic.h>

//Fusibili di configurazione
#pragma config FOSC = INTRCIO // Oscillator Selection bits (INTOSCIO oscillator: I/O function on RA4/OSC2/CLKOUT pin, I/O function on RA5/OSC1/CLKIN)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled and can be enabled by SWDTEN bit of the WDTCON register)
#pragma config PWRTE = ON // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF // MCLR Pin Function Select bit (MCLR pin function is digital input, MCLR internally tied to VDD)
#pragma config CP = OFF // Code Protection bit (Program memory code protection is disabled)
#pragma config CPD = OFF // Data Code Protection bit (Data memory code protection is disabled)
#pragma config BOREN = OFF // Brown-out Reset Selection bits (BOR disabled)
#pragma config IESO = OFF // Internal External Switchover bit (Internal External Switchover mode is disabled)
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is disabled)
#define _XTAL_FREQ 8000000 //Oscillatore impostato a 8 MHz

#define LedVerde RA4 //Led verde (stato antifurto)
#define LedRosso RA5 //Led rosso (stato antifurto)
#define EnableDati RB6 //Pin di gestione trasmissione porta seriale 485

//----------------------------------------------------------------------------

void __interrupt()intervallo(void) //Interrupt di TIMER0 settato a 1 ms
{
//RICEZIONE mediante interrupt (verifica ogni millisecondo)
while (RCIF) {ValoreRicevuto = RCREG;} //Se buffer ricezione pieno
//e assenza di trasmissione passa valore
if (T0IF) //Se overflow
{
if (tempo != 0)
{
tempo--; //Decremento
}
T0IF = 0; //Reset
}
}

unsigned char Trasmissione(unsigned char ValTrasmissione)

{
//INIZIO TRASMISSIONE
Routine_Ritardo(100); //Assestamento linea
RCIE = 0; //Disabilitazione interrupt ricezione
TXEN = 1; //Abilitazione trasmissione seriale
EnableDati = 1; //Abilitazione trasmissione RS485

Routine_Ritardo(150); //Assestamento linea
while (TXIF)
{
TXREG = ValTrasmissione; //Invio byte fino a quando il flag non si resetta
}
Routine_Ritardo(100); //Assestamento linea

EnableDati = 0; //Abilitazione ricezione RS485
//FINE TRASMISSIONE

//SETTAGGIO RICEZIONE
Routine_Ritardo(100); //Assestamento linea
TXEN = 0;//Disabilitazione trasmissione seriale
RCIE = 1; //Abilitazione interrupt ricezione

return 0;
}
void main(void)

{

// INIZIALIZZAZIONE HARDWARE

ANSEL = 0x00;
ANSELH= 0X00; //Esclusione porte analogiche, tutto digitale i/o

// PORT A
TRISA = 0b11001111; //Port A tutto IN tranne i bit 4, 5

// PORT B
TRISB = 0b00111111; //Port B tutto IN tranne i bit 6, 7

// PORT C
TRISC = 0b00001111; //Port C tutto IN //tranne i bit 4, 5, 6, 7
PORTC = 0b00000000; //Reset uscite


// Oscillatore impostato a 8MHz

OPTION_REG = 0b10000010; //Prescaler 1:8 e disabilitazione Pull-up
INTCON = 0b10100000;
OSCCON = 0b01110000; //Settaggio oscillatore interno a 8 MHz
TMR0 = 6; //Caricamento TIMER0 a 1 ms
RCIE = 1; //Interrupt ricezione abilitato
SYNC = 0; CREN = 1; SPEN = 1;//Settaggi per ricezione
BRGH = 1; BRG16 = 0; SPBRG = 51; //Settaggio per velocità di comunicazione (baud rate) 10417
PORTA = 0X00; PORTB = 0X00;// PORTC = 0X00; //Reset delle porte
EnableDati = 0; //Enable disabilitato per ricezione
Routine_Ritardo(30); //Assestamento

//----------------------------------------------------------------------------------------

while (1)
{

RC4 = 1;
if(RC3 == 0) {Routine_Ritardo(50); Trasmissione(23);}
else if(RC3 == 1) {Routine_Ritardo(50); Trasmissione(21); LedVerde = 0;}
switch (ValoreRicevuto)
{
case 21:
LedRosso = 1;
LedVerde = 0;

case 22:
LedVerde = 1;
LedRosso = 0;
}

if (ValoreRicevuto == 0) {LedVerde = 1; LedRosso = 0;}
else if (ValoreRicevuto != 0) {LedVerde = 0; LedRosso = 1;}
}
}
ciclingman
 
Posts: 18
Joined: Sun Mar 17, 2024 9:11 pm

Re: Serial communication RS-485 between Pic16F690/PIC16F1887

Postby AussieSusan » Mon Feb 02, 2026 3:09 am

My first suggestion is to simplify your code substantially.
Secondly, how do you know that the PIC16f690 is NOT receiving the correct data? Can you connect the PIC16F18877 to a PIC (or similar) that is running a terminal emulator and see what happens there?
I *assume* that the problem lies in the PIC16F690 but I suspect that you have not shown all of the code. For example, you only include 'pic.h' where I would expect to see 'xc.h' included as well.
Also I can't see where your variables are defined. This is critical because you are updating 'ValoreRiceVuto' in the ISR and referring to it in the main loop. that mean that the variable MUST be declared as volatile otherwise the main loop will probably never see any change.
Personally I would get rid of most of your code and simply send a known value and then loop until you receive a character back - as I say: simplify until you get things working.
Also I suspect there is a logic error in your main loop: you transmit a value (I assume that what 'Transmissione()' does) and then immediately check the value of 'ValoreRicevuto' in the switch statement for a value of 21 or 22 and sets the LEDs accordingly.
But you then immediately test to see if it is 0 or not and again set the LEDs.
Imagine you receive a value of 0 - the green LED will be lit (assuming '1' means turn on the LED) and the red LED is off and you then repeat the loop;. So far so good (except this is a log of work when nothing changes.
Now imagine that you get a value of 21. In the switch statement you turn the green LED off and the red LED on but the 'if' statement below immediately turns the green lLED back on and the red LED off.
The chances are that you would NEVER see the LED flicker.
There are probably other issues but that is enough for now.
AussieSusan
Verified identity
 
Posts: 183
Joined: Mon Jun 16, 2014 4:45 am
PIC experience: Experienced Hobbyist

Re: Serial communication RS-485 between Pic16F690/PIC16F1887

Postby ciclingman » Mon Feb 02, 2026 12:35 pm

I'm a passionate programmer and not a professional, but I've already done several projects, so don't stop to check if I've declared the variables or not; I didn't post all the code! Could you please tell me if the clock, timer0 and communication settings are correct for both PICs? If I was wrong, could you tell me where? I realized that I have to load XC.H as well
ciclingman
 
Posts: 18
Joined: Sun Mar 17, 2024 9:11 pm

Re: Serial communication RS-485 between Pic16F690/PIC16F1887

Postby ciclingman » Mon Feb 02, 2026 9:05 pm

After several tests, the PIC16F18877 receives but does not transmit. The PIC16F690 transmits but does not receive.
ciclingman
 
Posts: 18
Joined: Sun Mar 17, 2024 9:11 pm

Re: Serial communication RS-485 between Pic16F690/PIC16F1887

Postby AussieSusan » Tue Feb 03, 2026 3:29 am

I say again: how do you know? How do you know that the PIC16F690 transmits and the PIC16F18877 receives?
Have you tried using a terminal emulator on a PC instead of one of the MCUs?
General comments:
- if you have communication one way then the chances are that you have the baud rate settings correct for both MCUs
- timers have nothing to do with the UART module so (at least for now) get rid of them and all code associated with them
- don't use interrupts - just use blocking code until the communication is sorted out
For the PIC16F18877, don't keep turning the Tx side of the UART on and off - set up the UART and then leave things alone. You MUST follow the setup order as shown in the data sheet. I suspect that this may be why you can't get the MCU to transmit as you set the TXEN bit after the SPEN bit. You should test that the TX buffer is empty before you send and also test that there is something in the Rx buffer before you read it
For the PIC16F690, same comment about following the correct order of configuring the UART module. I suspect you can't receive because you set the CREN bit BEFORE the SPEN bit. As you can it can transmit but not receive, try connect the Rx and Tx pins together. That way you will receive whatever you send and so can help to debug the reception code
AussieSusan
Verified identity
 
Posts: 183
Joined: Mon Jun 16, 2014 4:45 am
PIC experience: Experienced Hobbyist

Re: Serial communication RS-485 between Pic16F690/PIC16F1887

Postby ciclingman » Tue Feb 03, 2026 12:37 pm

I'll try to do what you say. I base myself on a project, working, but the two ICPs are the same (PIC16F690). I am doing the tests through the two boards, which will have to communicate, using components on board, connected to the various outputs.
ciclingman
 
Posts: 18
Joined: Sun Mar 17, 2024 9:11 pm

PreviousNext

Return to SCI/USART/EUSART

Who is online

Users browsing this forum: No registered users and 1 guest