【问题标题】:AVR gcc, weird array behaviourAVR gcc,奇怪的数组行为
【发布时间】:2016-06-11 12:44:49
【问题描述】:

这是我第一次看到这样的东西。我开始怀疑这是硬件故障。 每当我尝试发送数组“test”的内容并且该数组大于 4 个元素时,或者我初始化声明中的所有元素时,它都包含 0xff 而不是我尝试初始化的值。

这很好用。当我在 while 中从数组中读取值(将它们发送到 lcd 和 uart)时,两个读数都与测试值一致:

uint8_t i=0;
uint8_t test[4] = {1,2,3,4};
     while(i<5){
     GLCD_WriteData(test[i]);
     USART_Transmit(test[i]);
     i++;
 }

这不是,它返回 0xff 而不是 test[i] 值:

uint8_t i=0;
uint8_t test[5] = {1,2,3,4,5};
     while(i<5){
     GLCD_WriteData(test[i]);
     USART_Transmit(test[i]);
     i++;
 }

但这行得通!它返回正确的值

uint8_t i=0;
uint8_t test[6] = {1,2,3,4,5};
     while(i<5){
     GLCD_WriteData(test[i]);
     USART_Transmit(test[i]);
     i++;
 }

这也有效:

uint8_t i=0;
uint8_t test[5];
test[0]=1;
test[1]=2;
test[2]=3;
test[3]=4;
test[4]=5;
     while(i<5){
     GLCD_WriteData(test[i]);
     USART_Transmit(test[i]);
     i++;
     }

在 linux 上编译时可以正常工作

我将一个 mcu 换成了另一个 mcu,它按应有的方式工作。应该是硬件问题

【问题讨论】:

  • 这个问题不是特别清楚。请不要只是粘贴代码并让我们在心理上区分它。 解释问题是什么。你说“返回 0xFF”——从哪里来?该代码未在任何地方显示。如果您的问题在于传输,我们为什么要关心接收端的结果?隔离问题。你正在发送一个UART,对吧?那么显而易见的调试步骤是查看端口实际输出的内容。
  • 您意识到,即使您的数组大小发生变化,循环的边界也不会改变,对吧?总是while(i&lt;5)。这就是为什么 ARRAY_LENGTH 宏很有用的原因。
  • 我编辑了我的帖子以正确形成它。问题是,当我以通常的方式初始化数组时,数组 []={1,2,3} 并且它大于 4 个元素而不是我的值,它包含 0xff。当我声明一个 6 个或更多元素数组并初始化它跳过最后一个元素时,它工作正常。我没有因为懒惰而改变 (i
  • 我假设在您的第一个块中,while 应该是 while (i&lt;4) {?
  • 端口可能存在流量控制问题

标签: c arrays gcc avr


【解决方案1】:

在第一个示例中,您将超出数组 test[4] 的范围。当数组只有 4 项长度时,您正在运行 5 次。

【讨论】:

  • 虽然他说第一个例子有效,但第二个例子没有。
【解决方案2】:

我认为您的问题是 USART 超载。我假设GLCD_WriteData() 非常快,并且USART_Transmit() 缓冲字符以进行传输,然后快速返回。我不知道你的硬件,所以我不能说 - 但是 USART 的四字符缓冲区听起来很合理。

您的五字符示例不起作用,因为您尝试传输的实际字符丢失了 - 所以它会放入 0xFF。您需要检查 USART 缓冲区的状态并等待它显示可用空间(注意 NOT 为空 - 效率低下!)。

在 8250 和 16450 UART 芯片中有两个状态位:

  • TSRET传输 Shift Register 是 E空的;
  • THRETransmit Holding Register 是 Empty。

THRE 可以设置,即使TSRE 不是 - 它很忙。我会测试 TSRE 并且在有空间之前不发送下一个字符 - 或者设置一个缓冲区和一个中断处理程序。

【讨论】:

  • I/O 硬件没有问题,MCU 检查 lcd 上的忙标志,并且 USART_transmit 只是一个单字符硬件缓冲区并且是空的,而这会停止程序,直到设置缓冲区空标志。我可以创建一个包含 128 个元素的数组,在 while 循环中为它们分配值,它会很好地打印出来。出于某种奇怪的原因,如果我执行 array[5] = {1,2,3,4,5} 并通过 while 循环读取它,它都是 0xFF。还有一件事,如果我一个一个地阅读它: USART_Transmit(array[0]).. to 5 很好,但是如果我在该代码中添加一个 read by while 它在​​两种情况下都会突然变成 0xff
【解决方案3】:

如果不是 I/O 硬件,那么我唯一能想到的另一件事就是编译器生成了不正确的代码。 USART_Transmit() 的确切声明是什么?它是否期望uint8_t?或者别的什么,比如int(出于某种原因)?

如果是别的东西,比如int,请试试下面的代码:

while(i<5){
    int c = test[i];         // Whatever USART_Transmit wants
    GLCD_WriteData(test[i]);
    USART_Transmit(c);
    i++;
} // while

如果这总是有效,那么您遇到的是编译器问题,而不是硬件问题。

编辑:提供USART_Transmit() 的代码:

void USART_Transmit( uint8_t data ) {
//Wait for empty transmit buffer
while( !( UCSR0A &amp; (1&lt;&lt;UDRE0)) );
//Put data into buffer, sends the data
UDR0 = data;
}

你有比 JTAG更好的东西 - 你有一个 LCD 显示器!虽然我不知道它有多少个字符,或者传输一个字符需要多长时间......

你可以试试这样的:

char Hex(uint8_t nibble) {
    return nibble<10 ?
           '0'+nibble :
           'A'+nibble-10;
} // Hex
...
void Send(uint8_t c) {
    uint8_t s;
    UDR0 = c; // Send character NOW: don't wait!
    do {
        s = UCSR0A; // Get current USART state
        //s = UCSR0A & (1<<UDRE0); // Or this: isolate ready bit...
        GLCD_WriteData('x');
        GLCD_WriteData(Hex(s >> 4));  // Write state-hi hex
        GLCD_WriteData(Hex(s & 0xF)); // Write state-lo hex
    } while (!(s & (1<<UDRE0)));      // Until is actually ready
} // Send(c)
...
Send('A');
Send('B');
Send('C');

假设 UDRE0 为 3,那么该代码将产生类似 x00x00x00x00x00x08x00x00x00x00x08x00x00x00x08 的序列(如果它正在工作)。如果它产生x08x08x08,那么你有一个卡住的 UCSR0A 位,它是硬件。

【讨论】:

  • void USART_Transmit( uint8_t data ) { //等待空传输缓冲区 while( !( UCSR0A & (1
【解决方案4】:

老问题,但给出我的反馈,因为这是我在搜索相同问题的解决方案时收到的第一个地方,甚至与原始问题中的代码示例得到完全相同的结果。

据我所知,这是一个糟糕的 Makefile,导致 avr-objcopy 遗漏了一些部分。

例如,在我的例子中,用于构建导致此问题的示例十六进制的原始参数:

${OBJCOPY} -j .text -O ihex led.elf led.hex

什么效果更好:

${OBJCOPY} -O ihex -R .eeprom led.elf led.hex

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-11-25
    • 2011-12-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-06
    • 1970-01-01
    • 1970-01-01
    • 2015-02-24
    相关资源
    最近更新 更多