diff --git a/Makefile b/Makefile index 3c5e405..dab2fe8 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,8 @@ PROJECT = f030f4 #SRCS = startup.c uplow.2.c hello.c #SRCS = startup.c clocks.c uptime.c #SRCS = startup.txeie.c txeie.c uptime.c -SRCS = startup.txeie.c gpioa.c dht11main.c dht11.c +#SRCS = startup.txeie.c gpioa.c dht11main.c dht11.c +SRCS = startup.txeie.c gpioa.c ds18b20main.c ds18b20.c OBJS = $(SRCS:.c=.o) LIBOBJS = printf.o putchar.o puts.o CPU = -mthumb -mcpu=cortex-m0 diff --git a/ds18b20.c b/ds18b20.c new file mode 100644 index 0000000..ab14e1d --- /dev/null +++ b/ds18b20.c @@ -0,0 +1,168 @@ +/* ds18b20.c -- 1-Wire digital thermometer */ +/* Copyright (c) 2020 Renaud Fivet */ + +#include "ds18b20.h" /* implements DS18B20 API */ + +#include "system.h" /* gpioa_(), usleep() */ + +#define DIO 13 +#define input() gpioa_input( DIO) +#define output() gpioa_output( DIO) +#define bread() gpioa_read( DIO) + +#define MAX_RETRIES 999 +#define wait_level( lvl) \ + retries = MAX_RETRIES ; \ + while( bread() != lvl) \ + if( retries-- == 0) \ + return DS18B20_FAIL_TOUT + +void ds18b20_init( void) { + input() ; /* Wire floating, HIGH by pull-up */ +} + +static ds18b20_retv_t initialization() { +/* Reset */ + output() ; /* Wire LOW */ + usleep( 480) ; + input() ; /* Wire floating, HIGH by pull-up */ + +/* Presence */ + int retries ; + wait_level( HIGH) ; /* Pull-up LOW -> HIGH, T1 */ + wait_level( LOW) ; /* DS18B20 asserts line to LOW, T2, T2 - T1 = 15~60us */ + wait_level( HIGH) ; /* DS18B20 releases lines, Pull-up LOW -> HIGH, T3 + ** T3 - T2 = 60~240us */ + usleep( 405) ; /* 480 = 405 + 15 + 60 */ + + return DS18B20_SUCCESS ; +} + +static void write( unsigned char uc) { +/* Transmit byte, least significant bit first */ + for( unsigned char curbit = 1 ; curbit ; curbit <<= 1) { + /* Transmit a bit takes 60us + 1us between transmit */ + /* Write 1: <15us LOW */ + /* Write 0: 60us LOW */ + unsigned t = uc & curbit ? 13 : 60 ; + output() ; /* Wire LOW */ + usleep( t) ; + input() ; /* Wire floating, HIGH by pull-up */ + usleep( 61 - t) ; + } +} + +static iolvl_t poll( void) { + output() ; /* Wire LOW */ + usleep( 1) ; + input() ; /* Wire floating, HIGH by pull-up */ + usleep( 5) ; + iolvl_t bit = bread() ; + usleep( 55) ; + return bit ; +} + +static unsigned char read( unsigned char *p, int size) { + unsigned char crc = 0 ; + + while( size--) { + /* Receive byte, least significant bit first */ + unsigned char uc = 0 ; + for( unsigned char curbit = 1 ; curbit ; curbit <<= 1) { + /* read bit */ + int v = poll() ; + if( v) + uc |= curbit ; + + /* update CRC */ + v ^= crc ; + crc >>= 1 ; + if( v & 1) + crc ^= 0x119 >> 1 ; /* reverse POLY = x^8 + x^5 + x^4 + 1 */ + } + + /* store byte */ + *p++ = uc ; + } + + return crc ; +} + +static ds18b20_retv_t read_scratchpad( unsigned char scratchpad[]) { + ds18b20_retv_t ret = initialization() ; + if( ret != DS18B20_SUCCESS) + return ret ; + + write( 0xCC) ; /* Skip ROM */ + write( 0xBE) ; /* Read Scratchpad */ + return read( scratchpad, 9) ? DS18B20_FAIL_CRC : DS18B20_SUCCESS ; +} + +ds18b20_retv_t ds18b20_convert( void) { + ds18b20_retv_t ret ; + + ret = initialization() ; + if( ret != DS18B20_SUCCESS) + return ret ; + + write( 0xCC) ; /* Skip ROM */ + write( 0x44) ; /* Convert T */ + return DS18B20_SUCCESS ; +} + +ds18b20_retv_t ds18b20_fetch( short *deciCtemp) { /* -550~1250 = -55.0~125.0 C */ + ds18b20_retv_t ret ; + unsigned char vals[ 9] ; /* scratchpad */ + + ret = read_scratchpad( vals) ; + if( ret != DS18B20_SUCCESS) + return ret ; + + *deciCtemp = *((short *) vals) * 10 / 16 ; + return DS18B20_SUCCESS ; +} + +ds18b20_retv_t ds18b20_read( short *deciCtemp) { /* -550~1250 = -55.0~125.0 C */ + ds18b20_retv_t ret ; + + ret = ds18b20_convert() ; + if( ret != DS18B20_SUCCESS) + return ret ; + + do + usleep( 4000) ; + while( poll() == LOW) ; /* up to 93.75ms for 9 bits, 750ms for 12 bits */ + + return ds18b20_fetch( deciCtemp) ; +} + +ds18b20_retv_t ds18b20_resolution( unsigned res) { /* 9..12 bits */ + ds18b20_retv_t ret ; + unsigned char vals[ 9] ; /* scratchpad */ + unsigned char curres ; + +/* read scratchpad */ + ret = read_scratchpad( vals) ; + if( ret != DS18B20_SUCCESS) + return ret ; + +/* update resolution if current value is different than requested */ + res = (res - 9) & 3 ; + curres = vals[ 4] >> 5 ; + if( curres != res) { + vals[ 4] = (vals[ 4] & 0x1F) | (res << 5) ; + ret = initialization() ; + if( ret != DS18B20_SUCCESS) + return ret ; + + write( 0xCC) ; /* Skip ROM */ + write( 0x4E) ; /* Write Scratchpad */ + write( vals[ 2]) ; + write( vals[ 3]) ; + write( vals[ 4]) ; + } + + return DS18B20_SUCCESS ; +} + +/* end of ds18b20.c */ diff --git a/ds18b20.h b/ds18b20.h new file mode 100644 index 0000000..7ec2d51 --- /dev/null +++ b/ds18b20.h @@ -0,0 +1,16 @@ +/* ds18b20.h -- 1-Wire temperature sensor */ +/* Copyright (c) 2020 Renaud Fivet */ + +typedef enum { + DS18B20_SUCCESS, + DS18B20_FAIL_TOUT, + DS18B20_FAIL_CRC +} ds18b20_retv_t ; + +void ds18b20_init( void) ; +ds18b20_retv_t ds18b20_resolution( unsigned res) ; /* 9..12 bits */ +ds18b20_retv_t ds18b20_convert( void) ; +ds18b20_retv_t ds18b20_fetch( short *deciCtemp) ;/* -550~1250 = -55.0~125.0 C */ +ds18b20_retv_t ds18b20_read( short *deciCtemp) ; /* -550~1250 = -55.0~125.0 C */ + +/* end of ds18b20.h */ diff --git a/ds18b20main.c b/ds18b20main.c new file mode 100644 index 0000000..d06b7d0 --- /dev/null +++ b/ds18b20main.c @@ -0,0 +1,37 @@ +/* ds18b20main.c -- sample temperature using 1-Wire temperature sensor */ +/* Copyright (c) 2020 Renaud Fivet */ + +#include + +#include "system.h" /* uptime */ +#include "ds18b20.h" /* ds18b20_() */ + +int main( void) { + unsigned last = 0 ; + + ds18b20_init() ; + ds18b20_resolution( 12) ; /* Set highest resolution: 12 bits */ + ds18b20_convert() ; /* start temperature conversion */ + for( ;;) + if( last == uptime) + yield() ; + else { + short val ; + + last = uptime ; + switch( ds18b20_fetch( &val)) { + case DS18B20_SUCCESS: + printf( "%i.%i\n", val / 10, val % 10) ; + break ; + case DS18B20_FAIL_TOUT: + puts( "Timeout") ; + break ; + case DS18B20_FAIL_CRC: + puts( "CRC Error") ; + } + + ds18b20_convert() ; /* start temperature conversion */ + } +} + +/* end of ds18b20main.c */