UDR 寄存器始终读取 0xFF
UDR register always reads 0xFF
我有一个 ATTiny,它应该通过 UART 接收命令。我有一个由八个 LED 组成的简单显示器,应该显示最近接收到的字节的内容。我正在使用中断来读取接收到的数据。无论我发送什么数据,UDR 总是在中断中读取 0xFF
。我知道中断被触发,因为显示从 0x00
变为 0xFF
,但它从不显示我通过串行总线发送的值。
这就是我启用 UART 的方式。
UBRRH = UBRRH_VALUE;
UBRRL = UBRRL_VALUE;
#if USE_2X
UCSRA |= (1U << U2X);
#else
UCSRA &= ~(1U << U2X);
#endif
// Enable receiver and interrupt
UCSRB = (1U << RXEN) | (1U << RXCIE);
// No parity, 8 Data Bits, 1 Stop Bit
UCSRC = (1U << UCSZ1) | (1U << UCSZ0);
这是中断中的代码。我已经测试了 display()
并且它自己可以正常运行因此暗示 message
总是 0xFF
.
ISR(USART_RXC_vect) {
uint8_t message = UDR;
display(message);
}
我确信我的计算机正在发送正确的信息,但我只用伪终端测试它以打印出发送的字节。我打算用示波器窥探硬件连接,但我不认为这是问题所在。是否有什么原因导致 UDR 始终读取为 0xFF?
编辑:
我已经窥探了与示波器的连接,并验证了计算机正在以正确的速率发送正确的数据。然而,ATTiny 没有以正确的波特率运行。在 2400 波特率下,脉冲长度应约为 400 微秒,但微控制器产生的脉冲长度超过 3 毫秒。这解释了为什么它总是读取 0xFF,当控制器认为它正在接收起始位时,计算机将发送几乎整个字节,当控制器试图读取剩余数据时,线路将未被驱动,导致它读取所有数据。我仍然不知道为什么会这样,因为我相信我在控制器上正确设置了波特率。
编辑:
问题已解决。默认情况下,时钟预分频器设置为 8,因此该设备仅以 1MHz 而不是 8MHz 运行。将时钟预分频器设置为 1 解决了问题。
uart 通信可能存在几个问题。首先检查一些东西:
- 控制器是否配置了正确的时钟?
- Internal/External
- 是否为
定义了 F_CPU?
- 是否为
定义了波特率?
- 您是否使用像 ATmega16 这样具有特殊寄存器访问权限的控制器?
- 如果您使用的是外部时钟(不应分离),是否在某些控制器的 FUSES 或特殊寄存器中禁用了 CKDIV8?
- 是:
- 波特率,
- 奇偶校验位,
- 停止位
在发射器和接收器上设置正确
调试:
- 如果您使用 PC 进行通信,请在 UART 适配器上创建环回并使用终端(TeraTerm、Putty 等)检查您发送的消息是否被正确接收。
- 您还可以启用 TX 控制器并检查环回是否在您的 uC 上工作。
- 如果可能尝试将接收到的数据写入一些 LED 以检查是否接收到某个日期
- 接收器和发射器之间的GND是否连接?
- 发射器和接收器之间的电压电平是否相同?
- 发射器和接收器有自己的信号源吗? (那就不要接VCC!)
- 检查控制器上的时钟是否正确(每秒打开一个具有
_delay_ms()
功能的led)
示例程序
#define F_CPU 12000000UL
#define BAUD 9600UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/setbaud.h>
ISR(USART_RXC_vect)
{
volatile unsigned char message = UDR;
// If it is possible try to write the received data to
// LEDs (if there are some at your board)
display(message);
}
int main()
{
// To allow changes to clock prescaler it is necessary to set the
// CCP register (Datasheet page 23)!
CCP = 0xD8;
// RESET the clock prescaler from /8 to /1 !!!!
// Or it is necessary to divide F_CPU through the CLK_PRESCALER
CLKPSR = 0x00;
UBRRH = UBRRH_VALUE;
UBRRL = UBRRL_VALUE;
#if USE_2X
UCSRA |= (1<<U2X);
#else
UCSRA &= ~(1<<U2X);
#endif
// Enable receiver and interrupt
UCSRB = (1U << RXEN) | (1U << RXCIE);
// No parity, 8 Data Bits, 1 Stop Bit
// Not necessary! Mostly ATmega controller
// have 8 bit mode initialized at startup
//UCSRC = (1U << UCSZ1) | (1U << UCSZ0);
// If you are using ATmega8/16 it is necessary to do some
// special things to write to the UBRRH and UCSRC register!
// See ATmega16 datasheet at page 162
// Do not forget to enable interrupts globally!
sei();
while(1);
}
请解释 display()
函数的作用...
我有一个 ATTiny,它应该通过 UART 接收命令。我有一个由八个 LED 组成的简单显示器,应该显示最近接收到的字节的内容。我正在使用中断来读取接收到的数据。无论我发送什么数据,UDR 总是在中断中读取 0xFF
。我知道中断被触发,因为显示从 0x00
变为 0xFF
,但它从不显示我通过串行总线发送的值。
这就是我启用 UART 的方式。
UBRRH = UBRRH_VALUE;
UBRRL = UBRRL_VALUE;
#if USE_2X
UCSRA |= (1U << U2X);
#else
UCSRA &= ~(1U << U2X);
#endif
// Enable receiver and interrupt
UCSRB = (1U << RXEN) | (1U << RXCIE);
// No parity, 8 Data Bits, 1 Stop Bit
UCSRC = (1U << UCSZ1) | (1U << UCSZ0);
这是中断中的代码。我已经测试了 display()
并且它自己可以正常运行因此暗示 message
总是 0xFF
.
ISR(USART_RXC_vect) {
uint8_t message = UDR;
display(message);
}
我确信我的计算机正在发送正确的信息,但我只用伪终端测试它以打印出发送的字节。我打算用示波器窥探硬件连接,但我不认为这是问题所在。是否有什么原因导致 UDR 始终读取为 0xFF?
编辑: 我已经窥探了与示波器的连接,并验证了计算机正在以正确的速率发送正确的数据。然而,ATTiny 没有以正确的波特率运行。在 2400 波特率下,脉冲长度应约为 400 微秒,但微控制器产生的脉冲长度超过 3 毫秒。这解释了为什么它总是读取 0xFF,当控制器认为它正在接收起始位时,计算机将发送几乎整个字节,当控制器试图读取剩余数据时,线路将未被驱动,导致它读取所有数据。我仍然不知道为什么会这样,因为我相信我在控制器上正确设置了波特率。
编辑: 问题已解决。默认情况下,时钟预分频器设置为 8,因此该设备仅以 1MHz 而不是 8MHz 运行。将时钟预分频器设置为 1 解决了问题。
uart 通信可能存在几个问题。首先检查一些东西:
- 控制器是否配置了正确的时钟?
- Internal/External
- 是否为
定义了 F_CPU? - 是否为
定义了波特率? - 您是否使用像 ATmega16 这样具有特殊寄存器访问权限的控制器?
- 如果您使用的是外部时钟(不应分离),是否在某些控制器的 FUSES 或特殊寄存器中禁用了 CKDIV8?
- 是:
- 波特率,
- 奇偶校验位,
- 停止位 在发射器和接收器上设置正确
调试:
- 如果您使用 PC 进行通信,请在 UART 适配器上创建环回并使用终端(TeraTerm、Putty 等)检查您发送的消息是否被正确接收。
- 您还可以启用 TX 控制器并检查环回是否在您的 uC 上工作。
- 如果可能尝试将接收到的数据写入一些 LED 以检查是否接收到某个日期
- 接收器和发射器之间的GND是否连接?
- 发射器和接收器之间的电压电平是否相同?
- 发射器和接收器有自己的信号源吗? (那就不要接VCC!)
- 检查控制器上的时钟是否正确(每秒打开一个具有
_delay_ms()
功能的led)
示例程序
#define F_CPU 12000000UL
#define BAUD 9600UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/setbaud.h>
ISR(USART_RXC_vect)
{
volatile unsigned char message = UDR;
// If it is possible try to write the received data to
// LEDs (if there are some at your board)
display(message);
}
int main()
{
// To allow changes to clock prescaler it is necessary to set the
// CCP register (Datasheet page 23)!
CCP = 0xD8;
// RESET the clock prescaler from /8 to /1 !!!!
// Or it is necessary to divide F_CPU through the CLK_PRESCALER
CLKPSR = 0x00;
UBRRH = UBRRH_VALUE;
UBRRL = UBRRL_VALUE;
#if USE_2X
UCSRA |= (1<<U2X);
#else
UCSRA &= ~(1<<U2X);
#endif
// Enable receiver and interrupt
UCSRB = (1U << RXEN) | (1U << RXCIE);
// No parity, 8 Data Bits, 1 Stop Bit
// Not necessary! Mostly ATmega controller
// have 8 bit mode initialized at startup
//UCSRC = (1U << UCSZ1) | (1U << UCSZ0);
// If you are using ATmega8/16 it is necessary to do some
// special things to write to the UBRRH and UCSRC register!
// See ATmega16 datasheet at page 162
// Do not forget to enable interrupts globally!
sei();
while(1);
}
请解释 display()
函数的作用...