void getTemperature(void) { int16 value; HalAdcSetReference(HAL_ADC_REF_125V); TR0 |= 1; ATEST |= 1; value = HalAdcRead(HAL_ADC_CHANNEL_TEMP, HAL_ADC_RESOLUTION_12); ATEST &= ~1; TR0 &= ~1; HalAdcSetReference(HAL_ADC_REF_AVDD); zclHomelink_Temperature = 2500 + ((value - ADC_TEMP_25C) * (int16)(100 / ADC_TEMP_BITS_PER_C)); }
/********************************************************************* * @fn readAdcData * * @brief Read ADC channel value * * @return none */ static uint16 readAdcData( uint8 channel ) { uint16 adcVdd3, adcChannel, vdd, voltage; HalAdcSetReference(HAL_ADC_REF_125V); adcVdd3 = HalAdcRead(HAL_ADC_CHN_VDD3, HAL_ADC_RESOLUTION_8); vdd = (adcVdd3) * 29; // (1240 * 3 / 127), ADC internal voltage for CC254x is 1.24V HalAdcSetReference( HAL_ADC_REF_AVDD ); adcChannel = HalAdcRead( channel, HAL_ADC_RESOLUTION_8); voltage = (uint16)( ((uint32)adcChannel * (uint32)vdd) / 127 ); return voltage; }
/*************************************************************************************************** * @fn BspRubyTmpMeas_offchip * * @brief Get temperature value from offchip sensor * * @param None * * * * * @return None ***************************************************************************************************/ uint16 BspRubyTmpMeas() { uint8 i; uint32 tmp=0; uint32 voltage; BSP_TMP_CHG_SBIT = 1; HalAdcSetReference(HAL_ADC_REF_AVDD); for(i=0;i<4;i++){ voltage = HalAdcRead(HAL_ADC_CHN_AIN6,HAL_ADC_RESOLUTION_14); // tmp = tmp+(1000*voltage/(8192-voltage)); tmp += voltage; } BSP_TMP_CHG_SBIT = 0; tmp = tmp/4; // tmp = voltage/4; // for(i=0;i<140;i++) // { // if((tmp<=tmp_table[i])&&(tmp>tmp_table[i+1])) // { // result = i/2; // break; // } // } return (uint16)tmp; }
/** * @fn batt_measure * * @brief Measure the battery level with the ADC * * @param none * * @return */ static unsigned char batt_measure(void) { unsigned short adc; // configure ADC and perform a read HalAdcSetReference(HAL_ADC_REF_125V); adc = HalAdcRead(HAL_ADC_CHANNEL_7, HAL_ADC_RESOLUTION_14); if (!BATCD_SBIT) { batt_level = 7; // battery charge } else if ((adc >= BATT_LEVEL_01)) { batt_level = 6; // battery full } else if ((adc >= BATT_LEVEL_02) && (adc < BATT_LEVEL_01)) { batt_level = 5; } else if ((adc >= BATT_LEVEL_03) && (adc < BATT_LEVEL_02)) { batt_level = 4; } else if ((adc >= BATT_LEVEL_04) && (adc < BATT_LEVEL_03)) { batt_level = 3; } else if ((adc >= BATT_LEVEL_05) && (adc < BATT_LEVEL_04)) { batt_level = 2; } else if ((adc >= BATT_LEVEL_06) && (adc < BATT_LEVEL_05)) { batt_level = 1; // battery empty } else { batt_level = 0; // battery shutdown } battmsg(("adc=%04x, lv=%02x\n", adc, batt_level)); return batt_level; }
/********************************************************************* * @fn battMeasure * * @brief Measure the battery level with the ADC and return * it as a percentage 0-100%. * * @return Battery level. */ static uint8 battMeasure( void ) { uint16 adc; uint8 percent; /** * Battery level conversion from ADC to a percentage: * * The maximum ADC value for the battery voltage level is 511 for a * 10-bit conversion. The ADC value is references vs. 1.25v and * this maximum value corresponds to a voltage of 3.75v. * * For a coin cell battery 3.0v = 100%. The minimum operating * voltage of the CC2540 is 2.0v so 2.0v = 0%. * * To convert a voltage to an ADC value use: * * (v/3)/1.25 * 511 = adc * * 3.0v = 409 ADC * 2.0v = 273 ADC * * We need to map ADC values from 409-273 to 100%-0%. * * Normalize the ADC values to zero: * * 409 - 273 = 136 * * And convert ADC range to percentage range: * * percent/adc = 100/136 = 25/34 * * Resulting in the final equation, with round: * * percent = ((adc - 273) * 25) + 33 / 34 */ // Configure ADC and perform a read HalAdcSetReference( HAL_ADC_REF_125V ); adc = HalAdcRead( HAL_ADC_CHANNEL_VDD, HAL_ADC_RESOLUTION_10 ); if (adc >= BATT_ADC_LEVEL_3V) { percent = 100; } else if (adc <= BATT_ADC_LEVEL_2V) { percent = 0; } else { percent = (uint8) ((((adc - BATT_ADC_LEVEL_2V) * 25) + 33) / 34); } return percent; }
/********************************************************************* * @fn battMeasure * * @brief Measure the battery level with the ADC and return * it as a percentage 0-100%. * * @return Battery level. */ static uint8 battMeasure( void ) { uint16 adc; uint8 percent; /** * Battery level conversion from ADC to a percentage: * * The maximum ADC value for the battery voltage level is 511 for a * 10-bit conversion. The ADC value is references vs. 1.25v and * this maximum value corresponds to a voltage of 3.75v. * * For a coin cell battery 3.0v = 100%. The minimum operating * voltage of the CC2540 is 2.0v so 2.0v = 0%. * * To convert a voltage to an ADC value use: * * (v/3)/1.25 * 511 = adc * * 3.0v = 409 ADC * 2.0v = 273 ADC * * We need to map ADC values from 409-273 to 100%-0%. * * Normalize the ADC values to zero: * * 409 - 273 = 136 * * And convert ADC range to percentage range: * * percent/adc = 100/136 = 25/34 * * Resulting in the final equation, with round: * * percent = ((adc - 273) * 25) + 33 / 34 */ // Call measurement setup callback if (battServiceSetupCB != NULL) { battServiceSetupCB(); } // Configure ADC and perform a read HalAdcSetReference( HAL_ADC_REF_125V ); adc = HalAdcRead( battServiceAdcCh, HAL_ADC_RESOLUTION_10 ); // Call measurement teardown callback if (battServiceTeardownCB != NULL) { battServiceTeardownCB(); } if (adc >= battMaxLevel) { percent = 100; } else if (adc <= battMinLevel) { percent = 0; } else { if (battServiceCalcCB != NULL) { percent = battServiceCalcCB(adc); } else { uint16 range = battMaxLevel - battMinLevel + 1; // optional if you want to keep it even, otherwise just take floor of divide // range += (range & 1); range >>= 2; // divide by 4 percent = (uint8) ((((adc - battMinLevel) * 25) + (range - 1)) / range); } } return percent; }
/************************************************************************************************** * @fn DataUpdate_ProcessEvent * * @brief Update values from A/D sensor and diags * * @param uint8 task_id * @param uint16 events - event mask * * @return uint16 - 0 (for now) ************************************************************************************************** */ uint16 DataUpdate_ProcessEvent(uint8 task_id, uint16 events) { #if ADV_DEBUG_MESSAGE_FORMAT==1 // variables that are needed if we're running the advanced debugging message format int vdd_div_3; int vdd; int16 tempvalCC2541; int spare; #endif int tempval; int16 tempval2; int16 tempval3; int16 tempval4; int16 tempavg; uint16 timeval; uint16 sensorval; #if USE_SEPARATE_TEMP_AD_CHANNEL==0 uint8 lmp_configured; uint8 lmp_configure_tries; #endif #ifdef FAKE_SENS_DATA #ifdef O2_SENSOR uint16 max_fake = 1000; uint16 min_fake = 600; static int16 fake_adj = 1; static uint16 fakesensorval = 600; #endif #ifdef CO_SENSOR uint16 max_fake = 1300; uint16 min_fake = 380; static int16 fake_adj = 1; static uint16 fakesensorval = 380; #endif #endif if (events & 1) { timeval = (uint16) (osal_GetSystemClock() & 0xffff); cyclecount++; if (cyclecount>9) { cyclecount=0; // Also, set P1_0 (the LED) as an output, and drive high P1DIR = P1DIR | 0x01; P1 = P1 | 0x01; } /* Enable channel */ ADCCFG |= 0x80; P0DIR = 0x83; // force P0.0, P0.1, and P0.7 to be inputs APCFG = 0x83; HalAdcSetReference (0x40); // use AIN7 for ref (0x08 would be AVDD5, 0x00 would be internal ref #if USE_SEPARATE_TEMP_AD_CHANNEL==0 // Configure LMP9100 to output temperature if (lmp91KinitComplete) { // Because the processor may have been sleeping, re-configure I2C intf. before // performing the I2C transaction HalI2CExitSleep(); lmp_configure_tries=0; lmp_configured=0; // We can't hang out in this loop forever, but we can retry a couple // of times, to get over any instability on the I2C bus while ((lmp_configure_tries<4) && (!lmp_configured)) { // Set this flag so that we presume that communication is working. // The flag will get cleared (quickly) as a side-effect in the // communication routines if we fail again. lmp91kOK=1; lmp_configured=LMP91000_I2CSwitchVoutToTempSensor(); lmp_configure_tries++; } // end while // Because the processor may go into sleep mode, save the state of the I2C // interface before continuing. HalI2CEnterSleep(); } // end if (lmp91KinitComplete) #endif // Read temperature from LMP9100 if (!lmp91kOK) { // If we're not communicating, then the LMP91000 may not be in the right // state, so just use a previous value. tempval = oldtempval; } else { tempval = HalAdcRead(HAL_ADC_CHANNEL_0, HAL_ADC_RESOLUTION_12); tempval2 = HalAdcRead(HAL_ADC_CHANNEL_0, HAL_ADC_RESOLUTION_12); tempval3 = HalAdcRead(HAL_ADC_CHANNEL_0, HAL_ADC_RESOLUTION_12); tempval4 = HalAdcRead(HAL_ADC_CHANNEL_0, HAL_ADC_RESOLUTION_12); // Get a bit of noise out of the temperature measurment by averaging 4 // samples. // By the way, we expect nominal values to be around 1100 or so // at room temperature, so we can fairly safely add 4 16-bit values // together without thinking too much about overflow. // If the nominal values were larger, we'd promote to a larger // data type before averaging. tempavg = (tempval+tempval2+tempval3+tempval4)/4; oldtempval=tempavg; } // Convert temp to tenths of degrees C, based on the table in // the datasheet for the LMP91000, and assuming a 2.5v ref tempval = convertTemp(tempavg); // Now, get ready to measure the oxygen sensor HalAdcSetReference (0x40); // use AIN7 for ref #if USE_SEPARATE_TEMP_AD_CHANNEL==0 if (lmp91KinitComplete) { // Because the processor may have been sleeping, re-configure I2C intf. before // performing the I2C transaction(s) HalI2CExitSleep(); lmp_configure_tries=0; lmp_configured=0; // we can't hang out in this loop forever, but we can retry a couple // of times, to get over any instability on the I2C while ((lmp_configure_tries<4) && (!lmp_configured)) { // Set this flag so that we presume that communication is working. // The flag will get cleared (quickly) as a side-effect in the // communication routines if we fail again. lmp91kOK=1; // Likely redundant, but doesn't hurt LMP91000_I2CConfigureForO2Sensor( SensTIAGain , SensRLoad, SensRefVoltageSource, SensIntZSel); if (lmp91kOK) { lmp_configured = LMP91000_I2CSwitchVoutToO2Sensor(SensModeOp); } lmp_configure_tries++; } // end while // Because the processor may go into sleep mode, save the state of the I2C // interface before continuing. HalI2CEnterSleep(); } // end if (lmp91KinitComplete) #endif if (!lmp91kOK) { // If we're not communicating, then the LMP91000 may not be in the right // state, so just use a previous value. sensorval = oldsensorval; } else { #if USE_SEPARATE_TEMP_AD_CHANNEL==1 sensorval = HalAdcRead(HAL_ADC_CHANNEL_1,HAL_ADC_RESOLUTION_12); #else sensorval = HalAdcRead(HAL_ADC_CHANNEL_0,HAL_ADC_RESOLUTION_12); #endif oldsensorval = sensorval; } // Depending on compile options, build the message, or gather // additional diagnostic info and then build the debug mode message #ifdef FAKE_SENS_DATA fakesensorval += fake_adj; if ((fakesensorval >= max_fake) || (fakesensorval <= min_fake)) fake_adj = -1 * fake_adj; sensorval = fakesensorval; #endif #if ADV_DEBUG_MESSAGE_FORMAT==0 updateSensorData ((uint16)timeval, (uint16)tempval, (uint16)sensorval); DataReadyFlag = 1; #else // Gather additional interesting diagnostic info before updating structure spare = HalAdcRead(0x01, HAL_ADC_RESOLUTION_12); // Spare A/D chan - use for battery measurement later // Turn on the test mode to enable temperature measurement // from the CC2544's internal temp sensor ATEST=1; // ATEST.ATEST_CTRL=0x01; TR0=1; // TR0.ADCTM=1; HalAdcSetReference(0); // use internal ref voltage (1.15 V) //HalAdcSetReference ( 0x80); // use AVDD5 pin for ref // CC2541 Internal temp sensor is A/D input 14 (0x0e) tempvalCC2541 = HalAdcRead(0x0E, HAL_ADC_RESOLUTION_12); /* Turn off test modes */ TR0=0; // TR0.ADCTM=0; ATEST=0; // The analog temperature sensor in the CC2544 should give back a value // of 1480 at 25 degrees C and VDD=3, // and will change by a value of 4.5 per degree C // // So, to get temperature in 0.1 degrees C units, consider the // following formula: // tempval2 = tempvalCC2541-1480; tempvalCC2541 = (int16) (250.0 + (tempval2/4.5)); HalAdcSetReference(0); // use internal ref voltage (1.15 V) // Pick up VDD divided by 3 vdd_div_3 = HalAdcRead(0x0F, HAL_ADC_RESOLUTION_12); // VDD/3 // Convert to millivolts (and get rid of the divide by 3, since we're doing math // vdd = (int) (1.15*vdd_div_3*3.0*1000.0 / 2047.0); // convert to millivolts // vdd = (int) (vdd_div_3 * 1.6853932584269662921348314606742); // more precisely vdd = (int) (vdd_div_3 * 1.6853); // close enough // Pick up the spare A/D input HalAdcSetReference (0x40); // use AIN7 for ref spare = HalAdcRead(0x01, HAL_ADC_RESOLUTION_12); updateSensorData ((uint16)timeval, (uint16)tempval, (uint16)sensorval, (uint16)tempvalCC2541, (uint16)vdd, (uint16)spare); DataReadyFlag = 1; #endif // Set the light control I/O (LightOn=1 => P1_1=0) nuSOCKET_updateLight(); // Also, set P1_0 (the LED) as an output, and drive low P1DIR = P1DIR | 0x01; P1 = P1&0xFE; return (events ^ 1);; } return (0); } // end DataUpdate_ProcessEvent()
void CurrentDetectionT1_Init(uint8 task_id) { IO_Init(); CurrentDetectionT1_TaskID = task_id; CurrentDetectionT1_NwkState = DEV_INIT; CurrentDetectionT1_TransID = 0; MT_UartInit(); MT_UartRegisterTaskID(task_id); // Device hardware initialization can be added here or in main() (Zmain.c). // If the hardware is application specific - add it here. // If the hardware is other parts of the device add it in main(). #if defined ( BUILD_ALL_DEVICES ) // The "Demo" target is setup to have BUILD_ALL_DEVICES and HOLD_AUTO_START // We are looking at a jumper (defined in CurrentDetectionT1Hw.c) to be jumpered // together - if they are - we will start up a coordinator. Otherwise, // the device will start as a router. if (readCoordinatorJumper()) zgDeviceLogicalType = ZG_DEVICETYPE_COORDINATOR; else zgDeviceLogicalType = ZG_DEVICETYPE_ROUTER; #endif // BUILD_ALL_DEVICES // Setup for the periodic message's destination address // Broadcast to everyone CurrentDetectionT1_Periodic_DstAddr.addrMode = (afAddrMode_t)Addr16Bit; CurrentDetectionT1_Periodic_DstAddr.endPoint = HEARTBEAT_ENDPOINT; CurrentDetectionT1_Periodic_DstAddr.addr.shortAddr = 0; // Fill out the endpoint description. CurrentDetectionT1_epDesc.endPoint = HEARTBEAT_ENDPOINT; CurrentDetectionT1_epDesc.task_id = &CurrentDetectionT1_TaskID; CurrentDetectionT1_epDesc.simpleDesc = (SimpleDescriptionFormat_t *)&CurrentDetectionT1_SimpleDesc; CurrentDetectionT1_epDesc.latencyReq = noLatencyReqs; // Register the endpoint description with the AF afRegister(&CurrentDetectionT1_epDesc); // Register for all key events - This app will handle all key events RegisterForKeys(CurrentDetectionT1_TaskID); nv_read_config(); HalAdcInit(); HalAdcSetReference(HAL_ADC_REF_AVDD); #ifdef DEBUG_TRACE //memset(serialNumber, 0, SN_LEN); //serialNumber[SN_LEN - 1] = 20; #endif memcpy(serialNumber, aExtendedAddress, SN_LEN); //Feed WatchDog WDCTL = 0xa0; WDCTL = 0x50; osal_start_timerEx(CurrentDetectionT1_TaskID, DTCT_HEARTBEAT_MSG_EVT, 10); osal_start_timerEx(CurrentDetectionT1_TaskID, DTCT_LED_WTD_EVT, 10); }
/********************************************************************* * @fn battMeasure * * @brief Measure the battery level with the ADC and return * it as a percentage 0-100%. * * @return Battery level. */ uint8 battMeasure( void ) { static unsigned char i; unsigned char j; static uint8 percent[16]; uint16 adc; uint16 buffer; /** * Battery level conversion from ADC to a percentage: * * The maximum ADC value for the battery voltage level is 511 for a * 10-bit conversion. The ADC value is references vs. 1.25v and * this maximum value corresponds to a voltage of 3.75v. * * For a coin cell battery 4.2v = 100%. The minimum operating * voltage of the CC2540 is 4.2v so 3.4v = 0%. * * To convert a voltage to an ADC value use: * * (v*1/3)/3.3 * 4095 = adc * * 4.2v = 1737 ADC * 3.4v = 1406 ADC * * We need to map ADC values from 434-351 to 100%-0%. * * Normalize the ADC values to zero: * * 433 - 351 = 82 * * And convert ADC range to percentage range: * * percent/adc = 100/82 = 50/41 * * Resulting in the final equation, with round: * * percent = ((adc - 351) * 50) / 41 */ // Call measurement setup callback if (battServiceSetupCB != NULL) { battServiceSetupCB(); } // Configure ADC and perform a read // HalAdcSetReference( HAL_ADC_REF_125V ); HalAdcSetReference(HAL_ADC_REF_AVDD); adc = HalAdcRead( battServiceAdcCh, HAL_ADC_RESOLUTION_12 ); // Call measurement teardown callback if (battServiceTeardownCB != NULL) { battServiceTeardownCB(); } if (adc >= battMaxLevel) { percent[i++] = (battMaxLevel - battMinLevel)>>1; }
uint8 simpleProfileReadConfig(uint16 uuid, uint8 *newValue) { uint8 len = 0; switch ( uuid ) { case SIMPLEPROFILE_CHAR1_UUID: case SIMPLEPROFILE_CHAR2_UUID: case SIMPLEPROFILE_CHAR4_UUID: break; case SIMPLEPROFILE_CHAR5_UUID: HalLcdWriteString( "Char 5 read", HAL_LCD_LINE_6 ); newValue[len++] = sys_config.update_time_ms>>24; newValue[len++] = sys_config.update_time_ms>>16; newValue[len++] = sys_config.update_time_ms>>8; newValue[len++] = sys_config.update_time_ms>>0; break; case SIMPLEPROFILE_CHAR6_UUID: { break; } case SIMPLEPROFILE_CHAR7_UUID: HalLcdWriteString( "Char 7 read", HAL_LCD_LINE_6 ); len = osal_strlen((char*)sys_config.name); osal_memcpy(newValue, sys_config.name, len); break; case SIMPLEPROFILE_CHAR8_UUID: HalLcdWriteString( "Char 8 read", HAL_LCD_LINE_6 ); // 最高温度报警 newValue[len++] = sys_config.tempeature_hight>>8; newValue[len++] = sys_config.tempeature_hight & 0xff; // 最低温度报警 newValue[len++] = sys_config.tempeature_low>>8; newValue[len++] = sys_config.tempeature_low & 0xff; break; case SIMPLEPROFILE_CHAR9_UUID: HalLcdWriteString( "Char 9 read", HAL_LCD_LINE_6 ); HalAdcSetReference( HAL_ADC_REF_AVDD ); { uint16 adc0, adc1; adc0 = HalAdcRead( HAL_ADC_CHANNEL_0, HAL_ADC_RESOLUTION_14 ) & 0x1fff; adc1 = HalAdcRead( HAL_ADC_CHANNEL_1, HAL_ADC_RESOLUTION_14 ) & 0x1fff; newValue[len++] = adc0>>8; newValue[len++] = adc0 & 0xFF; newValue[len++] = adc1>>8; newValue[len++] = adc1 & 0xFF; } break; case SIMPLEPROFILE_CHARA_UUID:// pwm HalLcdWriteString( "Char A read", HAL_LCD_LINE_6 ); newValue[len++] = sys_config.pwm[3]; newValue[len++] = sys_config.pwm[2]; newValue[len++] = sys_config.pwm[1]; newValue[len++] = sys_config.pwm[0]; break; default: len = 0; } return len; }