我希望你能帮助我解决这个非常奇怪的问题。我在这里尽可能多地综合了我的代码。
对 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;
}
}
所以,如果您同意,您可以写下您的答案,并提供一些解释,我很乐意将其标记为本次讨论的答案。 – 用户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;
}