RS485:来自微控制器的传输问题

RS485: Transmission issue from microcontroller

我有一个与来自微控制器的 "Transmission" 相关的问题。 微控制器可以接收,但不能发送。

这是我之前提出的问题

的一个附加问题

下面是max485与微控制器的接口:

这是我的代码快照:

// RS485
TRISBbits.TRISB6    = INPUT_PIN;        // RX - RB6/RP38 PIN<42>
TRISBbits.TRISB7    = OUTPUT_PIN;       // TX - RB7/RP39 PIN<43>
TRISBbits.TRISB8    = OUTPUT_PIN;       // !RE/DE Control Pin RB8/RP40 PIN<44>

// RS485 Config
#define RS485_TX    PORTBbits.RB6           // RS485 Transmitter
#define RS485_RX    LATBbits.LATB7          // RS485 Reciever
#define RS485_CTRL  LATBbits.LATB8          // RS485 Control Pin

// UART ISR
void __attribute__((interrupt, no_auto_psv)) _U4RXInterrupt(void) 
{
    rs485Char = U4RXREG;
    RS485_CTRL = 1;         // Enable driver
    U4TXREG = rs485Char;
    RS485_CTRL = 0;         // disable driver RE/DO
}  

void InitRs485(void){
        // configure U1MODE
    U4MODEbits.UARTEN = 0;      // Bit15 TX, RX DISABLED, ENABLE at end of func

    U4MODEbits.URXINV = 1;      // 1:URXINV Idle state is '0' ; 0=UxRX Idle state is '1';
    U4MODEbits.ABAUD = 0;       // Bit5 No Auto baud (would require sending '55')
    U4MODEbits.BRGH  = 0;       // Bit3 16 clocks per bit period
    U4MODEbits.PDSEL = 0;       // 0 : 8 bit,no parity; 1 : 8 bit,even parity; 2 : 8 bit,odd parity; 3 : 9 bit,no Parity
    U4MODEbits.STSEL = 1;       // 1 : 2 Stop bits; 0 : 1 Stop bits 
    U4MODEbits.LPBACK = 0;      // Lookback disable
    U4STAbits.URXISEL = 0;      // Interrupt flag bit is set when a character is received

    // Load a value into Baud Rate Generator.
    U4BRG = BRGVAL_RS485;             // 60Mhz osc, 9600 Baud

    // Load all values in for U1STA SFR
    U4STAbits.UTXISEL1 = 0;     // Bit15 Int when Char is transferred (1/2 config!)
    U4STAbits.UTXISEL0 = 0;     // Bit13 Other half of Bit15
    U4STAbits.UTXINV = 1;       // 1:UxTX Idle state is '0' ; 0=UxTX Idle state is '1';

    U4STAbits.UTXBRK = 0;       // Bit11 Disabled
    U4STAbits.UTXEN = 0;        // Bit10 TX pins controlled by peripheral
    U4STAbits.URXISEL = 0;      // Bits6,7 Int. on character received
    IPC22bits.U4RXIP = 7;
    IPC22bits.U4TXIP = 7;

    IFS5bits.U4TXIF = 0;        // Clear the Transmit Interrupt Flag
    IEC5bits.U4TXIE = 0;        // Enable Transmit Interrupts
    IFS5bits.U4RXIF = 0;        // Clear the Receive Interrupt Flag
    IEC5bits.U4RXIE = 0;        // Enable Receive Interrupts

    RPOR2bits.RP39R = 0x1D;     // dsPic33EP512GM604 => RP39 as U4TX PIN<43>
    _U4RXR = 38;                // dsPic33EP512GM604 => RP38 as U4RX PIN<42>

    U4MODEbits.UARTEN = 1;      // And turn the peripheral on
    U4STAbits.UTXEN = 1;

    // Hardware control bits
    IEC5bits.U4RXIE = 1;
    IFS5bits.U4RXIF = 0;
    RS485_CTRL = 0;             // disable driver; Receive Enable
}

在上面的代码中,我有一个 UART 接收中断例程。

无论何时收到任何字符,UART ISR 都会收到它,但无法传回任何内容。

在我的 ISR 中,我正在尝试发回收到的字符。

此问题可能与 max485 控制引脚 (!RE/DE) 有关,在我的代码中称为 RS485_CTRL

因此,我尝试按以下方式纠正问题:

  1. 如果ISR写成

    rs485Char = U4RXREG;
    RS485_CTRL = 1;         // Enable driver
    U4TXREG = rs485Char;
    

    然后微控制器发送 2 个字节,第一个是接收到的字符,第二个字节是一个错误字节即。0x00。此后 ISR 没有接收到任何字符。

  2. 如果ISR写成:

    rs485Char = U4RXREG;
    RS485_CTRL = 0;         // Disable driver
    U4TXREG = rs485Char;
    RS485_CTRL = 1;         // Enable driver
    

比它传输收到的第一个字符。但是在 ISR 进入无限循环之后,即。接收一个 NULL 字符并发送一个 NULL 字符。

根据RS485实施规则,

  1. RS485_CTRL(!RE/DE)应该是0才能接收到数据

  2. RS485_CTRL (!RE/DE) 应该为1才能传输数据。

我的微控制器充当从属设备,所以默认情况下我将其保持在监听模式。但是当接收到数据时,我无法传输。

请帮我找出我的错误???

根据@linuxfan的建议,正确的ISR应该如下:

// UART ISR
void __attribute__((interrupt, no_auto_psv)) _U4RXInterrupt(void) 
{
    rs485Char = U4RXREG;
    RS485_CTRL = 1;         // Enable driver
    U4TXREG = rs485Char;
    while(!U4STAbits.TRMT); // wait until character is transffered successfully
    RS485_CTRL = 0;         // disable driver RE/DO
} 

现在我的代码可以正常工作了。

LTE-485(RS-485 线路驱动器)有一个 "driver enable pin" 必须断言才能传输。你必须在开始发送一个字符之前断言它,并且你必须在最后一个字节完成传输后解除断言(你解除断言以便能够接收数据, 或者让一些其他设备来驱动总线。如果你不想接收,并且没有任何其他设备愿意传输,你可以保持断言。

在您的代码中有:

RS485_CTRL = 1; // Enable driver
U4TXREG = rs485Char;

你用RS485_CTRL=1使能驱动,然后加载UART移位寄存器,但也许你没有等到所有数据都移出。

为了等待数据移出,您可以加载一个定时器,它会在固定时间后触发:一个字符(可能是 10 位)以您编程的波特率移出所需的时间。每次传输一个字符时,启动此计时器。当计时器到期时,禁用 OE(输出驱动器启用)。

另一种方法是等待接收你刚刚发出的字符。您加载发送寄存器;当所有位都移出后,您将收到字符(RS-485 是总线)。届时,您可以根据需要禁用发射器。当然,如果你想背靠背传输一个字符流,这不是很好。此外,在您的硬件设置中,您不能这样做,因为您禁用了接收器(接收器启用和驱动器启用短接在一起)。

但你可以做我认为最好的。当你传输一个字符时,启用接口OE的驱动程序;然后使用 UART 的 TX 中断来传输下一个字符(如果有的话),或者如果没有更多要传输的内容,则取消断言驱动程序。注意使用正确的传输中断:一些 UART(我不知道你使用的那个)有缓冲 - 你需要在数据移出 时触发 的中断,而不是一个说 "you can load more data".

注意事项:您使用的是 DB9 连接器,使用引脚 2 和 3,并将它们标记为 TX 和 RX。好吧,RS-485 中 没有 TX 和 RX 线 :两条线分别命名为 A 和 B,并且都承载相同的平衡信号。这些导线在悬空时用于接收数据,如果由 LTC-485 驱动器驱动,则相同的导线用于传输数据。您可以很好地启用传输驱动程序并保持 "listen" 在线。您将收到刚刚发送的内容(这也可以诊断电线短路或驱动器烧毁)。您可以选择使用RS-232常用的连接器,也可以选择使用与RS-232相同的2脚和3脚,但决不能将RS-485同化为RS-232。