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。
因此,我尝试按以下方式纠正问题:
如果ISR写成
rs485Char = U4RXREG;
RS485_CTRL = 1; // Enable driver
U4TXREG = rs485Char;
然后微控制器发送 2 个字节,第一个是接收到的字符,第二个字节是一个错误字节即。0x00。此后 ISR 没有接收到任何字符。
如果ISR写成:
rs485Char = U4RXREG;
RS485_CTRL = 0; // Disable driver
U4TXREG = rs485Char;
RS485_CTRL = 1; // Enable driver
比它传输收到的第一个字符。但是在 ISR 进入无限循环之后,即。接收一个 NULL 字符并发送一个 NULL 字符。
根据RS485实施规则,
RS485_CTRL(!RE/DE)应该是0才能接收到数据
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。
我有一个与来自微控制器的 "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。
因此,我尝试按以下方式纠正问题:
如果ISR写成
rs485Char = U4RXREG; RS485_CTRL = 1; // Enable driver U4TXREG = rs485Char;
然后微控制器发送 2 个字节,第一个是接收到的字符,第二个字节是一个错误字节即。0x00。此后 ISR 没有接收到任何字符。
如果ISR写成:
rs485Char = U4RXREG; RS485_CTRL = 0; // Disable driver U4TXREG = rs485Char; RS485_CTRL = 1; // Enable driver
比它传输收到的第一个字符。但是在 ISR 进入无限循环之后,即。接收一个 NULL 字符并发送一个 NULL 字符。
根据RS485实施规则,
RS485_CTRL(!RE/DE)应该是0才能接收到数据
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。