USART 传输 - AVR (atmega169p) 接收 0 或 null 而不是 char 'a'

Posted

技术标签:

【中文标题】USART 传输 - AVR (atmega169p) 接收 0 或 null 而不是 char \'a\'【英文标题】:USART transmission - AVR (atmega169p) receives 0 or null instead of char 'a'USART 传输 - AVR (atmega169p) 接收 0 或 null 而不是 char 'a' 【发布时间】:2016-06-13 22:28:15 【问题描述】:

我正在尝试通过 USB 转串行电缆将带有白蚁的字符“a”发送到我的 AVR。这以前有效,但过了一段时间 atmel studio 没有将控制器显示为设备,我不得不将 atmel studio 更新到更高版本以识别控制器。我可能在尝试的过程中某处更改了代码,所以我不确定代码是否正确。

这是一个非常简单的程序,用于接收到达的第一个字符:

#include <avr/io.h>
#include "initialize.h"
#include "constantComfort.h"

char receivedchar;

void USART_receive_char(void)
    /* wait for data to be received */
    while( !(UCSR0A & (1<<RXC0)) );

    receivedchar = UDR0;


int main(void)

    init(0.5); //0.5 for interruptcycle in seconds
    USART_receive_char();
    writeLong(receivedchar,1);

如果我直接插入,write-long 可以将 'a' 写为 ascii-code 97,但是当我尝试接收 'a' 或其他字符时,它只显示 0。

AVR 的初始化看起来像这样,我很确定我已经相应地设置了白蚁程序。 9600 波特率,8 个数据位,1 个停止位,无奇偶校验。

//USART (for Serial connection to computer)
    #define F_CPU       1000000
    #define BAUDRATE    9600                            // 9600 bits/sec
    #define BAUD        ((F_CPU)/(BAUDRATE*16UL)-1)     // from formula

    /* enable USART0 module */
    PRR = (0<<PRUSART0);

    /* set baud rate to  defined baudrate*/
    UBRR0H = (BAUD>>8);
    UBRR0L = (BAUD);

    /* enable receiver and transmitter */
    UCSR0B |= (1<<RXEN0)|(1<<TXEN0);

    /* set frame format: 8 data bits, 1 stop bit (always 1 start bit)*/
    UCSR0C |= (0<<USBS0)|(3<<UCSZ00);

我很确定这是影响此问题的所有代码。我已经阅读了寄存器名称的手册,所以我相信初始化是正确的。

有人知道如何解决这个问题吗?

【问题讨论】:

如果你有示波器,你可以检查信号线。也许这是硬件连接的问题... 是的,我可能可以在实验室尝试一下。如果不是硬件问题就好了。 这是您的实际代码吗?您的编译器应该会抱怨,因为您在函数定义中调用 USART_receive_char(receivedchar); 而它不需要参数 PRR = (0&lt;&lt;PRUSART0); 看起来不像启用 @Ctx 它没有抱怨这个论点。虽然没有帮助改变它(将在一秒钟内编辑)。将PRUSART0 设置为 1 会关闭 USART。默认情况下它可能是0,我将它设置为0以确保。 【参考方案1】:

代码似乎是正确的,除了

 PRR = (0 << PRUSART0); // i think this does not work

试试这个

 PRR &= ~(1 << PRUSART0); 

然后启用 USART 接收中断试试这个

 #include <avr/interrupt.h>
 #include <inttypes.h>

 sei(); //global interrupt enable
 UCSR0B |= (1 << RXCIEn); //USART receive interrupt enable (datasheet page 195)

 ISR(USART_RXCn) (datasheet page 57)
 
 //LED_on switch ON or OFF one of your leds if the receive interrupt is triggered by incoming data from termite
 

对于波特率,试试这个(数据表第 176 页)

 UBRRH0 = (unsigned char)(BAUD>>8);
 UBRRL0 = (unsigned char)BAUD; // the type-casting to unsigned char

【讨论】:

PRR = (0 &lt;&lt; PRUSART); 确实有效。但我可能应该写PRR |= (0 &lt;&lt; PRUSART0); 以免覆盖其他位。另外我在主线程中使用忙等待,所以中断没有任何用处。不过好主意!我稍后需要打断,所以谢谢:) 不,不是PRR |= (0 &lt;&lt; PRUSART0);|-operator 是逻辑 OR,PRR |= (0&lt;&lt;PRUSART0); 表示 PRR = PRR | (0 &lt;&lt; PRUSART0); 与 0 的 OR 连接使值保持不变,因此可能使用 PRR &amp;= (0 &lt;&lt; PRUSART0);(& 是逻辑 AND)这将起作用。我使用二进制版本 PRR &= 0xb11111101 来取消设置 Bit1,因此我对此不太熟悉... 是的,这是真的……我的错!【参考方案2】:

atmega169p 的时钟频率为 8 MHz

我读到在“低功耗”模式下,avr 的时钟频率为 1 MHz,并且不知何故认为这是默认设置。

默认情况下,atmega169p 的时钟频率为 8 MHz,没有预分频,因此波特率计算错误,因此我认为 avr 读取速度不够快,因此接收到“0”。

正确代码sn-p:

    //USART (for Serial connection to computer)
    #define F_CPU       8000000 //>>>>>>>>>>  THIS ONE!  <<<<<<<<<<<<
    #define BAUDRATE    9600                            
    #define BAUD        ((F_CPU)/(BAUDRATE*16UL)-1)     

像在这段代码中那样更改为 8 MHz sn-p 解决了我的问题。

感谢您对我的代码中其他潜在问题的帮助!

【讨论】:

以上是关于USART 传输 - AVR (atmega169p) 接收 0 或 null 而不是 char 'a'的主要内容,如果未能解决你的问题,请参考以下文章

通过底层AVR方法实现SPI数据传输

进阶之路(基础篇) - 009 通过底层AVR方法实现SPI数据传输

AVR 微控制器中的 USART 数字逻辑是啥?

avr-gcc atmega164pa 错误端口未声明

AVR ATmega在主循环之前使用printf时保持重置

在 Atmel AVR studio 中使用 ATMega2560 读取 RC PWM 信号