Skip to content

Instantly share code, notes, and snippets.

@narrowtux
Created March 30, 2015 15:37
Show Gist options
  • Save narrowtux/4e8213db2b817fdfe863 to your computer and use it in GitHub Desktop.
Save narrowtux/4e8213db2b817fdfe863 to your computer and use it in GitHub Desktop.
Arduino SoftwareSerial 7E1 read support
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <Arduino.h>
#include <SoftwareSerial.h>
#ifndef SEVEN_E_1_SERIAL
#define SEVEN_E_1_SERIAL
#define _DEBUG 0
#define _DEBUG_PIN1 11
#define _DEBUG_PIN2 13
//
// Debugging
//
// This function generates a brief pulse
// for debugging or measuring on an oscilloscope.
inline void DebugPulse(uint8_t pin, uint8_t count) {
#if _DEBUG
volatile uint8_t *pport = portOutputRegister(digitalPinToPort(pin));
uint8_t val = *pport;
while (count--)
{
*pport = val | digitalPinToBitMask(pin);
*pport = val;
}
#endif
}
/**
* Modification of the SoftwareSerial class to support reading from 7E1 serial.
* Does not support any other baud rate than 9600 and does also not support sending data.
*/
class SevenE1Serial : public SoftwareSerial {
public:
SevenE1Serial(int RX, int TX) : SoftwareSerial(RX, TX) {}
void adjust() {
_rx_delay_centering = 105;
}
void recv() {
#if GCC_VERSION < 40302
// Work-around for avr-gcc 4.3.0 OSX version bug
// Preserve the registers that the compiler misses
// (courtesy of Arduino forum user *etracer*)
asm volatile(
"push r18 \n\t"
"push r19 \n\t"
"push r20 \n\t"
"push r21 \n\t"
"push r22 \n\t"
"push r23 \n\t"
"push r26 \n\t"
"push r27 \n\t"
::);
#endif
uint8_t d = 0;
// If RX line is high, then we don't see any start bit
// so interrupt is probably not for us
if (_inverse_logic ? rx_pin_read() : !rx_pin_read())
{
// Wait approximately 1/2 of a bit width to "center" the sample
tunedDelay(_rx_delay_centering);
DebugPulse(_DEBUG_PIN2, 1);
// Read each of the 7 data bits
for (uint8_t i=0x1; i < 0x80; i <<= 1)
{
tunedDelay(_rx_delay_intrabit);
DebugPulse(_DEBUG_PIN2, 1);
uint8_t noti = ~i;
if (rx_pin_read()) {
d |= i;
} else // else clause added to ensure function timing is ~balanced
d &= noti;
}
// read the parity bit
tunedDelay(_rx_delay_intrabit);
bool parityBit = rx_pin_read();
// skip the stop bit
tunedDelay(_rx_delay_stopbit);
DebugPulse(_DEBUG_PIN2, 1);
// check for parity even
bool parityValid = true;
if (parityBit != (d % 2 == 1)) {
parityValid = false;
}
if (_inverse_logic)
d = ~d;
// if parity valid, append byte to buffer
if (parityValid) {
// if buffer full, set the overflow flag and return
if ((_receive_buffer_tail + 1) % _SS_MAX_RX_BUFF != _receive_buffer_head)
{
// save new data in buffer: tail points to where byte goes
_receive_buffer[_receive_buffer_tail] = d; // save new byte
_receive_buffer_tail = (_receive_buffer_tail + 1) % _SS_MAX_RX_BUFF;
}
else
{
#if _DEBUG // for scope: pulse pin as overflow indictator
DebugPulse(_DEBUG_PIN1, 1);
#endif
_buffer_overflow = true;
}
}
}
#if GCC_VERSION < 40302
// Work-around for avr-gcc 4.3.0 OSX version bug
// Restore the registers that the compiler misses
asm volatile(
"pop r27 \n\t"
"pop r26 \n\t"
"pop r23 \n\t"
"pop r22 \n\t"
"pop r21 \n\t"
"pop r20 \n\t"
"pop r19 \n\t"
"pop r18 \n\t"
::);
#endif
}
};
#endif
@mediatechid
Copy link

hi..how to use this ? i need to comunicate from arduino to scale on 7E1

@narrowtux
Copy link
Author

Simply use it like you would use SoftwareSerial, but instead of that you write SevenE1Serial

@cedric-ak
Copy link

cedric-ak commented Sep 14, 2023

not compiling, are you able to provide an example how you got it to work? one of many errors below:

error: 'uint16_t SoftwareSerial::_rx_delay_centering' is private within this context
_rx_delay_centering = 105;

@narrowtux
Copy link
Author

This snippet was made eight years ago, arduino development environment has probably changed so much that it wouldn't even work any more, even if it compiled.

Sadly I can't help you with that, since I don't work with arduino any more, and also I don't have a device that uses this encoding.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment