Skip to content

Instantly share code, notes, and snippets.

@s-light
Last active January 18, 2017 17:44
Show Gist options
  • Save s-light/7bb6cf75f3e39063ad44 to your computer and use it in GitHub Desktop.
Save s-light/7bb6cf75f3e39063ad44 to your computer and use it in GitHub Desktop.
RS485 HalfDuplex Test for Controllino
/******************************************************************************
test__RS485_Controllino
Test for RS485 HalfDuplex ASCII comunication
debugout on usbserial interface: 115200baud
hardware:
Board:
Arduino compatible (with serial port)
LED on D2 (livesign)
RS485 tranceiver as Controllino boards (serialPort: TX3&RX3 + PJ5&PJ6)
libraries used:
~ slight_DebugMenu
written by stefan krueger (s-light),
github@s-light.eu, http://s-light.eu, https://github.com/s-light/
License: MIT
written by stefan krueger (s-light),
github@s-light.eu, http://s-light.eu, https://github.com/s-light/
changelog / history
16.12.2015 09:50 created (based on DebugMenu_Simple.ino)
TO DO:
~ xx
******************************************************************************/
/******************************************************************************
The MIT License (MIT)
Copyright (c) 2015 Stefan Krüger
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Includes
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// use "file.h" for files in same directory as .ino
// #include "file.h"
// use <file.h> for files in library directory
// #include <file.h>
#include <slight_DebugMenu.h>
// #include <Controllino.h>
#include <SPI.h>
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Info
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void sketchinfo_print(Print &out) {
out.println();
// "|~~~~~~~~~|~~~~~~~~~|~~~..~~~|~~~~~~~~~|~~~~~~~~~|"
out.println(F("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"));
out.println(F("| ^ ^ |"));
out.println(F("| (0,0) |"));
out.println(F("| ( _ ) |"));
out.println(F("| \" \" |"));
out.println(F("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"));
out.println(F("| test__RS485_Controllino.ino"));
out.println(F("| Test for RS485 HalfDuplex ASCII comunication..."));
out.println(F("|"));
out.println(F("| This Sketch has a debug-menu:"));
out.println(F("| send '?'+Return for help"));
out.println(F("|"));
out.println(F("| dream on & have fun :-)"));
out.println(F("|"));
out.println(F("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"));
out.println(F("|"));
//out.println(F("| Version: Nov 11 2013 20:35:04"));
out.print(F("| version: "));
out.print(F(__DATE__));
out.print(F(" "));
out.print(F(__TIME__));
out.println();
out.println(F("|"));
out.println(F("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"));
out.println();
//out.println(__DATE__); Nov 11 2013
//out.println(__TIME__); 20:35:04
}
// Serial.print to Flash: Notepad++ Replace RegEx
// Find what: Serial.print(.*)\("(.*)"\);
// Replace with: Serial.print\1\(F\("\2"\)\);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// definitions (global)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Debug Output
boolean infoled_state = 0;
#if defined (__AVR_ATmega32U4__)
const byte infoled_pin = 13; //D13
#else
const byte infoled_pin = 5; //D5
#endif
unsigned long debugOut_LiveSign_TimeStamp_LastAction = 0;
const uint16_t debugOut_LiveSign_UpdateInterval = 1000; //ms
boolean debugOut_LiveSign_Serial_Enabled = 0;
boolean debugOut_LiveSign_LED_Enabled = 1;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Menu
// slight_DebugMenu(Stream &in_ref, Print &out_ref, uint8_t input_length_new);
slight_DebugMenu myDebugMenu(Serial, Serial, 50);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// RS485
#if defined (__AVR_ATmega32U4__)
// use normal HW serial port on leonardo
Stream &serialPort = Serial1;
uint8_t pin_DE = 2;
uint8_t pin_XRE = 3;
#else
// CONTROLLINO
#define CONTROLLINO_BOARD
Stream &serialPort = Serial3;
#endif
const uint8_t buffer_size = 50;
slight_DebugMenu rs485_com(serialPort, serialPort, buffer_size);
// char buffer_send[buffer_size];
// uint8_t buffer_send_length = 0;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// functions
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// debug things
// freeRam found at
// http://forum.arduino.cc/index.php?topic=183790.msg1362282#msg1362282
// posted by mrburnette
int freeRam () {
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Menu System
// Main Menu
void handleMenu_Main(slight_DebugMenu *pInstance) {
Print &out = pInstance->get_stream_out_ref();
char *command = pInstance->get_command_current_pointer();
// out.print("command: '");
// out.print(command);
// out.println("'");
switch (command[0]) {
case 'h':
case 'H':
case '?': {
// help
out.println(F("____________________________________________________________"));
out.println();
out.println(F("Help for Commands:"));
out.println();
out.println(F("\t '?': this help"));
out.println(F("\t 'i': sketch info"));
out.println(F("\t 'y': toggle DebugOut livesign print"));
out.println(F("\t 'Y': toggle DebugOut livesign LED"));
out.println(F("\t 'x': tests"));
out.println();
out.println(F("\t 's': send on RS485 's:My Text To Send'"));
out.println(F("\t 'w': askfor weight"));
// out.println(F("\t 'f': DemoFadeTo(ID, value) 'f1:65535'"));
out.println();
out.println(F("____________________________________________________________"));
} break;
case 'i': {
sketchinfo_print(out);
} break;
case 'y': {
out.println(F("\t toggle DebugOut livesign Serial:"));
debugOut_LiveSign_Serial_Enabled = !debugOut_LiveSign_Serial_Enabled;
out.print(F("\t debugOut_LiveSign_Serial_Enabled:"));
out.println(debugOut_LiveSign_Serial_Enabled);
} break;
case 'Y': {
out.println(F("\t toggle DebugOut livesign LED:"));
debugOut_LiveSign_LED_Enabled = !debugOut_LiveSign_LED_Enabled;
out.print(F("\t debugOut_LiveSign_LED_Enabled:"));
out.println(debugOut_LiveSign_LED_Enabled);
} break;
case 'x': {
// get state
out.println(F("__________"));
out.println(F("Tests:"));
out.println(F("nothing to do."));
// uint16_t wTest = 65535;
// uint16_t wTest = atoi(&command[1]);
// out.print(F("wTest: "));
// out.print(wTest);
// out.println();
//
// out.print(F("1: "));
// out.print((byte)wTest);
// out.println();
//
// out.print(F("2: "));
// out.print((byte)(wTest>>8));
// out.println();
// out.print(F("send test string: '"));
// char *buffer = "ABCDEFG;";
// out.print(buffer);
// RS485_send(buffer, strlen(buffer));
out.println();
out.println(F("__________"));
} break;
//---------------------------------------------------------------------
case 's': {
out.print(F("\t send: "));
uint8_t input_length = strlen(&command[2]);
out.print(F("["));
out.print(input_length);
out.print(F("]"));
out.print(F(" "));
char buffer_send[buffer_size];
uint8_t buffer_send_length = 0;
buffer_send_length = input_length;
memset(buffer_send, '\0', buffer_size);
strcpy( buffer_send, &command[2]);
// buffer_send[input_length+0] = '\r';
// buffer_send[input_length+1] = '\n';
buffer_send_length = input_length+0;
out.print(F("'"));
out.print(buffer_send);
out.print(F("'"));
RS485_send(buffer_send, buffer_send_length);
out.println();
} break;
case 'w': {
out.print(F("\t askfor weight. "));
askfor_weight();
} break;
// case 'f': {
// out.print(F("\t DemoFadeTo "));
// // convert part of string to int
// // (up to first char that is not a number)
// uint8_t id = atoi(&command[1]);
// // convert single character to int representation
// // uint8_t id = &command[1] - '0';
// out.print(id);
// out.print(F(" : "));
// uint16_t value = atoi(&command[3]);
// out.print(value);
// out.println();
// //demo_fadeTo(id, value);
// out.println(F("\t demo for parsing values --> finished."));
// } break;
//---------------------------------------------------------------------
default: {
if(strlen(command) > 0) {
out.print(F("command '"));
out.print(command);
out.println(F("' not recognized. try again."));
}
pInstance->get_command_input_pointer()[0] = '?';
pInstance->set_flag_EOC(true);
}
} // end switch
// end Command Parser
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// RS485 scale module
void askfor_weight() {
// the scale module will give a answer some time in the future - we don't know excactly when.
// so in the rs485_com_comandparser we wait to see if we get something..
char *command = "Here comes the command to ask for the weight.";
RS485_send(command, sizeof(command));
}
void RS485_init() {
// init serial
#ifdef CONTROLLINO_BOARD
// setup Serial with Even Parity
Serial3.begin(9600, SERIAL_8E1);
// This will initialize Controllino RS485 pins
Controllino_RS485Init();
// the following is all done by Controllino_RS485Init
// DDRJ = DDRJ | B01100000;
// PORTJ = PORTJ & B10011111;
// pinMode(CONTROLLINO_RS485_TX, OUTPUT);
// pinMode(CONTROLLINO_RS485_RX, INPUT);
// pinMode(CONTROLLINO_RS485_RE, OUTPUT);
// pinMode(CONTROLLINO_RS485_DE, OUTPUT);
#else
// use normal HW serial port on leonardo
Serial1.begin(9600);
Serial.println(F("setup output pins:"));
pinMode(pin_DE, OUTPUT);
pinMode(pin_XRE, OUTPUT);
#endif
// setup EndOfCommand to include ';'
rs485_com.set_user_EOC_char(';');
rs485_com.set_callback(rs485_com_comandparser);
rs485_com.begin();
}
void RS485_send(char *buffer, uint8_t size) {
// for send and receive pleas check the pin configuration and the RS485 pin Out.
// normally the /RE pin is inverted. --> LOW = ACTIVE
// but it could be that the Controllino guys have setup the pin register as inverted output.
// (to confuse the user some more ;-)
// set direction to send
// Serial.println(F("set pins to sending:"));
#ifdef CONTROLLINO_BOARD
// that means DE HIGH and /RE HIGH
// PORTJ = PORTJ & B10011111;
// PORTJ = PORTJ | B01100000;
// digitalWrite (CONTROLLINO_RS485_RE, HIGH);
// digitalWrite (CONTROLLINO_RS485_DE, HIGH);
Controllino_SwitchRS485DE(HIGH);
Controllino_SwitchRS485RE(HIGH);
#else
digitalWrite (pin_DE, HIGH);
digitalWrite (pin_XRE, HIGH);
#endif
// set direction to send and receive
// Serial.println(F("set pins to sending&receiving:"));
// #ifdef CONTROLLINO_BOARD
// // that means DE HIGH and /RE LOW
// // for debuging..
// // PORTJ = PORTJ & B10011111;
// // PORTJ = PORTJ | B01000000;
// // digitalWrite (CONTROLLINO_RS485_RE, LOW);
// // digitalWrite (CONTROLLINO_RS485_DE, HIGH);
// Controllino_SwitchRS485DE(HIGH);
// Controllino_SwitchRS485RE(LOW);
// #else
// digitalWrite (pin_DE, HIGH);
// digitalWrite (pin_XRE, LOW);
// #endif
// write data out
// Serial.println(F("write data..."));
// write to debug out
// Serial.write(buffer, size);
// wait untill all is send.
// Serial.flush();
// write to RS485
serialPort.write(buffer, size);
// wait untill all is send.
serialPort.flush();
// Serial.println();
// set direction to read
// Serial.println(F("set pins to receiving"));
#ifdef CONTROLLINO_BOARD
// that means DE LOW and /RE LOW
// PORTJ = PORTJ & B10011111;
// PORTJ = PORTJ | B00000000;
// digitalWrite (CONTROLLINO_RS485_RE, LOW);
// digitalWrite (CONTROLLINO_RS485_DE, LOW);
Controllino_SwitchRS485DE(LOW);
Controllino_SwitchRS485RE(LOW);
#else
digitalWrite (pin_DE, LOW);
digitalWrite (pin_XRE, LOW);
#endif
}
void rs485_com_comandparser(slight_DebugMenu *pInstance) {
Print &out = pInstance->get_stream_out_ref();
char *command = pInstance->get_command_current_pointer();
// now we just print the returned buffer to Debug Serial:
Serial.print(F("RS485 received: "));
Serial.print(F("'"));
Serial.print(command);
Serial.print(F("'"));
Serial.println();
// here we can implement parsing of the returned values:
// if we have different commands that we have to parse differently we could
// use a switch to structure this.
// switch (command[0]) {
// case 'f': {
// // out.print(F("\t DemoFadeTo "));
// // // convert part of string to int
// // // (up to first char that is not a number)
// // uint8_t id = atoi(&command[1]);
// // // convert single character to int representation
// // // uint8_t id = &command[1] - '0';
// // out.print(id);
// // out.print(F(" : "));
// // uint16_t value = atoi(&command[3]);
// // out.print(value);
// // out.println();
// // //demo_fadeTo(id, value);
// // out.println(F("\t demo for parsing values --> finished."));
// } break;
// case 'a': {
// // other case...
// } break;
// //---------------------------------------------------------------------
// default: {
// if(strlen(command) > 0) {
// out.print(F("command '"));
// out.print(command);
// out.println(F("' not recognized. try again."));
// }
// }
// } // end switch
// end Command Parser
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// setup
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void setup() {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// initialise PINs
//LiveSign
pinMode(infoled_pin, OUTPUT);
digitalWrite(infoled_pin, HIGH);
// as of arduino 1.0.1 you can use INPUT_PULLUP
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// initialise serial
// for ATmega32U4 devices:
#if defined (__AVR_ATmega32U4__)
// wait for arduino IDE to release all serial ports after upload.
delay(2000);
#endif
Serial.begin(115200);
// for ATmega32U4 devices:
#if defined (__AVR_ATmega32U4__)
// Wait for Serial Connection to be Opend from Host or
// timeout after 6second
uint32_t timeStamp_Start = millis();
while( (! Serial) && ( (millis() - timeStamp_Start) < 6000 ) ) {
// nothing to do
}
#endif
Serial.println();
Serial.print(F("# Free RAM = "));
Serial.println(freeRam());
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// print welcome
sketchinfo_print(Serial);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// setup XXX1
// Serial.print(F("# Free RAM = "));
// Serial.println(freeRam());
//
// Serial.println(F("setup XXX1:")); {
//
// Serial.println(F("\t sub action"));
// }
// Serial.println(F("\t finished."));
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// show serial commands
myDebugMenu.set_callback(handleMenu_Main);
myDebugMenu.begin(true);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// RS485
RS485_init();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// go
Serial.println(F("Loop:"));
} /** setup **/
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// main loop
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void loop() {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// menu input
myDebugMenu.update();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// rs485 handling
rs485_com.update();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// timed things
// every XXXXms
// if ( ( millis() - ulTimeStamp_LastAction ) > cwUpdateInterval) {
// ulTimeStamp_LastAction = millis();
// // do something
// }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// debug output
if (
(millis() - debugOut_LiveSign_TimeStamp_LastAction) >
debugOut_LiveSign_UpdateInterval
) {
debugOut_LiveSign_TimeStamp_LastAction = millis();
if ( debugOut_LiveSign_Serial_Enabled ) {
Serial.print(millis());
Serial.print(F("ms;"));
Serial.print(F(" free RAM = "));
Serial.println(freeRam());
}
if ( debugOut_LiveSign_LED_Enabled ) {
infoled_state = ! infoled_state;
if (infoled_state) {
//set LED to HIGH
digitalWrite(infoled_pin, HIGH);
} else {
//set LED to LOW
digitalWrite(infoled_pin, LOW);
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// other things
} /** loop **/
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// THE END
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment