diff --git a/SConscript b/SConscript new file mode 100644 index 0000000..68e7b87 --- /dev/null +++ b/SConscript @@ -0,0 +1,20 @@ +from building import * +Import('rtconfig') + +src = [] +cwd = GetCurrentDir() + +# add ds18b20 src files. +if GetDepend('PKG_USING_DS18B20'): + src += Glob('src/sensor_dallas_ds18b20.c') + +if GetDepend('PKG_USING_DS18B20_SAMPLE'): + src += Glob('sample/ds18b20_sample.c') + +# add ds18b20 include path. +path = [cwd + '/inc'] + +# add src and include to group. +group = DefineGroup('ds18b20', src, depend = ['PKG_USING_DS18B20'], CPPPATH = path) + +Return('group') \ No newline at end of file diff --git a/inc/sensor_dallas_ds18b20.h b/inc/sensor_dallas_ds18b20.h new file mode 100644 index 0000000..767208d --- /dev/null +++ b/inc/sensor_dallas_ds18b20.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2019-07-15 WillianChan the first version. + * + */ + +#ifndef __DS18B20_H__ +#define __DS18B20_H__ + +#include +#include +#include +#include "sensor.h" + +#define CONNECT_SUCCESS 0 +#define CONNECT_FAILED 1 + +struct ds18b20_device +{ + rt_base_t pin; + rt_mutex_t lock; +}; +typedef struct ds18b20_device *ds18b20_device_t; + +uint8_t ds18b20_init(rt_base_t pin); +int32_t ds18b20_get_temperature(rt_base_t pin); +int rt_hw_ds18b20_init(const char *name, struct rt_sensor_config *cfg); + +#endif /* __DS18B20_H_ */ + + diff --git a/sample/ds18b20_sample.c b/sample/ds18b20_sample.c new file mode 100644 index 0000000..7c9879f --- /dev/null +++ b/sample/ds18b20_sample.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2019-07-24 WillianChan the first version + */ + +#include +#include +#include "sensor.h" +#include "sensor_dallas_ds18b20.h" + +/* Modify this pin according to the actual wiring situation */ +#define DS18B20_DATA_PIN GET_PIN(G, 9) + +static void read_temp_entry(void *parameter) +{ + rt_device_t dev = RT_NULL; + struct rt_sensor_data sensor_data; + rt_size_t res; + + dev = rt_device_find(parameter); + if (dev == RT_NULL) + { + rt_kprintf("Can't find device:%s\n", parameter); + return; + } + + if (rt_device_open(dev, RT_DEVICE_FLAG_RDWR) != RT_EOK) + { + rt_kprintf("open device failed!\n"); + return; + } + rt_device_control(dev, RT_SENSOR_CTRL_SET_ODR, (void *)100); + + while (1) + { + res = rt_device_read(dev, 0, &sensor_data, 1); + if (res != 1) + { + rt_kprintf("read data failed!size is %d\n", res); + rt_device_close(dev); + return; + } + else + { + if (sensor_data.data.temp >= 0) + { + rt_kprintf("temp:%3d.%dC, timestamp:%5d\n", + sensor_data.data.temp / 10, + sensor_data.data.temp % 10, + sensor_data.timestamp); + } + else + { + rt_kprintf("temp:-%2d.%dC, timestamp:%5d\n", + abs(sensor_data.data.temp / 10), + abs(sensor_data.data.temp % 10), + sensor_data.timestamp); + } + } + rt_thread_mdelay(100); + } +} + +static int ds18b20_read_temp_sample(void) +{ + rt_thread_t ds18b20_thread; + + ds18b20_thread = rt_thread_create("18b20tem", + read_temp_entry, + "temp_ds18b20", + 1024, + RT_THREAD_PRIORITY_MAX / 2, + 20); + if (ds18b20_thread != RT_NULL) + { + rt_thread_startup(ds18b20_thread); + } + + return RT_EOK; +} +INIT_APP_EXPORT(ds18b20_read_temp_sample); + +static int rt_hw_ds18b20_port(void) +{ + struct rt_sensor_config cfg; + + cfg.intf.user_data = (void *)DS18B20_DATA_PIN; + rt_hw_ds18b20_init("ds18b20", &cfg); + + return RT_EOK; +} +INIT_COMPONENT_EXPORT(rt_hw_ds18b20_port); diff --git a/src/sensor_dallas_ds18b20.c b/src/sensor_dallas_ds18b20.c new file mode 100644 index 0000000..c238e99 --- /dev/null +++ b/src/sensor_dallas_ds18b20.c @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2019-07-15 WillianChan the first version. + * + */ + +#include "sensor_dallas_ds18b20.h" +#include "sensor.h" +#include "board.h" +#include + +#define DBG_TAG "sensor.dallas.ds18b20" +#define DBG_LVL DBG_INFO + +#define SENSOR_TEMP_RANGE_MAX (125) +#define SENSOR_TEMP_RANGE_MIN (-55) + +RT_WEAK void rt_hw_us_delay(rt_uint32_t us) +{ + rt_uint32_t delta; + + us = us * (SysTick->LOAD / (1000000 / RT_TICK_PER_SECOND)); + delta = SysTick->VAL; + + while (delta - SysTick->VAL < us) continue; +} + +static void ds18b20_reset(rt_base_t pin) +{ + rt_pin_mode(pin, PIN_MODE_OUTPUT); + rt_pin_write(pin, PIN_LOW); + rt_hw_us_delay(780); /* 480us - 960us */ + rt_pin_write(pin, PIN_HIGH); + rt_hw_us_delay(40); /* 15us - 60us*/ +} + +static uint8_t ds18b20_connect(rt_base_t pin) +{ + uint8_t retry = 0; + rt_pin_mode(pin, PIN_MODE_INPUT); + + while (rt_pin_read(pin) && retry < 200) + { + retry++; + rt_hw_us_delay(1); + }; + + if(retry >= 200) + return CONNECT_FAILED; + else + retry = 0; + + while (!rt_pin_read(pin) && retry < 240) + { + retry++; + rt_hw_us_delay(1); + }; + + if(retry >= 240) + return CONNECT_FAILED; + + return CONNECT_SUCCESS; +} + +static uint8_t ds18b20_read_bit(rt_base_t pin) +{ + uint8_t data; + + rt_pin_mode(pin, PIN_MODE_OUTPUT); + rt_pin_write(pin, PIN_LOW); + rt_hw_us_delay(2); + rt_pin_write(pin, PIN_HIGH); + rt_pin_mode(pin, PIN_MODE_INPUT); + /* maybe 12us, maybe 5us, whatever...I have no idea */ + rt_hw_us_delay(5); + + if(rt_pin_read(pin)) + data = 1; + else + data = 0; + + rt_hw_us_delay(50); + + return data; +} + +static uint8_t ds18b20_read_byte(rt_base_t pin) +{ + uint8_t i, j, dat; + dat = 0; + + for (i = 1; i <= 8; i++) + { + j = ds18b20_read_bit(pin); + dat = (j << 7) | (dat >> 1); + } + + return dat; +} + +static void ds18b20_write_byte(rt_base_t pin, uint8_t dat) +{ + uint8_t j; + uint8_t testb; + rt_pin_mode(pin, PIN_MODE_OUTPUT); + + for (j = 1; j <= 8; j++) + { + testb = dat & 0x01; + dat = dat >> 1; + + if(testb) + { + rt_pin_write(pin, PIN_LOW); + rt_hw_us_delay(2); + rt_pin_write(pin, PIN_HIGH); + rt_hw_us_delay(60); + } + else + { + rt_pin_write(pin, PIN_LOW); + rt_hw_us_delay(60); + rt_pin_write(pin, PIN_HIGH); + rt_hw_us_delay(2); + } + } +} + +void ds18b20_start(rt_base_t pin) +{ + ds18b20_reset(pin); + ds18b20_connect(pin); + ds18b20_write_byte(pin, 0xcc); /* skip rom */ + ds18b20_write_byte(pin, 0x44); /* convert */ +} + +uint8_t ds18b20_init(rt_base_t pin) +{ + uint8_t ret = 0; + + ds18b20_reset(pin); + ret = ds18b20_connect(pin); + + return ret; +} + +int32_t ds18b20_get_temperature(rt_base_t pin) +{ + uint8_t TL, TH; + int32_t tem; + + ds18b20_start(pin); + ds18b20_init(pin); + ds18b20_write_byte(pin, 0xcc); + ds18b20_write_byte(pin, 0xbe); + TL = ds18b20_read_byte(pin); /* LSB first */ + TH = ds18b20_read_byte(pin); + if (TH > 7) + { + TH =~ TH; + TL =~ TL; + tem = TH; + tem <<= 8; + tem += TL; + tem = (int32_t)(tem * 0.0625 * 10 + 0.5); + return -tem; + } + else + { + tem = TH; + tem <<= 8; + tem += TL; + tem = (int32_t)(tem * 0.0625 * 10 + 0.5); + return tem; + } +} + +static rt_size_t _ds18b20_polling_get_data(rt_sensor_t sensor, struct rt_sensor_data *data) +{ + rt_int32_t temperature_x10; + if (sensor->info.type == RT_SENSOR_CLASS_TEMP) + { + temperature_x10 = ds18b20_get_temperature((rt_base_t)sensor->config.intf.user_data); + data->data.temp = temperature_x10; + data->timestamp = rt_sensor_get_ts(); + } + return 1; +} + +static rt_size_t ds18b20_fetch_data(struct rt_sensor_device *sensor, void *buf, rt_size_t len) +{ + RT_ASSERT(buf); + + if (sensor->config.mode == RT_SENSOR_MODE_POLLING) + { + return _ds18b20_polling_get_data(sensor, buf); + } + else + return 0; +} + +static rt_err_t ds18b20_control(struct rt_sensor_device *sensor, int cmd, void *args) +{ + rt_err_t result = RT_EOK; + + return result; +} + +static struct rt_sensor_ops sensor_ops = +{ + ds18b20_fetch_data, + ds18b20_control +}; + +int rt_hw_ds18b20_init(const char *name, struct rt_sensor_config *cfg) +{ + rt_int8_t result; + rt_sensor_t sensor_temp = RT_NULL; + + if (!ds18b20_init((rt_base_t)cfg->intf.user_data)) + { + /* temperature sensor register */ + sensor_temp = rt_calloc(1, sizeof(struct rt_sensor_device)); + if (sensor_temp == RT_NULL) + return -1; + + sensor_temp->info.type = RT_SENSOR_CLASS_TEMP; + sensor_temp->info.vendor = RT_SENSOR_VENDOR_DALLAS; + sensor_temp->info.model = "ds18b20"; + sensor_temp->info.unit = RT_SENSOR_UNIT_DCELSIUS; + sensor_temp->info.intf_type = RT_SENSOR_INTF_ONEWIRE; + sensor_temp->info.range_max = SENSOR_TEMP_RANGE_MAX; + sensor_temp->info.range_min = SENSOR_TEMP_RANGE_MIN; + sensor_temp->info.period_min = 5; + + rt_memcpy(&sensor_temp->config, cfg, sizeof(struct rt_sensor_config)); + sensor_temp->ops = &sensor_ops; + + result = rt_hw_sensor_register(sensor_temp, name, RT_DEVICE_FLAG_RDONLY, RT_NULL); + if (result != RT_EOK) + { + LOG_E("device register err code: %d", result); + goto __exit; + } + + } + return RT_EOK; + +__exit: + if (sensor_temp) + rt_free(sensor_temp); + return -RT_ERROR; +}