记一次stm8l程序跑飞
项目使用stm8l051f3做主控,CC2500做数据接收,不发送。
跑飞的现象就是,刚开始能运行,经过一段未知长度的时间,有可能是3分钟,有可能是30分钟,指示灯不再闪烁,中断按键单片机无反应。
接入调试器发现跑到了一个非常大的地址,已经超过了mcu的内部flash空间。可以确定是程序跑飞。
经验是:
程序跑飞,查条件语句是否都有做处理。
程序跑飞,查内存溢出。
查了好久,查出是内存溢出导致。
因为发送端发送的数据固定是32字节,所以在接收端只开辟了一个32字节的buffer去读取收到的数据。
/*******************************************************************************
* @brief GDO2中断处理函
* @param None
* @retval None ****************************************************************Author:Liming**/ void GDO2_Int(void) { uint8_t temp; unsigned char RecvBuffer[0x20]={0};//开辟32字节缓存 unsigned char RecvLength; if(EXTI_GetITStatus(EXTI_IT_Pin6) != RESET) { EXTI_ClearITPendingBit(EXTI_IT_Pin6); DelayNms(1);//等待接收完成 RecvLength = CC2500Recv(RecvBuffer); //获取收到的数据长度 temp = ProPacketCheck(RecvBuffer,RecvLength,0x0001,0x0003);//数据完整性校验 if((temp == 0x04)||(temp==0xff)) // 本机和广播信息需要处理 {
//数据处理
CC2500SetState(CC2500_STATUS_POWERDOWN_LEVEL2); } else CC2500SetState(CC2500_STATUS_RECEIVE); } }
//接收数据 unsigned char CC2500Recv(unsigned char *Buffer,unsigned char Mode) { unsigned char Result=0x00,Status=0x00; switch(CC2500State) { case 0x00: case 0x01: if(CC2500State) Delayms(0x07); else Delayus(0x30); Status=CC2500SpiReadStatus(RXBYTES); if(Status&0x80)//如果数据长度超过64字节 { CC2500SpiReadBuffer(FIFO,Buffer,0x40);//读取64字节 Result=0x40; } else if(Status&0x7F) { CC2500SpiReadBuffer(FIFO,Buffer,Status&0x7F);//读取收到的数据 Result=Status&0x7F; } CC2500SetState(Mode); break; } return Result;//返回读取的数据长度 }
但由于无线信号的干扰,CC2500可能会收到大于32字节的数据(虽然不是本系统需要的),
导致在从cc2500取出的时候,存入buffer的长度超过开辟的buffer空间。
解决办法1:既然知道是32字节数据,可以在
CC2500Recv接收函数里只接收32字节。
if(Status&0x80)//如果数据长度超过64字节
{
CC2500SpiReadBuffer(FIFO,Buffer,0x20);//读取32字节
Result=0x20;
}
else if(Status&0x7F)
{
CC2500SpiReadBuffer(FIFO,Buffer,0x20);//读取收到的数据
Result=0x20;
}
解决办法2:
GDO2_Int函数里开辟64字节空间即便是收到最多的数据也不会超出缓存空间。
unsigned char RecvBuffer[0x40]={0};//开辟64字节缓存
有了这次的程序跑飞的处理经历,再次验证了程序跑飞大部分都是内存溢出导致的说法。