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 18:17:52 2014 +0000
Revision:
6:70460dcbc43c
Parent:
5:e00f46d18514
Child:
7:cfe1e0eafb7e
Add display of the rs485 direction, seem to work

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