C - 在1021次迭代时发生段错误,无法在1020次迭代时打开i2c

时间:2018-03-14 12:05:05

标签: c file-io raspberry-pi segmentation-fault i2c

您好我在使用以下脚本连续将数据记录到.csv文件时出现问题

    int ddm(void)
{   
//  96 Temp MSB,    97 Temp LSB,    98 Vcc MSB,     99 Vcc LSB
//  100 TX_BIA MSB, 101 TX_BIA LSB,
//  102 TX MSB,     103 TX LSB,     104 RX MSB,     105 RX LSB

    FILE *focat;
    float temperature, vcc, tx_bias, optical_tx, optical_rx, RAW_tx, RAW_rx;
    char temp[10], vccc[10], txbi[10], optx[10], oprx[10], rwtx[30], rwrx[30];
    int i;
    //Open (or create) the csv file and write the heading row
    focat=fopen("fcatdata.csv", "w");

        if(focat == NULL)
        {
                printf("error openining file\n");
                exit(1);
        }
    fprintf(focat,"Temp, Vcc, Tx_Bias, Tx, Rx, RAWTx, RAWRx\n");
    fclose(focat);
    focat=fopen("fcatdata.csv", "a+");
    i=0;
    //start infinite loop
    for(;;) 
    {
    if(!read_eeprom(0x51));
    else exit(EXIT_FAILURE);
    i=i+1;

    //Taking MSB and LSB data and converting
    temperature =  (A51[96]+(float) A51[97]/256);
    vcc =                   (float)(A51[98]<<8  | A51[99])  * 0.0001;
    tx_bias =               (float)(A51[100]<<8 | A51[101]) * 0.002;
    optical_tx = 10 * log10((float)(A51[102]<<8 | A51[103]) * 0.0001);
    optical_rx = 10 * log10((float)(A51[104]<<8 | A51[105]) * 0.0001);

    RAW_tx =               ((float)(A51[102]<<8 | A51[103]) * 0.0001);
    RAW_rx =               ((float)(A51[104]<<8 | A51[105]) * 0.0001);

    //Display Diagnostics Monitoring Data in Terminal
    printf ("SFP Temperature = %4.4fC\n", temperature);
    printf ("Vcc, Internal supply = %4.4fV\n", vcc);
    printf ("TX bias current = %4.4fmA\n", tx_bias);
    printf ("Tx, Optical Power = %4.4f dBm", optical_tx);
    printf (", %6.6f mW\n", RAW_tx);
    printf ("Rx, Optical Power = %4.4f dBm", optical_rx);
    printf (", %6.6f mW\n", RAW_rx);
    printf ("iteration %d \n", i);

    //Change the integers into strings for appending to file
    sprintf(temp, "%4.4f", temperature);
    sprintf(vccc, "%4.4f", vcc);
    sprintf(txbi, "%4.4f", tx_bias);
    sprintf(optx, "%4.4f", optical_tx);
    sprintf(oprx, "%4.4f", optical_rx);
    sprintf(rwtx, "%6.6f", RAW_tx);
    sprintf(rwrx, "%6.6f", RAW_rx);

    //Appends DDM Data into a new row of a csv file
    //focat=fopen("fcatdata.csv", "a");
    fprintf(focat, "%s,%s,%s,%s,%s,%s,%s\n",temp,vccc,txbi,optx,oprx,rwtx,rwrx);
    //fclose(focat);

    }

    fclose(focat);
    return 0;
    }

当我设置代码以在进入循环之前打开.csv文件时,我在第1020次迭代时收到以下错误:

  

SFP温度= 31.9258C

     

Vcc,内部供应= 3.1374V

     

TX偏置电流= 8.0540mA

     

Tx,光功率= -1.8006 dBm,0.660600 mW

     

Rx,光功率= -40.0000 dBm,0.000100 mW

     

无法打开I2C设备:打开的文件太多

当我将注释更改为代码底部时,其内容如下:

//Appends DDM Data into a new row of a csv file
focat=fopen("fcatdata.csv", "a");
fprintf(focat, "%s,%s,%s,%s,%s,%s,%s\n",temp,vccc,txbi,optx,oprx,rwtx,rwrx);
fclose(focat);

然后在循环之前注释掉文件打开,随后在1021st循环迭代中出现以下错误:

  

SFP温度= 31.8906C

     

Vcc,内部电源= 3.1372V

     

TX偏置电流= 8.0620mA

     

Tx,光功率= -1.8006 dBm,0.660600 mW

     

Rx,光功率= -40.0000 dBm,0.000100 mW

     

细分错误

我认为这与ulimit - n显示1024的结果有某种关系,但我需要能够连续运行这个脚本一周,因此更改ulimit不是解决问题的真正解决方案。 / p>

我通过制作一个无休止循环的脚本并将整数i附加到csv文件并且远远超过1021行数据来测试这个理论。这一直困扰我一个星期。任何帮助表示赞赏。

批评格式等欢迎,我不经常在这里(或任何地方)发布

int read_eeprom(unsigned char address)
{
    int xio,i,fd1;
    xio = wiringPiI2CSetup (address);
    if (xio < 0) 
    {
        fprintf (stderr, "xio: Can't initialise I2C: %s\n",
                 strerror (errno));
        return 1;
    }
    for(i=0; i <128; i++) 
        {

        fd1 = wiringPiI2CReadReg8 (xio,i);
        if  (address == 0x50) 
            {
                A50[i] = fd1;
            }
        else 
            {
                A51[i] = fd1;
            }
        if (fd1 <0) 
            {
                fprintf (stderr, "xio: Can't read i2c address 0x%x: %s\n",
                         address, strerror (errno));
                return 1;
            }
        }
    return 0;
}

编辑1:澄清了文件打开和关闭的两种情况

修改2:添加了有关read_eeprom

中内容的信息

修改3 :在close(fp);

末尾添加read_eeprom解决

编辑4 close(xio);末尾添加read_eeprom,正确解决 - 致@JohnH

2 个答案:

答案 0 :(得分:0)

您只需在此过程中拨打wiringPiI2CSetup()一次。通过为xio使用静态变量可以实现这一点,这样它就可以保留调用之间的值:

int read_eeprom(unsigned char address)
{
    int i, value;
    static int xio = -1;

    if( xio == -1 ) {
       xio = wiringPiI2CSetup (address);
       if (xio < 0) {
           fprintf (stderr, "xio: Can't initialise I2C: %s\n",
                    strerror (errno));
           return 1;
       }
    }

    for(i=0; i <128; i++) {
        value = wiringPiI2CReadReg8 (xio,i);
        if( value > 0 ) {
            if (address == 0x50)
                A50[i] = value;
            else 
                A51[i] = value;
        }
        else {
            fprintf (stderr, "xio: Can't read i2c address 0x%x: %s\n",
                     address, strerror (errno));
            return 1;
        }
    }
    return 0;
}

另一种方法是每次进入路由时调用wiringPiI2CSetup(),然后在每次调用之间关闭它:

int read_eeprom(unsigned char address)
{
    int xio, i, value;
    xio = wiringPiI2CSetup (address);
    if (xio < 0) {
       fprintf (stderr, "xio: Can't initialise I2C: %s\n",
                strerror (errno));
       return 1;
    }

    for(i=0; i <128; i++) {
        value = wiringPiI2CReadReg8 (xio,i);
        if( value > 0 ) {
            if (address == 0x50)
                A50[i] = value;
            else 
                A51[i] = value;
        }
        else {
            fprintf (stderr, "xio: Can't read i2c address 0x%x: %s\n",
                     address, strerror (errno));
            close(xio);
            return 1;
        }
    }
    close(xio);
    return 0;
}

答案 1 :(得分:0)

通过在close(fd1);末尾添加read_eeprom解决问题,如下所示:

int read_eeprom(unsigned char address)
{
    int xio,i,fd1;
    xio = wiringPiI2CSetup (address);
    if (xio < 0) 
    {
        fprintf (stderr, "xio: Can't initialise I2C: %s\n",
                 strerror (errno));
        return 1;
    }
    //loop through addresses and extract data from eeprom
    for(i=0; i <128; i++) 
        {
        fd1 = wiringPiI2CReadReg8 (xio,i);
        if  (address == 0x50) 
            {
                A50[i] = fd1;
            }
        else 
            {
                A51[i] = fd1;
            }
        if (fd1 <0) 
            {
                fprintf (stderr, "xio: Can't read i2c address 0x%x: %s\n",
                         address, strerror (errno));
                return 1;
            }
        }
    //close fd1 to prevent segfault and "too many files open" errors
    close(fd1);
    return 0;
}

致@Mat确认 FD泄漏