【问题标题】:RS485: Transmission issue from microcontrollerRS485:来自微控制器的传输问题
【发布时间】:2017-07-21 23:35:08
【问题描述】:

我有一个与微控制器的“传输”相关的问题。 单片机可以接收,但不能发送。

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

下面是与微控制器的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 以传输数据。

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

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

根据@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
} 

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

【问题讨论】:

  • 9 路 D 型连接器的引脚 2 和 3 未正确标记。引脚 2 应标记为“A”,引脚 3 应标记为“B”以匹配 LTC-485。
  • @bradfordrg,感谢您的指点。我将在我的示意图中更改它。

标签: microcontroller microchip mplab rs485 dspic


【解决方案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。

【讨论】:

  • 非常感谢您的描述性回答。明白我的错误了。需要添加 while(!U4STAbits.TRMT); RS485_CTRL = 0; 这会一直等到字符传输成功。我会将其添加到我的问题中,以便其他人获得正确的结果。
  • @skg 是的,这个while(...TRMT) 是最简单的方法。这是浪费时间,尤其是在低波特率的情况下,但通常没关系。很高兴指出这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-18
  • 1970-01-01
  • 2012-08-26
  • 2019-05-17
  • 2022-09-26
相关资源
最近更新 更多