(编辑原来问题的很大一部分已经得到了某种程度的回答,因此已经过时了。要了解我现在正在寻找的内容的最新版本,请跳到编辑2,并将以下内容用作上下文参考。)
我试图从示波器上的微控制器解码软件UART。为此,我参考地面探测Tx线路,并使用示波器上的解码功能(Siglent SDS 1104X-E)。要在示波器端配置UART,我必须选择一个自定义波特率,因为我的软件UART的波特率没有正确微调。为此,我在UART数据中测量一个位的周期。然后,使用周期,我简单地将1bit除以周期,得到一个bps值。
例如,在我发送的一些UART数据中,我测量了1位的长度为0.2208ms,所以
(1比特)/ (0.2208 * 10^(-3)s) ~= 4529 BPS
然后我在示波器上设置自定义波特率为这个值,并按下解码按钮,期待看到一个很好的解码信号;然而,接收者似乎已经收到垃圾如下所示
让我困惑的是,如果我把波特率调低到4200波特左右,信号会被完美解码,如下图所示
这个值与我从信号中计算出来的实际波特率相差太远了,所以这里发生了什么?数据是准确和干净的,但解码它所需的波特率是如此之远。
我还想指出,我不认为这是示波器的问题,因为当我发送数据到我的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(); } }```