Search code examples
cprintfscanfsigned

C/C++: Variable Reset to 0 after scanf() Input for Next Variable


I've written a program that will take in various inputs to generate a list of ADC counts for an NTC thermistor across a temperature range. I've ran this in both Pelles C and GCC (vs code + MINgw). I'm seeing minTemp getting reset to 0 after maxTemp input is provided by the user. Prior to that it holds its value. I'm using -40 as the input to minTemp.

Why is minTemp being set to 0 when maxTemp gets its value from the user?

Here is the code:

#include <stdio.h>
#include <stdint.h>
#include <math.h>
#include <stdlib.h>

/******************************************************************************
* Defines
******************************************************************************/
/*! @brief 0 degree Celsius converted to Kelvin. */
#define NTC_DEGC_0                                  (273.15)
/*! @brief Maximal voltage (5V). */
#define NTC_VCOM                                    (5.0)
/*! @brief Resolution of measured voltage in Volts (U = 152.58789 uV *
 *  register_value), with 5V maximal voltage. */
#define NTC_REGISTER_RES                            (0.00015258789) // Can be calculated from ADC resolution and ADC reference voltage

/******************************************************************************
* Types
***************************************************************************** */
typedef struct
{
    uint32_t beta;         /*!< Beta parameter of NTC thermistor in [K].
                                Admissible range is from 1 to 1000000. */
    uint32_t rntc;         /*!< R_NTC - NTC fixed resistance in [Ohm].
                                Admissible range is from 1 to 1000000. */
    uint32_t refRes;       /*!< NTC Reference Resistance in [Ohm].
                                Admissible range is from 1 to 1000000. */
    uint8_t refTemp;       /*!< NTC Reference Temperature in degrees [Celsius].
                                Admissible range is from 0 to 200. */
} ntc_config_t;

/******************************************************************************
* Local Variables
******************************************************************************/
long double NtcRegisterRes;

/******************************************************************************
* Function Prototypes
******************************************************************************/
static void FillNtcTable(const ntc_config_t* const ntcConfig, int16_t minTemp,
                         int16_t maxTemp, uint16_t table[]);

/******************************************************************************
* Global Functions
******************************************************************************/
int main(void)
{
    ntc_config_t ntcConfig;
    long double voltRef = 5.0;
    long double res;
    int16_t minTemp = -40;
    int16_t maxTemp;
    uint16_t *table;
    int tableSize = 0;

    printf("This program will generate the NTC table based on various inputs.\n\n");
    // Beta
    printf("Beta: ");
    scanf("%d", &ntcConfig.beta);
    printf("%d\n", ntcConfig.beta);

    // Pull up resistance
    printf("Pull-up Resistance: ");
    scanf("%d", &ntcConfig.rntc);
    printf("%d\n", ntcConfig.rntc);

    // Reference temp
    printf("Reference Temperature (Degrees C): ");
    scanf("%hhu", &ntcConfig.refTemp);
    printf("%hhu\n", ntcConfig.refTemp);

    // Reference resistance
    printf("Reference Resistance (Ohms): ");
    scanf("%d", &ntcConfig.refRes);
    printf("%d\n", ntcConfig.refRes);

    // ADC voltage reference
    printf("ADC Reference Voltage: ");
    scanf("%Lf", &voltRef);
    printf("%Lf\n", voltRef);

    // ADC resolutions (in bits)
    printf("ADC Resolution (in bits): ");
    scanf("%Lf", &res);
    printf("%Lf\n", res);

    // NTC Register Resolution
    NtcRegisterRes = (long double)voltRef / pow(2, res);
    printf("%Le\n", NtcRegisterRes);

    // Min Temp for Table
    printf("Min Temp: ");
    scanf("%d", &minTemp);

    // Max Temp for Table
    printf("Max Temp: ");
    scanf("%d", &maxTemp);
    printf("max temp: %d\n", maxTemp);
    
    printf("min temp: %d\n", minTemp);
    tableSize = (maxTemp + abs(minTemp)) + 1;
    printf("table size: %d\n", tableSize);
    table = (uint16_t *)malloc(tableSize * sizeof(uint16_t));
    FillNtcTable(&ntcConfig, minTemp, maxTemp, table);
    
    // Print table
    for (int i = 0; i < tableSize; i++)
    {
        printf("Temp:\t%d\tADC:\t%d\n", (minTemp+i), table[i]);
    }

    // Free the memory
    free(table);

    return(0);
}

/******************************************************************************
* Local Functions
******************************************************************************/
/*!
 * @brief This function fills the NTC look up table.
 *
 * NTC look up table is intended for resistance to temperature conversion.
 * An array item contains raw value from a register. Index of the item is
 * temperature value.
 *
 * ArrayItem = (Vcom * Rntc) / (0.00015258789 * (NTC + Rntc))
 * Where:
 *  - ArrayItem is an item value of the table,
 *  - Vcom is maximal voltage (5V),
 *  - NTC is the resistance of NTC thermistor (Ohm),
 *  - 0.00015258789 is resolution of measured voltage in Volts
 *    (V = 152.58789 uV * Register_value),
 *  - Rntc is value of a resistor connected to Vcom (see MC3377x datasheet,
 *    section MC3377x PCB components).
 *
 * Beta formula used to calculate temperature based on NTC resistance:
 *   1 / T = 1 / T0 + (1 / Beta) * ln(Rt / R0)
 * Where:
 *  - R0 is the resistance (Ohm) at temperature T0 (Kelvin),
 *  - Beta is material constant (Kelvin),
 *  - T is temperature corresponding to resistance of the NTC thermistor.
 *
 * Equation for NTC value is given from the Beta formula:
 *   NTC = R0 * exp(Beta * (1/T - 1/T0))
 *
 * @param ntcConfig Pointer to NTC components configuration.
 */
static void FillNtcTable(const ntc_config_t* const ntcConfig, int16_t minTemp,
                         int16_t maxTemp, uint16_t table[])
{
    double ntcVal;
    double expArg;
    uint16_t i = 0;
    int32_t temp;

    for (temp = minTemp; temp <= maxTemp; temp++)
    {
        expArg = ntcConfig->beta * ((1.0 / (NTC_DEGC_0 + temp)) - (1.0 / (NTC_DEGC_0 + ntcConfig->refTemp)));
        ntcVal = exp(expArg) * ntcConfig->refRes;
        table[i] = (uint16_t)round(((NTC_VCOM * ntcVal) / (ntcVal + (double)ntcConfig->rntc)) / NtcRegisterRes);
        i++;
    }
}

minTemp Input: -40 maxtemp Input: 125 List generates for only 0 - 126. After stepping through in vs code, mintemp gets reset when maxTemp gets its value after scanf(). Not sure why.


Solution

  • I fixed the issue so you can use scanf with int16_t without having to create extra variables and such.

    Here is a glimpse of the output:

    Min Temp: 7
    Max Temp: 8
    max temp: 8
    min temp: 7
    table size: 16
    Temp:   7       ADC:    43
    Temp:   8       ADC:    43
    

    The solution I found was to use the library inttypes.h, then change the scanf from scanf("%d", &minTemp); to scanf("%" SCNd16, &minTemp);:

    #include <inttypes.h>
    #define __STDC_FORMAT_MACROS
    // More code here
    scanf("%" SCNd16, &minTemp);
    

    This is supposed to be part of the C99 standard

    Here is the whole code so you can copy and paste:

    #include <stdio.h>
    #include <stdint.h>
    #include <math.h>
    #include <stdlib.h>
    #include <inttypes.h>
    
    #define __STDC_FORMAT_MACROS
    
    /******************************************************************************
    * Defines
    ******************************************************************************/
    /*! @brief 0 degree Celsius converted to Kelvin. */
    #define NTC_DEGC_0                                  (273.15)
    /*! @brief Maximal voltage (5V). */
    #define NTC_VCOM                                    (5.0)
    /*! @brief Resolution of measured voltage in Volts (U = 152.58789 uV *
     *  register_value), with 5V maximal voltage. */
    #define NTC_REGISTER_RES                            (0.00015258789) // Can be calculated from ADC resolution and ADC reference voltage
    
    /******************************************************************************
    * Types
    ******************************************************************************/
    typedef struct
    {
        uint32_t beta;         /*!< Beta parameter of NTC thermistor in [K].
                                    Admissible range is from 1 to 1000000. */
        uint32_t rntc;         /*!< R_NTC - NTC fixed resistance in [Ohm].
                                    Admissible range is from 1 to 1000000. */
        uint32_t refRes;       /*!< NTC Reference Resistance in [Ohm].
                                    Admissible range is from 1 to 1000000. */
        uint8_t refTemp;       /*!< NTC Reference Temperature in degrees [Celsius].
                                    Admissible range is from 0 to 200. */
    } ntc_config_t;
    
    /******************************************************************************
    * Local Variables
    ******************************************************************************/
    long double NtcRegisterRes;
    
    /******************************************************************************
    * Function Prototypes
    ******************************************************************************/
    static void FillNtcTable(const ntc_config_t* const ntcConfig, int16_t minTemp,
                             int16_t maxTemp, uint16_t table[]);
    
    /******************************************************************************
    * Global Functions
    ******************************************************************************/
    int main(void)
    {
        ntc_config_t ntcConfig;
        long double voltRef = 5.0;
        long double res;
        int16_t minTemp = -40;
        int16_t maxTemp;
        uint16_t *table;
        int tableSize = 0;
    
        printf("This program will generate the NTC table based on various inputs.\n\n");
        // Beta
        printf("Beta: ");
        scanf("%d", &ntcConfig.beta);
        printf("%d\n", ntcConfig.beta);
    
        // Pull up resistance
        printf("Pull-up Resistance: ");
        scanf("%d", &ntcConfig.rntc);
        printf("%d\n", ntcConfig.rntc);
    
        // Reference temp
        printf("Reference Temperature (Degrees C): ");
        scanf("%hhu", &ntcConfig.refTemp);
        printf("%hhu\n", ntcConfig.refTemp);
    
        // Reference resistance
        printf("Reference Resistance (Ohms): ");
        scanf("%d", &ntcConfig.refRes);
        printf("%d\n", ntcConfig.refRes);
    
        // ADC voltage reference
        printf("ADC Reference Voltage: ");
        scanf("%Lf", &voltRef);
        printf("%Lf\n", voltRef);
    
        // ADC resolutions (in bits)
        printf("ADC Resolution (in bits): ");
        scanf("%Lf", &res);
        printf("%Lf\n", res);
    
        // NTC Register Resolution
        NtcRegisterRes = (long double)voltRef / pow(2, res);
        printf("%Le\n", NtcRegisterRes);
    
        // Min Temp for Table
        printf("Min Temp: ");
        scanf("%" SCNd16, &minTemp);
        printf("min temp: %d\n", minTemp);
    
        // Max Temp for Table
        printf("Max Temp: ");
        scanf("%" SCNd16, &maxTemp);
        printf("max temp: %d\n", maxTemp);    
    
        tableSize = (maxTemp + abs(minTemp)) + 1;
        printf("table size: %d\n", tableSize);
        table = (uint16_t *)malloc(tableSize * sizeof(uint16_t));
        FillNtcTable(&ntcConfig, minTemp, maxTemp, table);
        
        // Print table
        for (int i = 0; i < tableSize; i++)
        {
            printf("Temp:\t%d\tADC:\t%d\n", (minTemp+i), table[i]);
        }
    
        // Free the memory
        free(table);
    
        return(0);
    }
    
    /******************************************************************************
    * Local Functions
    ******************************************************************************/
    /*!
     * @brief This function fills the NTC look up table.
     *
     * NTC look up table is intended for resistance to temperature conversion.
     * An array item contains raw value from a register. Index of the item is
     * temperature value.
     *
     * ArrayItem = (Vcom * Rntc) / (0.00015258789 * (NTC + Rntc))
     * Where:
     *  - ArrayItem is an item value of the table,
     *  - Vcom is maximal voltage (5V),
     *  - NTC is the resistance of NTC thermistor (Ohm),
     *  - 0.00015258789 is resolution of measured voltage in Volts
     *    (V = 152.58789 uV * Register_value),
     *  - Rntc is value of a resistor connected to Vcom (see MC3377x datasheet,
     *    section MC3377x PCB components).
     *
     * Beta formula used to calculate temperature based on NTC resistance:
     *   1 / T = 1 / T0 + (1 / Beta) * ln(Rt / R0)
     * Where:
     *  - R0 is the resistance (Ohm) at temperature T0 (Kelvin),
     *  - Beta is material constant (Kelvin),
     *  - T is temperature corresponding to resistance of the NTC thermistor.
     *
     * Equation for NTC value is given from the Beta formula:
     *   NTC = R0 * exp(Beta * (1/T - 1/T0))
     *
     * @param ntcConfig Pointer to NTC components configuration.
     */
    static void FillNtcTable(const ntc_config_t* const ntcConfig, int16_t minTemp,
                             int16_t maxTemp, uint16_t table[])
    {
        double ntcVal;
        double expArg;
        uint16_t i = 0;
        int32_t temp;
    
        for (temp = minTemp; temp <= maxTemp; temp++)
        {
            expArg = ntcConfig->beta * ((1.0 / (NTC_DEGC_0 + temp)) - (1.0 / (NTC_DEGC_0 + ntcConfig->refTemp)));
            ntcVal = exp(expArg) * ntcConfig->refRes;
            table[i] = (uint16_t)round(((NTC_VCOM * ntcVal) / (ntcVal + (double)ntcConfig->rntc)) / NtcRegisterRes);
            i++;
        }
    }
    

    I used the compiler in https://www.onlinegdb.com/online_c_compiler so let me know if this solution works on yours. Else, I will remove this solution.