Hi all,
I am working on a project where I aim to receive data from a PLC and display it on a 4-digit 7-segment display. I have tested my code by sending data from a Python program, and it works flawlessly. The display shows the data correctly, and I also receive the acknowledgment as expected.
However, when I connect the PLC to the Arduino, the 7-segment display stops showing the expected data, and it seems I am not receiving the full data from the PLC. I have attached the data received from the PLC as seen in the Arduino Serial Monitor for reference
#include <SoftwareSerial.h>
#include <Arduino.h>
#include <math.h>
#define RE_DE 4 // RS-485 send/receive control pin
#define RX 2 // RS-485 RO to Arduino pin 2
#define TX 3 // RS-485 DI to Arduino pin 3
SoftwareSerial rs485(RX, TX);
byte receivedData[64]; // Buffer to store received data
int receivedIndex = 0;
// Define shared pins for all shift registers
const int latchPin = 10;
const int clockPin = 13;
const int dataPin = 5;
// Segment patterns for digits 0-9
const byte segmentData[] = {
0b00111111, // 0
0b00000110, // 1
0b01011011, // 2
0b01001111, // 3
0b01100110, // 4
0b01101101, // 5
0b01111101, // 6
0b00000111, // 7
0b01111111, // 8
0b01101111 // 9
};
// Number of digits per display
const int numDigits = 4;
// Number of displays
const int numDisplays = 6;
// Array to hold the data to be displayed
byte displayBuffer[numDigits * numDisplays] = {0};
void setup() {
pinMode(RE_DE, OUTPUT);
digitalWrite(RE_DE, LOW); // Set to receive mode
rs485.begin(9600); // Start RS-485 communication at 9600 baud
Serial.begin(9600); // For debugging
// Set shared pins as output
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
}
void loop() {
static unsigned long lastByteTime = 0;
static const unsigned long timeout = 50; // 50 ms timeout for message completion
// Read incoming data
while (rs485.available()) {
if (receivedIndex < sizeof(receivedData)) {
receivedData[receivedIndex++] = rs485.read();
lastByteTime = millis(); // Update the time of the last received byte
}
}
// Check if the message is complete or timed out
if (receivedIndex > 0 && millis() - lastByteTime > timeout) {
Serial.println("Full message received:");
printHex(receivedData, receivedIndex);
// Process the message
processMessage(receivedData, receivedIndex);
// Reset buffer for the next message
receivedIndex = 0;
}
// Update all displays based on the received data
updateDisplays();
}
// Function to process the received message
void processMessage(byte* data, int length) {
if (length < 9) { // Ensure at least the minimum length for header and payload
Serial.println("Error: Message too short.");
return;
}
// Extract and display data for six displays
int byteCount = data[6]; // Byte count
if (byteCount != 12) { // Ensure correct byte count for six displays (2 bytes each)
Serial.println("Error: Incorrect byte count.");
return;
}
for (int i = 0; i < 6; i++) {
int highByte = data[7 + (i * 2)];
int lowByte = data[8 + (i * 2)];
int value = (highByte << 8) | lowByte;
// Update the display buffer for the corresponding display
updateDisplayBuffer(value, i + 1); // Pass the value and display number
}
// Send acknowledgment after processing the message
sendAcknowledgment();
}
// Function to send acknowledgment response
void sendAcknowledgment() {
// Example acknowledgment message: 01 10 00 01 00 06 11 CB
byte ackMessage[] = {0x01, 0x10, 0x00, 0x01, 0x00, 0x06, 0x11, 0xCB};
// Switch to transmit mode
digitalWrite(RE_DE, HIGH);
// Send acknowledgment message
rs485.write(ackMessage, sizeof(ackMessage));
// Ensure the data is transmitted before switching back
rs485.flush();
// Switch back to receive mode
digitalWrite(RE_DE, LOW);
Serial.println("Acknowledgment sent.");
}
// Function to update the buffer for a specific display
void updateDisplayBuffer(int number, int display) {
// Calculate the starting position in the buffer for the specific display
int startShiftRegister = (display - 1) * numDigits;
// Flag to indicate if a non-zero digit has been encountered
bool hasNonZeroDigit = false;
// Store the digits in the buffer from most significant to least significant
for (int i = numDigits - 1; i >= 0; i--) {
int digit = number / pow(10, i);
digit %= 10;
// Suppress leading zeros
if (digit != 0 || hasNonZeroDigit || i == 0) {
hasNonZeroDigit = true;
displayBuffer[startShiftRegister + (numDigits - 1 - i)] = segmentData[digit];
} else {
// If it's a leading zero and hasn't encountered a non-zero digit, turn off the segments
displayBuffer[startShiftRegister + (numDigits - 1 - i)] = 0b00000000; // Turn off all segments
}
}
}
// Function to update all displays at once
void updateDisplays() {
// Prepare to send data to all shift registers
digitalWrite(latchPin, LOW);
// Shift out all data from the buffer in reverse order
for (int i = (numDigits * numDisplays) - 1; i >= 0; i--) {
shiftOut(dataPin, clockPin, MSBFIRST, displayBuffer[i]);
}
// Latch the data to display the updated numbers
digitalWrite(latchPin, HIGH);
delayMicroseconds(100);
digitalWrite(latchPin, LOW);
}
// Utility function to print data in hex format
void printHex(byte* data, int length) {
for (int i = 0; i < length; i++) {
if (data[i] < 0x10) Serial.print("0");
Serial.print(data[i], HEX);
Serial.print(" ");
}
Serial.println();
}
output from PLC in arduino serial monitor
error data from plc.txt (25.0 KB)
expected output from PLC in ardino :
00F79FBFBDDBBFDBD9AF9B4100B7FF5FBDD9D9A9DBDB2D1A00
Also I have join PLC directly with PC the help of RS-485 to USB converter I was able to received correct data from it but I am not able to identify the problem with arduino and PLC.
Circuit Diagram