【问题标题】:How to do hardware UART using Atmega8如何使用 Atmega8 做硬件 UART
【发布时间】:2020-12-02 09:47:49
【问题描述】:

我最近开始使用硬件 uart 对没有外部晶体的 Atmega8 进行串行通信编程。 我检查了许多代码示例和库。 但最后没有成功: 这是代码:

#define F_CPU 1000000UL
#define UART_BAUD 19200

#include <avr/io.h>
#include <util/delay.h>

#define BAUDRATE ((F_CPU)/(UART_BAUD*16UL)-1)            // set baud rate value for UBRR
  
// function to initialize UART
void uart_init (void)
{
    UBRRH = (BAUDRATE>>8);                      // shift the register right by 8 bits
    UBRRL = BAUDRATE;                           // set baud rate
    UCSRB|= (1<<TXEN)|(1<<RXEN);                // enable receiver and transmitter
    UCSRC|= (1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1);   // 8bit data format
}

// function to send data
void uart_transmit(unsigned char data)
{
    while (!( UCSRA & (1<<UDRE)));                // wait while register is free
    UDR = data;                                   // load data in the register
}

// function to receive data
unsigned char uart_recieve(void)
{
    while((!(UCSRA)) & (1<<RXC));                   // wait while data is being received
    return UDR;                                   // return 8-bit data
}

int main(void)

{
    DDRB = 0b00000001;              // set LED pin as OUTPUT 
    PORTB = 0b00000001;             // set all pins to LOW
    
    uart_init();
    while (1)
    {
        for(unsigned char i=10; i< 127; i++)
        {
            uart_transmit (i);
            _delay_ms(10);
        }
        uart_transmit ('A');
        uart_transmit (13);
        uart_transmit (10);
        _delay_ms(500);
        PORTB = 1-PORTB;
    }
     
    return 0;
}

编写代码以19200的波特率发送日期,8位长度,No奇偶校验位和1 停止位。

问题是,当我使用 USB 到 TTL 转换器和终端程序检查输出时,对于 19200-7-N-219200-7-N-1

0A 0B 0C 0D 0E - 0F 10 11 12 13    .....  .....
14 15 16 17 18 - 19 1A 1B 1C 1D    .....  .....
1E 1F 00 01 02 - 03 04 05 06 07    .....  .....
08 09 0A 0B 0C - 0D 0E 0F 10 11    .....  .....
12 13 14 15 16 - 17 18 19 1A 1B    .....  .....
1C 1D 1E 1F 20 - 21 22 23 24 25    ....   !"#$%
26 27 28 29 2A - 2B 2C 2D 2E 2F    &'()*  +,-./
30 31 32 33 34 - 35 36 37 38 39    01234  56789
3A 3B 3C 3D 3E - 3F 20 21 22 23    :;<=>  ? !"#
24 25 26 27 28 - 29 2A 2B 2C 2D    $%&'(  )*+,-
2E 2F 30 31 32 - 33 34 35 36 37    ./012  34567
38 39 3A 3B 3C - 3D 3E 21 0D 0A    89:;<  =>!..

在这种配置下,它似乎缺少一个位号。 6 对于 19200-8-N-219200-8-N-1 的配置,我在终端中得到以下结果

8A 8B 8C 8D 8E - 8F 90 91 92 93    .....  .....
94 95 96 97 98 - 99 9A 9B 9C 9D    .....  .....
9E 9F 80 81 82 - 83 84 85 86 87    .....  .....
88 89 8A 8B 8C - 8D 8E 8F 90 91    .....  .....
92 93 94 95 96 - 97 98 99 9A 9B    .....  .....
9C 9D 9E 9F A0 - A1 A2 A3 A4 A5    .....  .....
A6 A7 A8 A9 AA - AB AC AD AE AF    .....  .....
B0 B1 B2 B3 B4 - B5 B6 B7 B8 B9    .....  .....
BA BB BC BD BE - BF A0 A1 A2 A3    .....  .....
A4 A5 A6 A7 A8 - A9 AA AB AC AD    .....  .....
AE AF B0 B1 B2 - B3 B4 B5 B6 B7    .....  .....
B8 B9 BA BB BC - BD BE A1 23 E1    .....  ...#.

在这种配置下,似乎有一个额外的位没有。 8 设置为 1 并再次丢失位号。 6.

对问题根源有什么建议吗?

【问题讨论】:

  • 您确定将正确的 .hex 文件上传到您的 MCU 吗?我的意思是,也许您在旧固件版本中更改了UCSRC,然后您只认为它是错误的。
  • 我都检查过很多次了

标签: uart atmega avr-gcc


【解决方案1】:

#define BAUDRATE ((F_CPU)/(UART_BAUD*16UL)-1)

F_CPU = 1'000'000UART_BAUD = 19'200 向下舍入得到:

1000000 / (19200 * 16) - 1 = 2

实际的uart速度为

1000000 / 16 / (2 + 1) = 20833

这会给你 8.5% 的错误。

即使启用 2x 模式(UCSRA 中的U2X)也无济于事。当从 1MHz 源时钟时,无法正确设置 USART 以这种速度进行通信。

但是,当从内部 RC 振荡器计时时,您可以选择更高的预分频器输出速度(通过相应地设置熔丝,或以编程方式进行)。

例如您可以选择 2 MHz 主时钟频率并将 USART 设置为使用 2x 模式:

// rounding toward nearest integer, instead of downwards
// divide by 8 (instead of 16) in 2x mode
#define BAUDRATE ((F_CPU + (UART_BAUD*4))/(UART_BAUD*8)-1) // set baud rate value for UBRR

...

void uart_init (void)
{
    // the gcc compiler is able to update UBRRH and UBRRL on its own
    UBRR  = BAUDRATE;                           // set baud rate
    UCSRA = (1 << U2X);                         // enable 2x mode
    UCSRB = (1<<TXEN)|(1<<RXEN);                // enable receiver and transmitter
    UCSRC = (1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1);   // 8bit data format
}
...

现在,如果 F_CPU = 2'000'000BAUDRATE 值将是:

(2000000 + (4 * 19200)) / (8 * 19200) - 1 = 12

以及实际速度:

2000000 / 8 / (12 + 1) = 19231

误差小于 0.2%

【讨论】:

    【解决方案2】:

    终于解决了问题 我刚刚添加了一个外部晶体,它开始完美地工作。 没想到内部振荡器的影响这么大!!!!

    【讨论】:

    • 那么,内部 RC 无法处理这个波特率?也许帧 % 错误太大,请查看数据表中的表格。 :)
    猜你喜欢
    • 1970-01-01
    • 2019-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-07
    • 2023-03-10
    • 1970-01-01
    相关资源
    最近更新 更多