【问题标题】:How I can fix this code to allow my AVR to talk over serial port?如何修复此代码以允许我的 AVR 通过串行端口进行通信?
【发布时间】:2009-05-10 22:03:04
【问题描述】:

我最近一直在努力让我的 STK200 上的 ATmega162 通过 RS232 与我的计算机通信。我检查并确保 STK200 包含一个 MAX202CPE 芯片。

我已将芯片配置为使用其内部 8MHz 时钟并将其除以 8。

我试图从数据表中复制代码(并在编译器抱怨的地方进行了更改),但无济于事。

我的代码如下,有人可以帮我解决我遇到的问题吗?

我已经确认我的串口可以在其他设备上工作并且没有故障。

谢谢!

#include <avr/io.h>
#include <avr/iom162.h>

#define BAUDRATE 4800

void USART_Init(unsigned int baud)
{
    UBRR0H = (unsigned char)(baud >> 8);
    UBRR0L = (unsigned char)baud;

    UCSR0B = (1 << RXEN0) | (1 << TXEN0);

    UCSR0C = (1 << URSEL0) | (1 << USBS0) | (3 << UCSZ00);
}

void USART_Transmit(unsigned char data)
{
    while(!(UCSR0A & (1 << UDRE0)));

    UDR0 = data;
}

unsigned char USART_Receive()
{
    while(!(UCSR0A & (1 << RXC0)));

    return UDR0;
}

int main()
{

    USART_Init(BAUDRATE);

    unsigned char data;

    // all are 1, all as output
    DDRB = 0xFF;

    while(1)
    {
        data = USART_Receive();

        PORTB = data;

        USART_Transmit(data);


    }
}

【问题讨论】:

    标签: embedded serial-port avr


    【解决方案1】:

    我对 Greg 的回答发表了评论,但想再补充一件事。对于此类问题,调试的黄金标准方法是首先了解异步串行通信,然后使用示波器查看在线情况。如果正在交换字符并且这只是一个波特率问题,这将特别有用,因为您可以计算您看到的波特率,然后相应地调整除数。

    这是一个超级快速入门,毫无疑问,您可以在 Wikipedia 或其他地方找到更全面的内容。

    让我们假设 8 位,无奇偶校验,1 个停止位(最常见的设置)。那么如果正在传输的字符是 0x3f (= ascii '?'),那么该行如下所示;

    ...--+   +---+---+---+---+---+---+       +---+--...
         | S | 1   1   1   1   1   1 | 0   0 | E
         +---+                       +---+---+
    

    芯片高(1)电平为+5V,转换为RS232电平后为-12V。

    低(0)电平在芯片为0V,转换为RS232电平后为+12V。

    S 是起始位。

    然后我们有 8 个数据位,最低有效位在前,所以这里 00111111 = 0x3f = '?'。

    E 是停止(e 表示结束)位。

    时间是从左向右推进的,就像示波器显示一样,如果波特率为 4800,那么每个位跨度为 (1/4800) 秒 = 0.21 毫秒(大约)。

    接收器通过对线路进行采样并寻找下降沿来工作(静止线路始终只是逻辑“1”)。接收器知道波特率和起始位数(1),因此它测量从下降沿开始的半个位时间以找到起始位的中间,然后连续对线路采样 8 位时间以收集数据位。然后接收器再等待一个位时间(直到停止位的一半)并开始寻找另一个起始位(即下降沿)。同时,读取的字符可供系统的其余部分使用。发送器保证在停止位完成之前不会开始下一个下降沿。可以将发送器编程为始终等待更长的时间(使用额外的停止位),但这是一个遗留问题,仅在硬件和/或软件设置非常慢时才需要额外的停止位。

    【讨论】:

      【解决方案2】:

      我手边没有参考资料,但是波特率寄存器 UBRR 通常包含一个除数,而不是所需的波特率本身。 quick google search 表示 4800 波特的正确除数可能是 239。所以试试:

      divisor = 239;
      UBRR0H = (unsigned char)(divisor >> 8);
      UBRR0L = (unsigned char)divisor;
      

      如果这不起作用,请查看特定芯片的参考文档,了解正确的除数计算公式。

      【讨论】:

      • 我查找了我从事的一个旧 AVR 项目,其中最相关的代码行是;除数 = (u16)(SYSTEMCLOCK / (波特率 * 16)) - 1;使用我的 SYSTEMCLOCK 频率,这达到了 191。使用你的,可能是 13?但格雷格的回答可能更有可能是正确的。在这种情况下,芯片和时钟发生器的确切风格非常重要。
      【解决方案3】:

      为了调试 UART 通信,有两个有用的事情要做:

      1) 在连接器处进行环回,并确保您可以读回您所写的内容。如果您发送一个字符并准确地返回它,您就知道硬件接线正确,并且至少基本的 UART 寄存器配置集是正确的。

      2) 重复发送字符 0x55(“U”)——二进制位模式 01010101 可以让您在示波器上快速查看位宽,从而让您验证速度设置是否正确。

      【讨论】:

      • 第二种方法很神奇也很有用。它还负责 start bit 和 sop bit。
      【解决方案4】:

      更彻底地阅读数据表后,我错误地设置了波特率。 ATmega162 数据表有一个时钟频率图表,绘制了波特率和相应的误差。

      对于 4800 波特率和 1 MHz 时钟频率,误差为 0.2%,这对我来说是可以接受的。诀窍是将 12 传递给 USART_Init() 函数,而不是 4800。

      希望这对其他人有所帮助!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-04-09
        • 1970-01-01
        • 2014-12-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-08
        相关资源
        最近更新 更多