从 AVR USART 传输读取的数据损坏

Posted

技术标签:

【中文标题】从 AVR USART 传输读取的数据损坏【英文标题】:Broken data read from AVR USART transmission 【发布时间】:2013-10-29 08:03:22 【问题描述】:

我在 stk500 开发板上有一个 atmega162 芯片,通过串行电缆连接到 ubuntu。 在 atmega 上,我初始化 usart 并写入一些字节。在 Ubuntu 方面,something 来自管道,但绝对不是发送的内容......

更准确地说:对于发送的每个字节,我得到一系列大约 6 或 7 个字节,每个字节都有 0x00 或 0xC0 值。

我的代码的相关sn-ps:

编译标志:

CFLAGS = -g
CFLAGS += -mmcu=atmega162
CFLAGS += -W -Wall -Wshadow
CFLAGS += -Os
CFLAGS += -mcall-prologues
CFLAGS += -finline-limit=10
CFLAGS += -mno-interrupts
CFLAGS += -ffunction-sections
CFLAGS += -DF_CPU=7372800ULL

usart 函数:

void Serial0Init(int baud)

        unsigned int    ubrr;

        ubrr = ((F_CPU+8*baud)/(16*baud))-1;
        // Baud rate
        UBRR0H = (unsigned char)(ubrr>>8);
        UBRR0L = (unsigned char)ubrr;
        UCSR0A &= ~(1 << U2X0); // U2X off
        // Transmission settings
        UCSR0C = (1<<URSEL0)|(3<<UCSZ00);       // 8N1
        UCSR0B = (1<<RXEN0)|(1<<TXEN0);


unsigned char Serial0CheckTxReady()

        return (UCSR0A&_BV(UDRE0));     // nonzero if transmit register is ready to receive new data.


void Serial0Write(unsigned char data)

        while (Serial0CheckTxReady()==0)        // while NOT ready to transmit
                
        UDR0 = data;

主要代码:

Serial0Init(9600);
Serial0Write('!');

我使用简单的 python 脚本接收数据:

import serial
import os

port = serial.Serial('/dev/ttyS0', 9600)

print 'Reading from serial...'
while True:
  c = port.read()
  print c, ord(c)

我仔细检查了字节大小设置和波特率计算,一切似乎都很好......知道我做错了什么吗?

【问题讨论】:

这个问题看起来肯定是波特率问题。您确定您的 MCU 以 7.372 MHz 运行吗?我建议检查时钟源的保险丝设置。如果选择外部振荡器作为时钟源,您也应该检查其设置(例如 STK500 时钟发生器频率)。还要检查 Atmega161 兼容性保险丝。只要您为 Atmega162 进行编译,就应禁用兼容模式以防止可能的副作用。 还要检查用于计算ubrr 的表达式。使用 sizeof(int)==2 它的计算可能会导致溢出,从而导致不正确的结果。我建议对 UBRR0 值进行硬编码以进行测试。 好的,你的提示很有帮助。我发现了问题。这确实是波特率计算。固定公式如下: ubrr = ((F_CPU+8*(long int)baud)/(16*(long int)baud))-1; 换句话说 - 唯一的问题是隐藏转换为 16 位 int,这破坏了结果。 【参考方案1】:

据我所知(并且已经在 cmets 中被怀疑),波特率计算是错误的。 试试

UBRR = ((fOSC / (16 * BAUD)) - 1

结果是什么

UBRR = 47

适用于 9600 @ 7372800MHz。

【讨论】:

问题不在于公式本身(我在 avr 库中找到了它,所以我很确定它没问题),而是转换为 16 位 int。事实上,在转换为 long int 之后,我得到了 47 并且一切正常。 @Bob:你是对的,演员阵容是问题所在,但你等式中的 (8*(long int)baud)) 部分仍然是错误的。但是,这并不是什么大问题,因为它只会导致 47.5,由于整数除法,它变成了 47。 就像我说的:我在 avr 库中看到了这个技巧 - 它显然用于将结果四舍五入到最接近的整数值。换句话说,它是round(ubrr) 而不是 floor(ubrr)。 (事实上​​,当使用 usart 友好的时钟速率时,无论如何都没关系) @Bob:好吧,这很有道理。从这里没有进一步的论点;)

以上是关于从 AVR USART 传输读取的数据损坏的主要内容,如果未能解决你的问题,请参考以下文章

STM32-DMA数据传输(USART-ADC-数组)

STM32-DMA数据传输(USART-ADC-数组)

通过底层AVR方法实现SPI数据传输

AVR 微控制器中的 USART 数字逻辑是啥?

进阶之路(基础篇) - 009 通过底层AVR方法实现SPI数据传输

STM32 上的 USART 接收器