TCC 计时器在 ATXMEGA16E5 上明显无故停止

问题描述 投票:0回答:1

我希望你能帮助我解决这个非常奇怪的问题。我在这里尽可能多地综合了我的代码。

对 10 台相同设备进行统计,大约一半设备出现完全相同的问题,而其他设备则正常工作。

我使用uart向ATXMEGA16E5发送文本命令。

每个文本命令均由“myFunction”处理,更新索引“myIndex”处数组“Values”的特定值。

只有当“myIndex”等于3并且执行“InputValue”函数时(参见代码右侧的箭头),TCC4定时器才会停止。显然,函数和定时器之间没有任何联系。

如果我关闭然后打开并使用具有“myIndex”的所有其他值的同一设备,则不会出现问题。

我在单独的虚拟 C 程序上检查了“CommaIndex”和“InputValue”函数,它们都正常。

提前谢谢您。

#define BUFLEN 50       // for UART
#define CHARGE_LVLs     10 
char Rxbuf[BUFLEN];
volatile uint16_t Values[LVLs] = {12400, 4600, 2250, 1150, 430, 210, 15980, 15630, 15000, 13700};

int main(void)
{
    ...
    RTCInit();
    IRQInit(1, 1, 1);
    TimerInit();
    ...
    sei();
    
    while(1) 
    {
        ... 
        if(Rxflag==1)
        {
            if (strstr(Rxbuf, "myString,"))
                myFunction();
            Rxflag=0;
        }

    }
}

void myFunction()
{
    if(strstr(Rxbuf, ",abc,")) {myIndex=0; isUpdated = 1;}
    if(strstr(Rxbuf, ",def,")) {myIndex=1; isUpdated = 1;}
    if(strstr(Rxbuf, ",ghi,")) {myIndex=2; isUpdated = 1;}
    if(strstr(Rxbuf, ",lmn,")) {myIndex=3; isUpdated = 1;} // <------
    if(strstr(Rxbuf, ",opq,")) {myIndex=4; isUpdated = 1;}
    if(strstr(Rxbuf, ",rst,")) {myIndex=5; isUpdated = 1;}
    if(strstr(Rxbuf, ",uvz,")) {myIndex=6; isUpdated = 1;}
    if(strstr(Rxbuf, ",123,")) {myIndex=7; isUpdated = 1;}
    if(strstr(Rxbuf, ",456,")) {myIndex=8; isUpdated = 1;}
    if(strstr(Rxbuf, ",789,")) {myIndex=9; isUpdated = 1;}
    
    if(isUpdated == 1)
    {
        if(strstr(Rxbuf, WRITE_CALIB))
        {
            comma_index = CommaIndex(s, BUFLEN);
            if (InputValue(s, comma_index) > MAXVALUE) // <------
                Values[myIndex] = MAXVALUE;
            else
                Values[myIndex] = InputValue(s, comma_index);
            
            answ=1;
            UsartSendString(OK);
        }
    }
    
    UsartSendString("\r\n");
}

char CommaIndex(char s[], char strlength)
{
    int i;
    
    for(i=5; i<strlength; i++)  
        if (s[i] == ',')
        break;
    return (char)i;
}

uint16_t InputValue(char s[], char comma_index)
{
    return atoi(s+comma_index+1);
}

void IRQInit(char hi, char med, char lo) {
    PMIC.CTRL = (hi<<PMIC_HILVLEN_bp)|(med<<PMIC_MEDLVLEX_bp)|(lo<<PMIC_LOLVLEN_bp);
}

void RTCInit(void) {
    RTC.PER = 100;                              // 100ms
    RTC.INTCTRL = RTC_OVFINTLVL_MED_gc;         
    RTC.CTRL = RTC_PRESCALER_DIV1_gc;           // No prescaler
}

void TimerInit(void)
{
    TCC4.CTRLA =  TC_CLKSEL_DIV64_gc;           // CLKSEL=DIV64 : 32MHz/64=500KHz
    TCC4.PER = 4;                               // 500KHz/4 = 125KHz        @ 32 MHz
    TCC4.INTCTRLA = TC_CCAINTLVL_HI_gc;         // Int pri HI 
    TCC4.CTRLGCLR = 0b00000000;                 // Up direction
}

// *** Timer Overflow: 125KHz (8us) ***
ISR(TCC4_OVF_vect)
{
    if(emission)
    {
        PULSE_ON;
        
        emission = 0;
    }
    else
    {
        PULSE_OFF;
    }
    
    //************************************
    // Only for debug *********
    interruptCounter++;
    
    if (interruptCounter > 125000)
    {
        UsartSendString("Running");
        interruptCounter = 0;
    }
    //************************************

    TCC4.INTFLAGS = 1;
}

************************ 更新**************************** **********

抱歉我长时间沉默,但我需要一些时间来执行Craig Estey建议的一些测试,我真诚地感谢他的关注。

我尝试回答他的问题并提供一些评论和代码以便清楚起见。

“strstr 是字符串函数,因此它在末尾需要一个 0x00 终止符” -> 我在 RxBuf 中的字符串末尾强制使用 0x00 终止符。问题仍然存在。

发送到 atmega 的消息格式为:cmnd,lmn,1000,其中 cmnd 始终是 4 个字符的单词,lmn 是 myFunction 中提供的组合之一(见上文),1000 是0 到 16383 之间的数字。

我知道缓冲区何时有完整消息检查‘ ’ 始终存在的字符。

我确信 myFunction 被调用一次,并且在给定消息的过程中它不会受到干扰。我仔细检查了这一点。

即使出现问题,Rx ISR 也不会丢弃传入数据,因为Values数组已正确更新。

我看到的是:

  • 如果在
    myFunction
    中对两行
    UsartSendString
    进行了注释,则不会出现该问题。
  • 如果在
    UsartTxChar
    中添加 1 毫秒延迟(见下文),即使将
    UsartSendString
    中的两行
    myFunction
    保留为未注释,也不会出现该问题。 这实际上可能是一个解决方案,但我不确定这是真正的解决方案,而不仅仅是一个解决方法。
void
UsartInit(void)
{

    USARTC0.CTRLA = USART_DRIE_bm | USART_RXCINTLVL_MED_gc; // RX Int + Med pri
    USARTC0.CTRLB = USART_RXEN_bm | USART_TXEN_bm;  // RX & TX enable, Clk 1x
    USARTC0.CTRLC = USART_CMODE_ASYNCHRONOUS_gc | USART_CHSIZE_8BIT_gc; // Asynch, 8 bit, 1 stop, par none
    USARTC0.CTRLD = 0;                  // No encoding
    USARTC0.BAUDCTRLA = 51;             // BSEL
    USARTC0.BAUDCTRLB = 0b00100000;     // BSCALE 2 @ 32MHz
}

void
UsartTxChar(char b)
{
    USARTC0.DATA = b;

    _delay_ms(1);  // <---- THIS SOLVES THE ISSUE *****************

    while (!(USARTC0.STATUS & USART_TXCIF_bm)) {
    };

}

void
UsartSendString(char *b)
{
    int i;

    i = 0;
    while (b[i]) {
        UsartTxChar(b[i]);
        i++;
    }
}

ISR(USARTC0_RXC_vect)
{

    Rxchar = USARTC0.DATA;

    if (!Rxflag) {
        Rxbuf[Rxpnt] = Rxchar;
        Rxpnt++;
        if (Rxpnt == BUFLEN)
            Rxpnt--;
    }

    if (Rxchar == '\n') {
        Rxflag = 1;
        Rxpnt = 0;
    }
}
c timer interrupt atmega
1个回答
0
投票

所以,如果您同意,您可以写下您的答案,并提供一些解释,我很乐意将其标记为本次讨论的答案。 – 用户1941332

好的。其中大部分内容都包含在热门评论中。

如果向间歇性失败的代码添加延迟“修复”了问题,那么这意味着程序尚未修复。真正的问题只是被掩盖了。

这是您的传输代码:

void
UsartTxChar(char b)
{
    USARTC0.DATA = b;

    _delay_ms(1);                       // <---- THIS SOLVES THE ISSUE *****************

    while (!(USARTC0.STATUS & USART_TXCIF_bm)) {
    };

}

正确的 USART 发送功能指出了问题。我们必须旋转状态寄存器,等待发送缓冲区被清除,然后才能向发送器输出新字符。 而且,您测试的状态位不正确。这是重构的代码:

void UsartTxChar(char b) { while (! (USARTC0.STATUS & USART_DREIF_bm)); USARTC0.DATA = b; }

© www.soinside.com 2019 - 2024. All rights reserved.