这是我单片机主循环函数,在我发送开启笔模式的时候,开始调用处理笔数据的函数,但是这个函数是不是会无线循环导致后面发送的usb命令和串口命令都无法接收到 while(1) { // 调用处理笔数据的函数 if (GetPenMode() == 0x01) { // 如果成功处理数据,则可以进一步处理 PenBuf,或者做其他逻辑 //printf("[0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x]\n", //PenBuf[0],PenBuf[1],PenBuf[2],PenBuf[3],PenBuf[4],PenBuf[5],PenBuf[6],PenBuf[7],PenBuf[8],PenBuf[9]); if(ProcessPenData()) { USB_Send(USB_ENDPOINT_INDEX,PenBuf,10); } } //获取usb命令 switch(Get_hid_CC()){ case 0x01: printf("软件复位!!!\n"); soft_reset(); break; case 0x02: printf("获取设备状态!!!\n"); //添加检查状态代码 //end UINT8 CD[3]={0xE5,0x01,0x00}; lenth= setRetBuf_CD(OZHX_OK,0x02,&CD[0],sizeof(CD)); USB_Send(USB_ENDPOINT_INDEX, retBuf, lenth); break; case 0x03: printf("获取设备信息!!!\n"); UINT8 SN[8] = {0x00}; ReadChipSN(SN); UINT8 CD_DATA_Status[]={0xD0,0x03,venderN[0],venderN[1],venderN[2], 0xD1,0x0f,fwVersion[0],fwVersion[1],fwVersion[2],fwVersion[3],fwVersion[4],fwVersion[5], fwVersion[6],fwVersion[7],fwVersion[8],fwVersion[9],fwVersion[10],fwVersion[11], fwVersion[12],fwVersion[13],fwVersion[14], 0xD2,0x04,0x00,0x00,HI_BYTE(SCREEN_W),LO_BYTE(SCREEN_W), 0xD3,0x04,0x00,0x00,HI_BYTE(SCREEN_H),LO_BYTE(SCREEN_H), 0xD4,0x02,HI_BYTE(PRESSURE_MAX),LO_BYTE(PRESSURE_MAX), 0xD5,0x08,SN[0],SN[1],SN[2],SN[3],SN[4],SN[5],SN[6],SN[7], 0xD9,0x02,HI_BYTE(MAXPACKLEN),LO_BYTE(MAXPACKLEN) }; lenth = setRetBuf_CD(OZHX_OK,0x03,&CD_DATA_Status[0],sizeof(CD_DATA_Status)); USB_Send(USB_ENDPOINT_INDEX, retBuf, lenth); break; case 0x10: if(GetPenMode() == 0x01) { printf("开启笔签字模式\n"); } else if(GetPenMode() == 0x02) { printf("关闭笔签字模式\n"); } break; default: break; } //获取串口命令 if (UART_RecvByte(SCI2,&data) == TRUE)//串口接收到数据 { /************************端点1发送测试******************************/ if(data == 0x30) { send_buffer[0] = 0x1c; send_buffer[1] = send_buffer[1]+1; USB_Send(USB_ENDPOINT_INDEX, send_buffer, 10); data = 0x00; } if(data == 0x31) { send_buffer[0] = 0x1b; send_buffer[1] = send_buffer[1]+1; USB_Send(USB_ENDPOINT_INDEX, send_buffer, 64); data = 0x00; } if(data == 0x32) { soft_reset(); data = 0x00; } } }// ProcessPenData函数,用于读取10个字节数据并处理 INT8 ProcessPenData() { UINT8 tempBuf[GET_DATA_LENGTH]; // 临时缓冲区,用于存储每次读取的 10 个字节 UINT8 dataByte; INT8 status; UINT16 i = 0; // 读取 10 个字节的数据 while (i < GET_DATA_LENGTH) { status = UART_RecvByte(SCI_BT, &dataByte); // 从SCI_BT串口读取一个字节 if (status) // 如果成功接收到数据 { tempBuf[i] = dataByte; // 存储到临时缓冲区 i++; // 读取字节计数增加 } } // 如果数据符合条件,则进行处理 if (tempBuf[0] == 0x80 || tempBuf[0] == 0xA0 || tempBuf[0] == 0xA1) { // 清除不需要的字节 tempBuf[7] = 0x00; tempBuf[8] = 0x00; tempBuf[9] = 0x00; // 构造 PenBuf 数据 PenBuf[0] = 0x1C; PenBuf[1] = 0x01; PenBuf[2] = (tempBuf[2] << 2) | ((tempBuf[6] >> 5) & 0x03); // X-axis Low Byte PenBuf[3] = (tempBuf[1] << 1) | ((tempBuf[2] & 0x40) >> 6); // X-axis High Byte PenBuf[4] = (tempBuf[4] << 2) | ((tempBuf[6] >> 3) & 0x03); // Y-axis Low Byte PenBuf[5] = (tempBuf[3] << 1) | ((tempBuf[4] & 0x40) >> 6); // Y-axis High Byte PenBuf[6] = ((tempBuf[6] & 0x01) << 7) | (tempBuf[5]); // Pen pressure Low Byte PenBuf[7] = (tempBuf[6] & 0x06) >> 1; // Pen pressure High Byte PenBuf[8] = 0x00; PenBuf[9] = 0x00; } return 1; // 返回 1 表示数据处理成功 }
时间: 2025-06-22 07:21:34 浏览: 13
<think>嗯,用户的问题是关于他们的单片机主循环函数在发送开启笔模式后,处理笔数据的函数是否会导致无限循环,从而无法接收后续的USB和串口命令。我需要仔细分析他们提供的代码,找出可能的问题点。
首先,主循环是一个while(1)结构,里面依次处理笔数据、USB命令和串口命令。看起来这三个部分是按顺序执行的。当GetPenMode()返回0x01时,会调用ProcessPenData()函数。然后继续处理USB和串口命令。
但用户担心ProcessPenData()会不会导致无限循环。看一下ProcessPenData()的代码,这个函数内部有一个while循环,试图读取10个字节的数据。每次循环调用UART_RecvByte,如果成功接收数据,就存入tempBuf,直到读完10个字节。问题在于,如果UART_RecvByte在没有数据的时候会阻塞或者返回失败,那么这里可能会一直等待,导致整个主循环卡在这里,无法继续执行后面的USB和串口处理。
比如,如果SCI_BT串口的数据不够10个字节,UART_RecvByte可能会一直等待,导致i无法增加到10,从而一直卡在while循环里。这样,主循环中的其他部分(如Get_hid_CC()和UART_RecvByte(SCI2))就无法及时执行,导致后续命令无法处理。
接下来,我需要确认UART_RecvByte的实现。如果这个函数是阻塞式的,即没有数据时会一直等待,那么确实会导致ProcessPenData()卡住,进而阻塞整个主循环。如果UART_RecvByte是非阻塞的,返回false或类似状态,那么ProcessPenData可能在数据不足时立即返回,但根据用户代码中的ProcessPenData返回1,似乎无论如何都会返回成功,这可能有问题。
另外,主循环的结构是否有问题?当进入处理笔数据时,每次循环都会调用ProcessPenData,而该函数内部可能阻塞,导致主循环无法及时处理其他命令。应该建议用户采用非阻塞的方式读取数据,例如使用缓冲区累积数据,而不是在ProcessPenData中一次性读取10个字节,这样可以避免阻塞。
可能的解决方案包括:修改ProcessPenData函数,使其非阻塞,每次只读取当前可用的数据,并记录已读取的字节数,等累积到10个字节再处理。或者,在主循环中增加超时机制,避免长时间阻塞。另外,检查UART_RecvByte的实现,确保它不会无限等待数据,而是立即返回是否有数据可用。
另外,用户的主循环中的if (GetPenMode() == 0x01)条件,是否在开启笔模式后一直为真,导致每次循环都进入ProcessPenData,如果ProcessPenData内部阻塞,就会导致后面的代码无法执行。因此,可能需要调整逻辑,确保在处理笔数据时,不会妨碍其他命令的处理。
总结问题原因:ProcessPenData中的while循环可能在数据不足时阻塞,导致主循环无法继续执行后续的USB和串口命令处理。需要将数据读取改为非阻塞方式,或者确保UART_RecvByte不会阻塞,从而允许主循环继续运行。</think>根据代码逻辑分析,确实存在因`ProcessPenData()`的阻塞式读取导致主循环卡死的风险。以下是逐步说明和解决方案:
---
### 一、问题定位
#### 1. `ProcessPenData()`的阻塞逻辑
代码中以下部分会造成**同步阻塞**:
```c
while (i < GET_DATA_LENGTH) {
status = UART_RecvByte(SCI_BT, &dataByte);
if (status) {
tempBuf[i] = dataByte;
i++;
}
}
```
- **风险点**:如果`UART_RecvByte()`是阻塞式读取(即无数据时持续等待),此循环会卡在未收到足够数据的状态,导致主循环无法继续执行后续的`Get_hid_CC()`和串口命令处理。
---
### 二、影响分析
1. **USB命令无法响应**
当卡在`ProcessPenData()`时,`switch(Get_hid_CC())`无法被及时执行,USB命令队列会堆积或丢失。
2. **串口命令无法处理**
主循环无法进入`UART_RecvByte(SCI2,&data)`的判断逻辑,导致串口数据无法被读取。
---
### 三、解决方案
#### 方案1:改用非阻塞读取(推荐)
修改`ProcessPenData()`的逻辑,仅读取当前可用的数据:
```c
INT8 ProcessPenData() {
static UINT8 bufferIndex = 0; // 静态变量保存读取进度
UINT8 dataByte;
while (bufferIndex < GET_DATA_LENGTH) {
if (UART_RecvByte(SCI_BT, &dataByte) == TRUE) {
tempBuf[bufferIndex] = dataByte;
bufferIndex++;
} else {
return 0; // 无数据时立即退出,等待下次调用
}
}
bufferIndex = 0; // 重置索引
// 后续数据处理...
return 1;
}
```
#### 方案2:增加超时机制
在读取数据时加入超时判断,避免无限等待:
```c
INT8 ProcessPenData() {
UINT8 tempBuf[GET_DATA_LENGTH];
UINT32 timeout = 0;
UINT8 i = 0;
while (i < GET_DATA_LENGTH && timeout < MAX_TIMEOUT) {
if (UART_RecvByte(SCI_BT, &tempBuf[i])) {
i++;
}
timeout++;
DelayUs(10); // 适当延时防止忙等
}
if (i == GET_DATA_LENGTH) {
// 数据处理...
return 1;
}
return 0; // 超时返回失败
}
```
---
### 四、主循环优化建议
1. **异步事件驱动**
使用中断或DMA接收UART数据,将数据存入缓冲区,主循环只需检查缓冲区是否完整。
```c
// 中断服务例程中填充缓冲区
void UART_ISR() {
static UINT8 index = 0;
UART_RecvByte(SCI_BT, &tempBuf[index]);
index = (index + 1) % GET_DATA_LENGTH;
}
```
2. **状态机设计**
将笔数据处理、USB命令、串口命令拆分为独立状态,通过标志位协调执行顺序。
---
### 五、验证方法
1. **调试输出**
在`ProcessPenData()`中加入调试信息,观察是否每次调用都能及时返回:
```c
printf("ProcessPenData: Read %d bytes\n", i);
```
2. **压力测试**
同时发送大量USB命令和笔数据,观察系统是否能正常响应。
---
通过上述修改,可确保主循环不会因单个功能阻塞而影响整体实时性。
阅读全文
相关推荐
















