From 43424ca5be4b190463e4cdedad0b7d329189bf2b Mon Sep 17 00:00:00 2001 From: IOsetting Date: Sun, 5 Jun 2022 12:01:19 +0800 Subject: [PATCH] feat: add rom search method for ds18b20 --- demo/gpio/ds18b20/ds18b20.c | 168 ---------- demo/gpio/ds18b20/multiple-ds18b20/ds18b20.c | 301 ++++++++++++++++++ .../ds18b20/{ => multiple-ds18b20}/ds18b20.h | 56 +++- demo/gpio/ds18b20/multiple-ds18b20/main.c | 79 +++++ demo/gpio/ds18b20/single-ds18b20/ds18b20.c | 301 ++++++++++++++++++ demo/gpio/ds18b20/single-ds18b20/ds18b20.h | 168 ++++++++++ .../main.c} | 26 +- 7 files changed, 920 insertions(+), 179 deletions(-) delete mode 100644 demo/gpio/ds18b20/ds18b20.c create mode 100644 demo/gpio/ds18b20/multiple-ds18b20/ds18b20.c rename demo/gpio/ds18b20/{ => multiple-ds18b20}/ds18b20.h (66%) create mode 100644 demo/gpio/ds18b20/multiple-ds18b20/main.c create mode 100644 demo/gpio/ds18b20/single-ds18b20/ds18b20.c create mode 100644 demo/gpio/ds18b20/single-ds18b20/ds18b20.h rename demo/gpio/ds18b20/{ds18b20_stc8h3k.c => single-ds18b20/main.c} (71%) diff --git a/demo/gpio/ds18b20/ds18b20.c b/demo/gpio/ds18b20/ds18b20.c deleted file mode 100644 index 81809e0..0000000 --- a/demo/gpio/ds18b20/ds18b20.c +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright 2021 IOsetting -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "ds18b20.h" - -void DS18B20_Init(void) -{ - DS18B20_DQ_PULLUP(); - DS18B20_DQ_OUTPUT(); - DS18B20_DQ = SET; - SYS_DelayUs(1000); - DS18B20_DQ = RESET; - SYS_DelayUs(1000); - DS18B20_DQ = SET; - SYS_DelayUs(2000); -} - -__BIT DS18B20_Reset(void) -{ - __BIT b; - - /* Line low, and wait 480us */ - DS18B20_DQ = RESET; - DS18B20_DQ_OUTPUT(); - SYS_DelayUs(500); - /* Release line and wait for 70us */ - DS18B20_DQ_INPUT(); - SYS_DelayUs(70); - /* Check bit value, success if low */ - b = DS18B20_DQ; - /* Delay for 410 us */ - SYS_DelayUs(410); - /* Return value of presence pulse, 0 = OK, 1 = ERROR */ - return b; -} - -__BIT DS18B20_ReadBit(void) -{ - __BIT b = RESET; - - /* Line low */ - DS18B20_DQ = RESET; - DS18B20_DQ_OUTPUT(); - SYS_DelayUs(2); - - /* Release line */ - DS18B20_DQ_INPUT(); - SYS_DelayUs(10); - - /* Read line value */ - if (DS18B20_DQ) { - /* Bit is HIGH */ - b = SET; - } - - /* Wait 50us to complete 60us period */ - SYS_DelayUs(50); - - /* Return bit value */ - return b; -} - -uint8_t DS18B20_ReadByte(void) -{ - uint8_t i = 8, byte = 0; - while (i--) - { - byte >>= 1; - byte |= (DS18B20_ReadBit() << 7); - } - return byte; -} - -void DS18B20_WriteBit(__BIT b) -{ - if (b) - { - /* Set line low */ - DS18B20_DQ = RESET; - DS18B20_DQ_OUTPUT(); - SYS_DelayUs(10); - - /* Bit high */ - DS18B20_DQ_INPUT(); - - /* Wait for 55 us and release the line */ - SYS_DelayUs(55); - DS18B20_DQ_INPUT(); - } - else - { - /* Set line low */ - DS18B20_DQ = RESET; - DS18B20_DQ_OUTPUT(); - SYS_DelayUs(65); - - /* Bit high */ - DS18B20_DQ_INPUT(); - - /* Wait for 5 us and release the line */ - SYS_DelayUs(5); - DS18B20_DQ_INPUT(); - } - -} - -void DS18B20_WriteByte(uint8_t byte) -{ - uint8_t i = 8; - /* Write 8 bits */ - while (i--) - { - /* LSB bit is first */ - DS18B20_WriteBit(byte & 0x01); - byte >>= 1; - } -} - -void DS18B20_StartAll(void) -{ - /* Reset pulse */ - DS18B20_Reset(); - /* Skip rom */ - DS18B20_WriteByte(ONEWIRE_CMD_SKIPROM); - /* Start conversion on all connected devices */ - DS18B20_WriteByte(DS18B20_CMD_CONVERTTEMP); -} - -__BIT DS18B20_AllDone(void) -{ - /* If read bit is low, then device is not finished yet with calculation temperature */ - return DS18B20_ReadBit(); -} - -uint16_t DS18B20_ReadTemperature(void) -{ - uint16_t temperature; - uint8_t i = 0; - uint8_t data[9]; - - /* Reset line */ - DS18B20_Reset(); - /* Skip ROM */ - DS18B20_WriteByte(ONEWIRE_CMD_SKIPROM); - /* Read scratchpad command by onewire protocol */ - DS18B20_WriteByte(ONEWIRE_CMD_RSCRATCHPAD); - - /* Get data */ - for (i = 0; i < 9; i++) - { - /* Read byte by byte */ - data[i] = DS18B20_ReadByte(); - } - temperature = data[1]; - temperature = temperature << 8 | data[0]; - return temperature; -} diff --git a/demo/gpio/ds18b20/multiple-ds18b20/ds18b20.c b/demo/gpio/ds18b20/multiple-ds18b20/ds18b20.c new file mode 100644 index 0000000..f024b23 --- /dev/null +++ b/demo/gpio/ds18b20/multiple-ds18b20/ds18b20.c @@ -0,0 +1,301 @@ +// Copyright 2021 IOsetting +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "ds18b20.h" + +void DS18B20_Init(void) +{ + DS18B20_DQ_PULLUP(); + DS18B20_DQ_OUTPUT(); + DS18B20_DQ = SET; + SYS_DelayUs(1000); + DS18B20_DQ = RESET; + SYS_DelayUs(1000); + DS18B20_DQ = SET; + SYS_DelayUs(2000); +} + +__BIT DS18B20_Reset(void) +{ + __BIT b; + + /* Line low, and wait 480us */ + DS18B20_DQ = RESET; + DS18B20_DQ_OUTPUT(); + SYS_DelayUs(500); + /* Release line and wait for 70us */ + DS18B20_DQ_INPUT(); + SYS_DelayUs(70); + /* Check bit value, success if low */ + b = DS18B20_DQ; + /* Delay for 410 us */ + SYS_DelayUs(410); + /* Return value of presence pulse, 0 = OK, 1 = ERROR */ + return b; +} + +__BIT DS18B20_ReadBit(void) +{ + __BIT b = RESET; + + /* Line low */ + DS18B20_DQ = RESET; + DS18B20_DQ_OUTPUT(); + SYS_DelayUs(2); + + /* Release line */ + DS18B20_DQ_INPUT(); + SYS_DelayUs(10); + + /* Read line value */ + if (DS18B20_DQ) { + /* Bit is HIGH */ + b = SET; + } + + /* Wait 50us to complete 60us period */ + SYS_DelayUs(50); + + /* Return bit value */ + return b; +} + +uint8_t DS18B20_ReadByte(void) +{ + uint8_t i = 8, byte = 0; + while (i--) + { + byte >>= 1; + byte |= (DS18B20_ReadBit() << 7); + } + return byte; +} + +void DS18B20_WriteBit(__BIT b) +{ + if (b) + { + /* Set line low */ + DS18B20_DQ = RESET; + DS18B20_DQ_OUTPUT(); + SYS_DelayUs(10); + + /* Bit high */ + DS18B20_DQ_INPUT(); + + /* Wait for 55 us and release the line */ + SYS_DelayUs(55); + DS18B20_DQ_INPUT(); + } + else + { + /* Set line low */ + DS18B20_DQ = RESET; + DS18B20_DQ_OUTPUT(); + SYS_DelayUs(65); + + /* Bit high */ + DS18B20_DQ_INPUT(); + + /* Wait for 5 us and release the line */ + SYS_DelayUs(5); + DS18B20_DQ_INPUT(); + } +} + +void DS18B20_WriteByte(uint8_t byte) +{ + uint8_t i = 8; + /* Write 8 bits */ + while (i--) + { + /* LSB bit is first */ + DS18B20_WriteBit(byte & 0x01); + byte >>= 1; + } +} + +void DS18B20_ReadScratchpad(uint8_t *buf) +{ + uint8_t i = 0; + /* Reset line */ + DS18B20_Reset(); + /* Skip ROM */ + DS18B20_WriteByte(ONEWIRE_CMD_SKIPROM); + /* Read scratchpad command by onewire protocol */ + DS18B20_WriteByte(ONEWIRE_CMD_RSCRATCHPAD); + + /* Get data */ + for (i = 0; i < 9; i++) + { + /* Read byte by byte */ + *buf++ = DS18B20_ReadByte(); + } +} + +uint8_t DS18B20_Crc(uint8_t *addr, uint8_t len) +{ + uint8_t crc = 0, inbyte, i, mix; + + while (len--) + { + inbyte = *addr++; + for (i = 8; i; i--) + { + mix = (crc ^ inbyte) & 0x01; + crc >>= 1; + if (mix) + { + crc ^= 0x8C; + } + inbyte >>= 1; + } + } + /* Return calculated CRC */ + return crc; +} + +void DS18B20_StartAll(void) +{ + /* Reset pulse */ + DS18B20_Reset(); + /* Skip rom */ + DS18B20_WriteByte(ONEWIRE_CMD_SKIPROM); + /* Start conversion on all connected devices */ + DS18B20_WriteByte(DS18B20_CMD_CONVERTTEMP); +} + +__BIT DS18B20_AllDone(void) +{ + /* If read bit is low, then device is not finished yet with calculation temperature */ + return DS18B20_ReadBit(); +} + +void DS18B20_ReadRom(uint8_t *buf) +{ + uint8_t i = 0; + /* Reset pulse */ + DS18B20_Reset(); + /* Read rom */ + DS18B20_WriteByte(ONEWIRE_CMD_READROM); + /* Get data */ + for (i = 0; i < 8; i++) + { + /* Read byte by byte */ + *buf++ = DS18B20_ReadByte(); + } +} + +void DS18B20_Select(const uint8_t* addr) +{ + uint8_t len = 8; + DS18B20_WriteByte(ONEWIRE_CMD_MATCHROM); + while (len--) + { + DS18B20_WriteByte(*addr++); + } +} + +void DS18B20_Start(const uint8_t *addr) +{ + /* Reset pulse */ + DS18B20_Reset(); + /* Select ROM number */ + DS18B20_Select(addr); + /* Start conversion on selected device */ + DS18B20_WriteByte(DS18B20_CMD_CONVERTTEMP); +} + +void DS18B20_ReadScratchpadFromAddr(const uint8_t *addr, uint8_t *buf) +{ + uint8_t i = 0; + /* Reset line */ + DS18B20_Reset(); + /* Select ROM number */ + DS18B20_Select(addr); + /* Read scratchpad command by onewire protocol */ + DS18B20_WriteByte(ONEWIRE_CMD_RSCRATCHPAD); + + /* Get data */ + for (i = 0; i < 9; i++) + { + /* Read byte by byte */ + *buf++ = DS18B20_ReadByte(); + } +} + +uint8_t DS18B20_Detect(uint8_t *buff, uint8_t *stack, uint8_t split_point) +{ + uint8_t len = 64, pos = 0; + /* Start from deepest point */ + split_point = (split_point == 0x00)? 0xFF : split_point; + /* Reset line */ + DS18B20_Reset(); + /* Start searching */ + DS18B20_WriteByte(ONEWIRE_CMD_SEARCHROM); + + while (len--) + { + // Read the value and its complement value of this bit + __BIT pb = DS18B20_ReadBit(); + __BIT cb = DS18B20_ReadBit(); + if (pb && cb) // no device + { + return 0; + } + else if (pb) // bit = 1 + { + *(buff + pos / 8) |= 0x01 << (pos % 8); + DS18B20_WriteBit(SET); + // confirm: set this bit to 1 + *(stack + pos / 8) |= 0x01 << (pos % 8); + } + else if (cb) // bit = 0 + { + *(buff + pos / 8) &= ~(0x01 << (pos % 8)); + DS18B20_WriteBit(RESET); + // confirm: set this bit to 1 + *(stack + pos / 8) |= 0x01 << (pos % 8); + } + else // bit can be 0 or 1, possible split point + { + if (split_point == 0xFF || pos > split_point) + { + // new split point, try 0 + *(buff + pos / 8) &= ~(0x01 << (pos % 8)); + DS18B20_WriteBit(RESET); + // unconfirm: set this bit to 0 + *(stack + pos / 8) &= ~(0x01 << (pos % 8)); + // record this new split point + split_point = pos; + } + else if (pos == split_point) + { + // reach split point, try 1 + *(buff + pos / 8) |= 0x01 << (pos % 8); + DS18B20_WriteBit(SET); + // confirm: set this bit to 1 + *(stack + pos / 8) |= 0x01 << (pos % 8); + } + else // middle point, use existing bit + { + DS18B20_WriteBit(*(buff + pos / 8) >> (pos % 8) & 0x01); + } + } + pos++; + } + // Relocate split point, move it to the last *unconfirmed* bit of stack + while (split_point > 0 && *(stack + split_point / 8) >> (split_point % 8) & 0x01 == 0x01) split_point--; + return split_point; +} \ No newline at end of file diff --git a/demo/gpio/ds18b20/ds18b20.h b/demo/gpio/ds18b20/multiple-ds18b20/ds18b20.h similarity index 66% rename from demo/gpio/ds18b20/ds18b20.h rename to demo/gpio/ds18b20/multiple-ds18b20/ds18b20.h index 94c74ca..e4a3654 100644 --- a/demo/gpio/ds18b20/ds18b20.h +++ b/demo/gpio/ds18b20/multiple-ds18b20/ds18b20.h @@ -100,7 +100,22 @@ void DS18B20_WriteBit(__BIT b); void DS18B20_WriteByte(uint8_t byte); /** - * @brief Start all DS18B20 + * @brief 8-bit CRC calculation + * + * @param addr + * @param len + * @return crc result + */ +uint8_t DS18B20_Crc(uint8_t *addr, uint8_t len); + +/** + * @brief Read SRAM scratchpad + * @param buf a 9-byte buffer, Byte 8 contains the CRC code for bytes 0 through 7 + */ +void DS18B20_ReadScratchpad(uint8_t *buf); + +/** + * @brief Start conversion on all slaves */ void DS18B20_StartAll(void); @@ -111,10 +126,43 @@ void DS18B20_StartAll(void); __BIT DS18B20_AllDone(void); /** - * @brief Read 16 bits temperature - * @return temperature value + * @brief Read 64-bit ROM: 8-bit family code "0x28", unique 48-bit serial number, 8-bit CRC + * @note This command can only be used if there is a single DS18B20 on the bus. + * If multiple slaves are present, a data collision will occur(a wired AND result). + * @param buf a 8-byte buffer */ -uint16_t DS18B20_ReadTemperature(void); +void DS18B20_ReadRom(uint8_t *buf); +/** + * @brief Select a slave on the bus + * @note Only the slave that exactly matches the 64-bit ROM code sequence will respond to + * the function command issued by the master; all other slaves on the bus will wait + * for a reset pulse. + * @param addr 64-bit ROM code + */ +void DS18B20_Select(const uint8_t* addr); + +/** + * @brief Start conversion on selected slave + * @param addr 64-bit ROM code + */ +void DS18B20_Start(const uint8_t *addr); + +/** + * @brief Read SRAM scratchpad from selected slave + * + * @param addr 64-bit ROM code + * @param buf a 9-byte buffer, Byte 8 contains the CRC code for bytes 0 through 7 + */ +void DS18B20_ReadScratchpadFromAddr(const uint8_t *addr, uint8_t *buf); + +/** + * @brief Perform one ROM search + * @param buff 8-byte array for ROM bytes + * @param stack 8-byte array for search stack + * @param split_point deepest split point of last search + * @return new split point + */ +uint8_t DS18B20_Detect(uint8_t *buff, uint8_t *stack, uint8_t split_point); #endif // __DS18B20_H_ diff --git a/demo/gpio/ds18b20/multiple-ds18b20/main.c b/demo/gpio/ds18b20/multiple-ds18b20/main.c new file mode 100644 index 0000000..7f533f7 --- /dev/null +++ b/demo/gpio/ds18b20/multiple-ds18b20/main.c @@ -0,0 +1,79 @@ +// Copyright 2021 IOsetting +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/*** + * Example code of communication on 1-Wire bus with multiple DS18B20 + * + * Board: STC8H3K32 + * + * P35 -> DQ + * GND -> GND + * 3.3V -> VCC + */ + +#include "fw_hal.h" +#include "ds18b20.h" + +uint8_t DS18B20_Buff[9], addr[8], Search_Stack[8]; + +void PrintArray(uint8_t *arr, uint8_t start, uint8_t end) +{ + uint8_t i; + for (i = start; i < end; i++) + { + UART1_TxHex(*(arr + i)); + } +} + +int main(void) +{ + uint8_t i, sp; + + SYS_SetClock(); + // UART1, baud 115200, baud source Timer1, 1T mode, no interrupt + UART1_Config8bitUart(UART1_BaudSource_Timer1, HAL_State_ON, 115200); + DS18B20_Init(); + + while(1) + { + // Reset split point and search for all DS18B20 + sp = 0; + do + { + // ROM search and store ROM bytes to addr + sp = DS18B20_Detect(addr, Search_Stack, sp); + // Print the new split point and address + UART1_TxHex(sp); + UART1_TxChar(' '); + PrintArray(addr, 0, 8); + // Convert and read from this address + DS18B20_Start(addr); + while (!DS18B20_AllDone()) + { + UART1_TxChar('.'); + SYS_Delay(50); + } + DS18B20_ReadScratchpadFromAddr(addr, DS18B20_Buff); + PrintArray(DS18B20_Buff, 0, 9); + UART1_TxChar(' '); + i = DS18B20_Crc(DS18B20_Buff, 8); + UART1_TxString("CRC:"); + UART1_TxHex(i); + UART1_TxChar(' '); + UART1_TxString("\r\n"); + } while (sp); + + SYS_Delay(1000); + } +} diff --git a/demo/gpio/ds18b20/single-ds18b20/ds18b20.c b/demo/gpio/ds18b20/single-ds18b20/ds18b20.c new file mode 100644 index 0000000..f024b23 --- /dev/null +++ b/demo/gpio/ds18b20/single-ds18b20/ds18b20.c @@ -0,0 +1,301 @@ +// Copyright 2021 IOsetting +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "ds18b20.h" + +void DS18B20_Init(void) +{ + DS18B20_DQ_PULLUP(); + DS18B20_DQ_OUTPUT(); + DS18B20_DQ = SET; + SYS_DelayUs(1000); + DS18B20_DQ = RESET; + SYS_DelayUs(1000); + DS18B20_DQ = SET; + SYS_DelayUs(2000); +} + +__BIT DS18B20_Reset(void) +{ + __BIT b; + + /* Line low, and wait 480us */ + DS18B20_DQ = RESET; + DS18B20_DQ_OUTPUT(); + SYS_DelayUs(500); + /* Release line and wait for 70us */ + DS18B20_DQ_INPUT(); + SYS_DelayUs(70); + /* Check bit value, success if low */ + b = DS18B20_DQ; + /* Delay for 410 us */ + SYS_DelayUs(410); + /* Return value of presence pulse, 0 = OK, 1 = ERROR */ + return b; +} + +__BIT DS18B20_ReadBit(void) +{ + __BIT b = RESET; + + /* Line low */ + DS18B20_DQ = RESET; + DS18B20_DQ_OUTPUT(); + SYS_DelayUs(2); + + /* Release line */ + DS18B20_DQ_INPUT(); + SYS_DelayUs(10); + + /* Read line value */ + if (DS18B20_DQ) { + /* Bit is HIGH */ + b = SET; + } + + /* Wait 50us to complete 60us period */ + SYS_DelayUs(50); + + /* Return bit value */ + return b; +} + +uint8_t DS18B20_ReadByte(void) +{ + uint8_t i = 8, byte = 0; + while (i--) + { + byte >>= 1; + byte |= (DS18B20_ReadBit() << 7); + } + return byte; +} + +void DS18B20_WriteBit(__BIT b) +{ + if (b) + { + /* Set line low */ + DS18B20_DQ = RESET; + DS18B20_DQ_OUTPUT(); + SYS_DelayUs(10); + + /* Bit high */ + DS18B20_DQ_INPUT(); + + /* Wait for 55 us and release the line */ + SYS_DelayUs(55); + DS18B20_DQ_INPUT(); + } + else + { + /* Set line low */ + DS18B20_DQ = RESET; + DS18B20_DQ_OUTPUT(); + SYS_DelayUs(65); + + /* Bit high */ + DS18B20_DQ_INPUT(); + + /* Wait for 5 us and release the line */ + SYS_DelayUs(5); + DS18B20_DQ_INPUT(); + } +} + +void DS18B20_WriteByte(uint8_t byte) +{ + uint8_t i = 8; + /* Write 8 bits */ + while (i--) + { + /* LSB bit is first */ + DS18B20_WriteBit(byte & 0x01); + byte >>= 1; + } +} + +void DS18B20_ReadScratchpad(uint8_t *buf) +{ + uint8_t i = 0; + /* Reset line */ + DS18B20_Reset(); + /* Skip ROM */ + DS18B20_WriteByte(ONEWIRE_CMD_SKIPROM); + /* Read scratchpad command by onewire protocol */ + DS18B20_WriteByte(ONEWIRE_CMD_RSCRATCHPAD); + + /* Get data */ + for (i = 0; i < 9; i++) + { + /* Read byte by byte */ + *buf++ = DS18B20_ReadByte(); + } +} + +uint8_t DS18B20_Crc(uint8_t *addr, uint8_t len) +{ + uint8_t crc = 0, inbyte, i, mix; + + while (len--) + { + inbyte = *addr++; + for (i = 8; i; i--) + { + mix = (crc ^ inbyte) & 0x01; + crc >>= 1; + if (mix) + { + crc ^= 0x8C; + } + inbyte >>= 1; + } + } + /* Return calculated CRC */ + return crc; +} + +void DS18B20_StartAll(void) +{ + /* Reset pulse */ + DS18B20_Reset(); + /* Skip rom */ + DS18B20_WriteByte(ONEWIRE_CMD_SKIPROM); + /* Start conversion on all connected devices */ + DS18B20_WriteByte(DS18B20_CMD_CONVERTTEMP); +} + +__BIT DS18B20_AllDone(void) +{ + /* If read bit is low, then device is not finished yet with calculation temperature */ + return DS18B20_ReadBit(); +} + +void DS18B20_ReadRom(uint8_t *buf) +{ + uint8_t i = 0; + /* Reset pulse */ + DS18B20_Reset(); + /* Read rom */ + DS18B20_WriteByte(ONEWIRE_CMD_READROM); + /* Get data */ + for (i = 0; i < 8; i++) + { + /* Read byte by byte */ + *buf++ = DS18B20_ReadByte(); + } +} + +void DS18B20_Select(const uint8_t* addr) +{ + uint8_t len = 8; + DS18B20_WriteByte(ONEWIRE_CMD_MATCHROM); + while (len--) + { + DS18B20_WriteByte(*addr++); + } +} + +void DS18B20_Start(const uint8_t *addr) +{ + /* Reset pulse */ + DS18B20_Reset(); + /* Select ROM number */ + DS18B20_Select(addr); + /* Start conversion on selected device */ + DS18B20_WriteByte(DS18B20_CMD_CONVERTTEMP); +} + +void DS18B20_ReadScratchpadFromAddr(const uint8_t *addr, uint8_t *buf) +{ + uint8_t i = 0; + /* Reset line */ + DS18B20_Reset(); + /* Select ROM number */ + DS18B20_Select(addr); + /* Read scratchpad command by onewire protocol */ + DS18B20_WriteByte(ONEWIRE_CMD_RSCRATCHPAD); + + /* Get data */ + for (i = 0; i < 9; i++) + { + /* Read byte by byte */ + *buf++ = DS18B20_ReadByte(); + } +} + +uint8_t DS18B20_Detect(uint8_t *buff, uint8_t *stack, uint8_t split_point) +{ + uint8_t len = 64, pos = 0; + /* Start from deepest point */ + split_point = (split_point == 0x00)? 0xFF : split_point; + /* Reset line */ + DS18B20_Reset(); + /* Start searching */ + DS18B20_WriteByte(ONEWIRE_CMD_SEARCHROM); + + while (len--) + { + // Read the value and its complement value of this bit + __BIT pb = DS18B20_ReadBit(); + __BIT cb = DS18B20_ReadBit(); + if (pb && cb) // no device + { + return 0; + } + else if (pb) // bit = 1 + { + *(buff + pos / 8) |= 0x01 << (pos % 8); + DS18B20_WriteBit(SET); + // confirm: set this bit to 1 + *(stack + pos / 8) |= 0x01 << (pos % 8); + } + else if (cb) // bit = 0 + { + *(buff + pos / 8) &= ~(0x01 << (pos % 8)); + DS18B20_WriteBit(RESET); + // confirm: set this bit to 1 + *(stack + pos / 8) |= 0x01 << (pos % 8); + } + else // bit can be 0 or 1, possible split point + { + if (split_point == 0xFF || pos > split_point) + { + // new split point, try 0 + *(buff + pos / 8) &= ~(0x01 << (pos % 8)); + DS18B20_WriteBit(RESET); + // unconfirm: set this bit to 0 + *(stack + pos / 8) &= ~(0x01 << (pos % 8)); + // record this new split point + split_point = pos; + } + else if (pos == split_point) + { + // reach split point, try 1 + *(buff + pos / 8) |= 0x01 << (pos % 8); + DS18B20_WriteBit(SET); + // confirm: set this bit to 1 + *(stack + pos / 8) |= 0x01 << (pos % 8); + } + else // middle point, use existing bit + { + DS18B20_WriteBit(*(buff + pos / 8) >> (pos % 8) & 0x01); + } + } + pos++; + } + // Relocate split point, move it to the last *unconfirmed* bit of stack + while (split_point > 0 && *(stack + split_point / 8) >> (split_point % 8) & 0x01 == 0x01) split_point--; + return split_point; +} \ No newline at end of file diff --git a/demo/gpio/ds18b20/single-ds18b20/ds18b20.h b/demo/gpio/ds18b20/single-ds18b20/ds18b20.h new file mode 100644 index 0000000..e4a3654 --- /dev/null +++ b/demo/gpio/ds18b20/single-ds18b20/ds18b20.h @@ -0,0 +1,168 @@ +// Copyright 2021 IOsetting +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef __FW_DS18B20__ +#define __FW_DS18B20__ + +#include "fw_hal.h" + +/** + * DS18B20 - Programmable Resolution 1-Wire Digital Thermometer + * + * To-92 Pins: + * With the flat side facing you and with the leads pointing down, they are GND, DQ and Vdd + * +*/ + +#define DS18B20_DQ P35 +#define DS18B20_DQ_PULLUP() GPIO_SetPullUp(GPIO_Port_3, GPIO_Pin_5, HAL_State_ON) +#define DS18B20_DQ_INPUT() GPIO_P3_SetMode(GPIO_Pin_5, GPIO_Mode_Input_HIP) +#define DS18B20_DQ_OUTPUT() GPIO_P3_SetMode(GPIO_Pin_5, GPIO_Mode_InOut_OD) +#define DS18B20_DQ_LOW() DS18B20_DQ=RESET +#define DS18B20_DQ_HIGH() DS18B20_DQ=SET + +/* OneWire commands */ +#define ONEWIRE_CMD_RSCRATCHPAD 0xBE +#define ONEWIRE_CMD_WSCRATCHPAD 0x4E +#define ONEWIRE_CMD_CPYSCRATCHPAD 0x48 +#define ONEWIRE_CMD_RECEEPROM 0xB8 +#define ONEWIRE_CMD_RPWRSUPPLY 0xB4 +#define ONEWIRE_CMD_SEARCHROM 0xF0 +#define ONEWIRE_CMD_READROM 0x33 +#define ONEWIRE_CMD_MATCHROM 0x55 +#define ONEWIRE_CMD_SKIPROM 0xCC + +#define DS18B20_FAMILY_CODE 0x28 +#define DS18B20_CMD_ALARMSEARCH 0xEC + +/* DS18B20 read temperature command */ +#define DS18B20_CMD_CONVERTTEMP 0x44 /* Convert temperature */ +#define DS18B20_DECIMAL_STEPS_12BIT 0.0625 +#define DS18B20_DECIMAL_STEPS_11BIT 0.125 +#define DS18B20_DECIMAL_STEPS_10BIT 0.25 +#define DS18B20_DECIMAL_STEPS_9BIT 0.5 + +/* Bits locations for resolution */ +#define DS18B20_RESOLUTION_R1 6 +#define DS18B20_RESOLUTION_R0 5 + +typedef enum { + DS18B20_Resolution_9bits = 9, /*!< DS18B20 9 bits resolution */ + DS18B20_Resolution_10bits = 10, /*!< DS18B20 10 bits resolution */ + DS18B20_Resolution_11bits = 11, /*!< DS18B20 11 bits resolution */ + DS18B20_Resolution_12bits = 12 /*!< DS18B20 12 bits resolution */ +} DS18B20_Resolution_t; + +/** + * @brief Initialize DS18B20 + */ +void DS18B20_Init(void); + +/** + * @brief Reset DS18B20 + * @return bit value + */ +__BIT DS18B20_Reset(void); + +/** + * @brief Read one bit from DS18B20 + * @return bit value + */ +__BIT DS18B20_ReadBit(void); + +/** + * @brief Read one byte from DS18B20 + * @return byte value + */ +uint8_t DS18B20_ReadByte(void); + +/** + * @brief Write one bit to DS18B20 + * @param b bit value + */ +void DS18B20_WriteBit(__BIT b); + +/** + * @brief Write one byte to DS18B20 + * @param byte byte value + */ +void DS18B20_WriteByte(uint8_t byte); + +/** + * @brief 8-bit CRC calculation + * + * @param addr + * @param len + * @return crc result + */ +uint8_t DS18B20_Crc(uint8_t *addr, uint8_t len); + +/** + * @brief Read SRAM scratchpad + * @param buf a 9-byte buffer, Byte 8 contains the CRC code for bytes 0 through 7 + */ +void DS18B20_ReadScratchpad(uint8_t *buf); + +/** + * @brief Start conversion on all slaves + */ +void DS18B20_StartAll(void); + +/** + * @brief If read bit is low, then device is not finished yet with calculation temperature + * @return bit value + */ +__BIT DS18B20_AllDone(void); + +/** + * @brief Read 64-bit ROM: 8-bit family code "0x28", unique 48-bit serial number, 8-bit CRC + * @note This command can only be used if there is a single DS18B20 on the bus. + * If multiple slaves are present, a data collision will occur(a wired AND result). + * @param buf a 8-byte buffer + */ +void DS18B20_ReadRom(uint8_t *buf); + +/** + * @brief Select a slave on the bus + * @note Only the slave that exactly matches the 64-bit ROM code sequence will respond to + * the function command issued by the master; all other slaves on the bus will wait + * for a reset pulse. + * @param addr 64-bit ROM code + */ +void DS18B20_Select(const uint8_t* addr); + +/** + * @brief Start conversion on selected slave + * @param addr 64-bit ROM code + */ +void DS18B20_Start(const uint8_t *addr); + +/** + * @brief Read SRAM scratchpad from selected slave + * + * @param addr 64-bit ROM code + * @param buf a 9-byte buffer, Byte 8 contains the CRC code for bytes 0 through 7 + */ +void DS18B20_ReadScratchpadFromAddr(const uint8_t *addr, uint8_t *buf); + +/** + * @brief Perform one ROM search + * @param buff 8-byte array for ROM bytes + * @param stack 8-byte array for search stack + * @param split_point deepest split point of last search + * @return new split point + */ +uint8_t DS18B20_Detect(uint8_t *buff, uint8_t *stack, uint8_t split_point); + +#endif // __DS18B20_H_ diff --git a/demo/gpio/ds18b20/ds18b20_stc8h3k.c b/demo/gpio/ds18b20/single-ds18b20/main.c similarity index 71% rename from demo/gpio/ds18b20/ds18b20_stc8h3k.c rename to demo/gpio/ds18b20/single-ds18b20/main.c index da77ad2..707c8af 100644 --- a/demo/gpio/ds18b20/ds18b20_stc8h3k.c +++ b/demo/gpio/ds18b20/single-ds18b20/main.c @@ -13,7 +13,8 @@ // limitations under the License. /*** - * Demo: DS18B20 + * Example code of communication with single DS18B20 + * * Board: STC8H3K32 * * P35 -> DQ @@ -24,11 +25,18 @@ #include "fw_hal.h" #include "ds18b20.h" -uint16_t temp; +void PrintArray(uint8_t *arr, uint8_t start, uint8_t end) +{ + uint8_t i; + for (i = start; i < end; i++) + { + UART1_TxHex(*(arr + i)); + } +} int main(void) { - uint16_t temperature; + uint8_t buff[9], i; SYS_SetClock(); // UART1, baud 115200, baud source Timer1, 1T mode, no interrupt @@ -41,11 +49,15 @@ int main(void) while (!DS18B20_AllDone()) { UART1_TxChar('.'); - SYS_Delay(1); + SYS_Delay(50); } - temperature = DS18B20_ReadTemperature(); - UART1_TxHex(temperature >> 8); - UART1_TxHex(temperature & 0xFF); + DS18B20_ReadScratchpad(buff); + PrintArray(buff, 0, 9); + UART1_TxChar(' '); + i = DS18B20_Crc(buff, 8); + UART1_TxString("CRC:"); + UART1_TxHex(i); + UART1_TxChar(' '); UART1_TxString("\r\n"); SYS_Delay(1000); }