That really isn't true. RS-485 is only half-duplex, which means you have to enable transmitting to send anything, and disable it to receive. The connections for doing that are shown in the original diagram. It's easy enough to enable transmission--just set the control line high, then start sending characters--but knowing when to set it low again can be tricky. If you know that the unit on the other end of the line won't make its own transmission for some time, you can just use a timeout after the processor transmits. But if it might respond quickly, you may have to watch for the USART Transmit Complete flag, or get an interrupt from it, and change from transmit to receive when it occurs. It's the TXC0 bit in the UCSR0A register.RS-485 communication is no different from serial UART communication.
State the model number of the device and post links to the description and user manual.
I usually program this (ring-buffered serial data) in a serial data SEND/RECV state machine loop so there are no busy waits for T/R delay timing or serial data.Something to note with the Arduino serial communication that might save you a lot of headache.
In the infinite wisdom of Arduino developers, in effort to make things more streamline from a code perspective.
When you send serial data it loads a buffer that is sent in the background allowing you to perform other tasks with your code.
How does this affect RS485? When you enable the RS485 transmitter pin, send your data, and disable the RS485 transmitter pin, the data buffer might not be done sending data by the time you disable the RS485 transmitter pin. This would effectivly result in cutting off the end of your data packet. One solution is to wait after you transmit before disabling the pin. Or monitor the outgoing buffer and disable the transmit when it is done. (The latter is a bit more tricky, and I don't have an elegant solution. Perhaps someone here could address this? )
/*
* check if we are done with interrupt background buffered transmission of serial data with FIFO
*
* TRMT: Transmit Shift Register is Empty bit (read-only)
* 1 = Transmit shift register is empty and transmit buffer is empty (the last transmission has completed)
* 0 = Transmit shift register is not empty, a transmission is in progress or queued in the transmit buffer
*
* • 8-level deep First-In-First-Out (FIFO) transmit data buffer, • 8-level deep FIFO receive data buffer
* Interrupt is generated and asserted while the transmit buffer is empty
*
* so this will return 'true' after the buffer is empty 'interrupt' and after the last bit is on the wire
*/
static bool u6_trmt(void)
{
return !(U6STA & _U6STA_TRMT_MASK); // note, we invert the TRMT bit so it's true while transmitting
}
// switch RS transceiver to transmit mode and wait if not tx
static void half_dup_tx(bool delay)
{
if (DERE_Get()) {
return;
}
DERE_Set(); // enable modbus transmitter
if (delay) {
delay_ms(2);
}
}
// switch RS transceiver to receive mode and wait if not rx
static void half_dup_rx(bool delay)
{
if (!DERE_Get()) {
return;
}
if (delay) {
delay_ms(2);
}
DERE_Clear(); // enable modbus receiver
}
// ISR function for TMR9
void timer_2ms_tick(uint32_t status, uintptr_t context)
{
M.clock_500hz++;
M.clock_10hz++;
}
uint32_t get_500hz(uint8_t mode)
{
static uint32_t tmp = 0;
if (mode) {
return tmp;
}
tmp = M.clock_500hz;
return tmp;
}
void clear_500hz(void)
{
M.clock_500hz = 0;
}
int8_t master_controller_work(C_data * client)
{
// ...
case INIT:
client->trace = 7;
/*
* MODBUS master query speed
*/
#ifdef FASTQ
if (get_10hz(false) >= CDELAY) {
#else
if (get_2hz(FALSE) >= QDELAY) {
#endif
half_dup_tx(false); // no delays here
M.recv_count = 0;
client->cstate = SEND;
clear_500hz();
client->trace = 71;
}
break;
case SEND:
client->trace = 8;
if (get_500hz(false) >= TDELAY) { // RS485 duplex delay state machine counter timer
client->trace = 9;
UART6_Write((uint8_t*) & cc_buffer, client->req_length);
UART3_Write((uint8_t*) "M\r\n", 3); // MODBUS trace signal to serial debug port
client->trace = 91;
client->cstate = RECV;
clear_500hz(); // state machine execute background timer clear
client->trace = 10;
}
break;
case RECV:
client->trace = 11;
if (u6_trmt()) { // check for serial UART transmit shift register and buffer empty
clear_500hz(); // keep clearing timer
}
if (get_500hz(false) >= TDELAY) { // // RS485 duplex delay state machine counter timer
uint16_t c_crc, c_crc_rec;
client->trace = 12;
BSP_LED3_Set();
half_dup_rx(false); // no delays here
/*
* check received response data for size and format for each command sent
*/
switch (client->modbus_command) {
case G_SET: // check for controller error codes
client->trace = 13;
client->req_length = sizeof(i400_freset);
// ...
}
by Duane Benson
by Aaron Carman
by Duane Benson