0

我正在尝试使用 ATMEGA328P 实现中断驱动的 UART 通信。我需要实现的是通过 UART 发送命令(字符数组),以便将值提取到main例程中的变量中,以便我可以在电路中编程行为。

我发送的数据格式如下2 255 0 255 0 0 255 1000:(用于 RGB LED 灯)这描述long intmode、2 RGB 颜色和duration.

到目前为止,这就是我所拥有的main

while(1)
{
    if(rxFlag==1){
        char * pEnd;
        mode = strtol(buffer,&pEnd,10);
        Ri = strtol (pEnd, &pEnd,10);
        Gi = strtol (pEnd, &pEnd,10);
        Bi = strtol (pEnd, &pEnd,10);
        Rf = strtol (pEnd, &pEnd,10);
        Gf = strtol (pEnd, &pEnd,10);
        Bf = strtol (pEnd, &pEnd,10);
        duration = strtol (pEnd,NULL,10);
        rxFlag=0;
    }

    switch(mode){
        case 1: // fixed color
            fixed(Rf, Gf, Bf);
            break;
        case 2: // yoyo pulse
            yoyo(Ri,Gi,Bi,Rf,Gf,Bf,duration);
            break;
        default:// red blinky
            fixed(0,255,255);
            _delay_ms(500);
            fixed(255,255,255);
            _delay_ms(500);
            break;

    }
}

以及处理接收的 ISR(中断服务程序):

ISR(USART_RX_vect)
{   
   while ( !(UCSR0A & (1<<RXC0)) );
   if (rxn==80){ // if BUFFER_SIZE is reached, reset to start of buffer.
       rxn=0;
   }
   buffer[rxn++] = UDR0; // increment rxn and return new value.
   if(buffer[rxn]=='\0'){
    rxFlag=1; // notify main of receipt of data.
   }
}

如您所见,我仅在检测到\0流末尾的 时才尝试更新变量的值。

这就像(在 ISR 中):

  • 读取传入的字节并将其存储在最多 80 字节长的缓冲区中
  • 如果一个\0进来,让主知道它有新数据要处理

main

  • 如果有新数据,将缓冲区分成long int并存储值
  • 清除新数据标志
  • 根据新的价值观行事。

问题是这并没有按照我的意愿进行,我有点迷路了。我知道我的switch陈述可以正常工作,因为变量具有正确的值。我已将问题缩小到通信/缓冲区填充阶段被破坏或变量值的提取被破坏,但不确定是哪一个或两者都有。

任何人都可以分享任何见解吗?

4

1 回答 1

1

编辑:有更多时间考虑这个问题。忽略我之前的回答。

确保使用关键字volatile声明您的缓冲区。

您在不执行任何处理的情况下进行包装的事实也令人担忧。对于循环缓冲区,跟踪头部、尾部和当前大小要好得多。

#define BUFF_MAX_BYTES 80

#define TRUE 1
#define FALSE 0

typedef unsigned char boolean;

static volatile unsigned char buff[BUFF_MAX_BYTES];

static volatile unsigned char buffHead = 0;
static volatile unsigned char buffTail = 0;
static volatile unsigned char buffSize = 0;

boolean store_byte(unsigned char b)
{
    boolean success = TRUE;

    if(buffSize < BUFF_MAX_BYTES){
        buff[buffTail] = b;
        buffSize++;
        buffTail = (buffTail + 1) % BUFF_MAX_BYTES;
    } else{
        success = FALSE;
    }

    return success;
}

boolean eol_received(void)
{
    unsigned char prev_index = (buffTail == 0) ? BUFF_MAX_BYTES - 1 : buffTail - 1;
    boolean eol = FALSE;

    if(buff[prev_index] == '\0'){
        eol = TRUE;
    }

    return eol;
}

// Because strtol has no conception of where the buffer ends and wraps, you
// will have to create a modified version that can handle this case.
//
// A simple approach would be to calculate the length of your message, copy
// it to another buffer for parsing (advancing buffHead as you read bytes),
// and then call strtol on this new buffer.

ISR(USART_RX_vect)
{   
    while ( !(UCSR0A & (1<<RXC0)) );

    if(!store_byte(UDR0)){
        // Use a flag to inform main() of overflow, handle as appropriate
    }

    rxFlag = eol_received() ? 1 : 0;
}
于 2014-06-23T23:30:07.887 回答