我正在写Atmega162
和PC
之间的通信。
在我的PCB
我有接口RS485
(由MAX485
从RS422
转换),它通过ADAM-4520
收发器进入COM port
。
我一直在终端中测试我的程序,这对我来说似乎很奇怪,从MCU
发送字符工作正常,但是从PC
收到的字符被更改了(我无法弄清楚这种转换的任何方案)。
例如,这些 ASCII 字符是这样解释的:
0 => 0
1 => 64
2 => 32
3 => 32
4 => 16
5 => 65
6 => 16
7 => 16
8 => 8
'1' => 204
'2' => 102
'3' => 70
'4' => 51
'5' => 141
'6' => 35
'7' => 51
'8' => 6
'9' => 142
我一直在测试它的几个传输参数,但它似乎没有帮助。源代码在这里:
void USART_init()
{
UCSR0B |= (1<<RXEN0) | (1<<TXEN0) | (1<<RXCIE0);
UCSR0C |= (1<<UCSZ10)|(1<<UCSZ00)|(1<<USBS0)|(1<<UPM10);
UBRR0H = 0;
UBRR0L = 12;
DDRD |= 1<<PD1;
_delay_ms(1);
}
void USART_Transmit( unsigned char data )
{
PORTD |= 1<<PD4;
while ( !( UCSR0A & (1<<UDRE0)) );
UDR0 = data;
while (!(UCSR0A & (1 << TXC0)))
PORTD &= ~(1<<PD4);
}
ISR(USART0_RXC_vect)
{
unsigned char a;
while ( !(UCSR0A & (1<<RXC0)) );
a = UDR0;
speed_1 = a;
}
PD4
发送和接收之间切换。
看起来空闲行在您的设置中被错误地处理了。
让我们看看通过RS-485/RS-422传输是什么样的。默认情况下,当不传输任何设备时,线路处于空闲状态。通常,它们由端子电阻器拉在一起,线路两端没有差分电压。或者有偏置电阻拉线,使A和B之间产生200mV(逻辑1
)差。
驱动器使能且传输0或1时,变送器将线路拉开,使两端的差分电压超过200mV,并带有一个或另一个符号。
字节的传输看起来像这样
............ 0 1000 1100 1 1 ............
(idle line) | | (data) | | | (idle again)
driver enabled | | | driver disabled
start bit parity |
stop bit
在此示例中,正在传输数字1
(0x31十六进制或00110001 bin),假设启用了偶数奇偶校验。
在UART上,每个传输的字节由一个起始位(这是逻辑0
)开始,然后数据以小端形式传输(即从最低有效位开始),并通过传输一个或多个停止位来完成,这是逻辑1
。
通常,空闲线路被接收器视为1
,从1
到0
的第一个转换被视为起始位。
但是,让我们看看当空闲行被视为逻辑0
时会发生什么?
000000000000 0 1000 1100 11 000000000000
(nothing, ||^^ ^^^^ ^^ |
framing error) || data treated as stop
1 treated as idle|
0 treated as start
在这种情况下,起始位(电平 0)被忽略,第一个1
位被视为先前传输的停止位。之后0
第一位被视为字节的起始位,随后的 8 位被视为数据。
在我们的示例中,数据将是11001100,即 204。让我们看看其他例子
transmitted '4' (0x34): ..... 0 0010 1100 11 ...........
received: S 1100 11 00 - result 51
transmitted '5' (0x35): ..... 0 1010 1100 01 ...........
received: S10 1100 01 0 - result 141
transmitted '6' (0x36): ..... 0 0110 1100 01 ...........
received: S 1100 01 00 - result 35
transmitted '7' (0x37): ..... 0 1110 1100 11 ...........
received: S 1100 11 00 - result 51
transmitted '8' (0x38): ..... 0 0001 1100 11 ...........
received: S0 11 00000 - result 6
transmitted 0: ..... 0 0000 0000 01 ...........
received: S00000000 - result 0
尽管我的假设并没有为您的示例的前半部分加起来。 例如,对于 1,我希望您得到数字 192,对于 5 - 193,除非您在禁用奇偶校验时得到这些数字:
transmitted 1: ..... 0 1000 0000 1 ...........
received: S00 0000 1 0 - result 64
transmitted 2: ..... 0 0100 0000 1 ...........
received: S0 0000 1 00 - result 32
transmitted 3: ..... 0 1100 0000 1 ...........
received: S0 0000 1 00 - result 32
transmitted 5: ..... 0 1010 0000 1 ...........
received: S10 0000 1 0 - result 65
transmitted 8: ..... 0 0001 0000 1 ...........
received: S000 1 0000 - result 8
我的结论:您必须检查从PC到MCU的RS-422线。它有一些问题,使接收方认为当线路处于空闲状态时存在逻辑0
。可能有偏置电阻的连接方式错误。
而且,正如评论中所说,您在初始化方面存在问题:
UCSR0C |= (1<<UCSZ10)|(1<<UCSZ00)|(1<<USBS0)|(1<<UPM10);
^^^^^^ has to be UCSZ01
但是,由于您使用的是|=
而不是简单的分配,并且默认情况下UCSZ01
位是1
,这也可以按预期工作。
也是循环
while ( !(UCSR0A & (1<<RXC0)) );
不应在中断处理程序中。由于中断仅在设置RXC
位时触发,因此您可以假设UDR
中有数据,否则,此循环可能会永远挂起您的中断例程。