I'm currently working on a project using XC8, C, and a PIC18F66K22 as a master device for Modbus RTU communication (rs485). Despite a seemingly functional hardware setup with USART2 (TX=RG1, RX=RG2, R/T=RG3), I'm encountering issues with the code. The communication isn't working as intended, and when using a COM port toolkit for monitoring, it appears to be sending garbage data.
If anyone could provide assistance or guidance to troubleshoot this issue, I would greatly appreciate it. Thank you.
have been trying a lot.
the code:
// PIC18F66K22 Configuration Bit Settings
#pragma config RETEN=OFF, INTOSCSEL=HIGH, SOSCSEL=DIG, XINST=OFF, FOSC=INTIO2, PLLCFG=ON, FCMEN=OFF, IESO=OFF // Configuration word 1
#pragma config PWRTEN=OFF, BOREN=ON, BORV=3, BORPWR=HIGH, WDTEN=SWDTDIS, WDTPS=1024 // Configuration word 2
#pragma config RTCOSC=SOSCREF, CCP2MX=PORTC, MSSPMSK=MSK5, STVREN=ON, MCLRE=OFF // Configuration word 3
#pragma config BBSIZ=BB1K // Configuration word 4
#pragma config CP0=ON, CP1=ON, CP2=ON, CP3=ON, CPB=OFF, CPD=OFF // Configuration word 5
#pragma config WRT0=OFF, WRT1=OFF, WRT2=OFF, WRT3=OFF, WRTC=ON, WRTB=OFF, WRTD=OFF // Configuration word 6
#pragma config EBRT0=OFF, EBRT1=OFF, EBRT2=OFF, EBRT3=OFF, EBRTB=OFF // Configuration word 7
#include <xc.h> //default
#define _XTAL_FREQ 64000000 // 64MHz
//declare used funcsions:
void InitializeSerialPort();
void WriteModbusData(uint8_t* data, int length);
void SendStatusRequest(uint8_t address, uint8_t* modbusData);
uint16_t CalculateCRC(uint8_t* data, int length);
void main(void) //start main
{
InitializeSerialPort(); //set UART settings.
__delay_ms(100); //delay for a bit
while (1) //while true
{
uint8_t modbusData[8]; //create an array
SendStatusRequest(0x01, modbusData); //setting the array based on the MODBUS data sent in this case " 01 03 00 00 00 10 "
WriteModbusData(modbusData, sizeof(modbusData)); //write the data (send).
__delay_ms(100); //delay after each message & repeat the process.
}
} //end main
void InitializeSerialPort()
{
// Configure pins for serial communication
TRISG2 = 1; // RX pin set as input
TRISG1 = 0; // TX pin set as output
TRISG3 = 0; // R/T pin set as output
// Set AN18 as digital I/O - data-sheet page 22
ANSEL18 = 0; // RG2 needs to be done just for 18 because the ANSEL chanel is Analog Input and the rest (17 & 19) are outputs
// Disable 9-bit mode
TX92 = 0; // Disable 9 bit sending.
RX92 = 0; // Disable 9 Bit reception.
// Enable Asynchronous serial port
SYNC2 = 0; // Asynchronous mode.
SPEN2 = 1; // Enable serial port pins
// Prepare for transmission & reception
TXEN2 = 1; // Enable transmission.
CREN2 = 1; // Enable reception
// High-speed mode
BRGH2 = 1; //-----------------------)
BAUDCON2 |= 0x08;
// Calculate and set SPBRG value for 9600 BPS baud rate according to the data-sheet page 332.
const unsigned int spbrg_value = (_XTAL_FREQ / (64 * 9600)) - 1;
// BRG16: 16-Bit Baud Rate Register Enable bit
//1 = 16-bit Baud Rate Generator – SPBRGHx and SPBRGx
//0 = 8-bit Baud Rate Generator – SPBRGx only (Compatible mode), SPBRGHx value ignored PAGE 330
// BRG16 = 1 (if needed, otherwise leave it as it is)
SPBRGH2 = spbrg_value & 0xFF; // Low byte
SPBRG2 = (spbrg_value >> 8) & 0xFF; // High byte
}
void WriteModbusData(uint8_t* data, int length)
{
for (int i = 0; i < length; i++)
{
while (!TX2IF)
{} //wait until transmit buffer is empty
TXREG2 = data[i]; // Write data to transmit buffer
}
}
void SendStatusRequest(uint8_t address, uint8_t* modbusData)
{
// Construct the Modbus status request message
modbusData[0] = address; // Slave address
modbusData[1] = 0x03; // Function code (Read Holding Registers)
modbusData[2] = 0x00; // Starting register address (high byte)
modbusData[3] = 0x00; // Starting register address (low byte)
modbusData[4] = 0x00; // Quantity of registers (high byte)
modbusData[5] = 0x0A; // Quantity of registers (low byte) (10)
uint16_t crc = CalculateCRC(modbusData, 6); //calculate CRC for the sent data
modbusData[6] = (uint8_t)(crc & 0xFF); // CRC low byte
modbusData[7] = (uint8_t)(crc >> 8); // CRC high byte
}
uint16_t CalculateCRC(uint8_t* data, int length) //based on the CRC16 algorithm.
{
uint16_t crc = 0xFFFF;
for (int i = 0; i < length; i++)
{
crc ^= data[i];
for (int j = 0; j < 8; j++)
crc = (crc & 1) ? (crc >> 1) ^ 0xA001 : crc >> 1;
}
return crc;
}
I have extensively checked the hardware setup, ensuring the connections and configurations align with the specifications. I also went through the PIC18F66K22 datasheet meticulously to identify any discrepancies or missed details.