Last active
January 18, 2017 17:44
-
-
Save s-light/7bb6cf75f3e39063ad44 to your computer and use it in GitHub Desktop.
RS485 HalfDuplex Test for Controllino
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/****************************************************************************** | |
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), | |
[email protected], http://s-light.eu, https://github.com/s-light/ | |
License: MIT | |
written by stefan krueger (s-light), | |
[email protected], 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