0

我有一个与微控制器的“传输”相关的问题。微控制器可以接收,但无法发送。

这是我之前提出的问题的另一个问题[这里]

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

与微控制器的 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
} 

现在我的代码按预期工作正常。

4

1 回答 1

1

LTE-485(RS-485 线路驱动器)有一个“驱动器启用引脚”,必须将其置位才能进行传输。您必须在开始发送字符之前断言它,并且必须在最后一个字节完成传输后取消断言(为了能够接收数据或让其他设备驱动总线。如果您不想接收,并且您没有任何其他设备愿意发送,则可以将其保持为断言状态)。

在您的代码中有:

RS485_CTRL = 1;// 启用驱动程序
U4TXREG = rs485Char;

您使用 RS485_CTRL=1 启用驱动程序,然后加载 UART 移位寄存器,但也许您不会等待所有数据移出的时间。

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

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

但是你可以做我认为最好的事情。发送char时,开启接口OE的驱动;然后使用 UART 的 TX 中断传输下一个字符(如果有),或者如果没有更多要传输的内容,则取消断言驱动程序。请注意使用正确的传输中断:某些 UART(我不知道您正在使用的那个)具有缓冲功能 - 您需要在数据移出时触发的中断,而不是说“您可以加载更多数据”的中断.

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

于 2017-03-02T14:11:55.997 回答