可能由 strcpy 引起的 HardFault
HardFault caused probably by strcpy
LPC1769中运行s下面的函数。我使用 FreeRTOS 版本 10。
我有 HardFault
。我已经调试过了,我想我在长时间后解决了这个问题。
如果我运行这个函数它给出HardFault
。最初,我怀疑 substr3
函数中的 malloc
导致了它。释放内存分配没有帮助。因此,我开始逐块注释掉代码,直到我在 parseMessage
函数中找到问题的更准确位置。
如果我注释掉 /* START OF PROBLEMATIC AREA */
和 /* END OF PROBLEMATIC AREA */
之间的行
其余代码可以正常工作。
我在那个代码块中所做的一切,都是在结构变量中赋值。该结构是全局的并已初始化。我相信这些线路最终会导致问题。也许间接地,我还不知道那么远。
例如strcpy(productInfoLeft.ucActualID, pid);
如果我 运行 parseMessage
中的所有代码,它适用于一条或几条消息,它们解析正常,然后 MCU 停止响应。
在名为 common.h
的文件中构造
struct ProductInfoLeft
{
char ucActualID[ 7 ];
char ucProductName[ 13 ];
char ucBestBeforeDate[ 13 ];
char ucPrinted[ 4 ];
char ucToBePrinted[ 4 ];
char ucLane[ 3 ];
char ucLcdNumber [ 2 ];
char ucPrinterLane [ 3 ];
char ucSupplierInfo [ 13 ];
};
extern struct ProductInfoLeft productInfoLeft;
struct ProductInfoRight
{
char ucActualID[ 7 ];
char ucProductName[ 13 ];
char ucBestBeforeDate[ 13 ];
char ucPrinted[ 4 ];
char ucToBePrinted[ 4 ];
char ucLane[ 3 ];
char ucLcdNumber [ 2 ];
char ucPrinterLane [ 3 ];
char ucSupplierInfo [ 13 ];
};
extern struct ProductInfoRight productInfoRight;
结构初始化发生在名为 lcdtasks.c
;
的文件中
struct ProductInfoLeft productInfoLeft = {
.ucActualID = "",
.ucProductName = "",
.ucBestBeforeDate = "",
.ucPrinted = "",
.ucToBePrinted = "",
.ucLane = "",
.ucLcdNumber = "",
.ucPrinterLane = "",
.ucSupplierInfo = ""
};
struct ProductInfoRight productInfoRight = {
.ucActualID = "",
.ucProductName = "",
.ucBestBeforeDate = "",
.ucPrinted = "",
.ucToBePrinted = "",
.ucLane = "",
.ucLcdNumber = "",
.ucPrinterLane = "",
.ucSupplierInfo = ""
};
另一个名为 uarttask.c
;
的文件中的解析器函数
void parseMessage(char * message){
//Sample data
//const char* str = "7E00002A347C31323030302D3132353330387C33302E30372E323032307C31317C33307C33317C31352D31367C31357C317C57656E67657274880D0000";
// Parsing the frame
char* start;
char* len;
char* cmd;
char* data;
char* chksum;
char* end;
stripEOL(message);
unsigned int messagelen = strlen(message);
start = substr3(message, 0, 2);
len = substr3(message, 2, 4);
cmd = substr3(message, 6, 2);
data = substr3(message, 8, messagelen-8-4);
chksum = substr3(message, messagelen-4, 2);
end = substr3(message, messagelen-2, 2);
// Converting hex (only for data) to string
char str[250];
hex_to_string(data, str, sizeof(str));
// Parsing the data in variables
//Sample data content to be parsed in variables;
//char str1[50] ="7|10000-145310|12.10.2018|1|10|0|15-16|15|1|Wegert";
char pid[6], pname[12], bbdate[10], pnr[2], ltoprinted[3], lprinted[3], planes[5], laneNr[2], lcdNr[1], sinfo[12];
strcpy(pid, strtok(str , "|"));
strcpy(pname, strtok(NULL , "|"));
strcpy(bbdate, strtok(NULL, "|"));
strcpy(pnr , strtok(NULL, "|"));
strcpy(ltoprinted , strtok(NULL, "|"));
strcpy(lprinted, strtok(NULL, "|"));
strcpy(planes, strtok(NULL, "|"));
strcpy(laneNr, strtok(NULL, "|"));
strcpy(lcdNr, strtok(NULL, "|"));
strcpy(sinfo, strtok(NULL, "|"));
uint8_t resultLCDNr1 = strncmp(lcdNr, "1", 1);
uint8_t resultLCDNr2 = strncmp(lcdNr, "2", 1);
uint8_t result7E = strcmp(start, pcStart);
uint8_t result0D = strcmp(end, pcEnd);
uint8_t result2A = strcmp(cmd, pcProductChange);
uint8_t result30 = strcmp(cmd, pcSupplierChange);
char planeleft[2], planeright[2], tempplanes[5];
strcpy(tempplanes, planes); // If this is used, the next strcpy causes lprinted variable's first element to be "0\"
strcpy(planeleft, strtok(tempplanes , "-"));
strcpy(planeright, strtok(NULL , "-"));
/* START OF PROBLEMATIC AREA */
if (result7E == 0 && result0D == 0){
if (result2A == 0){ //Product Change
if (resultLCDNr1 == 0){
strcpy(productInfoLeft.ucActualID, pid);
strcpy(productInfoLeft.ucPrinterLane, planeleft);
strcpy(productInfoLeft.ucProductName, pname);
strcpy(productInfoLeft.ucBestBeforeDate, bbdate);
strcpy(productInfoLeft.ucPrinted, lprinted);
strcpy(productInfoLeft.ucToBePrinted, ltoprinted);
strcpy(productInfoLeft.ucLane, laneNr);
strcpy(productInfoLeft.ucLcdNumber, lcdNr);
strcpy(productInfoLeft.ucSupplierInfo, sinfo);
}else if (resultLCDNr2 == 0){
strcpy(productInfoRight.ucActualID, pid);
strcpy(productInfoRight.ucPrinterLane, planeright);
strcpy(productInfoRight.ucProductName, pname);
strcpy(productInfoRight.ucBestBeforeDate, bbdate);
strcpy(productInfoRight.ucPrinted, lprinted);
strcpy(productInfoRight.ucToBePrinted, ltoprinted);
strcpy(productInfoRight.ucLane, laneNr);
strcpy(productInfoRight.ucLcdNumber, lcdNr);
strcpy(productInfoRight.ucSupplierInfo, sinfo);
}else{
return;
}
SetProductChangeOnLCD(lcdNr);
}
if (result30 == 0){ //Supply Change
if (resultLCDNr1 == 0){
strcpy(productInfoLeft.ucActualID, pid);
strcpy(productInfoLeft.ucPrinterLane, planeleft);
strcpy(productInfoLeft.ucProductName, pname);
strcpy(productInfoLeft.ucBestBeforeDate, bbdate);
strcpy(productInfoLeft.ucPrinted, lprinted);
strcpy(productInfoLeft.ucToBePrinted, ltoprinted);
strcpy(productInfoLeft.ucLane, laneNr);
strcpy(productInfoLeft.ucLcdNumber, lcdNr);
strcpy(productInfoLeft.ucSupplierInfo, sinfo);
}else if (resultLCDNr2 == 0){
strcpy(productInfoRight.ucActualID, pid);
strcpy(productInfoRight.ucPrinterLane, planeright);
strcpy(productInfoRight.ucProductName, pname);
strcpy(productInfoRight.ucBestBeforeDate, bbdate);
strcpy(productInfoRight.ucPrinted, lprinted);
strcpy(productInfoRight.ucToBePrinted, ltoprinted);
strcpy(productInfoRight.ucLane, laneNr);
strcpy(productInfoRight.ucLcdNumber, lcdNr);
strcpy(productInfoRight.ucSupplierInfo, sinfo);
}else{
return;
}
SetSupplierChangeOnLCD(lcdNr);
}
}
/* END OF PROBLEMATIC AREA */
free(start);
free(len);
free(cmd);
free(data);
free(chksum);
free(end);
}
子字符串函数:
char *substr3(char const *input, size_t start, size_t len) {
char *ret = malloc(len+1);
memcpy(ret, input+start, len);
ret[len] = '[=13=]';
return ret;
}
仅供将来参考,我喜欢分享我的发现和解决问题的方法。
有两个问题。一种是用于 strcpy 的带有 char 的数组大小。正如一些贡献者提到的那样,没有正确设置。
一旦数组大小固定,另一个问题就会以更清晰的方式暴露出来。这是关于 malloc 的。出于某种原因,尽管一些评论在各种资源中另有说明,但如果您在 FreeRTOS 实现中使用 malloc,则您可能会遇到 HardFault。一旦我切换到 FreeRTOS 建议的 malloc 和 free 函数,事情就变得平淡无奇了。 HardFault 问题神奇地消失了。
我只是放置了两个包装器函数(在公共文件中的某处),甚至没有更改我的 malloc 和 free 调用。;
创建使用 built-in FreeRTOS 堆的 malloc/free 函数非常简单。我们只是包装了 pvPortMalloc/pvPortFree 个调用:
void* malloc(size_t size)
{
void* ptr = NULL;
if(size > 0)
{
// We simply wrap the FreeRTOS call into a standard form
ptr = pvPortMalloc(size);
} // else NULL if there was an error
return ptr;
}
void free(void* ptr)
{
if(ptr)
{
// We simply wrap the FreeRTOS call into a standard form
vPortFree(ptr);
}
}
请注意:您不能将其用于堆模式 #1,但不能用于其他堆模式(2、3、4 和 5)。我建议开始使用 portable/MemMang/heap_4.c
LPC1769中运行s下面的函数。我使用 FreeRTOS 版本 10。
我有 HardFault
。我已经调试过了,我想我在长时间后解决了这个问题。
如果我运行这个函数它给出HardFault
。最初,我怀疑 substr3
函数中的 malloc
导致了它。释放内存分配没有帮助。因此,我开始逐块注释掉代码,直到我在 parseMessage
函数中找到问题的更准确位置。
如果我注释掉 /* START OF PROBLEMATIC AREA */
和 /* END OF PROBLEMATIC AREA */
之间的行
其余代码可以正常工作。
我在那个代码块中所做的一切,都是在结构变量中赋值。该结构是全局的并已初始化。我相信这些线路最终会导致问题。也许间接地,我还不知道那么远。
例如strcpy(productInfoLeft.ucActualID, pid);
如果我 运行 parseMessage
中的所有代码,它适用于一条或几条消息,它们解析正常,然后 MCU 停止响应。
在名为 common.h
struct ProductInfoLeft
{
char ucActualID[ 7 ];
char ucProductName[ 13 ];
char ucBestBeforeDate[ 13 ];
char ucPrinted[ 4 ];
char ucToBePrinted[ 4 ];
char ucLane[ 3 ];
char ucLcdNumber [ 2 ];
char ucPrinterLane [ 3 ];
char ucSupplierInfo [ 13 ];
};
extern struct ProductInfoLeft productInfoLeft;
struct ProductInfoRight
{
char ucActualID[ 7 ];
char ucProductName[ 13 ];
char ucBestBeforeDate[ 13 ];
char ucPrinted[ 4 ];
char ucToBePrinted[ 4 ];
char ucLane[ 3 ];
char ucLcdNumber [ 2 ];
char ucPrinterLane [ 3 ];
char ucSupplierInfo [ 13 ];
};
extern struct ProductInfoRight productInfoRight;
结构初始化发生在名为 lcdtasks.c
;
struct ProductInfoLeft productInfoLeft = {
.ucActualID = "",
.ucProductName = "",
.ucBestBeforeDate = "",
.ucPrinted = "",
.ucToBePrinted = "",
.ucLane = "",
.ucLcdNumber = "",
.ucPrinterLane = "",
.ucSupplierInfo = ""
};
struct ProductInfoRight productInfoRight = {
.ucActualID = "",
.ucProductName = "",
.ucBestBeforeDate = "",
.ucPrinted = "",
.ucToBePrinted = "",
.ucLane = "",
.ucLcdNumber = "",
.ucPrinterLane = "",
.ucSupplierInfo = ""
};
另一个名为 uarttask.c
;
void parseMessage(char * message){
//Sample data
//const char* str = "7E00002A347C31323030302D3132353330387C33302E30372E323032307C31317C33307C33317C31352D31367C31357C317C57656E67657274880D0000";
// Parsing the frame
char* start;
char* len;
char* cmd;
char* data;
char* chksum;
char* end;
stripEOL(message);
unsigned int messagelen = strlen(message);
start = substr3(message, 0, 2);
len = substr3(message, 2, 4);
cmd = substr3(message, 6, 2);
data = substr3(message, 8, messagelen-8-4);
chksum = substr3(message, messagelen-4, 2);
end = substr3(message, messagelen-2, 2);
// Converting hex (only for data) to string
char str[250];
hex_to_string(data, str, sizeof(str));
// Parsing the data in variables
//Sample data content to be parsed in variables;
//char str1[50] ="7|10000-145310|12.10.2018|1|10|0|15-16|15|1|Wegert";
char pid[6], pname[12], bbdate[10], pnr[2], ltoprinted[3], lprinted[3], planes[5], laneNr[2], lcdNr[1], sinfo[12];
strcpy(pid, strtok(str , "|"));
strcpy(pname, strtok(NULL , "|"));
strcpy(bbdate, strtok(NULL, "|"));
strcpy(pnr , strtok(NULL, "|"));
strcpy(ltoprinted , strtok(NULL, "|"));
strcpy(lprinted, strtok(NULL, "|"));
strcpy(planes, strtok(NULL, "|"));
strcpy(laneNr, strtok(NULL, "|"));
strcpy(lcdNr, strtok(NULL, "|"));
strcpy(sinfo, strtok(NULL, "|"));
uint8_t resultLCDNr1 = strncmp(lcdNr, "1", 1);
uint8_t resultLCDNr2 = strncmp(lcdNr, "2", 1);
uint8_t result7E = strcmp(start, pcStart);
uint8_t result0D = strcmp(end, pcEnd);
uint8_t result2A = strcmp(cmd, pcProductChange);
uint8_t result30 = strcmp(cmd, pcSupplierChange);
char planeleft[2], planeright[2], tempplanes[5];
strcpy(tempplanes, planes); // If this is used, the next strcpy causes lprinted variable's first element to be "0\"
strcpy(planeleft, strtok(tempplanes , "-"));
strcpy(planeright, strtok(NULL , "-"));
/* START OF PROBLEMATIC AREA */
if (result7E == 0 && result0D == 0){
if (result2A == 0){ //Product Change
if (resultLCDNr1 == 0){
strcpy(productInfoLeft.ucActualID, pid);
strcpy(productInfoLeft.ucPrinterLane, planeleft);
strcpy(productInfoLeft.ucProductName, pname);
strcpy(productInfoLeft.ucBestBeforeDate, bbdate);
strcpy(productInfoLeft.ucPrinted, lprinted);
strcpy(productInfoLeft.ucToBePrinted, ltoprinted);
strcpy(productInfoLeft.ucLane, laneNr);
strcpy(productInfoLeft.ucLcdNumber, lcdNr);
strcpy(productInfoLeft.ucSupplierInfo, sinfo);
}else if (resultLCDNr2 == 0){
strcpy(productInfoRight.ucActualID, pid);
strcpy(productInfoRight.ucPrinterLane, planeright);
strcpy(productInfoRight.ucProductName, pname);
strcpy(productInfoRight.ucBestBeforeDate, bbdate);
strcpy(productInfoRight.ucPrinted, lprinted);
strcpy(productInfoRight.ucToBePrinted, ltoprinted);
strcpy(productInfoRight.ucLane, laneNr);
strcpy(productInfoRight.ucLcdNumber, lcdNr);
strcpy(productInfoRight.ucSupplierInfo, sinfo);
}else{
return;
}
SetProductChangeOnLCD(lcdNr);
}
if (result30 == 0){ //Supply Change
if (resultLCDNr1 == 0){
strcpy(productInfoLeft.ucActualID, pid);
strcpy(productInfoLeft.ucPrinterLane, planeleft);
strcpy(productInfoLeft.ucProductName, pname);
strcpy(productInfoLeft.ucBestBeforeDate, bbdate);
strcpy(productInfoLeft.ucPrinted, lprinted);
strcpy(productInfoLeft.ucToBePrinted, ltoprinted);
strcpy(productInfoLeft.ucLane, laneNr);
strcpy(productInfoLeft.ucLcdNumber, lcdNr);
strcpy(productInfoLeft.ucSupplierInfo, sinfo);
}else if (resultLCDNr2 == 0){
strcpy(productInfoRight.ucActualID, pid);
strcpy(productInfoRight.ucPrinterLane, planeright);
strcpy(productInfoRight.ucProductName, pname);
strcpy(productInfoRight.ucBestBeforeDate, bbdate);
strcpy(productInfoRight.ucPrinted, lprinted);
strcpy(productInfoRight.ucToBePrinted, ltoprinted);
strcpy(productInfoRight.ucLane, laneNr);
strcpy(productInfoRight.ucLcdNumber, lcdNr);
strcpy(productInfoRight.ucSupplierInfo, sinfo);
}else{
return;
}
SetSupplierChangeOnLCD(lcdNr);
}
}
/* END OF PROBLEMATIC AREA */
free(start);
free(len);
free(cmd);
free(data);
free(chksum);
free(end);
}
子字符串函数:
char *substr3(char const *input, size_t start, size_t len) {
char *ret = malloc(len+1);
memcpy(ret, input+start, len);
ret[len] = '[=13=]';
return ret;
}
仅供将来参考,我喜欢分享我的发现和解决问题的方法。
有两个问题。一种是用于 strcpy 的带有 char 的数组大小。正如一些贡献者提到的那样,没有正确设置。
一旦数组大小固定,另一个问题就会以更清晰的方式暴露出来。这是关于 malloc 的。出于某种原因,尽管一些评论在各种资源中另有说明,但如果您在 FreeRTOS 实现中使用 malloc,则您可能会遇到 HardFault。一旦我切换到 FreeRTOS 建议的 malloc 和 free 函数,事情就变得平淡无奇了。 HardFault 问题神奇地消失了。
我只是放置了两个包装器函数(在公共文件中的某处),甚至没有更改我的 malloc 和 free 调用。;
创建使用 built-in FreeRTOS 堆的 malloc/free 函数非常简单。我们只是包装了 pvPortMalloc/pvPortFree 个调用:
void* malloc(size_t size)
{
void* ptr = NULL;
if(size > 0)
{
// We simply wrap the FreeRTOS call into a standard form
ptr = pvPortMalloc(size);
} // else NULL if there was an error
return ptr;
}
void free(void* ptr)
{
if(ptr)
{
// We simply wrap the FreeRTOS call into a standard form
vPortFree(ptr);
}
}
请注意:您不能将其用于堆模式 #1,但不能用于其他堆模式(2、3、4 和 5)。我建议开始使用 portable/MemMang/heap_4.c