// Lots of the info came from: https://teslabs.com/openplayer/docs/docs/other/ds18b20_pre1.pdf and https://www.circuitbread.com/tutorials/embedded-c-programming-with-the-pic18f14k50-12-digital-thermometer // Also needed to use a scope to check the timings were reasonably accurate #include #include #include #include #include #include "ds18b20.h" #include "misc.h" // Delay function void ds18b20_delay_us(uint32_t us) { for (uint32_t i = 0; i < (us * 3); i++) { __asm__("nop"); } } void ds18b20_delay_us_nop() { __asm__("nop"); } // OneWire low-level functions static void ds18b20_pin_mode_output(uint32_t ds18b20_port, uint32_t ds18b20_pin) { gpio_mode_setup(ds18b20_port, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, ds18b20_pin); } static void ds18b20_pin_mode_input(uint32_t ds18b20_port, uint32_t ds18b20_pin) { gpio_mode_setup(ds18b20_port, GPIO_MODE_INPUT, GPIO_PUPD_NONE, ds18b20_pin); } static void ds18b20_write_bit(uint32_t ds18b20_port, uint32_t ds18b20_pin, uint8_t bit) { ds18b20_pin_mode_output(ds18b20_port, ds18b20_pin); gpio_clear(ds18b20_port, ds18b20_pin); if (bit) { delay_us(1); // Short low pulse for '1' gpio_set(ds18b20_port, ds18b20_pin); ds18b20_pin_mode_input(ds18b20_port, ds18b20_pin); } delay_us(60); ds18b20_pin_mode_input(ds18b20_port, ds18b20_pin); delay_us(10); } static uint8_t ds18b20_read_bit(uint32_t ds18b20_port, uint32_t ds18b20_pin) { uint8_t bit; ds18b20_pin_mode_output(ds18b20_port, ds18b20_pin); gpio_clear(ds18b20_port, ds18b20_pin); // ds18b20_delay_us(1); // gpio_set(ds18b20_port, ds18b20_pin); ds18b20_pin_mode_input(ds18b20_port, ds18b20_pin); ds18b20_delay_us(10); bit = gpio_get(ds18b20_port, ds18b20_pin); ds18b20_delay_us(50); return bit; } uint8_t ds18b20_reset(uint32_t ds18b20_port, uint32_t ds18b20_pin) { uint8_t presence; ds18b20_pin_mode_output(ds18b20_port, ds18b20_pin); gpio_clear(ds18b20_port, ds18b20_pin); ds18b20_delay_us(960); ds18b20_pin_mode_input(ds18b20_port, ds18b20_pin); ds18b20_delay_us(120); presence = gpio_get(ds18b20_port, ds18b20_pin); ds18b20_delay_us(840); return presence == 0; // If presence is detected, return 1 } void ds18b20_write_byte(uint32_t ds18b20_port, uint32_t ds18b20_pin, uint8_t byte) { for (uint8_t i = 0; i < 8; i++) { ds18b20_write_bit(ds18b20_port, ds18b20_pin, byte & 0x01); byte >>= 1; } ds18b20_pin_mode_input(ds18b20_port, ds18b20_pin); } uint8_t ds18b20_read_byte(uint32_t ds18b20_port, uint32_t ds18b20_pin) { uint8_t byte = 0; //Value to be returned for (uint8_t i = 0; i< 8; i++)//Loop to read the whole byte { byte >>= 1; //Shift the byte at one bit to the right if (ds18b20_read_bit(ds18b20_port, ds18b20_pin)) //If 1 has been read byte |= 0x80; //Then add it to the byte } return (byte); } // DS18B20 high-level functions void ds18b20_start_conversion(uint32_t ds18b20_port, uint32_t ds18b20_pin) { ds18b20_reset(ds18b20_port, ds18b20_pin); delay_ms(1); ds18b20_write_byte(ds18b20_port, ds18b20_pin, 0xCC); // Skip ROM delay_ms(1); ds18b20_write_byte(ds18b20_port, ds18b20_pin, 0x44); // Start conversion delay_ms(1); } int16_t ds18b20_read_raw_temperature(uint32_t ds18b20_port, uint32_t ds18b20_pin) { uint8_t scratchpad[10]; int16_t temp_raw; ds18b20_reset(ds18b20_port, ds18b20_pin); delay_ms(1); ds18b20_write_byte(ds18b20_port, ds18b20_pin, 0xCC); // Skip ROM delay_ms(1); ds18b20_write_byte(ds18b20_port, ds18b20_pin, 0xBE); // Read Scratchpad delay_ms(1); // Read all 9 bytes of the scratchpad for (int i = 0; i <= 9; i++) { scratchpad[i] = ds18b20_read_byte(ds18b20_port, ds18b20_pin); } // Raw temperature is stored in the first two bytes uint8_t temp_lsb = scratchpad[0]; uint8_t temp_msb = scratchpad[1]; temp_raw = (temp_msb << 8) | temp_lsb; return (temp_raw * 625) / 10; // Scale to Celsius * 1000 }