I just received an AAG RS485 Weather Station and I'd like some advice on communicating with it. It uses a binary command string with a three character header "+ws" followed by a length byte, RS485 node address, a mode and type byte, variable length data and "NOP" bytes and an 8 bit checksum. I wanted a function to handle the different length command strings. This is what I came up with for starters. Attached is a description of four typical commands. I am using 0x00 for a "NOP".
/* Routines to handle sending variable length commands to AAG RS485 Weather Station
"Type" determines how many arguments are passed to the function that writes the bytes
out to the interface. Using SoftwareSerial with an additional pin DD to control the
RS485 chip. The checksum is calculated on the fly by summing the bytes into an 8 bit integer
and ignoring the overflow.
18 August 2011 EJ
*/
#include <stdarg.h>
#include <SoftwareSerial.h>
const int DD = 5; // data direction pin 5, xmit = HIGH, recv = LOW
const int RXpin = 6;
const int TXpin = 7;
SoftwareSerial RS485(RXpin, TXpin);
int xmit = HIGH;
int recv = LOW;
uint8_t head[3] = {
0x2B, 0x77, 0x73}; // "+ws"
void sendCommand(uint8_t* Head, uint8_t Length, uint8_t Node, uint8_t Mode, uint8_t Type, ...){
uint8_t chksum;
va_list argp;
int _count;
int _mode;
int _status;
int _level;
int _threshold;
int _speed;
int _direction;
va_start(argp, Type);
digitalWrite(DD, xmit); //set RS485 to transmit
for (int i = 0; i < 3; i++){
RS485.write(*Head++);
}
RS485.write(Length);
RS485.write(Node);
chksum = chksum + Node;
RS485.write(Mode);
chksum = chksum + Mode;
RS485.write(Type);
chksum = chksum + Type;
switch(Type)
{
case 0xa1:
_count = va_arg(argp, int);
while (_count > 0) {
RS485.write(0x00);
_count--;
}
break;
case 0xa2:
_mode = va_arg(argp, int);
RS485.write(_mode);
_status = va_arg(argp, int);
RS485.write(_status);
_level = va_arg(argp, int);
RS485.write(_level);
_threshold = va_arg(argp, int);
RS485.write(_threshold);
break;
case 0xa3:
_speed = va_arg(argp, int);
RS485.write(_speed);
while (_count > 0) {
RS485.write(0x00);
_count--;
}
break;
case 0xa4:
_direction = va_arg(argp, int);
RS485.write(_direction);
break;
}
va_end(argp);
RS485.write(chksum);
digitalWrite(DD, recv); //set RS485 to receive
}
void setup() {
pinMode(DD,OUTPUT);
digitalWrite(DD, recv);
RS485.begin(9600);
// Example of three types of commands
sendCommand(head, 7, 0, 0xeb, 0xa1,4); // read al the data
sendCommand(head, 7, 0, 0xeb, 0xa2,0,0,0,0); // turn off the LEDS
sendCommand(head, 6, 0, 0xeb, 0xa3, 100, 2); // set the speed cal to 100
}
void loop() {
}
Can anyone see any problems or suggest a better/different way?
Link to the command protocol: http://www.aag.com.mx/aagusa/contents/en-us/Description%20of%20WSV3%20Interface%20(485).pdf
wsv3 protocol.tiff (126 KB)