3.
\$\begingroup\$

(编辑原来问题的很大一部分已经得到了某种程度的回答,因此已经过时了。要了解我现在正在寻找的内容的最新版本,请跳到编辑2,并将以下内容用作上下文参考。)

我试图从示波器上的微控制器解码软件UART。为此,我参考地面探测Tx线路,并使用示波器上的解码功能(Siglent SDS 1104X-E)。要在示波器端配置UART,我必须选择一个自定义波特率,因为我的软件UART的波特率没有正确微调。为此,我在UART数据中测量一个位的周期。然后,使用周期,我简单地将1bit除以周期,得到一个bps值。

例如,在我发送的一些UART数据中,我测量了1位的长度为0.2208ms,所以

(1比特)/ (0.2208 * 10^(-3)s) ~= 4529 BPS

然后我在示波器上设置自定义波特率为这个值,并按下解码按钮,期待看到一个很好的解码信号;然而,接收者似乎已经收到垃圾如下所示

用计算的波特率解码UART

让我困惑的是,如果我把波特率调低到4200波特左右,信号会被完美解码,如下图所示

UART数据

这个值与我从信号中计算出来的实际波特率相差太远了,所以这里发生了什么?数据是准确和干净的,但解码它所需的波特率是如此之远。

我还想指出,我不认为这是示波器的问题,因为当我发送数据到我的PC通过FTDI突破,并监控它

screen/dev/ttyUSB0 4529

我收到了垃圾数据。接收的字符是未知的,结果是未知的ascii字符符号;但是在这种情况下不同的是,即使我改变波特率屏幕,无论我把它改成什么,它仍然无法解码数据。更奇怪的是,无论我发送什么,我都能收到正确数量的字符,只是字符本身由于某些原因无法识别,即使示波器可以很好地解码它们。所以我很困惑这里发生了什么。

编辑1:

我把波特率提高到4735bps,在标准的4800 bps的2%以内,我用示波器试了试,它仍然无法解码。直到我手动将示波器上的接收波特率降低到大约4400bps,它才能够解码数据。

此外,我确信这不是示波器的问题,因为我使用了一个终端程序(picoterm)并试图以这种方式读取数据。我连接了4800波特集,它无法读取数据,只产生未知的ascii字符。然后我在程序中把它调到4400波特,它能够很好地接收数据。因此,在这个数据流中,有一种东西使得它的波特率小于它计算出来的波特率。。。

编辑2:

从那以后,我对这个问题做了一些改变和发现。我对数据进行了一些更精确和更有条理的测量,我发现接收器无法正确地解码数据,因为比特长度在位与位之间变化足够大(从我测量的数据变化高达16%),它会导致波特率在整个字符中移动相当大的数量,这使得接收器解码数据相当困难。因此,现在的探索已经演变成试图追踪导致比特长度变化的原因。

有人向我指出,我应该避免使用内部振荡器,因为它对UART不够精确,我至少应该在示波器上验证振荡器信号。所以我就这么做了。我修改了一个熔丝位,将振荡器输出到一个引脚上,并对其进行了测量,结果发现振荡器中有相当大的抖动。因此,我改变了微控制器保险丝位,以允许外部时钟源,我现在从我的函数生成器(Siglent SDG 2042X)提供8MHz方波。振荡器现在非常稳定,几乎没有抖动。

在对振荡器进行了修改之后,我发送了更多的测试数据,但不幸的是,位的定时问题仍然存在。我在看我的代码,我想可能会发生的事情是微控制器在计算操作上被挂断了,代码中的什么东西会增加波特率的轻微延迟。我不确定这是否是一个问题,但如果这是一个与代码相关的时间问题,那么我就很难解决这个问题。

以下是我用于定时/延迟功能和ATtiny84A微控制器传输功能的代码,供您参考:

void timer_delay(void) //设置延迟的定时器,以给出位的特定长度。{tcnt0 = 0;//重置时间TCCR0B |= (1 << CS01);//使用/8预分频器启动定时器。而(!(TIFR0 & (1 << OCF0A))); // Wait until the compare interrupt flag is set TIFR0 |= (1 << OCF0A); // Reset the Compare flag TCCR0B &=~ (1 << CS01); // Stop the timer. } void uart_tx(unsigned char *transmit_data) { uint8_t string_length = strlen(transmit_data); for (unsigned char character = 0; character < string_length; character++) { // Set TX low for start bit PORTB &=~ (1 << PORTB1); timer_delay(); for (unsigned char character_bit = 0; character_bit < 8; character_bit++) // Loop through each bit in the character { if ((1 << character_bit) & transmit_data[character]) // Check if the bit is a 1 { PORTB |= (1 << PORTB1); // transmit a 1 timer_delay(); } else { // else if the bit is a 0 PORTB &=~ (1 << PORTB1); // transmit a 0 timer_delay(); } } PORTB |= (1 << PORTB1); // transmit the stop bit timer_delay(); } }```
\ \ endgroup \美元
2.
  • \$\begingroup\$ 这条长长的评论链已经超出了评论的合理范围。因此,它将被移动到聊天室(下面的链接),并且应该在聊天室中继续由于将评论移动到聊天室只能进行一次,因此此处发布的任何试图澄清和理解问题的进一步评论可能会被删除,恕不另行通知。请保持聊天状态!当有人从聊天中获得足够的信息来发布有效的答案时,请这样做。聊天过程中决定的问题的任何事实更新都应该通过编辑问题来进行。谢谢! \ \ endgroup \美元
    SamGibson
    5月6日12:30
  • \$\begingroup\$ 评论不用于扩展讨论;这段对话已经结束了搬到聊天. \ \ endgroup \美元
    SamGibson
    5月6日12:31

你的回答

点击“发布您的答案”,您同意我们的建议服务条款,隐私政策cookie策略

浏览已标记的其他问题问你自己的问题.