C语言 USART 错误的数据传入



我正在写Atmega162PC之间的通信。

在我的PCB我有接口RS485(由MAX485RS422转换),它通过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,从10的第一个转换被视为起始位。

但是,让我们看看当空闲行被视为逻辑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中有数据,否则,此循环可能会永远挂起您的中断例程。

最新更新