123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464 |
- /*
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- /*
- noInterrupts();
- ^~~~
- warning: 'taskEXIT_CRITICAL(mux)' is deprecated in ESP-IDF, consider using 'portEXIT_CRITICAL(mux)'
- interrupts();
- ^~
- /Users/thomaschef/Documents/Develop/ESP32/HomeEnergyMeter/main/ds18b20.c: In function 'ds18b20_reset':
- /Users/thomaschef/Documents/Develop/ESP32/HomeEnergyMeter/main/ds18b20.c:123:13: warning: 'taskENTER_CRITICAL(mux)' is deprecated in ESP-IDF, consider using 'portENTER_CRITICAL(mux)'
- noInterrupts();
- ^~~~
- /Users/thomaschef/Documents/Develop/ESP32/HomeEnergyMeter/main/ds18b20.c:131:13: warning: 'taskEXIT_CRITICAL(mux)' is deprecated in ESP-IDF, consider using 'portEXIT_CR
- */
- #include "freertos/FreeRTOS.h"
- #include "freertos/task.h"
- #include "driver/gpio.h"
- #include "esp32/rom/ets_sys.h"
- #include "ds18b20.h"
- #include "config.h"
- #ifdef ENABLE_DS18B20
- // OneWire commands
- #define GETTEMP 0x44 // Tells device to take a temperature reading and put it on the scratchpad
- #define SKIPROM 0xCC // Command to address all devices on the bus
- #define SELECTDEVICE 0x55 // Command to address all devices on the bus
- #define COPYSCRATCH 0x48 // Copy scratchpad to EEPROM
- #define READSCRATCH 0xBE // Read from scratchpad
- #define WRITESCRATCH 0x4E // Write to scratchpad
- #define RECALLSCRATCH 0xB8 // Recall from EEPROM to scratchpad
- #define READPOWERSUPPLY 0xB4 // Determine if device needs parasite power
- #define ALARMSEARCH 0xEC // Query bus for devices with an alarm condition
- // Scratchpad locations
- #define TEMP_LSB 0
- #define TEMP_MSB 1
- #define HIGH_ALARM_TEMP 2
- #define LOW_ALARM_TEMP 3
- #define CONFIGURATION 4
- #define INTERNAL_BYTE 5
- #define COUNT_REMAIN 6
- #define COUNT_PER_C 7
- #define SCRATCHPAD_CRC 8
- // DSROM FIELDS
- #define DSROM_FAMILY 0
- #define DSROM_CRC 7
- // Device resolution
- #define TEMP_9_BIT 0x1F // 9 bit
- #define TEMP_10_BIT 0x3F // 10 bit
- #define TEMP_11_BIT 0x5F // 11 bit
- #define TEMP_12_BIT 0x7F // 12 bit
- uint8_t DS_GPIO;
- uint8_t init=0;
- uint8_t bitResolution=12;
- uint8_t devices=0;
- DeviceAddress ROM_NO;
- uint8_t LastDiscrepancy;
- uint8_t LastFamilyDiscrepancy;
- bool LastDeviceFlag;
- /// Sends one bit to bus
- void ds18b20_write(char bit){
- if (bit & 1) {
- gpio_set_direction(DS_GPIO, GPIO_MODE_OUTPUT);
- noInterrupts();
- gpio_set_level(DS_GPIO,0);
- ets_delay_us(6);
- gpio_set_direction(DS_GPIO, GPIO_MODE_INPUT); // release bus
- ets_delay_us(64);
- interrupts();
- } else {
- gpio_set_direction(DS_GPIO, GPIO_MODE_OUTPUT);
- noInterrupts();
- gpio_set_level(DS_GPIO,0);
- ets_delay_us(60);
- gpio_set_direction(DS_GPIO, GPIO_MODE_INPUT); // release bus
- ets_delay_us(10);
- interrupts();
- }
- }
- // Reads one bit from bus
- unsigned char ds18b20_read(void){
- unsigned char value = 0;
- gpio_set_direction(DS_GPIO, GPIO_MODE_OUTPUT);
- noInterrupts();
- gpio_set_level(DS_GPIO, 0);
- ets_delay_us(6);
- gpio_set_direction(DS_GPIO, GPIO_MODE_INPUT);
- ets_delay_us(9);
- value = gpio_get_level(DS_GPIO);
- ets_delay_us(55);
- interrupts();
- return (value);
- }
- // Sends one byte to bus
- void ds18b20_write_byte(char data){
- unsigned char i;
- unsigned char x;
- for(i=0;i<8;i++){
- x = data>>i;
- x &= 0x01;
- ds18b20_write(x);
- }
- ets_delay_us(100);
- }
- // Reads one byte from bus
- unsigned char ds18b20_read_byte(void){
- unsigned char i;
- unsigned char data = 0;
- for (i=0;i<8;i++)
- {
- if(ds18b20_read()) data|=0x01<<i;
- ets_delay_us(15);
- }
- return(data);
- }
- // Sends reset pulse
- unsigned char ds18b20_reset(void){
- unsigned char presence;
- gpio_set_direction(DS_GPIO, GPIO_MODE_OUTPUT);
- noInterrupts();
- gpio_set_level(DS_GPIO, 0);
- ets_delay_us(480);
- gpio_set_level(DS_GPIO, 1);
- gpio_set_direction(DS_GPIO, GPIO_MODE_INPUT);
- ets_delay_us(70);
- presence = (gpio_get_level(DS_GPIO) == 0);
- ets_delay_us(410);
- interrupts();
- return presence;
- }
- bool ds18b20_setResolution(const DeviceAddress tempSensorAddresses[], int numAddresses, uint8_t newResolution) {
- bool success = false;
- // handle the sensors with configuration register
- newResolution = constrain(newResolution, 9, 12);
- uint8_t newValue = 0;
- ScratchPad scratchPad;
- // loop through each address
- for (int i = 0; i < numAddresses; i++){
- // we can only update the sensor if it is connected
- if (ds18b20_isConnected((DeviceAddress*) tempSensorAddresses[i], scratchPad)) {
- switch (newResolution) {
- case 12:
- newValue = TEMP_12_BIT;
- break;
- case 11:
- newValue = TEMP_11_BIT;
- break;
- case 10:
- newValue = TEMP_10_BIT;
- break;
- case 9:
- default:
- newValue = TEMP_9_BIT;
- break;
- }
- // if it needs to be updated we write the new value
- if (scratchPad[CONFIGURATION] != newValue) {
- scratchPad[CONFIGURATION] = newValue;
- ds18b20_writeScratchPad((DeviceAddress*) tempSensorAddresses[i], scratchPad);
- }
- // done
- success = true;
- }
- }
- return success;
- }
- void ds18b20_writeScratchPad(const DeviceAddress *deviceAddress, const uint8_t *scratchPad) {
- ds18b20_reset();
- ds18b20_select(deviceAddress);
- ds18b20_write_byte(WRITESCRATCH);
- ds18b20_write_byte(scratchPad[HIGH_ALARM_TEMP]); // high alarm temp
- ds18b20_write_byte(scratchPad[LOW_ALARM_TEMP]); // low alarm temp
- ds18b20_write_byte(scratchPad[CONFIGURATION]);
- ds18b20_reset();
- }
- bool ds18b20_readScratchPad(const DeviceAddress *deviceAddress, uint8_t* scratchPad) {
- // send the reset command and fail fast
- int b = ds18b20_reset();
- if (b == 0) return false;
- ds18b20_select(deviceAddress);
- ds18b20_write_byte(READSCRATCH);
- // Read all registers in a simple loop
- // byte 0: temperature LSB
- // byte 1: temperature MSB
- // byte 2: high alarm temp
- // byte 3: low alarm temp
- // byte 4: DS18B20 & DS1822: configuration register
- // byte 5: internal use & crc
- // byte 6: DS18B20 & DS1822: store for crc
- // byte 7: DS18B20 & DS1822: store for crc
- // byte 8: SCRATCHPAD_CRC
- for (uint8_t i = 0; i < 9; i++) {
- scratchPad[i] = ds18b20_read_byte();
- }
- b = ds18b20_reset();
- return (b == 1);
- }
- void ds18b20_select(const DeviceAddress *address){
- uint8_t i;
- ds18b20_write_byte(SELECTDEVICE); // Choose ROM
- for (i = 0; i < 8; i++) ds18b20_write_byte(((uint8_t *)address)[i]);
- }
- void ds18b20_requestTemperatures(){
- ds18b20_reset();
- ds18b20_write_byte(SKIPROM);
- ds18b20_write_byte(GETTEMP);
- unsigned long start = esp_timer_get_time() / 1000ULL;
- while (!isConversionComplete() && ((esp_timer_get_time() / 1000ULL) - start < millisToWaitForConversion())) vPortYield();
- }
- bool isConversionComplete() {
- uint8_t b = ds18b20_read();
- return (b == 1);
- }
- uint16_t millisToWaitForConversion() {
- switch (bitResolution) {
- case 9:
- return 94;
- case 10:
- return 188;
- case 11:
- return 375;
- default:
- return 750;
- }
- }
- bool ds18b20_isConnected(const DeviceAddress *deviceAddress, uint8_t *scratchPad) {
- bool b = ds18b20_readScratchPad(deviceAddress, scratchPad);
- return b && !ds18b20_isAllZeros(scratchPad) && (ds18b20_crc8(scratchPad, 8) == scratchPad[SCRATCHPAD_CRC]);
- }
- uint8_t ds18b20_crc8(const uint8_t *addr, uint8_t len){
- uint8_t crc = 0;
- while (len--) {
- crc = *addr++ ^ crc; // just re-using crc as intermediate
- crc = pgm_read_byte(dscrc2x16_table + (crc & 0x0f)) ^
- pgm_read_byte(dscrc2x16_table + 16 + ((crc >> 4) & 0x0f));
- }
- return crc;
- }
- bool ds18b20_isAllZeros(const uint8_t * const scratchPad) {
- for (size_t i = 0; i < 9; i++) {
- if (scratchPad[i] != 0) {
- return false;
- }
- }
- return true;
- }
- float ds18b20_getTempC(const DeviceAddress *deviceAddress) {
- ScratchPad scratchPad;
- if (ds18b20_isConnected(deviceAddress, scratchPad)){
- int16_t rawTemp = calculateTemperature(deviceAddress, scratchPad);
- if (rawTemp <= DEVICE_DISCONNECTED_RAW)
- return DEVICE_DISCONNECTED_C;
- // C = RAW/128
- // F = (C*1.8)+32 = (RAW/128*1.8)+32 = (RAW*0.0140625)+32
- return (float) rawTemp/128.0f;
- }
- return DEVICE_DISCONNECTED_C;
- }
- // reads scratchpad and returns fixed-point temperature, scaling factor 2^-7
- int16_t calculateTemperature(const DeviceAddress *deviceAddress, uint8_t* scratchPad) {
- int16_t fpTemperature = (((int16_t) scratchPad[TEMP_MSB]) << 11) | (((int16_t) scratchPad[TEMP_LSB]) << 3);
- return fpTemperature;
- }
- // Returns temperature from sensor
- float ds18b20_get_temp(void) {
- if(init==1){
- unsigned char check;
- char temp1=0, temp2=0;
- check=ds18b20_RST_PULSE();
- if(check==1)
- {
- ds18b20_send_byte(0xCC);
- ds18b20_send_byte(0x44);
- vTaskDelay(750 / portTICK_RATE_MS);
- check=ds18b20_RST_PULSE();
- ds18b20_send_byte(0xCC);
- ds18b20_send_byte(0xBE);
- temp1=ds18b20_read_byte();
- temp2=ds18b20_read_byte();
- check=ds18b20_RST_PULSE();
- float temp=0;
- temp=(float)(temp1+(temp2*256))/16;
- return temp;
- }
- else{return 0;}
- }
- else{return 0;}
- }
- void ds18b20_init(int GPIO) {
- DS_GPIO = GPIO;
- gpio_pad_select_gpio(DS_GPIO);
- init = 1;
- }
- //
- // You need to use this function to start a search again from the beginning.
- // You do not need to do it for the first search, though you could.
- //
- void reset_search() {
- devices=0;
- // reset the search state
- LastDiscrepancy = 0;
- LastDeviceFlag = false;
- LastFamilyDiscrepancy = 0;
- for (int i = 7; i >= 0; i--) {
- ROM_NO[i] = 0;
- }
- }
- // --- Replaced by the one from the Dallas Semiconductor web site ---
- //--------------------------------------------------------------------------
- // Perform the 1-Wire Search Algorithm on the 1-Wire bus using the existing
- // search state.
- // Return TRUE : device found, ROM number in ROM_NO buffer
- // FALSE : device not found, end of search
- bool search(uint8_t *newAddr, bool search_mode) {
- uint8_t id_bit_number;
- uint8_t last_zero, rom_byte_number;
- bool search_result;
- uint8_t id_bit, cmp_id_bit;
- unsigned char rom_byte_mask, search_direction;
- // initialize for search
- id_bit_number = 1;
- last_zero = 0;
- rom_byte_number = 0;
- rom_byte_mask = 1;
- search_result = false;
- // if the last call was not the last one
- if (!LastDeviceFlag) {
- // 1-Wire reset
- if (!ds18b20_reset()) {
- // reset the search
- LastDiscrepancy = 0;
- LastDeviceFlag = false;
- LastFamilyDiscrepancy = 0;
- return false;
- }
- // issue the search command
- if (search_mode == true) {
- ds18b20_write_byte(0xF0); // NORMAL SEARCH
- } else {
- ds18b20_write_byte(0xEC); // CONDITIONAL SEARCH
- }
- // loop to do the search
- do {
- // read a bit and its complement
- id_bit = ds18b20_read();
- cmp_id_bit = ds18b20_read();
- // check for no devices on 1-wire
- if ((id_bit == 1) && (cmp_id_bit == 1)) {
- break;
- } else {
- // all devices coupled have 0 or 1
- if (id_bit != cmp_id_bit) {
- search_direction = id_bit; // bit write value for search
- } else {
- // if this discrepancy if before the Last Discrepancy
- // on a previous next then pick the same as last time
- if (id_bit_number < LastDiscrepancy) {
- search_direction = ((ROM_NO[rom_byte_number]
- & rom_byte_mask) > 0);
- } else {
- // if equal to last pick 1, if not then pick 0
- search_direction = (id_bit_number == LastDiscrepancy);
- }
- // if 0 was picked then record its position in LastZero
- if (search_direction == 0) {
- last_zero = id_bit_number;
- // check for Last discrepancy in family
- if (last_zero < 9)
- LastFamilyDiscrepancy = last_zero;
- }
- }
- // set or clear the bit in the ROM byte rom_byte_number
- // with mask rom_byte_mask
- if (search_direction == 1)
- ROM_NO[rom_byte_number] |= rom_byte_mask;
- else
- ROM_NO[rom_byte_number] &= ~rom_byte_mask;
- // serial number search direction write bit
- ds18b20_write(search_direction);
- // increment the byte counter id_bit_number
- // and shift the mask rom_byte_mask
- id_bit_number++;
- rom_byte_mask <<= 1;
- // if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask
- if (rom_byte_mask == 0) {
- rom_byte_number++;
- rom_byte_mask = 1;
- }
- }
- } while (rom_byte_number < 8); // loop until through all ROM bytes 0-7
- // if the search was successful then
- if (!(id_bit_number < 65)) {
- // search successful so set LastDiscrepancy,LastDeviceFlag,search_result
- LastDiscrepancy = last_zero;
- // check for last device
- if (LastDiscrepancy == 0) {
- LastDeviceFlag = true;
- }
- search_result = true;
- }
- }
- // if no device found then reset counters so next 'search' will be like a first
- if (!search_result || !ROM_NO[0]) {
- devices=0;
- LastDiscrepancy = 0;
- LastDeviceFlag = false;
- LastFamilyDiscrepancy = 0;
- search_result = false;
- } else {
- for (int i = 0; i < 8; i++){
- newAddr[i] = ROM_NO[i];
- }
- devices++;
- }
- return search_result;
- }
- #endif // ENABLE_DS18B20
|