pas*_*sty 5 c avr atmega serial-port usart
Atmega162
我正在写和之间的通信PC
。
在我的PCB
I 上有接口RS485
(从 转换RS422
而来MAX485
),它通过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
Run Code Online (Sandbox Code Playgroud)
我已经测试了它的几个传输参数,但似乎没有帮助。源代码在这里:
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;
}
Run Code Online (Sandbox Code Playgroud)
PD4
在发送和接收之间切换。
看来您的设置中对空闲线路的处理错误。
让我们看看 RS-485/RS-422 上的传输是什么样的。默认情况下,当没有设备传输时,线路处于空闲状态。通常,它们由终端电阻拉在一起,并且线路上没有差分电压。或者有偏置电阻拉动线路以1
在 A 和 B 之间产生 200mV(逻辑)差异。
当发送器驱动器启用并且正在发送 0 或 1 时,发送器将线路拉开,使线路上的差分电压超过 200mV,并带有一个符号或另一个符号。
一个字节的传输看起来像这样
............ 0 1000 1100 1 1 ............
(idle line) | | (data) | | | (idle again)
driver enabled | | | driver disabled
start bit parity |
stop bit
Run Code Online (Sandbox Code Playgroud)
在此示例中,1
假设启用偶校验,则传输数字(0x31 十六进制或 00110001 二进制)。
在 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
Run Code Online (Sandbox Code Playgroud)
在这种情况下,起始位(级别 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
Run Code Online (Sandbox Code Playgroud)
尽管我的假设并不符合你的前半部分例子。例如,对于 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
Run Code Online (Sandbox Code Playgroud)
我的结论是:你必须检查从PC到MCU的RS-422线。它存在一些问题,使接收方认为0
线路处于空闲状态时是合乎逻辑的。可能是偏置电阻连接错误。
而且,正如评论中所说,您在初始化方面遇到了问题:
UCSR0C |= (1<<UCSZ10)|(1<<UCSZ00)|(1<<USBS0)|(1<<UPM10);
^^^^^^ has to be UCSZ01
Run Code Online (Sandbox Code Playgroud)
但是,由于您使用的|=
是而不是简单的分配,并且UCSZ01
bit 默认情况下是1
,所以这也可能按预期工作。
还有循环
while ( !(UCSR0A & (1<<RXC0)) );
Run Code Online (Sandbox Code Playgroud)
不应该在中断处理程序中。RXC
由于只有当设置位时才会触发中断,因此您可以假设 中有数据UDR
,否则,此循环可能会永远挂起您的中断例程。