可能由 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