Software UART program using Infra-Red LED and IR-Detector
Dependents: TestVirtualisation Bf_SoftSerial_IR
Revision 15:8d343be3382d, committed 2020-05-15
- Comitter:
- kenjiArai
- Date:
- Fri May 15 04:11:01 2020 +0000
- Parent:
- 14:dc766032cdd6
- Commit message:
- Updated several functions based on SoftSerial library.
Changed in this revision
diff -r dc766032cdd6 -r 8d343be3382d SoftSerial_IR.cpp --- a/SoftSerial_IR.cpp Fri Dec 28 10:03:35 2018 +0000 +++ b/SoftSerial_IR.cpp Fri May 15 04:11:01 2020 +0000 @@ -1,17 +1,19 @@ -// Apply for Infrared LED and IR-Detector -// Modified by JH1PJL Dec. 28th, 2018 +// Modified by K.Arai / JH1PJL May 15th, 2020 #include "SoftSerial_IR.h" -SoftSerial_IR::SoftSerial_IR(PinName TX, PinName RX, const char* name) { +SoftSerial_IR::SoftSerial_IR(PinName TX, PinName RX, const char* name) +{ tx_en = rx_en = false; read_buffer = 0; if (TX != NC) { + //tx = new DigitalOut(TX); tx = new PwmOut(TX); tx_en = true; + tx->period(1.0f / 38000.0f); // PWM = 38kHz + //tx->write(1); tx->write(0.0f); tx_bit = -1; - tx->period(1.0f / 38000.0f); // PWM = 38kHz txticker.attach(this, &SoftSerial_IR::tx_handler); } if (RX != NC) { @@ -19,39 +21,32 @@ rx_en = true; out_valid = false; rxticker.attach(this, &SoftSerial_IR::rx_handler); - rx->fall(this, &SoftSerial_IR::rx_gpio_irq_handler); + rx->fall(callback(this, &SoftSerial_IR::rx_gpio_irq_handler)); } - + baud(2400); format(); - set_parameter(); } -SoftSerial_IR::~SoftSerial_IR() { - if (tx_en){ +SoftSerial_IR::~SoftSerial_IR() +{ + if (tx_en) { delete(tx); } - if (rx_en){ + if (rx_en) { delete(rx); } } -void SoftSerial_IR::baud(int baudrate) { +void SoftSerial_IR::baud(int baudrate) +{ bit_period = 1000000 / baudrate; } -void SoftSerial_IR::format(int bits, Parity parity, int stop_bits) { +void SoftSerial_IR::format(int bits, Parity parity, int stop_bits) +{ _bits = bits; _parity = parity; _stop_bits = stop_bits; - _total_bits = 1 + _bits + _stop_bits + (bool)_parity; + _total_bits = 2 + _bits + _stop_bits + (bool)_parity; } - -void SoftSerial_IR::set_parameter( - uint32_t tick_offset, - int32_t rx_detect_center_offset - ) -{ - timestamp_offset = tick_offset; - overhead_us_IR = rx_detect_center_offset; -}
diff -r dc766032cdd6 -r 8d343be3382d SoftSerial_IR.h --- a/SoftSerial_IR.h Fri Dec 28 10:03:35 2018 +0000 +++ b/SoftSerial_IR.h Fri May 15 04:11:01 2020 +0000 @@ -1,29 +1,54 @@ -// Apply for Infrared LED and IR-Detector -// Modified by JH1PJL Dec. 28th, 2018 +/* + Original Library by Erik- & SonyPony + https://os.mbed.com/users/Sissors/code/SoftSerial/ + + Modified by K.Arai / JH1PJL May 15th, 2020 -#ifndef SOFTSERIALIR_H -#define SOFTSERIALIR_H + modified functions + tx_handler() + prepare_tx() + prime() + rx_gpio_irq_handler() and others + */ + +#ifndef SOFTSERIAL_IR_H +#define SOFTSERIAL_IR_H #include "mbed.h" #include "SoftSerial_Ticker_IR.h" +#define DEBUG_TIMING 2 // 0=no debug, 1=tx, 2=rx + +#if (MBED_MAJOR_VERSION == 2) +# define YIELD {;} +#elif (MBED_MAJOR_VERSION == 5) +# define YIELD {ThisThread::yield();} +#endif + /** A software serial implementation * */ -class SoftSerial_IR: public Stream { +class SoftSerial_IR: public Stream +{ public: /** * Constructor * * @param TX Name of the TX pin, NC for not connected - * @param RX Name of the RX pin, NC for not connected, - * must be capable of being InterruptIn + * @param RX Name of the RX pin, NC for not connected, + * must be capable of being InterruptIn * @param name Name of the connection */ SoftSerial_IR(PinName TX, PinName RX, const char* name = NULL); virtual ~SoftSerial_IR(); + /** Set the baud rate of the serial port + * + * @param baudrate The baudrate of the serial port (default = 2400). + */ + void baud(int baudrate); + enum Parity { None = 0, Odd, @@ -41,8 +66,9 @@ * * @param bits The number of bits in a word (default = 8) * @param parity The parity used - * (SerialBase::None, SerialBase::Odd, SerialBase::Even, - * SerialBase::Forced1, SerialBase::Forced0; default = SerialBase::None) + * (SoftSerial_IR::None, SoftSerial_IR::Odd, SoftSerial_IR::Even, + * SoftSerial_IR::Forced1, SoftSerial_IR::Forced0; + * default = SoftSerial_IR::None) * @param stop The number of stop bits (default = 1) */ void format(int bits=8, Parity parity=SoftSerial_IR::None, int stop_bits=1); @@ -66,51 +92,43 @@ /** Attach a function to call whenever a serial interrupt is generated * * @param fptr A pointer to a void function, or 0 to set as none - * @param type Which serial interrupt to attach the member function to - * (Seriall::RxIrq for receive, TxIrq for transmit buffer empty) + * @param type Which serial interrupt to attach the member function + * to (Seriall::RxIrq for receive, TxIrq for transmit buffer empty) */ - void attach(void (*fptr)(void), IrqType type=RxIrq) { - fpointer[type].attach(fptr); + void attach(void (*fptr)(void), IrqType type=RxIrq) + { + fpointer[type] = Callback<void()>(fptr); } - /** Attach a member function to call whenever a serial interrupt - * is generated + /** Attach a member function to call + * whenever a serial interrupt is generated * * @param tptr pointer to the object to call the member function on * @param mptr pointer to the member function to be called * @param type Which serial interrupt to attach the member function - * to (Seriall::RxIrq for receive, TxIrq for transmit buffer empty) + * to (Seriall::RxIrq for receive, TxIrq for transmit buffer empty) */ template<typename T> - void attach(T* tptr, void (T::*mptr)(void), IrqType type=RxIrq) { - fpointer[type].attach(tptr, mptr); + void attach(T* tptr, void (T::*mptr)(void), IrqType type=RxIrq) + { + fpointer[type] = Callback<void()>(tptr, mptr); } /** Generate a break condition on the serial line */ void send_break(); - /** Set adjust parameter - * - * @param tick_offset Due to timestamp offset, need adjust it - * @param rx_detect_center_offset offset for RX bit Hi&Lo detection timing - */ - void set_parameter(uint32_t tick_offset = 3550 , - int32_t rx_detect_center_offset = -50); - protected: + //DigitalOut *tx; PwmOut *tx; InterruptIn *rx; - + bool tx_en, rx_en; int bit_period; int _bits, _stop_bits, _total_bits; Parity _parity; - - FunctionPointer fpointer[2]; - int32_t overhead_us_IR; - uint32_t timestamp_offset; + Callback<void()> fpointer[2]; //rx void rx_gpio_irq_handler(void); @@ -119,19 +137,20 @@ volatile int out_buffer; volatile bool out_valid; bool rx_error; - FlexTicker_IR rxticker; - + FlexTicker rxticker; + + bool rx_1st; + uint32_t rx_st_time; + //tx void tx_handler(void); void prepare_tx(int c); - FlexTicker_IR txticker; + FlexTicker txticker; int _char; volatile int tx_bit; virtual int _getc(); virtual int _putc(int c); - - void baud(int baudrate); }; #endif
diff -r dc766032cdd6 -r 8d343be3382d SoftSerial_Ticker_IR.h --- a/SoftSerial_Ticker_IR.h Fri Dec 28 10:03:35 2018 +0000 +++ b/SoftSerial_Ticker_IR.h Fri May 15 04:11:01 2020 +0000 @@ -1,42 +1,47 @@ -// Apply for Infrared LED and IR-Detector -// Modified by JH1PJL Dec. 28th, 2018 +//A modified version of the regular ticker/timeout libraries +// to allow us to do timeout without losing accuracy -// A modified version of the regular ticker/timeout libraries -// to allow us to do timeout without losing accuracy +// Modified by K.Arai / JH1PJL May 15th, 2020 -#ifndef FLEXTICKERIR_H -#define FLEXTICKERIR_H +#ifndef FLEXTICKER_H +#define FLEXTICKER_H #include "mbed.h" -class FlexTicker_IR: public TimerEvent { - public: +class FlexTicker: public TimerEvent +{ +public: template<typename T> - void attach(T* tptr, void (T::*mptr)(void)) { - _function.attach(tptr, mptr); + void attach(T* tptr, void (T::*mptr)(void)) + { + _function = Callback<void()>(tptr, mptr); } - + /** Detach the function */ - void detach() { + void detach() + { remove(); } - - void setNext(int delay) { + + void setNext(int delay) + { insert(event.timestamp + delay); } - - void prime(uint32_t offset) { - event.timestamp = us_ticker_read() - offset; + + void prime(int comp_time = 0) + { + event.timestamp = us_ticker_read() + comp_time; } - + protected: - virtual void handler() { + virtual void handler() + { _function.call(); } - + unsigned int _delay; - FunctionPointer _function; + Callback<void()> _function; }; #endif \ No newline at end of file
diff -r dc766032cdd6 -r 8d343be3382d SoftSerial_rx_IR.cpp --- a/SoftSerial_rx_IR.cpp Fri Dec 28 10:03:35 2018 +0000 +++ b/SoftSerial_rx_IR.cpp Fri May 15 04:11:01 2020 +0000 @@ -1,44 +1,100 @@ -// Apply for Infrared LED and IR-Detector -// Modified by JH1PJL Dec. 28th, 2018 +// Modified by K.Arai / JH1PJL May 15th, 2020 #include "SoftSerial_IR.h" -//extern DigitalOut myled; // Debug +//------------------------------------------------------------------------------ +#if defined(TARGET_NUCLEO_L152RE) +# define MAGIC_NUM (-560) +#elif defined(TARGET_NUCLEO_F401RE) +# define MAGIC_NUM (-205) +#elif defined(TARGET_NUCLEO_F411RE) +# define MAGIC_NUM (-180) +#elif defined(TARGET_NUCLEO_F446RE) +# define MAGIC_NUM (-115) +#elif defined(TARGET_NUCLEO_L432KC) +# define MAGIC_NUM (-50) +#elif defined(TARGET_NUCLEO_L476RG) +# define MAGIC_NUM (-50) +#elif defined(TARGET_K64F) +# define MAGIC_NUM (0) +#else +# warning "you need to tune MAGIC_NUM! in SoftSerial_rx_IR.cpp" +# define MAGIC_NUM (0) +#endif +//------------------------------------------------------------------------------ -int SoftSerial_IR::_getc( void ) { - while(!readable()); + +// please make a constructor in main.cpp if you use below pc & led +#if DEBUG_TIMING == 2 + extern Serial pc; + extern DigitalOut test_point; +# define TP_ON {test_point = 1;} +# define TP_OFF {test_point = 0;} +# define DBG_PRINTF(...) pc.printf(__VA_ARGS__) +#else +# define TP_ON {;} +# define TP_OFF {;} +# define DBG_PRINTF(...) {;} +#endif + + +int SoftSerial_IR::_getc( void ) +{ + while(!readable()) { + YIELD; + } out_valid = false; return out_buffer; } -int SoftSerial_IR::readable(void) { +int SoftSerial_IR::readable(void) +{ return out_valid; } //Start receiving byte -void SoftSerial_IR::rx_gpio_irq_handler(void) { - //myled = !myled; // Debug - rxticker.prime(timestamp_offset); - rxticker.setNext(bit_period + (bit_period >> 1) - overhead_us_IR); +void SoftSerial_IR::rx_gpio_irq_handler(void) +{ + TP_ON; + rxticker.prime(MAGIC_NUM); rx->fall(NULL); rx_bit = 0; rx_error = false; -}; + // dummy setting for 1st timer interrupt + rx_1st = true; + rx_st_time = us_ticker_read(); + rxticker.setNext(10); + TP_OFF; +}; -void SoftSerial_IR::rx_handler(void) { - //myled = !myled; // Debug +void SoftSerial_IR::rx_handler(void) +{ + TP_ON; + // dummy IRQ for 1st shot + if (rx_1st) { + rx_1st = false; + int next_preiod = us_ticker_read() - rx_st_time; + next_preiod = bit_period + (bit_period >> 1) - next_preiod; + if (next_preiod > 0) { + rxticker.setNext(next_preiod); + } else { + rxticker.setNext(5); + } + TP_OFF; + return; + } //Receive data int val = rx->read(); - + rxticker.setNext(bit_period); rx_bit++; - - + if (rx_bit <= _bits) { read_buffer |= val << (rx_bit - 1); + TP_OFF; return; } - + //Receive parity bool parity_count; if (rx_bit == _bits + 1) { @@ -63,26 +119,31 @@ if ((!parity_count) && (_parity == Odd)) rx_error = true; return; + case None: + default: + ; } } - + //Receive stop if (rx_bit < _bits + (bool)_parity + _stop_bits) { if (!val) rx_error = true; + TP_OFF; return; - } - + } + //The last stop bit if (!val) rx_error = true; - + if (!rx_error) { out_valid = true; out_buffer = read_buffer; fpointer[RxIrq].call(); } read_buffer = 0; - rxticker.detach(); - rx->fall(this, &SoftSerial_IR::rx_gpio_irq_handler); + rxticker.detach(); + rx->fall(callback(this, &SoftSerial_IR::rx_gpio_irq_handler)); + TP_OFF; }
diff -r dc766032cdd6 -r 8d343be3382d SoftSerial_tx_IR.cpp --- a/SoftSerial_tx_IR.cpp Fri Dec 28 10:03:35 2018 +0000 +++ b/SoftSerial_tx_IR.cpp Fri May 15 04:11:01 2020 +0000 @@ -1,91 +1,124 @@ -// Apply for Infrared LED and IR-Detector -// Modified by JH1PJL Dec. 28th, 2018 +// Modified by K.Arai / JH1PJL May 15th, 2020 #include "SoftSerial_IR.h" +// please make a constructor in main.cpp if you use below pc & led +#if DEBUG_TIMING == 1 + extern Serial pc; + extern DigitalOut test_point; +# define TP_ON {test_point = 1;} +# define TP_OFF {test_point = 0;} +# define DBG_PRINTF(...) pc.printf(__VA_ARGS__) +#else +# define TP_ON {;} +# define TP_OFF {;} +# define DBG_PRINTF(...) {;} +#endif + int SoftSerial_IR::_putc(int c) { - while(!writeable()); + while(!writeable()) { + YIELD; + } prepare_tx(c); tx_bit = 0; - txticker.prime(timestamp_offset); + //tx->write(1); + tx->write(0.0f); // output 1 + txticker.prime(); tx_handler(); return 0; } void SoftSerial_IR::send_break(void) { - while(!writeable()); + while(!writeable()) { + YIELD; + } //Just to make sure it appears as non-writable to other threads/IRQs - tx_bit = 0; + tx_bit = 0; + //tx->write(0); tx->write(0.5f); // output 0 wait_us((bit_period * _total_bits * 3) / 2); + //tx->write(1); tx->write(0.0f); // output 1 tx_bit = -1; } int SoftSerial_IR::writeable(void) { - if (!tx_en) + if (!tx_en) { return false; - if (tx_bit == -1) + } + if (tx_bit == -1) { return true; + } return false; } void SoftSerial_IR::tx_handler(void) { + TP_ON; if (tx_bit == _total_bits) { tx_bit = -1; + //tx->write(1); + tx->write(0.0f); // output 1 fpointer[TxIrq].call(); + TP_OFF; return; } - - //Flip output - float tx_out = tx->read(); - int cur_out = 0; - if (tx_out == 0.5f){ // current duty 50% - cur_out = 0; // current = 0 - tx->write(0.0f); // output port 0 to 1 + if (tx_bit == 0){ + //tx->write(1); + tx->write(0.0f); // output 1 + txticker.setNext(10); } else { - cur_out = 1; // current = 1 - tx->write(0.5f); // output port 1 to 0 + int bitchk = _char >> tx_bit; + if (bitchk & 1) { + //tx->write(1); + tx->write(0.0f); // output 1 + } else { + //tx->write(0); + tx->write(0.5f); // output 0 + } + txticker.setNext(bit_period); } - - //Calculate when to do it again - int count = bit_period; tx_bit++; - while(((_char >> tx_bit) & 0x01) == !cur_out) { - count+=bit_period; - tx_bit++; - } - - txticker.setNext(count); + TP_OFF; } void SoftSerial_IR::prepare_tx(int c) { - _char = c << 1; + _char = c << 2; // set start bit as bit1 and dummy as bit0 bool parity; switch (_parity) { case Forced1: _char |= 1 << (_bits + 1); + break; case Even: parity = false; for (int i = 0; i<_bits; i++) { - if (((_char >> i) & 0x01) == 1) + if (((_char >> i) & 0x01) == 1) { parity = !parity; + } } _char |= parity << (_bits + 1); + break; case Odd: parity = true; for (int i = 0; i<_bits; i++) { - if (((_char >> i) & 0x01) == 1) + if (((_char >> i) & 0x01) == 1) { parity = !parity; + } } _char |= parity << (_bits + 1); + break; + case Forced0: + case None: + default: + ; } - - _char |= 0xFFFF << (1 + _bits + (bool)_parity); - _char &= ~(1<<_total_bits); + // added one dummy at LSB bit + int num = 1 + _bits + (bool)_parity + 1; + _char |= 0xffffffff << num; + _char |= 1UL; + _char &= ~(1 << _total_bits); }