This is a RS485 class that uses the second UART and was tested on a Nucleo F030R8. A main demo program howto use the class is included. This class control the direction pin on the transceiver buffer automatically, and used transmit and receive interrupts. Ring buffers (256 bytes) are implemented on both transmission and reception. It assumes a ADM3485 'type' buffer where pins 2 ans 3 are connected and seen as direction. This test program could easily be adapted as base for other programs.

Dependencies:   mbed

Committer:
creatron
Date:
Tue Nov 11 19:19:47 2014 +0000
Revision:
7:cfe1e0eafb7e
Parent:
6:70460dcbc43c
Child:
8:595258a79939
This version both the transmit and receive seem to operate

Who changed what in which revision?

UserRevisionLine numberNew contents of line
creatron 0:044dfba47660 1 #include "mbed.h"
creatron 0:044dfba47660 2
creatron 0:044dfba47660 3 #include "RawSerial.h"
creatron 0:044dfba47660 4 #include "dlms_comms.h"
creatron 0:044dfba47660 5
creatron 0:044dfba47660 6 //#define DEBUG_DLMS_COMMS
creatron 0:044dfba47660 7
creatron 0:044dfba47660 8 // Instantiate the raw serial (2nd uart) Tx then Rx
creatron 0:044dfba47660 9 RawSerial rs485(PA_9, PA_10);
creatron 0:044dfba47660 10 // pin to switch the rs485 buffer direction
creatron 7:cfe1e0eafb7e 11 DigitalOut dir_485 (PB_0);
creatron 7:cfe1e0eafb7e 12 //bool dir_485 = 0;
creatron 0:044dfba47660 13
creatron 0:044dfba47660 14 /** ---------------------------------------------------------------------------
creatron 0:044dfba47660 15 * @brief C O N S T R U C T O R
creatron 0:044dfba47660 16 */
creatron 0:044dfba47660 17 dlms_comms::dlms_comms (void)
creatron 0:044dfba47660 18 {
creatron 0:044dfba47660 19 // enable the rs485 buffer receiver,
creatron 0:044dfba47660 20 dir_485 = 0;
creatron 0:044dfba47660 21
creatron 0:044dfba47660 22 // clear the pointers and ring buffer
creatron 0:044dfba47660 23 rx_head_ptr = 0;
creatron 0:044dfba47660 24 rx_tail_ptr = 0;
creatron 0:044dfba47660 25 memset (rx_buffer, 0, sizeof(rx_buffer));
creatron 0:044dfba47660 26
creatron 0:044dfba47660 27 // transmit empty flag .. need to set buffer
creatron 0:044dfba47660 28 // in receive mode again after we have transmitted
creatron 0:044dfba47660 29 // all data characters
creatron 1:7091401482c5 30 // rs485.attach(this,
creatron 1:7091401482c5 31 // &dlms_comms::Tx_interrupt,
creatron 7:cfe1e0eafb7e 32 // //RawSerial::TxIrq
creatron 7:cfe1e0eafb7e 33 // Serial::TxIrq);
creatron 7:cfe1e0eafb7e 34
creatron 7:cfe1e0eafb7e 35 // attach the receiver input to 'run' a method
creatron 7:cfe1e0eafb7e 36 rs485.attach(NULL, Serial::TxIrq);
creatron 7:cfe1e0eafb7e 37
creatron 7:cfe1e0eafb7e 38 // when characters received
creatron 7:cfe1e0eafb7e 39 rs485.attach(this,
creatron 7:cfe1e0eafb7e 40 &dlms_comms::Rx_interrupt,
creatron 7:cfe1e0eafb7e 41 //RawSerial::RxIrq
creatron 7:cfe1e0eafb7e 42 Serial::RxIrq);
creatron 7:cfe1e0eafb7e 43 timer = NULL;
creatron 0:044dfba47660 44 debug_uart = NULL;
creatron 3:29454cac7930 45 tx_irq_count = 0l;
creatron 3:29454cac7930 46 rx_irq_count = 0l;
creatron 7:cfe1e0eafb7e 47
creatron 7:cfe1e0eafb7e 48
creatron 7:cfe1e0eafb7e 49 /** Set the flow control type on the serial port
creatron 7:cfe1e0eafb7e 50 *
creatron 7:cfe1e0eafb7e 51 * @param type the flow control type (Disabled, RTS, CTS, RTSCTS)
creatron 7:cfe1e0eafb7e 52 * @param flow1 the first flow control pin (RTS for RTS or RTSCTS, CTS for CTS)
creatron 7:cfe1e0eafb7e 53 * @param flow2 the second flow control pin (CTS for RTSCTS)
creatron 7:cfe1e0eafb7e 54 */
creatron 7:cfe1e0eafb7e 55 // rs485.set_flow_control(RTSCTS , //Flow type,
creatron 7:cfe1e0eafb7e 56 // dir_485, //PB_0, //PinName flow1=NC,
creatron 7:cfe1e0eafb7e 57 // dir_485 //PB_0 //PinName flow2=NC
creatron 7:cfe1e0eafb7e 58 // );
creatron 0:044dfba47660 59 }
creatron 0:044dfba47660 60 /** ---------------------------------------------------------------------------
creatron 0:044dfba47660 61 * @brief bq34z110::init_port_expander Put all ports in INPUT mode
creatron 0:044dfba47660 62 * @param parent_uart The debug uart class pionter
creatron 0:044dfba47660 63 * @param parent_timer The main timer (system tick) class pointer
creatron 0:044dfba47660 64 */
creatron 0:044dfba47660 65 void dlms_comms::init (RawSerial * parent_uart,
creatron 0:044dfba47660 66 Timer * parent_timer)
creatron 0:044dfba47660 67 {
creatron 0:044dfba47660 68 // we use the parent timer and debug port
creatron 0:044dfba47660 69 debug_uart = parent_uart;
creatron 0:044dfba47660 70 timer = parent_timer;
creatron 0:044dfba47660 71 //#ifdef DEBUG_DLMS_COMMS
creatron 7:cfe1e0eafb7e 72 //debug_uart->printf (" init_dlms_comms..\r\n");
creatron 0:044dfba47660 73 //#endif
creatron 0:044dfba47660 74 }
creatron 0:044dfba47660 75 /** ---------------------------------------------------------------------------
creatron 0:044dfba47660 76 * @brief dlms_comms::initialise This method initialise the rs485 comms port
creatron 0:044dfba47660 77 *
creatron 0:044dfba47660 78 * @param baudrate The RS485 baudrate
creatron 0:044dfba47660 79 * @param bits The RS485 number of bits (8)
creatron 0:044dfba47660 80 * @param parity The parity required 'n','o', 'e'
creatron 0:044dfba47660 81 * @param stop_bits The number of stop bits 1 or 2
creatron 0:044dfba47660 82 */
creatron 0:044dfba47660 83 void dlms_comms::initialise (INT_16 baudrate,
creatron 0:044dfba47660 84 UINT_8 bits,
creatron 0:044dfba47660 85 UINT_8 parity,
creatron 0:044dfba47660 86 UINT_8 stop_bits )
creatron 0:044dfba47660 87 {
creatron 0:044dfba47660 88 // default comms parameters
creatron 0:044dfba47660 89 SerialBase::Parity my_parity = SerialBase::None;
creatron 3:29454cac7930 90 tx_irq_count = 0l;
creatron 3:29454cac7930 91 rx_irq_count = 0l;
creatron 0:044dfba47660 92 // set the class baudrate
creatron 0:044dfba47660 93 rs485.baud(baudrate);
creatron 0:044dfba47660 94 // enable the receiver on the tranceiver buffer chip
creatron 0:044dfba47660 95 dir_485 = 0;
creatron 0:044dfba47660 96 // clear the ring buffer
creatron 0:044dfba47660 97 rx_head_ptr = 0;
creatron 0:044dfba47660 98 rx_tail_ptr = 0;
creatron 0:044dfba47660 99 memset (rx_buffer, 0, sizeof(rx_buffer));
creatron 0:044dfba47660 100 // set the enum parity as required by class
creatron 0:044dfba47660 101 switch (parity)
creatron 0:044dfba47660 102 {
creatron 0:044dfba47660 103 default:
creatron 0:044dfba47660 104 case 'n' :
creatron 0:044dfba47660 105 my_parity = SerialBase::None;
creatron 0:044dfba47660 106 break;
creatron 0:044dfba47660 107 case 'o':
creatron 0:044dfba47660 108 my_parity = SerialBase::Odd;
creatron 0:044dfba47660 109 break;
creatron 0:044dfba47660 110 case 'e':
creatron 0:044dfba47660 111 my_parity = SerialBase::Even;
creatron 0:044dfba47660 112 break;
creatron 0:044dfba47660 113 }
creatron 0:044dfba47660 114 // lets doit .. config the rs485 now
creatron 0:044dfba47660 115 rs485.format((int) bits,
creatron 0:044dfba47660 116 my_parity,
creatron 0:044dfba47660 117 (int) stop_bits);
creatron 7:cfe1e0eafb7e 118 //# ifdef DEBUG_DLMS_COMMS
creatron 7:cfe1e0eafb7e 119 //debug_uart->printf (" init_dlms_comms..Baudrate (%d) %d bits Parity=%c\r\n",
creatron 7:cfe1e0eafb7e 120 // baudrate, bits, parity);
creatron 7:cfe1e0eafb7e 121 //# endif
creatron 0:044dfba47660 122 // dummy send packet to rs485
creatron 0:044dfba47660 123 //send_packet ("\r\nHello cruel world\r\n",12);
creatron 6:70460dcbc43c 124 if ( rs485.readable())
creatron 6:70460dcbc43c 125 rs485.getc();
creatron 0:044dfba47660 126 }
creatron 0:044dfba47660 127 /** ---------------------------------------------------------------------------
creatron 0:044dfba47660 128 * @brief dlms_comms::get_dir485 . This method returns the state of the rs485
creatron 0:044dfba47660 129 * direction
creatron 0:044dfba47660 130 */
creatron 0:044dfba47660 131 bool dlms_comms::get_dir485 (void)
creatron 0:044dfba47660 132 {
creatron 0:044dfba47660 133 return dir_485;
creatron 0:044dfba47660 134 }
creatron 0:044dfba47660 135 /** ---------------------------------------------------------------------------
creatron 0:044dfba47660 136 * @brief dlms_comms::Tx_interrupt
creatron 0:044dfba47660 137 */
creatron 0:044dfba47660 138 void dlms_comms::Tx_interrupt(void)
creatron 0:044dfba47660 139 {
creatron 3:29454cac7930 140 tx_irq_count++;
creatron 0:044dfba47660 141 // enable the receiver, we are finito with the transmission of characters
creatron 0:044dfba47660 142 // this changes the direction on the transceiver buffer
creatron 7:cfe1e0eafb7e 143 rs485.attach(NULL, Serial::RxIrq);
creatron 7:cfe1e0eafb7e 144 dir_485 = 0;
creatron 0:044dfba47660 145 }
creatron 0:044dfba47660 146 /** ---------------------------------------------------------------------------
creatron 0:044dfba47660 147 * @brief dlms_comms::Rx_interrupt . This method received all characters from
creatron 0:044dfba47660 148 * the uart and saved it in a ring buffer, 256 bytes long. The CPU only has 16
creatron 0:044dfba47660 149 * byte fifo, this makes it a 256 bit fifo
creatron 0:044dfba47660 150 */
creatron 0:044dfba47660 151 void dlms_comms::Rx_interrupt(void)
creatron 0:044dfba47660 152 {
creatron 0:044dfba47660 153 UINT_8 value;
creatron 3:29454cac7930 154 rx_irq_count++;
creatron 0:044dfba47660 155 // read the uart and place character in ring buffer
creatron 0:044dfba47660 156 value = rs485.getc();
creatron 0:044dfba47660 157 rx_buffer[rx_head_ptr++] = value;
creatron 0:044dfba47660 158 }
creatron 0:044dfba47660 159 /** ---------------------------------------------------------------------------
creatron 0:044dfba47660 160 * @brief dlms_comms::available This method return if we have any characters
creatron 0:044dfba47660 161 * available (received on the rs485 port)
creatron 0:044dfba47660 162 * @return true if characters received on the rs485
creatron 0:044dfba47660 163 */
creatron 0:044dfba47660 164 bool dlms_comms::char_available (void)
creatron 0:044dfba47660 165 {
creatron 0:044dfba47660 166 if (rx_head_ptr == rx_tail_ptr)
creatron 0:044dfba47660 167 // nope
creatron 0:044dfba47660 168 return false;
creatron 0:044dfba47660 169 else
creatron 0:044dfba47660 170 return true;
creatron 0:044dfba47660 171 }
creatron 0:044dfba47660 172 /** ---------------------------------------------------------------------------
creatron 0:044dfba47660 173 * @brief dlms_comms::get_char This method return the last character received
creatron 0:044dfba47660 174 * on the rs485 port
creatron 0:044dfba47660 175 * @return Unsigned byte
creatron 0:044dfba47660 176 * @note The user must make sure that characters are available before, else
creatron 0:044dfba47660 177 * this method shall wait for the next character, no timeouts yet
creatron 0:044dfba47660 178 */
creatron 0:044dfba47660 179 UINT_8 dlms_comms::get_char (void)
creatron 0:044dfba47660 180 {
creatron 0:044dfba47660 181 // we have to wait for at least on charcter in the ring buffer
creatron 0:044dfba47660 182 while (char_available() == false);
creatron 0:044dfba47660 183 // return the character
creatron 0:044dfba47660 184 return (rx_buffer[rx_tail_ptr++]);
creatron 0:044dfba47660 185 }
creatron 0:044dfba47660 186 /** ---------------------------------------------------------------------------
creatron 0:044dfba47660 187 * @brief dlms_comms::send_packet This method sends a serial packet data to the
creatron 0:044dfba47660 188 * rs485 bus, the directoion of the tranceiver chip is changed to transmit and
creatron 0:044dfba47660 189 * the packet is tranmitted.
creatron 0:044dfba47660 190 * @param ptr Pointer address for start of the packet
creatron 0:044dfba47660 191 * @param length Packet length
creatron 0:044dfba47660 192 * @note The direction is changed with a interrupt when the transmitter
creatron 0:044dfba47660 193 * is empty
creatron 0:044dfba47660 194 */
creatron 0:044dfba47660 195 void dlms_comms::send_packet (const UINT_8 *ptr,
creatron 0:044dfba47660 196 const UINT_8 length)
creatron 0:044dfba47660 197 {
creatron 0:044dfba47660 198 // local stack variable
creatron 0:044dfba47660 199 UINT_8 * tmp_ptr =(UINT_8 *) ptr;
creatron 0:044dfba47660 200
creatron 0:044dfba47660 201 // change the tranceiver direction to output
creatron 0:044dfba47660 202 dir_485 = 1;
creatron 0:044dfba47660 203 for (UINT_8 i= 0; i < length; i++)
creatron 0:044dfba47660 204 {
creatron 0:044dfba47660 205 rs485.putc (*tmp_ptr++);
creatron 0:044dfba47660 206 }
creatron 7:cfe1e0eafb7e 207 rs485.attach(this,
creatron 7:cfe1e0eafb7e 208 &dlms_comms::Tx_interrupt,
creatron 7:cfe1e0eafb7e 209 //RawSerial::TxIrq
creatron 7:cfe1e0eafb7e 210 Serial::TxIrq);
creatron 0:044dfba47660 211 }
creatron 3:29454cac7930 212 UINT_64 dlms_comms::ret_rx_irq_count (void)
creatron 0:044dfba47660 213 {
creatron 3:29454cac7930 214 return rx_irq_count;
creatron 3:29454cac7930 215 }
creatron 3:29454cac7930 216 UINT_64 dlms_comms::ret_tx_irq_count (void)
creatron 3:29454cac7930 217 {
creatron 3:29454cac7930 218 return tx_irq_count;
creatron 0:044dfba47660 219 }
creatron 6:70460dcbc43c 220 bool dlms_comms::ret_dir_485 (void)
creatron 6:70460dcbc43c 221 {
creatron 6:70460dcbc43c 222 return dir_485;
creatron 6:70460dcbc43c 223 }
creatron 0:044dfba47660 224 //----[ the end ]--------------------------------------------------------------