Dear Forum,
I'm trying to write an Arduino sketch that would communicate with a RS232 controlled Audio Player.
I can write and read serial data via hard- or software serial and get the player to respond but it's a bit flakey. I guess it has to do with timing and CRC.
What would be the best appoach for the following:
send array of 6 HEX values, the last being CRC - wait for the response (4 values, start marker, last bit is CRC) - and continue with new values
I read thru Serial Input Basics - updated
but I think my basic programming skills are to little that I need some help how to start.
I want the sketch to be as fast as the player can handle, so I can send volume fades via RS232.
Thanks!
You need to dig up data about the Audio Player. We can't.
Find out about the protocol used.
For RS232 the baudrate is the main timing. What do You think of?
Sending BCD, HEX or what.... Player documentation. Throwing in a CRC as a guess sounds no good.
Sooner or later the code will be asked for. Use autoformat in the IDE and code tags, </>, in this window.
thanks for the quick reply.
I have all the documentation, I just wanted to ask for a general best practice approach. (if such exists...)
This is my code so far, but I can't get the CRC calculated for the reply of the player, so I calculated it myslef and put it as a fixed CRC as stop bit. That would be another question for later how to do that inside the sketch...
This is just an experimental sketch so it is quite a mess, sorry...
#include <SoftwareSerial.h> . // ESP Variante funktioniert mit Wemos D1 Board
SoftwareSerial rs232(10, 11); // RX, TX auf Wemos D4 und D5
const byte numBytes = 4;
byte receivedBytes[numBytes];
byte numReceived = 0;
boolean newData = false;
// Waveplayer Kommandos
//byte crc8;
byte recvVal[8];
byte devID = 0x00;
byte chVol[] = {0x86, devID, 0x02, 0x01, 0x00, 0x00}; // 0x02 = Set Volume, 0x04= Change Volume, 0x01-08 Channel Volume, 0x0x = Volume Setting 0-255 *0,
byte message [6];
bool lockout = false;
byte vol = 255;
void setup() {
Serial.begin(9600);
rs232.begin(9600); // Software Serial
delay(50);
}
void loop() {
recvBytesWithStartEndMarkers();
showNewData();
if (lockout == false) {
//vol = random(0,255);
writeVol(20);
delay (5);
}
delay(1000);
}
//ENDE DES LOOPS!!!!
//______________________
// write
void writeVol(int volume) {
chVol[4] = volume;
chVol[5] = crc_8(chVol, sizeof(chVol));
delay(5);
rs232.write(chVol, sizeof(chVol));
}
// CRC Berechnung
byte crc_8(byte msg[], byte len)
{
byte crc = 0x00;
byte data;
bool flag;
byte polynom = 0xD5;
for (int i = 0; i < len; i++)
{
data = msg[i];
for (int bit = 0; bit < 8; bit++)
{
flag = (crc & 0x80) == 0x80 ? true : false;
crc <<= 1;
crc |= (data & 0x80) == 0x80 ? (byte)1 : (byte)0;
data <<= 1;
if (flag) crc ^= polynom;
}
} return crc;
}
void recvBytesWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
byte startMarker = 0x84;
byte endMarker = 0xBB;
byte rb;
while (rs232.available() > 0 && newData == false) {
rb = rs232.read();
if (recvInProgress == true) {
if (rb != endMarker) {
receivedBytes[ndx] = rb;
ndx++;
if (ndx >= numBytes) {
ndx = numBytes - 1;
}
}
else {
receivedBytes[ndx] = '\0'; // terminate the string
recvInProgress = false;
numReceived = ndx; // save the number for use when printing
ndx = 0;
newData = true;
}
}
else if (rb == startMarker) {
recvInProgress = true;
}
}
}
void showNewData() {
if (newData == true) {
Serial.print("This just in ... ");
for (byte n = 0; n < numReceived; n++) {
Serial.print(receivedBytes[n], HEX);
Serial.print(' ');
}
Serial.println();
showGroupsOfBytes();
newData = false;
lockout = false;
}
}
void showGroupsOfBytes() {
for (byte n = 0; n < numReceived; n++) {
Serial.print(receivedBytes[n], HEX);
Serial.print(' ');
if ((n + 1) % 5 == 0) {
Serial.println();
}
}
Serial.println();
}
I'm not familiar with this "accent".
CRC can be seen as a shift register with feedback. Did make a CRC15, I think, but that's a long time ago.....
Do some Google about CRC if You like. A hand calculated CRC only works for exactly that one message. You surely know that. Any other message and You're toast.
Let's see if some more knowing helper steps in.
Are you using a TTL to RS-232 adapter? If so, which one and how do you have it wired? If not, you need one.
Paul
Thanks for checking.
As I mentioned, I have it all working but want find a more robust sending method if I want to increase speed.
I certainly use a level converter that is connected as in the sketch, to software serial pins.
If that is the case, you need to increase speed and THEN see if you need a more robust sending method. Of course, then you need a more robust receiving method as well.
Paul
If you can provide a link to the player as @Railroader suggested in #2, then we could begin to suggest a CRC implementation that would work with it.
If the datasheet has some example command messages, then we/you can use these to check that the CRC algorithm is working correctly.
The CRC calculation code is supplied by the vendor and is working well. What would you improve?
My question was more regarding of a general concept to solve these RS232 timings. Is it okay to use the serial.read/serial.write from the arduino or should I better use a interupt timer.
I assumed that you had a problem with the CRC calculations because:
The sketch you posted in #3 looks about right. 9600 baud should be within the limits of a software serial implementation.
IT is time for you to let all the rest of understand what you are referring to!
Paul
sorry if's not well explained what I actually mean.
Step1: Calculate CRC and write serial data.
Step2: Wait for response
Step3: Receive response
Step4: Calculate CRC of response, if valid go to step1, if not?
In my research I often saw people adding delays after certain steps to make sure the loop is not faster than the serial communication. That's what I mean with timing.
this is my sketch so far. there will be constant communication on the serial line, that's why I want to make sure the code is efficient and good. I'm not a developer, so that's why I thought the forum here could lead me to some "standard concepts" with RS232 communication...
#include <Wire.h> // add i2c library
#include <SoftwareSerial.h> . // ESP Variante funktioniert mit Wemos D1 Board
SoftwareSerial rs232(10, 11); // RX, TX auf Wemos D4 und D5
int LED = 13;
int env1 = 0;
int env2 = 0;
int env3 = 0;
int env4 = 0;
int env5 = 0;
int env6 = 0;
int env7 = 0;
int env8 = 0;
byte recvVol [] = {env1, env2, env3, env4, env5, env6, env7, env8};
const byte numBytes = 4;
byte receivedBytes[numBytes];
byte numReceived = 0;
byte bytes = 8;
byte endMarker = 0x00;
boolean newData = false;
// Waveplayer Kommandos
//byte crc8;
byte endCRC[3];
byte recvVal[8];
byte devID = 0x00;
byte chVol[] = {0x86, devID, 0x02, 0x01, 0x00, 0x00}; // 0x02 = Set Volume, 0x04= Change Volume, 0x01-08 Channel Volume, 0x0x = Volume Setting 0-255 *0,
byte message [6];
bool lockout = false;
byte vol = 255;
void receiveEvent(int bytes) // I2C receive from D1
{
for(int i=0; i<bytes; i++)
{
recvVol[i] = Wire.read();
if (lockout == false){
writeVol(1,recvVol[0]);
}
}
}
void setup() {
Wire.begin(9);
Wire.onReceive(receiveEvent);
Serial.begin(9600);
rs232.begin(9600); // Software Serial
delay(50);
}
void loop() {
recvBytesWithStartEndMarkers();
showNewData();
}
//ENDE DES LOOPS!!!!
//______________________
// write to serial
void writeVol(int ch,int volume) {
chVol[3] = ch;
chVol[4] = volume;
chVol[5] = crc_8(chVol, sizeof(chVol));
delay(5);
rs232.write(chVol, sizeof(chVol));
rs232.flush();
}
// CRC Berechnung
byte crc_8(byte msg[], byte len)
{
byte crc = 0x00;
byte data;
bool flag;
byte polynom = 0xD5;
for (int i = 0; i < len; i++)
{
data = msg[i];
for (int bit = 0; bit < 8; bit++)
{
flag = (crc & 0x80) == 0x80 ? true : false;
crc <<= 1;
crc |= (data & 0x80) == 0x80 ? (byte)1 : (byte)0;
data <<= 1;
if (flag) crc ^= polynom;
}
} return crc;
}
void recvBytesWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
byte startMarker = 0x84;
byte rb;
while (rs232.available() > 0 && newData == false) {
rb = rs232.read();
if (recvInProgress == true) {
if (rb != endMarker) {
lockout = false;
receivedBytes[ndx] = rb;
ndx++;
if (ndx >= numBytes) {
ndx = numBytes - 1;
}
}
else {
receivedBytes[ndx] = '\0'; // terminate the string
recvInProgress = false;
numReceived = ndx; // save the number for use when printing
ndx = 0;
newData = true;
}
}
else if (rb == startMarker) {
recvInProgress = true;
for(int n=0; n<2; n++){
endCRC[n] = rb;
}
endMarker = crc_8(endCRC, sizeof(endCRC));
delay(1);
}
}
}
void showNewData() {
if (newData == true) {
Serial.print("This just in ... ");
for (byte n = 0; n < numReceived; n++) {
Serial.print(receivedBytes[n], HEX);
Serial.print(' ');
}
Serial.println();
showGroupsOfBytes();
newData = false;
}
}
void showGroupsOfBytes() {
for (byte n = 0; n < numReceived; n++) {
Serial.print(receivedBytes[n], HEX);
Serial.print(' ');
if ((n + 1) % 5 == 0) {
Serial.println();
}
}
Serial.println();
}
All that has NOTHING to do with RS-232 timing. All the code is under your control. Measure the time you are concerned with and adjust the code.
I think you are seeing ghosts, not reality.
Getting a program to work the way you want is the only test you need to make. Most people are satisfied with what you have already,
Paul
that doesn't really help improving the code
if you are unwilling to measure, then you will never know if you improve or make it worse.
Paul
what measurements are you suggesting? The actual bits I am sending and receiving via Oszilloscope and the time my processor needs to cycle thru the loop calculating CRCs?
I am suggesting you record the time, millis() at the start of code you are concerned with and then again at the end. The difference is the time to run that piece of code. May have to use microseconds.
The reality is if you code runs faster than the time it takes to transmit one byte of information, any change you make will have zero effect on the serial transmission time. That is dependent on the Baud rate or bits per second. At 9600 bps, you can send 960 characters in 1 second. You can execute a lot of instructions in the time to send one character.
Paul
Got it. Thank you, that was helpful.
This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.