Manuel Caballero / HX711

Dependents:   EXPO_ANDA EXPO_ANDA_Copilotoco

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers HX711.cpp Source File

HX711.cpp

00001 /**
00002  * @brief       HX711.h
00003  * @details     24-Bit Analog-to-Digital Converter (ADC) for Weigh Scales.
00004  *              Function file.
00005  *
00006  *
00007  * @return      NA
00008  *
00009  * @author      Manuel Caballero
00010  * @date        11/September/2017
00011  * @version     11/September/2017    The ORIGIN
00012  * @pre         NaN.
00013  * @warning     NaN
00014  * @pre         This code belongs to Nimbus Centre ( http://www.nimbus.cit.ie ).
00015  */
00016 
00017 #include "HX711.h"
00018 
00019 
00020 HX711::HX711 ( PinName PD_SCK, PinName DOUT )
00021     : _PD_SCK               ( PD_SCK )
00022     , _DOUT                 ( DOUT )
00023 {
00024 
00025 }
00026 
00027 
00028 HX711::~HX711()
00029 {
00030 }
00031 
00032 
00033 
00034 /**
00035  * @brief       HX711_Reset   ( void )
00036  *
00037  * @details     It performs an internal reset.
00038  *
00039  * @param[in]    NaN.
00040  *
00041  * @param[out]   NaN.
00042  *
00043  *
00044  * @return       Status of HX711_Reset.
00045  *
00046  *
00047  * @author      Manuel Caballero
00048  * @date        11/September/2017
00049  * @version     11/September/2017   The ORIGIN
00050  * @pre         When PD_SCK pin changes from low to high and stays at high for
00051  *              longer than 60μs, HX711 enters power down mode.
00052  *
00053  *              When PD_SCK returns to low, chip will reset and enter normal
00054  *              operation mode.
00055  * @warning     NaN.
00056  */
00057 HX711::HX711_status_t  HX711::HX711_Reset   ( void )
00058 {
00059     _PD_SCK  =  HX711_PIN_HIGH;
00060     wait_us ( 120 );                                                            // Datasheet p5. At least 60us ( Security Factor: 2*60us = 120us )
00061     _PD_SCK  =  HX711_PIN_LOW;
00062 
00063 
00064 
00065     if ( _DOUT == HX711_PIN_HIGH )
00066         return   HX711_SUCCESS;
00067     else
00068         return   HX711_FAILURE;
00069 }
00070 
00071 
00072 
00073 /**
00074  * @brief       HX711_PowerDown   ( void )
00075  *
00076  * @details     It puts the device in power-down mode.
00077  *
00078  * @param[in]    NaN.
00079  *
00080  * @param[out]   NaN.
00081  *
00082  *
00083  * @return       Status of HX711_PowerDown.
00084  *
00085  *
00086  * @author      Manuel Caballero
00087  * @date        11/September/2017
00088  * @version     11/September/2017   The ORIGIN
00089  * @pre         When PD_SCK pin changes from low to high and stays at high for
00090  *              longer than 60μs, HX711 enters power down mode.
00091  * @warning     NaN.
00092  */
00093 HX711::HX711_status_t  HX711::HX711_PowerDown   ( void )
00094 {
00095     _PD_SCK  =  HX711_PIN_HIGH;
00096     wait_us ( 120 );                                                            // Datasheet p5. At least 60us ( Security Factor: 2*60us = 120us )
00097 
00098 
00099 
00100     if ( _DOUT == HX711_PIN_HIGH )
00101         return   HX711_SUCCESS;
00102     else
00103         return   HX711_FAILURE;
00104 }
00105 
00106 
00107 
00108 /**
00109  * @brief       HX711_SetChannelAndGain   ( HX711_channel_gain_t myChannel_Gain )
00110  *
00111  * @details     It sets both the channel and the gain for the next measurement.
00112  *
00113  * @param[in]    myChannel_Gain:    Channel and Gain to perform the new measurement.
00114  *
00115  * @param[out]   NaN.
00116  *
00117  *
00118  * @return       Status of HX711_SetChannelAndGain.
00119  *
00120  *
00121  * @author      Manuel Caballero
00122  * @date        11/September/2017
00123  * @version     11/September/2017   The ORIGIN
00124  * @pre         NaN.
00125  * @warning     NaN.
00126  */
00127 HX711::HX711_status_t  HX711::HX711_SetChannelAndGain    ( HX711_channel_gain_t myChannel_Gain )
00128 {
00129     uint32_t myPulses   =    0;
00130     uint32_t i          =    0;                                                 // Counter and timeout variable
00131 
00132     // Select the gain/channel
00133     switch ( myChannel_Gain ) {
00134         default:
00135         case CHANNEL_A_GAIN_128 :
00136             _HX711_CHANNEL_GAIN  =   CHANNEL_A_GAIN_128 ;                        // Update the gain parameter
00137             myPulses             =   25;
00138             break;
00139 
00140         case CHANNEL_B_GAIN_32 :
00141             _HX711_CHANNEL_GAIN  =   CHANNEL_B_GAIN_32 ;                         // Update the gain parameter
00142             myPulses             =   26;
00143             break;
00144 
00145         case CHANNEL_A_GAIN_64 :
00146             _HX711_CHANNEL_GAIN  =   CHANNEL_A_GAIN_64 ;                         // Update the gain parameter
00147             myPulses             =   27;
00148             break;
00149     }
00150 
00151 
00152     // Wait until the device is ready or timeout
00153     i        =   23232323;
00154     _PD_SCK  =  HX711_PIN_LOW;
00155     while ( ( _DOUT == HX711_PIN_HIGH ) && ( --i ) );
00156 
00157     // Check if something is wrong with the device because of the timeout
00158     if ( i < 1 )
00159         return   HX711_FAILURE;
00160 
00161     // Change the gain for the NEXT mesurement ( previous data will be ignored )
00162     do {
00163         wait_us ( 1 );                                                          // Datasheet p5. T3 and T4 ( Min. 0.2us | Typ. 1us )
00164         _PD_SCK  =  HX711_PIN_HIGH;
00165         wait_us ( 1 );                                                          // Datasheet p5. T3 and T4 ( Min. 0.2us | Typ. 1us )
00166         _PD_SCK  =  HX711_PIN_LOW;
00167 
00168         myPulses--;
00169     } while ( myPulses > 0 );
00170 
00171 
00172 
00173 
00174     if ( _DOUT == HX711_PIN_HIGH )
00175         return   HX711_SUCCESS;
00176     else
00177         return   HX711_FAILURE;
00178 }
00179 
00180 
00181 
00182 /**
00183  * @brief       HX711_GetChannelAndGain   ( void )
00184  *
00185  * @details     It gets both the channel and the gain for the current measurement.
00186  *
00187  * @param[in]    NaN.
00188  *
00189  * @param[out]   NaN.
00190  *
00191  *
00192  * @return       Channel and Gain.
00193  *
00194  *
00195  * @author      Manuel Caballero
00196  * @date        12/September/2017
00197  * @version     12/September/2017   The ORIGIN
00198  * @pre         NaN.
00199  * @warning     NaN.
00200  */
00201 HX711::HX711_channel_gain_t  HX711::HX711_GetChannelAndGain ( void )
00202 {
00203     return   _HX711_CHANNEL_GAIN;
00204 }
00205 
00206 
00207 
00208 /**
00209  * @brief       HX711_ReadRawData   ( HX711_channel_gain_t myChannel_Gain, Vector_count_t*, uint32_t )
00210  *
00211  * @details     It reads the raw data from the device according to the channel
00212  *              and its gain.
00213  *
00214  * @param[in]    myChannel_Gain:    Channel and Gain to perform the new read.
00215  * @param[in]    myAverage:         How many measurement we have to get and deliver the average.
00216  *
00217  * @param[out]   myNewRawData:      The new value from the device.
00218  *
00219  *
00220  * @return       Status of HX711_ReadRawData.
00221  *
00222  *
00223  * @author      Manuel Caballero
00224  * @date        11/September/2017
00225  * @version     12/September/2017   Gain mode was fixed, now it gets the value
00226  *                                  a given gain/channel. A timeout was added to
00227  *                                  avoid the microcontroller gets stuck.
00228  *              11/September/2017   The ORIGIN
00229  * @pre         NaN.
00230  * @warning     NaN.
00231  */
00232 HX711::HX711_status_t  HX711::HX711_ReadRawData    ( HX711_channel_gain_t myChannel_Gain, Vector_count_t* myNewRawData, uint32_t myAverage )
00233 {
00234     uint32_t i           =   0;                                                 // Counter and timeout variable
00235     uint32_t ii          =   0;                                                 // Counter variable
00236     uint32_t myAuxData   =   0;
00237     uint32_t myPulses    =   0;
00238 
00239 
00240 
00241     myNewRawData->myRawValue    =   0;                                          // Reset variable at the beginning
00242 
00243     // Check the gain if it is different, update it ( previous data will be ignored! )
00244     if ( myChannel_Gain != _HX711_CHANNEL_GAIN )
00245         HX711_SetChannelAndGain ( myChannel_Gain );
00246 
00247 
00248     // Start collecting the new measurement as many as myAverage
00249     for ( ii = 0; ii < myAverage; ii++ ) {
00250         // Reset the value
00251         myAuxData    =   0;
00252 
00253         // Wait until the device is ready or timeout
00254         i        =   23232323;
00255         _PD_SCK  =  HX711_PIN_LOW;
00256         while ( ( _DOUT == HX711_PIN_HIGH ) && ( --i ) );
00257 
00258         // Check if something is wrong with the device because of the timeout
00259         if ( i < 1 )
00260             return   HX711_FAILURE;
00261 
00262 
00263         // Read the data
00264         for ( i = 0; i < 24; i++ ) {
00265             wait_us ( 1 );                                                      // Datasheet p5. T3 and T4 ( Min. 0.2us | Typ. 1us )
00266             _PD_SCK  =  HX711_PIN_HIGH;
00267             wait_us ( 1 );                                                      // Datasheet p5. T3 and T4 ( Min. 0.2us | Typ. 1us )
00268             myAuxData    <<=     1;
00269             _PD_SCK  =  HX711_PIN_LOW;
00270 
00271             // High or Low bit
00272             if ( _DOUT == HX711_PIN_HIGH )
00273                 myAuxData++;
00274         }
00275 
00276         // Last bit to release the bus
00277         wait_us ( 1 );                                                          // Datasheet p5. T3 and T4 ( Min. 0.2us | Typ. 1us )
00278         _PD_SCK  =  HX711_PIN_HIGH;
00279         wait_us ( 1 );                                                          // Datasheet p5. T3 and T4 ( Min. 0.2us | Typ. 1us )
00280         _PD_SCK  =  HX711_PIN_LOW;
00281 
00282 
00283         // Depending on the Gain we have to generate more CLK pulses
00284         switch ( _HX711_CHANNEL_GAIN ) {
00285             default:
00286             case CHANNEL_A_GAIN_128 :
00287                 myPulses             =   25;
00288                 break;
00289 
00290             case CHANNEL_B_GAIN_32 :
00291                 myPulses             =   26;
00292                 break;
00293 
00294             case CHANNEL_A_GAIN_64 :
00295                 myPulses             =   27;
00296                 break;
00297         }
00298 
00299         // Generate those extra pulses for the next measurement
00300         for ( i = 25; i < myPulses; i++ ) {
00301             wait_us ( 1 );                                                      // Datasheet p5. T3 and T4 ( Min. 0.2us | Typ. 1us )
00302             _PD_SCK  =  HX711_PIN_HIGH;
00303             wait_us ( 1 );                                                      // Datasheet p5. T3 and T4 ( Min. 0.2us | Typ. 1us )
00304             _PD_SCK  =  HX711_PIN_LOW;
00305         }
00306 
00307         // Update data to get the average
00308         myAuxData                  ^=    0x800000;
00309         myNewRawData->myRawValue   +=    myAuxData;
00310     }
00311 
00312     myNewRawData->myRawValue    /=    ( float )myAverage;
00313 
00314 
00315 
00316     if ( _DOUT == HX711_PIN_HIGH )
00317         return   HX711_SUCCESS;
00318     else
00319         return   HX711_FAILURE;
00320 }
00321 
00322 
00323 
00324 /**
00325  * @brief       HX711_ReadData_WithCalibratedMass ( HX711_channel_gain_t myChannel_Gain, Vector_count_t* myNewRawData, uint32_t myAverage )
00326  *
00327  * @details     It reads data with a calibrated mass on the load cell.
00328  *
00329  * @param[in]    myChannel_Gain:        Gain/Channel to perform the new measurement.
00330  * @param[in]    myAverage:             How many data to read.
00331  *
00332  * @param[out]   myNewRawData:          myRawValue_WithCalibratedMass ( ADC code taken with calibrated mass ).
00333  *
00334  *
00335  * @return       Status of HX711_ReadData_WithCalibratedMass.
00336  *
00337  *
00338  * @author      Manuel Caballero
00339  * @date        12/September/2017
00340  * @version     12/September/2017   The ORIGIN
00341  * @pre         NaN.
00342  * @warning     NaN.
00343  */
00344 HX711::HX711_status_t  HX711::HX711_ReadData_WithCalibratedMass   ( HX711_channel_gain_t myChannel_Gain, Vector_count_t* myNewRawData, uint32_t myAverage )
00345 {
00346     HX711_status_t        aux;
00347 
00348     // Perform a new bunch of readings
00349     aux  =   HX711_ReadRawData ( myChannel_Gain, myNewRawData, myAverage );
00350 
00351 
00352     // Update the value with a calibrated mass
00353     myNewRawData->myRawValue_WithCalibratedMass  =   myNewRawData->myRawValue;
00354 
00355 
00356 
00357     if ( aux == HX711_SUCCESS )
00358         return   HX711_SUCCESS;
00359     else
00360         return   HX711_FAILURE;
00361 }
00362 
00363 
00364 
00365 /**
00366  * @brief       HX711_ReadData_WithoutMass ( HX711_channel_gain_t myChannel_Gain, Vector_count_t* myNewRawData, uint32_t myAverage )
00367  *
00368  * @details     It reads data without any mass on the load cell.
00369  *
00370  * @param[in]    myChannel_Gain:        Gain/Channel to perform the new measurement.
00371  * @param[in]    myAverage:             How many data to read.
00372  *
00373  * @param[out]   myNewRawData:          myRawValue_WithoutCalibratedMass ( ADC code taken without any mass ).
00374  *
00375  *
00376  * @return       Status of HX711_ReadData_WithoutMass.
00377  *
00378  *
00379  * @author      Manuel Caballero
00380  * @date        12/September/2017
00381  * @version     12/September/2017   The ORIGIN
00382  * @pre         NaN.
00383  * @warning     NaN.
00384  */
00385 HX711::HX711_status_t  HX711::HX711_ReadData_WithoutMass   ( HX711_channel_gain_t myChannel_Gain, Vector_count_t* myNewRawData, uint32_t myAverage )
00386 {
00387     HX711_status_t        aux;
00388 
00389     // Perform a new bunch of readings
00390     aux  =   HX711_ReadRawData ( myChannel_Gain, myNewRawData, myAverage );
00391 
00392 
00393     // Update the value without any mass
00394     myNewRawData->myRawValue_WithoutCalibratedMass  =   myNewRawData->myRawValue;
00395 
00396 
00397 
00398     if ( aux == HX711_SUCCESS )
00399         return   HX711_SUCCESS;
00400     else
00401         return   HX711_FAILURE;
00402 }
00403 
00404 
00405 
00406 /**
00407  * @brief       HX711_CalculateMass ( Vector_count_t* myNewRawData, uint32_t myCalibratedMass, HX711_scale_t myScaleCalibratedMass )
00408  *
00409  * @details     It calculates the mass.
00410  *
00411  * @param[in]    myNewRawData:              It has myRawValue_WithCalibratedMass ( ADC code taken with calibrated mass ),
00412  *                                          myRawValue_WithoutCalibratedMass ( ADC code taken without any mass ) and
00413  *                                          myRawValue ( the current data taken by the system ).
00414  * @param[in]    myCalibratedMass:          A known value for the calibrated mass when myRawValue_WithCalibratedMass was
00415  *                                          calculated.
00416  * @param[in]    myScaleCalibratedMass:     The range of the calibrated mass ( kg, g, mg or ug ).
00417  *
00418  * @param[out]   NaN.
00419  *
00420  *
00421  * @return       The calculated mass.
00422  *
00423  *
00424  * @author      Manuel Caballero
00425  * @date        12/September/2017
00426  * @version     13/September/2017   Adapt the scale was fixed, myFactor now works as expected.
00427  *              12/September/2017   The ORIGIN
00428  * @pre         NaN.
00429  * @warning     NaN.
00430  */
00431 HX711::Vector_mass_t  HX711::HX711_CalculateMass ( Vector_count_t* myNewRawData, float myCalibratedMass, HX711_scale_t myScaleCalibratedMass )
00432 {
00433     // Terminology by Texas Instruments: sbau175a.pdf, p8 2.1.1 Calculation of Mass
00434     float m, w_zs;
00435     float c_zs, w_fs, c_fs, w_t;
00436     float c = 0;
00437     float myFactor   =   1.0;
00438 
00439     Vector_mass_t w;
00440 
00441 
00442     // Adapt the scale ( kg as reference )
00443     switch ( myScaleCalibratedMass ) {
00444         default:
00445         case HX711_SCALE_kg :
00446             // myFactor     =   1.0;
00447             break;
00448 
00449         case HX711_SCALE_g :
00450             myFactor     /=   1000.0;
00451             break;
00452 
00453         case HX711_SCALE_mg :
00454             myFactor     /=   1000000.0;
00455             break;
00456 
00457         case HX711_SCALE_ug :
00458             myFactor     /=   1000000000.0;
00459             break;
00460 
00461     }
00462 
00463 
00464     // Calculate the Calibration Constant ( m )
00465     w_fs    =    ( myCalibratedMass / myFactor );                               // User-specified calibration mass
00466     c_zs    =    myNewRawData->myRawValue_WithoutCalibratedMass;                // ADC measurement taken with no load
00467     c_fs    =    myNewRawData->myRawValue_WithCalibratedMass;                   // ADC code taken with the calibration mass applied
00468 
00469     m       =    ( float )( w_fs / ( ( c_fs ) - c_zs  ) );                      // The Calibration Constant
00470 
00471 
00472     // Calculate the zero-scale mass ( w_zs )
00473     w_zs    =    - ( m * c_zs );
00474 
00475 
00476     // Calculate the mass ( w )
00477     w_t     =    myNewRawData->myRawValue_TareWeight;                           // ADC code taken without any mass after the system is calibrated;
00478     c       =    myNewRawData->myRawValue;                                      // The ADC code
00479 
00480     w.myMass   =    ( m * c ) + w_zs - w_t;                                     // The mass according to myScaleCalibratedMass
00481 
00482 
00483     // Update Internal Parameters
00484     _HX711_USER_CALIBATED_MASS   =   myCalibratedMass;
00485     _HX711_SCALE                 =   myScaleCalibratedMass;
00486 
00487 
00488 
00489     return   w;
00490 }
00491 
00492 
00493 
00494 /**
00495  * @brief       HX711_SetAutoTare ( HX711_channel_gain_t ,float ,HX711_scale_t ,Vector_count_t* ,float )
00496  *
00497  * @details     It reads data without any mass on the load cell after the system is calibrated to calculate the tare weight.
00498  *
00499  * @param[in]    myChannel_Gain:            Gain/Channel to perform the new measurement.
00500  * @param[in]    myCalibratedMass:          A known value for the calibrated mass when myRawValue_WithCalibratedMass was
00501  *                                          calculated.
00502  * @param[in]    myScaleCalibratedMass:     The range of the calibrated mass ( kg, g, mg or ug ).
00503  * @param[in]    myTime:                    How long the auto-set lasts.
00504  *
00505  * @param[out]   myNewRawData:              myRawValue_TareWeight ( ADC code taken without any mass ).
00506  *
00507  *
00508  * @return       Status of HX711_SetAutoTare.
00509  *
00510  *
00511  * @author      Manuel Caballero
00512  * @date        12/September/2017
00513  * @version     12/September/2017   The ORIGIN
00514  * @pre         NaN.
00515  * @warning     NaN.
00516  */
00517 HX711::HX711_status_t  HX711::HX711_SetAutoTare   ( HX711_channel_gain_t myChannel_Gain, float myCalibratedMass, HX711_scale_t myScaleCalibratedMass, Vector_count_t* myNewRawData, float myTime )
00518 {
00519     HX711_status_t        aux;
00520     Vector_mass_t         myCalculatedMass;
00521     float                 myAuxData = 0;
00522     uint32_t              i = 0;
00523 
00524 
00525     // Perform a new bunch of readings every 1 second
00526     for ( i = 0; i < myTime; i++ ) {
00527         aux          =   HX711_ReadRawData ( myChannel_Gain, myNewRawData, 10 );
00528         myAuxData   +=   myNewRawData->myRawValue;
00529         wait(1);
00530     }
00531 
00532     myNewRawData->myRawValue    =    ( float )( myAuxData / myTime );
00533 
00534     // Turn it into mass
00535     myCalculatedMass     =   HX711_CalculateMass ( myNewRawData, myCalibratedMass, myScaleCalibratedMass );
00536 
00537     // Update the value without any mass
00538     myNewRawData->myRawValue_TareWeight  =   myCalculatedMass.myMass;
00539     
00540     
00541     // Update Internal Parameters
00542     _HX711_USER_CALIBATED_MASS   =   myCalibratedMass;
00543     _HX711_SCALE                 =   myScaleCalibratedMass;
00544 
00545 
00546 
00547     if ( aux == HX711_SUCCESS )
00548         return   HX711_SUCCESS;
00549     else
00550         return   HX711_FAILURE;
00551 }
00552 
00553 
00554 
00555 /**
00556  * @brief       HX711_SetManualTare ( float myTareWeight )
00557  *
00558  * @details     It sets a tare weight manually.
00559  *
00560  * @param[in]    myTareWeight:          Tare weight.
00561  *
00562  * @param[out]   NaN.
00563  *
00564  *
00565  * @return       myRawValue_TareWeight.
00566  *
00567  *
00568  * @author      Manuel Caballero
00569  * @date        12/September/2017
00570  * @version     12/September/2017   The ORIGIN
00571  * @pre         NaN.
00572  * @warning     NaN.
00573  */
00574 HX711::Vector_count_t  HX711::HX711_SetManualTare   ( float myTareWeight )
00575 {
00576     Vector_count_t myNewTareWeight;
00577 
00578     // Update the value defined by the user
00579     myNewTareWeight.myRawValue_TareWeight  =   myTareWeight;
00580 
00581 
00582 
00583     return   myNewTareWeight;
00584 }
00585 
00586 
00587 
00588 /**
00589  * @brief       HX711_CalculateVoltage ( Vector_count_t* ,float )
00590  *
00591  * @details     It calculates the mass.
00592  *
00593  * @param[in]    myChannel_Gain:            Gain/Channel of the measurement.
00594  * @param[in]    myNewRawData:              myRawValue ( the current data taken by the system ).
00595  * @param[in]    myVoltageReference:        The voltage at the converter reference input.
00596  *
00597  * @param[out]   NaN.
00598  *
00599  *
00600  * @return       The calculated voltage.
00601  *
00602  *
00603  * @author      Manuel Caballero
00604  * @date        12/September/2017
00605  * @version     12/September/2017   The ORIGIN
00606  * @pre         NaN.
00607  * @warning     NaN.
00608  */
00609 HX711::Vector_voltage_t  HX711::HX711_CalculateVoltage ( Vector_count_t* myNewRawData, float myVoltageReference )
00610 {
00611     // Terminology by Texas Instruments: sbau175a.pdf, p12 3.2 Measurement Modes Raw
00612     float x, B, A;
00613 
00614     Vector_voltage_t v;
00615 
00616     
00617     x   =    myNewRawData->myRawValue;
00618     B   =    ( 16777216.0 - 1.0 );
00619     
00620     // Adatp the gain
00621     switch ( _HX711_CHANNEL_GAIN ) {
00622         default:
00623         case CHANNEL_A_GAIN_128 :
00624             A             =   128.0;
00625             break;
00626 
00627         case CHANNEL_B_GAIN_32 :
00628             A             =   32.0;
00629             break;
00630 
00631         case CHANNEL_A_GAIN_64 :
00632             A             =   64.0;
00633             break;
00634     }
00635 
00636 
00637     // Calculate the voltage ( v )
00638     v.myVoltage = ( float )( ( x / B ) * ( myVoltageReference / A ) );          // The voltage
00639 
00640 
00641 
00642 
00643     return   v;
00644 }