133 lines
4.0 KiB
C
133 lines
4.0 KiB
C
// 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 <libopencm3/stm32/gpio.h>
|
|
#include <libopencm3/stm32/rcc.h>
|
|
#include <libopencm3/cm3/systick.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#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
|
|
} |