UART发生意外的Atmega16响应


8

UART发生意外的Atmega16响应

问题摘要

我已经用代码刷新了Atmega16,这应该导致Atmega16通过终端发送回我发送给它的任何字符。我得到了答复,但是我发送的角色很少。通过更改波特率,我可以看到正确的输出,但是我不明白为什么正确的波特率有效。

更多详情

我正在尝试自己学习更多有关固件编程的信息,因为我很喜欢。到目前为止,在uni上进行的固件编程中,我们已经获得了框架代码文件,这些文件可以完成许多外围设备接口并为我们设置了文件,但是我想自己学习一下。在整个帖子中,我对我在这里所做的事情有一些疑问,但我将在最后逐条列出。如果您对我的知识有任何误解或潜在的空白,我将不胜感激您可能会提供的任何意见。

编码

我纷纷亮出到我Atmega16的代码“在AVR-GCC使用USART”取几乎行线从教程发现此页面上。我只添加了F_CPU的#define。原始代码没有针对F_CPU的#define,因此我的代码无法在AtmelStudio 7中进行编译。有人可以解释为什么作者未在原始文件中定义F_CPU吗?我猜他们可能正在使用Atmel Studio 7以外的其他工具或编译器,但我不能肯定地说。

#include <avr/io.h>
#define F_CPU 7372800 //this was chosen because the tutorial states this is the frequency we want to operate at
#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((( F_CPU / 16) + ( USART_BAUDRATE / 2)) / ( USART_BAUDRATE )) - 1)

int main ( void )
{
    char ReceivedByte ;
    UCSRB = (1 << RXEN ) | (1 << TXEN ); // Turn on the transmission and reception circuitry
    UCSRC = (1 << URSEL ) | (1 << UCSZ0 ) | (1 << UCSZ1 ); // Use 8- bit character sizes
    UBRRH = ( BAUD_PRESCALE >> 8); // Load upper 8- bits of the baud rate value into the high byte of the UBRR register
    UBRRL = BAUD_PRESCALE ; // Load lower 8- bits of the baud rate value into the low byte of theUBRR register
    for (;;) // Loop forever
    {
        while (( UCSRA & (1 << RXC )) == 0) {}; // Do nothing until data have been received and is ready to be read from UDR
        ReceivedByte = UDR ; // Fetch the received byte value into the variable " ByteReceived "
        while (( UCSRA & (1 << UDRE )) == 0) {}; // Do nothing until UDR is ready for more data to be written to it
        UDR = ReceivedByte ; // Echo back the received byte back to the computer
    }
}

硬件设置

硬件设置照片

  • MCU:Atmega16;
  • 工具链:Atmel Studio 7,与AVR Dragon一起闪烁;
  • 电源:从大学提供的开发板获得的5V电压轨(从计算机USB获得)。100nF陶瓷圆盘电容器,用于面包板电源线上的旁路
  • USB转串口转换器:这个。USB到串行转换器上的TXD连接到RXD Atmega(引脚15)。转换器上的RXD连接到Atmega(引脚14)上的RXD。
  • 终端软件:PuTTY(波特率为9600)。

    错误回答的证据

    重申一下,Atmega 应该返回发送给它的内容,即OUTPUT应该与INPUT完全相同。

    腻子输出

    输入输出值FF6ž>d0空间0X8

    示波器捕获

    我已将Picoscope与串行解码一起使用,以检查Atmega是否接收到正确的输入(看来是正确的)。例如,当我按“ f”键时,它就可以正确接收。输出仍然是“ 6”(有时是“&”号)。

在Atmega16的RX引脚上捕获示波器,表明已通过终端软件('f')发送了正确的字符

在Atmega16的TX引脚上捕获示波器,表明发送了不希望的响应(“ 6”)

我偶然发现的修复程序,我不明白

如果我将波特率更改为2500in PuTTY,则所有显示均正确。我随机选择了此值,但我不知道它为什么起作用(这使我相信我在与波特率有关的地方犯了一个错误,但是我看不到我在哪里完全复制了本教程……我思想)。

问题

  1. 我做错了什么/这是怎么回事?
  2. 为什么原始教程没有#define F_CPU?
  3. 为什么将波特率设置为2500可以解决此问题?(我怀疑如果回答了问题1,就会回答这个问题)

2
仅将F_CPU定义为某个值并不能使微控制器以该频率运行。F_CPU应该定义为您配置运行微型计算机的频率-但我看不到任何证据表明您已在任何地方配置了微型计算机
brhans

写得很好的问题。唯一可以改善的地方是示意图。
布莱尔·丰维尔

+1仅用于 大号一个ŤËX表。
阿森纳

我注意到面包板上没有外部晶体。您是否在使用内部RC时钟?您希望处理器以什么频率运行?
scotty3785 '18

感谢您对F_CPU的讨论,我做了一些调查和研究,并发布了解决方案。我想这对您来说是显而易见的(现在对我而言),但是它可能会对其他人有所帮助。
daviegravee

Answers:


0

我知道了!感谢有关OP的关于F_CPU的评论,我做了一些调查(这对大家来说都是显而易见的)。

简要解决方案摘要

Atmega16没有以我认为的频率运行,因为我不了解如何更改其系统频率。通过检查Atmel Studio中的保险丝,我可以看到我以2MHz运行(据我所知,这不是标准时钟频率,但我不会讲),而不是本教程的7.3728MHz。

F_CPU并没有改变它的MCU(ATmega16的)的时钟频率。为了使代码示例正常工作,Atmega16的频率更改为7.3728MHz。它仍然以保险丝定义的频率运行(在这种情况下为2MHz,更多信息请参见下文),因此所需波特率的纸面计算与实际使用的不同。

工作代码

#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 2000000 //THIS LINE IS **NOT** CHANGING THE FREQUENCY OF THE MCU: CHANGE MCU FREQUENCY IN FUSES
#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((( F_CPU / 16) + ( USART_BAUDRATE / 2)) / ( USART_BAUDRATE )) - 1)

int main ( void ){
    char ReceivedByte ;
    UCSRB = (1 << RXEN ) | (1 << TXEN ); // Turn on the transmission and reception circuitry
    UCSRC = (1 << URSEL ) | (1 << UCSZ0 ) | (1 << UCSZ1 ); // Use 8- bit character sizes
    UBRRH = ( BAUD_PRESCALE >> 8); // Load upper 8- bits of the baud rate value into the high byte of the UBRR register
    UBRRL = BAUD_PRESCALE ; // Load lower 8- bits of the baud rate value into the low byte of theUBRR register
    for (;;){ // Loop forever
        while (( UCSRA & (1 << RXC )) == 0) {}; // Do nothing until data have been received and is ready to be read from UDR
        ReceivedByte = UDR ; // Fetch the received byte value into the variable " ByteReceived "
        while (( UCSRA & (1 << UDRE )) == 0) {}; // Do nothing until UDR is ready for more data to be written to it
        UDR = ReceivedByte ; // Echo back the received byte back to the computer
    }
}

更多详情

期望中的波特率VS什么的Atmega在实际

所需的波特率(来自教程)为9600,这是我在PuTTY中使用的波特率。可以使用Atmega16数据表的表60(第147页)中突出显示的公式来计算实际波特率。

从147页的Atmega16数据表计算波特率和UBRR的方程式表

在代码示例BAUD_PRESCALE中,UBRR在计算中。BAUD_PRESCALE使用为F_CPU和定义的值评估为47 USART_BAUDRATE

波特=FØsC16UBRR+1个
波特=20000001647+1个
波特2604

这就是问题的根源。Atmega16的工作频率为2MHz,这意味着f_ {osc}的值与教程示例不同,波特率为2604,而不是9600。

注意,f_osc是实际的MCU,其中的系统频率通过确定F_CPU

因此,这也回答了我的第三个问题:将波特率更改为2,500足够接近MCU的工作波特率,终端可以正确地解释结果。

更改MCU的频率

要更改AtmelStudio 7中MCU的频率,请执行以下操作:

Tools > Device programming > Fuses > Change SUT_CKSEL (or LOW.SUT_CKSEL in my case) to desired frequency (make sure you have read up on the side effects of this). 

示例中使用的频率不是标准的内部时钟频率,因此我将坚持使用2MHz。

我自己的问题的答案摘要

  1. 我做错了什么/这是怎么回事?:实际上没有将时钟频率更改为教程中的时钟频率,从而导致波特率与预期的波特率不同,从而使终端软件(PuTTY)与MCU不同步。
  2. 为什么原始教程没有#define F_CPU?:仍不能完全确定,但我想这是在教程中未提供的makefile中定义的,并且作者没有使用像Atmel Studio这样的IDE
  3. 为什么将波特率设置为2500可以解决此问题?(我怀疑如果回答了问题1,就会回答这个问题)答案:幸运地猜到了一个接近Atmega16波特率的数字
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.