先描述一下问题吧,调试单片机程序,用的是华大的一款国产单片机:HDSCl130,专门用于做低功耗的单片机,只开启rtc定时唤醒的话,功耗在0.5uA左右,功耗已经算是很低了,这就不多说了,还是说重点吧。
今天在调试设备的时候,用的NB模块联网,联网成功后我把设备断电了,然后重新上电。按理说应该会有一个重新联网的过程,但是我看jlink打印信息,竟然没有执行重新联网。正常情况下设备重新上电,单片机复位,将所有的变量重新恢复到初始值,只要恢复到初始值,NB模块就会重新联网,我debug调试之后发现在参数确实每次初始化为原始值了,但是在某个地方执行之后,初始值全部变掉了,如下图:
#define SAVE_SYS_INFO_LEN 512
device_t smoke_fog_detector = {
.state = DEVICE_STATE_STANDBY,
.frozen_data_nums = 0,
.alarm_data_nums = 0,
.alarm_data_break_nums = 0,
.alarm_data_grand_total = 0,
.alarm_data_test_grand_total = 0,
.alarm_data_break_grand_total = 0,
.frozen_cycle_type = TYPE_DAY,
.smog_threshold = 2400,
.vdd_shreshold = 2400,
.beyond_smog_delay = 0x02,
.noise_reduct_dely_time = 0x0f,
.frozen_cycle_time = 24,
.wake_up_check_cricle = 8,
.selfcheck_dely_time = 0x0f,
.system_type = 0x80,
.system_addr = 0,
.device_type = 0x15,
.device_addr = {0x00},
.device_mark = {0x00},
.factory_code = {0x00},
.date = {0x00},
.soft_version = {0x00},
.hard_version = {0x00},
.comm_protocol = {0x00},
.comm_protocol_version = {0x00}
};
当时定义了一个大的结构体,需要将结构体内部分参数保存在flash中,如果将整个结构体都保存flash的话就好办了,直接sizeof求结构体的长度,然后根据长度写入flash。但实际不是,只是保存结构体中部分参数。于是我就加了一个宏定义来定义长度。因为结构体中的参数是一点一点加的,这就导致每次修改结构体,都要修改宏定义SAVE_SYS_INFO_LEN的值。索性我就直接先定义长度为512.接下来就悲剧了。先看下边一个函数:
/***************************************************************************
* @fn save_sys_info
*
* @brief
*
* @data
*
* @param void
*
* @return void
***************************************************************************
*/
void save_sys_info(void)
{
uint8_t save_info[SAVE_SYS_INFO_LEN];
static device_t smoke_fog_detector_pre;
if(memcmp(&smoke_fog_detector_pre,&smoke_fog_detector,SAVE_SYS_INFO_LEN) == 0)
return;
memcpy(&smoke_fog_detector_pre,&smoke_fog_detector,SAVE_SYS_INFO_LEN);
memcpy(save_info,&smoke_fog_detector,SAVE_SYS_INFO_LEN);
Flash_SectorErase(SMOG_DETECTOR_SYS_INFO_PTR);
Flash_WriteByte(SMOG_DETECTOR_SYS_INFO_PTR,(uint8_t *)save_info,SAVE_SYS_INFO_LEN);
}
该函数是保存结构体中的参数到flash的操作,其写入flash的长度是SAVE_SYS_INFO_LEN,正是上方我定义的512的长度。当时没注意这个地方,起始写入flash是没什么问题的,关键是读,看下方函数:
/***************************************************************************
* @fn restore_sys_info
*
* @brief
*
* @data
*
* @param void
*
* @return void
***************************************************************************
*/
void restore_sys_info(void)
{
uint32_t flash_empty_flag = *(uint32_t *)SMOG_DETECTOR_SYS_INFO_PTR;
if(flash_empty_flag != 0xFFFFFFFF)
{
memcpy((uint8_t *)&smoke_fog_detector, (uint8_t *)SMOG_DETECTOR_SYS_INFO_PTR, SAVE_SYS_INFO_LEN);
}
}
从flash中将读取到的数据赋值给该结构体,但是现在有一个问题,该结构体的长度也就100多个字节,可我读取的长度是多少?SAVE_SYS_INFO_LEN这么长,512个字节。也就是说剩下的300多字节放到哪?结构体放不下了啊,上边代码中我只提供了一个结构体的首地址,从该首地址将读到的数据依次赋值。这种情况就会造成内存溢出,把剩下的300多字节也依照结构体首地址的偏移依次赋值下去,这就和一开始我说的NB模块重新上电之后无法重新联网的问题对应上了。因为每次上电之后都会从flash中将保存的数据重新赋值给结构体,但是结构体只能接收100多个字节,其他字节理所应当就给了ram中其他全局变量,这也就造成了设备重新上电之后某些全局变量被重新赋值导致程序运行异常。
先描述一下问题吧,调试单片机程序,用的是华大的一款国产单片机:HDSCl130,专门用于做低功耗的单片机,只开启rtc定时唤醒的话,功耗在0.5uA左右,功耗已经算是很低了,这就不多说了,还是说重点吧。
今天在调试设备的时候,用的NB模块联网,联网成功后我把设备断电了,然后重新上电。按理说应该会有一个重新联网的过程,但是我看jlink打印信息,竟然没有执行重新联网。正常情况下设备重新上电,单片机复位,将所有的变量重新恢复到初始值,只要恢复到初始值,NB模块就会重新联网,我debug调试之后发现在参数确实每次初始化为原始值了,但是在某个地方执行之后,初始值全部变掉了,如下图:
#define SAVE_SYS_INFO_LEN 512
device_t smoke_fog_detector = {
.state = DEVICE_STATE_STANDBY,
.frozen_data_nums = 0,
.alarm_data_nums = 0,
.alarm_data_break_nums = 0,
.alarm_data_grand_total = 0,
.alarm_data_test_grand_total = 0,
.alarm_data_break_grand_total = 0,
.frozen_cycle_type = TYPE_DAY,
.smog_threshold = 2400,
.vdd_shreshold = 2400,
.beyond_smog_delay = 0x02,
.noise_reduct_dely_time = 0x0f,
.frozen_cycle_time = 24,
.wake_up_check_cricle = 8,
.selfcheck_dely_time = 0x0f,
.system_type = 0x80,
.system_addr = 0,
.device_type = 0x15,
.device_addr = {0x00},
.device_mark = {0x00},
.factory_code = {0x00},
.date = {0x00},
.soft_version = {0x00},
.hard_version = {0x00},
.comm_protocol = {0x00},
.comm_protocol_version = {0x00}
};
当时定义了一个大的结构体,需要将结构体内部分参数保存在flash中,如果将整个结构体都保存flash的话就好办了,直接sizeof求结构体的长度,然后根据长度写入flash。但实际不是,只是保存结构体中部分参数。于是我就加了一个宏定义来定义长度。因为结构体中的参数是一点一点加的,这就导致每次修改结构体,都要修改宏定义SAVE_SYS_INFO_LEN的值。索性我就直接先定义长度为512.接下来就悲剧了。先看下边一个函数:
/***************************************************************************
* @fn save_sys_info
*
* @brief
*
* @data
*
* @param void
*
* @return void
***************************************************************************
*/
void save_sys_info(void)
{
uint8_t save_info[SAVE_SYS_INFO_LEN];
static device_t smoke_fog_detector_pre;
if(memcmp(&smoke_fog_detector_pre,&smoke_fog_detector,SAVE_SYS_INFO_LEN) == 0)
return;
memcpy(&smoke_fog_detector_pre,&smoke_fog_detector,SAVE_SYS_INFO_LEN);
memcpy(save_info,&smoke_fog_detector,SAVE_SYS_INFO_LEN);
Flash_SectorErase(SMOG_DETECTOR_SYS_INFO_PTR);
Flash_WriteByte(SMOG_DETECTOR_SYS_INFO_PTR,(uint8_t *)save_info,SAVE_SYS_INFO_LEN);
}
该函数是保存结构体中的参数到flash的操作,其写入flash的长度是SAVE_SYS_INFO_LEN,正是上方我定义的512的长度。当时没注意这个地方,起始写入flash是没什么问题的,关键是读,看下方函数:
/***************************************************************************
* @fn restore_sys_info
*
* @brief
*
* @data
*
* @param void
*
* @return void
***************************************************************************
*/
void restore_sys_info(void)
{
uint32_t flash_empty_flag = *(uint32_t *)SMOG_DETECTOR_SYS_INFO_PTR;
if(flash_empty_flag != 0xFFFFFFFF)
{
memcpy((uint8_t *)&smoke_fog_detector, (uint8_t *)SMOG_DETECTOR_SYS_INFO_PTR, SAVE_SYS_INFO_LEN);
}
}
从flash中将读取到的数据赋值给该结构体,但是现在有一个问题,该结构体的长度也就100多个字节,可我读取的长度是多少?SAVE_SYS_INFO_LEN这么长,512个字节。也就是说剩下的300多字节放到哪?结构体放不下了啊,上边代码中我只提供了一个结构体的首地址,从该首地址将读到的数据依次赋值。这种情况就会造成内存溢出,把剩下的300多字节也依照结构体首地址的偏移依次赋值下去,这就和一开始我说的NB模块重新上电之后无法重新联网的问题对应上了。因为每次上电之后都会从flash中将保存的数据重新赋值给结构体,但是结构体只能接收100多个字节,其他字节理所应当就给了ram中其他全局变量,这也就造成了设备重新上电之后某些全局变量被重新赋值导致程序运行异常。
举报