用LM3S9B92写了一个CAN转UART的程序,里面有个很奇特的bug


如题,这个bug是这样的:我用CAN调试工具给板子发数据,如果每帧定义8个字节,发一帧二帧没问题,到三帧以上的时候,串口那边就会少显示一个字节,而每帧定义少于8个字节的时候发多少帧都没有问题。代码如下:

   
  #include "inc/hw_ints.h"
  
#include "inc/hw_memmap.h"
#include "inc/hw_sysctl.h"
#include "inc/hw_can.h"
#include "inc/hw_gpio.h"
#include "inc/hw_uart.h"
#include "inc/hw_types.h"
#include "driverlib/can.h"
#include "driverlib/debug.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/rom.h"
#include "driverlib/sysctl.h"
#include "driverlib/systick.h"
#include "driverlib/uart.h"
#include "utils/uartstdio.h"

// CAN先进先出队列的大小
#define CAN_FIFO_SIZE (8 * 16)

volatile unsigned long g_ulMsg1Count = 0;
volatile unsigned long g_ulMsg2Count = 0;
volatile unsigned long g_bErrFlag = 0;
volatile unsigned long g_bRXFlag1 = 0;

tCANMsgObject g_sCANMsgObject1;
tCANMsgObject g_sCANMsgObject2;

// 接收缓冲区
unsigned char g_ucMsg1[CAN_FIFO_SIZE];
// 发送缓冲区
unsigned char g_ucMsg2[CAN_FIFO_SIZE];
// UART数据缓冲区
unsigned char g_ucUartData[CAN_FIFO_SIZE];

//*****************************************************************************
//
// CAN0中断服务程序
//
//****************************************************************************
void CAN0IntHandler(void)
{
unsigned long ulStatus;

ulStatus = ROM_CANIntStatus(CAN0_BASE,CAN_INT_STS_CAUSE);
if(ulStatus == CAN_INT_INTID_STATUS)
{
ulStatus = ROM_CANStatusGet(CAN0_BASE,CAN_STS_CONTROL);
g_bErrFlag = 1;
}
//
// 前16个消息对象为接收缓冲区
//
else if(ulStatus <= 16)
{
//
//读取数据
//
ROM_CANMessageGet(CAN0_BASE, ulStatus, &g_sCANMsgObject1, 1);
//
//移动缓冲区读指针
//
g_sCANMsgObject1.pucMsgData += g_sCANMsgObject1.ulMsgLen;
g_ulMsg1Count += g_sCANMsgObject1.ulMsgLen;
g_bRXFlag1 = 1;
g_bErrFlag = 0;
}
//
// 后16个消息对象为发送缓冲区
//
else
{
ROM_CANIntClear(CAN0_BASE, ulStatus);
g_ulMsg2Count += g_sCANMsgObject2.ulMsgLen;;
g_bErrFlag = 0;
}
}

//*****************************************************************************
//
// UART0中断服务程序
//
//*****************************************************************************
void UART0IntHandler(void)
{
unsigned char i = 0;
unsigned char count = 0;
unsigned long ulStatus;

ulStatus = ROM_UARTIntStatus(UART0_BASE, true);
ROM_UARTIntClear(UART0_BASE, ulStatus);

while(ROM_UARTCharsAvail(UART0_BASE))
{
g_ucUartData[count]=ROM_UARTCharGetNonBlocking(UART0_BASE);
count++;
if(count==CAN_FIFO_SIZE)
{
break;
}
ROM_SysCtlDelay(ROM_SysCtlClockGet()/150);
}

//
// 防止超时中断误动作
//
if(count>0)
{
//
// 闪烁用户指示灯LED
//
ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_0, ~ROM_GPIOPinRead(GPIO_PORTD_BASE, GPIO_PIN_0));

for(i=0; i<count; i++)
{
g_ucMsg2[i] = g_ucUartData[i];
g_ucUartData[i] = 0;
}

//
// 发送报文
//
g_sCANMsgObject2.ulMsgID = 0x00; // 无报文ID
g_sCANMsgObject2.ulMsgIDMask = 0x00; // 无报文ID屏蔽码
g_sCANMsgObject2.ulFlags = MSG_OBJ_TX_INT_ENABLE;
for(i = 0; i < (count / 8) ;i++)
{
g_sCANMsgObject2.ulMsgLen = 8;
g_sCANMsgObject2.pucMsgData = &g_ucMsg2[i * 8];
if(i != (count/8 - 1) || (count % 8) != 0)
{
//
// 指示非最后一帧数据
//
g_sCANMsgObject2.ulFlags |= MSG_OBJ_FIFO;
}
else
g_sCANMsgObject2.ulFlags &= ~MSG_OBJ_FIFO;
ROM_CANMessageSet(CAN0_BASE, i+17, &g_sCANMsgObject2, MSG_OBJ_TYPE_TX);
}
if((count % 8) != 0)
{
//
// 发送最后一帧数据
//
g_sCANMsgObject2.ulMsgLen = count % 8;
g_sCANMsgObject2.pucMsgData = &g_ucMsg2[i * 8];
g_sCANMsgObject2.ulFlags &= ~MSG_OBJ_FIFO;
ROM_CANMessageSet(CAN0_BASE, i+17, &g_sCANMsgObject2, MSG_OBJ_TYPE_TX);
}
}
}

//
// 初始化接收缓冲区
//
void
CANFIFOInit(unsigned long ulSize)
{
int i;

g_sCANMsgObject1.ulMsgID = 0x00;
g_sCANMsgObject1.ulMsgIDMask = 0x00;
g_sCANMsgObject1.ulFlags = MSG_OBJ_RX_INT_ENABLE;
g_sCANMsgObject1.pucMsgData = g_ucMsg1;

for(i=0; i<ulSize ; i++)
{

if(i != (ulSize-1) )
{

//
// 指示非最后一帧
//
g_sCANMsgObject1.ulFlags |= MSG_OBJ_FIFO;
}
else
{
//
// 清除非最后一帧标志
//
g_sCANMsgObject1.ulFlags &= ~MSG_OBJ_FIFO;
}
g_sCANMsgObject1.ulMsgLen = 8;
ROM_CANMessageSet(CAN0_BASE, i + 1, &g_sCANMsgObject1, MSG_OBJ_TYPE_RX);
}
}

//*****************************************************************************
//
// 主函数
//
//*****************************************************************************
int
main(void)
{

int i;
// unsigned long iLen;
//
// 设置外部8MHz晶振为系统时钟源。
//
/*ROM_SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
SYSCTL_XTAL_8MHZ); */
ROM_SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN |
SYSCTL_XTAL_16MHZ);

//
// 使能用户指示灯用到的端口D。
//
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);

//
// 配置D端口的第0脚为输出模式,驱动用户指示灯。
//
ROM_GPIOPinTypeGPIOOutput(GPIO_PORTD_BASE, GPIO_PIN_0);
ROM_GPIOPadConfigSet(GPIO_PORTD_BASE, GPIO_PIN_0, GPIO_STRENGTH_2MA,
GPIO_PIN_TYPE_STD_WPU);

//
// 设置指示灯初始状态:熄灭。
//
ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_0, 0);

//
// 使能外设UART0。
//
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

//
// 将GPIO A0和A1管脚设置为UART0功能管脚。
//
ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

//
// 配置UART0为115200波特率、8-N-1 数据模式。
//
ROM_UARTConfigSetExpClk(UART0_BASE, ROM_SysCtlClockGet(), 115200,
(UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
UART_CONFIG_PAR_NONE));

//
// 使能UART0中断,中断源为接收中断和超时中断。
//
ROM_IntEnable(INT_UART0);
ROM_UARTIntEnable(UART0_BASE, UART_INT_RX | UART_INT_RT);

//
// 配置CAN0
//
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_CAN0);
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
ROM_GPIOPinConfigure(GPIO_PB4_CAN0RX);
ROM_GPIOPinConfigure(GPIO_PB5_CAN0TX);
//
// 将GPIO B4和B5管脚设置为CAN0功能管脚。
//
ROM_GPIOPinTypeCAN(GPIO_PORTB_BASE, GPIO_PIN_4 | GPIO_PIN_5);

//
// 设置CAN0的波特率为500Kbps。
//
ROM_CANInit(CAN0_BASE);
ROM_CANBitRateSet(CAN0_BASE, ROM_SysCtlClockGet(), 500000);
ROM_IntEnable(INT_CAN0);
//
// 使能CAN0中断。
//
ROM_CANIntEnable(CAN0_BASE, CAN_INT_MASTER | CAN_INT_ERROR | CAN_INT_STATUS);
//ROM_IntEnable(INT_CAN0);
ROM_CANEnable(CAN0_BASE);

//
// 使能全局中断。
//
ROM_IntMasterEnable();
//
// 初始化预接收数据长度
//
// iLen=0;

//
// 初始化各个缓冲区
//
for(i=0; i<CAN_FIFO_SIZE; i++)
{
g_ucMsg1[i]= 0x00;
g_ucMsg2[i]= 0x00;
g_ucUartData[i]= 0x00;
}

CANFIFOInit(16);
//
// 延时100ms
//
ROM_SysCtlDelay(ROM_SysCtlClockGet()/30);

// 死循环
while(1)
{

while(g_bRXFlag1)
{
g_bRXFlag1 = 0;
for(i=0; i<g_ulMsg1Count; i++)
{
ROM_UARTCharPutNonBlocking(UART0_BASE, g_ucMsg1[i]);
g_ucMsg1[i] = 0;
}

//
// 闪烁用户指示灯LED。
//
ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_0, ~ROM_GPIOPinRead(GPIO_PORTD_BASE, GPIO_PIN_0));
//
// 重设接收指针以及收到的字节数
//
g_sCANMsgObject1.pucMsgData = g_ucMsg1;
g_ulMsg1Count = 0;
}


}
}

本来想贴出调试的截图的,无奈总是上传不了,望高手来解答。

嵌入式 c

触手伸遍全世界 10 years, 5 months ago

Your Answer