Manages the 1-wire bus
Dependents: oldheating heating
1-wire/1-wire-device.c@11:3859fee99d5d, 2021-02-18 (annotated)
- Committer:
- andrewboyson
- Date:
- Thu Feb 18 16:47:12 2021 +0000
- Revision:
- 11:3859fee99d5d
- Parent:
- 1:c272b1fcc834
Added 'value not set' to the list of possible values.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
andrewboyson | 0:b4b170ce93a4 | 1 | #include <stdint.h> |
andrewboyson | 0:b4b170ce93a4 | 2 | #include <stdbool.h> |
andrewboyson | 0:b4b170ce93a4 | 3 | |
andrewboyson | 0:b4b170ce93a4 | 4 | #include "1-wire.h" |
andrewboyson | 0:b4b170ce93a4 | 5 | #include "log.h" |
andrewboyson | 0:b4b170ce93a4 | 6 | #include "1-wire-device.h" |
andrewboyson | 0:b4b170ce93a4 | 7 | #include "ds18b20.h" |
andrewboyson | 0:b4b170ce93a4 | 8 | #include "hrtimer.h" |
andrewboyson | 0:b4b170ce93a4 | 9 | |
andrewboyson | 0:b4b170ce93a4 | 10 | #define SEND_BUFFER_LENGTH 10 |
andrewboyson | 0:b4b170ce93a4 | 11 | #define RECV_BUFFER_LENGTH 10 |
andrewboyson | 0:b4b170ce93a4 | 12 | static char send[SEND_BUFFER_LENGTH]; |
andrewboyson | 0:b4b170ce93a4 | 13 | static char recv[RECV_BUFFER_LENGTH]; |
andrewboyson | 0:b4b170ce93a4 | 14 | static int sendlen = 0; |
andrewboyson | 0:b4b170ce93a4 | 15 | static int recvlen = 0; |
andrewboyson | 0:b4b170ce93a4 | 16 | |
andrewboyson | 0:b4b170ce93a4 | 17 | int DeviceScanMs = 0; |
andrewboyson | 0:b4b170ce93a4 | 18 | int DeviceCount = 0; |
andrewboyson | 0:b4b170ce93a4 | 19 | char DeviceList[DEVICE_MAX * 8]; |
andrewboyson | 0:b4b170ce93a4 | 20 | char* DeviceAddress(int device) |
andrewboyson | 0:b4b170ce93a4 | 21 | { |
andrewboyson | 0:b4b170ce93a4 | 22 | return DeviceList + device * 8; |
andrewboyson | 0:b4b170ce93a4 | 23 | } |
andrewboyson | 0:b4b170ce93a4 | 24 | void DeviceAddressToString(char* pAddress, char* pText) |
andrewboyson | 0:b4b170ce93a4 | 25 | { |
andrewboyson | 0:b4b170ce93a4 | 26 | char *pAddressAfter = pAddress + 8; |
andrewboyson | 0:b4b170ce93a4 | 27 | for (char* p = pAddress; p < pAddressAfter; p++) |
andrewboyson | 0:b4b170ce93a4 | 28 | { |
andrewboyson | 0:b4b170ce93a4 | 29 | char highnibble = *p >> 4; //Unsigned so fills with zeros |
andrewboyson | 0:b4b170ce93a4 | 30 | char lownibble = *p & 0xF; |
andrewboyson | 0:b4b170ce93a4 | 31 | *pText++ = highnibble < 0xA ? highnibble + '0' : highnibble - 0xA + 'A'; //Replace high nibble with its ascii equivalent |
andrewboyson | 0:b4b170ce93a4 | 32 | *pText++ = lownibble < 0xA ? lownibble + '0' : lownibble - 0xA + 'A'; //Replace low nibble with its ascii equivalent |
andrewboyson | 0:b4b170ce93a4 | 33 | *pText++ = p < pAddressAfter - 1 ? ' ' : 0; //Put in a space between the bytes or a NUL at the end of the last one |
andrewboyson | 0:b4b170ce93a4 | 34 | } |
andrewboyson | 0:b4b170ce93a4 | 35 | } |
andrewboyson | 0:b4b170ce93a4 | 36 | void DeviceParseAddress(char* pText, char *pAddress) |
andrewboyson | 0:b4b170ce93a4 | 37 | { |
andrewboyson | 0:b4b170ce93a4 | 38 | int highNibble = 1; |
andrewboyson | 0:b4b170ce93a4 | 39 | char *pAddressAfter = pAddress + 8; |
andrewboyson | 0:b4b170ce93a4 | 40 | while(*pText && pAddress < pAddressAfter) |
andrewboyson | 0:b4b170ce93a4 | 41 | { |
andrewboyson | 0:b4b170ce93a4 | 42 | int nibble = -1; |
andrewboyson | 0:b4b170ce93a4 | 43 | if (*pText >= '0' && *pText <= '9') nibble = *pText - '0'; |
andrewboyson | 0:b4b170ce93a4 | 44 | if (*pText >= 'A' && *pText <= 'F') nibble = *pText - 'A' + 0xA; |
andrewboyson | 0:b4b170ce93a4 | 45 | if (*pText >= 'a' && *pText <= 'f') nibble = *pText - 'a' + 0xA; |
andrewboyson | 0:b4b170ce93a4 | 46 | if (nibble >= 0) //Ignore characters which do not represent a hex number |
andrewboyson | 0:b4b170ce93a4 | 47 | { |
andrewboyson | 0:b4b170ce93a4 | 48 | if (highNibble) |
andrewboyson | 0:b4b170ce93a4 | 49 | { |
andrewboyson | 0:b4b170ce93a4 | 50 | *pAddress = nibble << 4; //Set the high nibble of the current address byte and zero the low nibble |
andrewboyson | 0:b4b170ce93a4 | 51 | highNibble = 0; //Move onto the low nibble of this address byte |
andrewboyson | 0:b4b170ce93a4 | 52 | } |
andrewboyson | 0:b4b170ce93a4 | 53 | else //low nibble |
andrewboyson | 0:b4b170ce93a4 | 54 | { |
andrewboyson | 0:b4b170ce93a4 | 55 | *pAddress += nibble; //Add the low nibble to the current address byte |
andrewboyson | 0:b4b170ce93a4 | 56 | highNibble = 1; //Move onto the high nibble of the next address byte |
andrewboyson | 0:b4b170ce93a4 | 57 | pAddress++; |
andrewboyson | 0:b4b170ce93a4 | 58 | } |
andrewboyson | 0:b4b170ce93a4 | 59 | } |
andrewboyson | 0:b4b170ce93a4 | 60 | pText++; |
andrewboyson | 0:b4b170ce93a4 | 61 | } |
andrewboyson | 0:b4b170ce93a4 | 62 | while (pAddress < pAddressAfter) *pAddress++ = 0; //Set any remaining bytes to zero |
andrewboyson | 0:b4b170ce93a4 | 63 | } |
andrewboyson | 0:b4b170ce93a4 | 64 | |
andrewboyson | 0:b4b170ce93a4 | 65 | char rom[8]; |
andrewboyson | 0:b4b170ce93a4 | 66 | bool allRomsFound = false; |
andrewboyson | 0:b4b170ce93a4 | 67 | static void searchRom(int first) |
andrewboyson | 0:b4b170ce93a4 | 68 | { |
andrewboyson | 0:b4b170ce93a4 | 69 | sendlen = 1; |
andrewboyson | 0:b4b170ce93a4 | 70 | send[0] = 0xF0; //Search Rom |
andrewboyson | 0:b4b170ce93a4 | 71 | recvlen = 0; |
andrewboyson | 0:b4b170ce93a4 | 72 | for (int i = 0; i < recvlen; i++) recv[i] = 0; |
andrewboyson | 0:b4b170ce93a4 | 73 | if (first) OneWireSearch(send[0], rom, &allRomsFound); |
andrewboyson | 0:b4b170ce93a4 | 74 | else OneWireSearch(send[0], NULL, NULL); |
andrewboyson | 0:b4b170ce93a4 | 75 | } |
andrewboyson | 0:b4b170ce93a4 | 76 | static void readScratchpad(int device) |
andrewboyson | 0:b4b170ce93a4 | 77 | { |
andrewboyson | 0:b4b170ce93a4 | 78 | sendlen = 10; |
andrewboyson | 0:b4b170ce93a4 | 79 | send[0] = 0x55; //Match Rom |
andrewboyson | 0:b4b170ce93a4 | 80 | for (int i = 0; i < 8; i++) send[i+1] = DeviceList[device * 8 + i]; |
andrewboyson | 0:b4b170ce93a4 | 81 | send[9] = 0xBE; //Read Scratchpad |
andrewboyson | 0:b4b170ce93a4 | 82 | recvlen = 9; |
andrewboyson | 0:b4b170ce93a4 | 83 | for (int i = 0; i < recvlen; i++) recv[i] = 0; |
andrewboyson | 0:b4b170ce93a4 | 84 | OneWireExchange(sendlen, recvlen, send, recv, 0); |
andrewboyson | 0:b4b170ce93a4 | 85 | } |
andrewboyson | 0:b4b170ce93a4 | 86 | static void convertT() |
andrewboyson | 0:b4b170ce93a4 | 87 | { |
andrewboyson | 0:b4b170ce93a4 | 88 | sendlen = 2; |
andrewboyson | 0:b4b170ce93a4 | 89 | send[0] = 0xCC; //Skip Rom |
andrewboyson | 0:b4b170ce93a4 | 90 | send[1] = 0x44; //Convert T |
andrewboyson | 0:b4b170ce93a4 | 91 | recvlen = 0; |
andrewboyson | 0:b4b170ce93a4 | 92 | for (int i = 0; i < recvlen; i++) recv[i] = 0; |
andrewboyson | 0:b4b170ce93a4 | 93 | OneWireExchange(sendlen, recvlen, send, recv, 750); |
andrewboyson | 0:b4b170ce93a4 | 94 | } |
andrewboyson | 0:b4b170ce93a4 | 95 | enum { |
andrewboyson | 0:b4b170ce93a4 | 96 | IDLE, |
andrewboyson | 0:b4b170ce93a4 | 97 | LIST_FIRST_DEVICE, |
andrewboyson | 0:b4b170ce93a4 | 98 | LIST_NEXT_DEVICE, |
andrewboyson | 0:b4b170ce93a4 | 99 | LIST_DEVICE_CHECK, |
andrewboyson | 0:b4b170ce93a4 | 100 | CONVERT_T, |
andrewboyson | 0:b4b170ce93a4 | 101 | CONVERT_T_CHECK, |
andrewboyson | 0:b4b170ce93a4 | 102 | ENUMERATE_START, |
andrewboyson | 0:b4b170ce93a4 | 103 | ENUMERATE, |
andrewboyson | 0:b4b170ce93a4 | 104 | READ_SCRATCHPAD, |
andrewboyson | 0:b4b170ce93a4 | 105 | EXTRACT_TEMPERATURE |
andrewboyson | 0:b4b170ce93a4 | 106 | }; |
andrewboyson | 0:b4b170ce93a4 | 107 | static volatile int state = IDLE; |
andrewboyson | 0:b4b170ce93a4 | 108 | bool DeviceBusy() { return state; } |
andrewboyson | 0:b4b170ce93a4 | 109 | static void establishDeviceScanMs() |
andrewboyson | 0:b4b170ce93a4 | 110 | { |
andrewboyson | 0:b4b170ce93a4 | 111 | |
andrewboyson | 0:b4b170ce93a4 | 112 | //Get the scan time in counts and stop if it's the first one |
andrewboyson | 0:b4b170ce93a4 | 113 | static uint32_t scanTimer = 0; |
andrewboyson | 0:b4b170ce93a4 | 114 | bool firstScan = !scanTimer; |
andrewboyson | 0:b4b170ce93a4 | 115 | uint32_t elapsed = HrTimerSinceRepetitive(&scanTimer); |
andrewboyson | 0:b4b170ce93a4 | 116 | if (firstScan) return; |
andrewboyson | 0:b4b170ce93a4 | 117 | |
andrewboyson | 0:b4b170ce93a4 | 118 | //Calculate the scan time in ms and record the scan time for the next pass |
andrewboyson | 0:b4b170ce93a4 | 119 | int scanMs = elapsed / 96000; |
andrewboyson | 0:b4b170ce93a4 | 120 | |
andrewboyson | 0:b4b170ce93a4 | 121 | //Calculate the difference beween this scan time and the average and update the average |
andrewboyson | 0:b4b170ce93a4 | 122 | int diffMs = scanMs - DeviceScanMs; |
andrewboyson | 0:b4b170ce93a4 | 123 | if (diffMs > 0xF || diffMs < 0xF) |
andrewboyson | 0:b4b170ce93a4 | 124 | { |
andrewboyson | 0:b4b170ce93a4 | 125 | DeviceScanMs += (scanMs - DeviceScanMs) >> 4; |
andrewboyson | 0:b4b170ce93a4 | 126 | } |
andrewboyson | 0:b4b170ce93a4 | 127 | else |
andrewboyson | 0:b4b170ce93a4 | 128 | { |
andrewboyson | 0:b4b170ce93a4 | 129 | if (scanMs > DeviceScanMs) DeviceScanMs++; |
andrewboyson | 0:b4b170ce93a4 | 130 | if (scanMs < DeviceScanMs) DeviceScanMs--; |
andrewboyson | 0:b4b170ce93a4 | 131 | } |
andrewboyson | 0:b4b170ce93a4 | 132 | } |
andrewboyson | 0:b4b170ce93a4 | 133 | static int handlestate() |
andrewboyson | 0:b4b170ce93a4 | 134 | { |
andrewboyson | 0:b4b170ce93a4 | 135 | if (OneWireBusy()) return 0; |
andrewboyson | 0:b4b170ce93a4 | 136 | static int device; |
andrewboyson | 0:b4b170ce93a4 | 137 | switch (state) |
andrewboyson | 0:b4b170ce93a4 | 138 | { |
andrewboyson | 0:b4b170ce93a4 | 139 | case IDLE: |
andrewboyson | 0:b4b170ce93a4 | 140 | establishDeviceScanMs(); |
andrewboyson | 0:b4b170ce93a4 | 141 | state = LIST_FIRST_DEVICE; |
andrewboyson | 0:b4b170ce93a4 | 142 | break; |
andrewboyson | 0:b4b170ce93a4 | 143 | |
andrewboyson | 0:b4b170ce93a4 | 144 | case LIST_FIRST_DEVICE: |
andrewboyson | 0:b4b170ce93a4 | 145 | device = 0; |
andrewboyson | 0:b4b170ce93a4 | 146 | searchRom(1); |
andrewboyson | 0:b4b170ce93a4 | 147 | state = LIST_DEVICE_CHECK; |
andrewboyson | 0:b4b170ce93a4 | 148 | break; |
andrewboyson | 0:b4b170ce93a4 | 149 | case LIST_DEVICE_CHECK: |
andrewboyson | 0:b4b170ce93a4 | 150 | if (OneWireResult()) state = IDLE; |
andrewboyson | 0:b4b170ce93a4 | 151 | else state = LIST_NEXT_DEVICE; |
andrewboyson | 0:b4b170ce93a4 | 152 | break; |
andrewboyson | 0:b4b170ce93a4 | 153 | case LIST_NEXT_DEVICE: |
andrewboyson | 0:b4b170ce93a4 | 154 | for (int i = 0; i < 8; i++) DeviceList[8 * device + i] = rom[i]; |
andrewboyson | 0:b4b170ce93a4 | 155 | device++; |
andrewboyson | 0:b4b170ce93a4 | 156 | if (allRomsFound || device >= DEVICE_MAX) |
andrewboyson | 0:b4b170ce93a4 | 157 | { |
andrewboyson | 0:b4b170ce93a4 | 158 | DeviceCount = device; |
andrewboyson | 0:b4b170ce93a4 | 159 | state = CONVERT_T; |
andrewboyson | 0:b4b170ce93a4 | 160 | } |
andrewboyson | 0:b4b170ce93a4 | 161 | else |
andrewboyson | 0:b4b170ce93a4 | 162 | { |
andrewboyson | 0:b4b170ce93a4 | 163 | searchRom(0); |
andrewboyson | 0:b4b170ce93a4 | 164 | state = LIST_DEVICE_CHECK; |
andrewboyson | 0:b4b170ce93a4 | 165 | } |
andrewboyson | 0:b4b170ce93a4 | 166 | break; |
andrewboyson | 0:b4b170ce93a4 | 167 | |
andrewboyson | 0:b4b170ce93a4 | 168 | case CONVERT_T: |
andrewboyson | 0:b4b170ce93a4 | 169 | convertT(); |
andrewboyson | 0:b4b170ce93a4 | 170 | state = CONVERT_T_CHECK; |
andrewboyson | 0:b4b170ce93a4 | 171 | break; |
andrewboyson | 0:b4b170ce93a4 | 172 | case CONVERT_T_CHECK: |
andrewboyson | 0:b4b170ce93a4 | 173 | if (OneWireResult()) state = IDLE; |
andrewboyson | 0:b4b170ce93a4 | 174 | else state = ENUMERATE_START; |
andrewboyson | 0:b4b170ce93a4 | 175 | break; |
andrewboyson | 0:b4b170ce93a4 | 176 | |
andrewboyson | 0:b4b170ce93a4 | 177 | case ENUMERATE_START: |
andrewboyson | 0:b4b170ce93a4 | 178 | device = -1; |
andrewboyson | 0:b4b170ce93a4 | 179 | state = ENUMERATE; |
andrewboyson | 0:b4b170ce93a4 | 180 | break; |
andrewboyson | 0:b4b170ce93a4 | 181 | case ENUMERATE: |
andrewboyson | 0:b4b170ce93a4 | 182 | device++; |
andrewboyson | 0:b4b170ce93a4 | 183 | if (device >= DeviceCount) state = IDLE; |
andrewboyson | 0:b4b170ce93a4 | 184 | else if (DeviceList[device * 8] == DS18B20_FAMILY_CODE) state = READ_SCRATCHPAD; |
andrewboyson | 0:b4b170ce93a4 | 185 | else state = ENUMERATE; |
andrewboyson | 0:b4b170ce93a4 | 186 | break; |
andrewboyson | 0:b4b170ce93a4 | 187 | |
andrewboyson | 0:b4b170ce93a4 | 188 | case READ_SCRATCHPAD: |
andrewboyson | 0:b4b170ce93a4 | 189 | readScratchpad(device); |
andrewboyson | 0:b4b170ce93a4 | 190 | state = EXTRACT_TEMPERATURE; |
andrewboyson | 0:b4b170ce93a4 | 191 | break; |
andrewboyson | 0:b4b170ce93a4 | 192 | case EXTRACT_TEMPERATURE: |
andrewboyson | 0:b4b170ce93a4 | 193 | DS18B20ReadValue(OneWireResult(), device, recv[0], recv[1]); |
andrewboyson | 0:b4b170ce93a4 | 194 | state = ENUMERATE; |
andrewboyson | 0:b4b170ce93a4 | 195 | break; |
andrewboyson | 0:b4b170ce93a4 | 196 | |
andrewboyson | 0:b4b170ce93a4 | 197 | default: |
andrewboyson | 0:b4b170ce93a4 | 198 | LogF("Unknown DS18B20 state %d\r\n", state); |
andrewboyson | 0:b4b170ce93a4 | 199 | return -1; |
andrewboyson | 0:b4b170ce93a4 | 200 | } |
andrewboyson | 0:b4b170ce93a4 | 201 | return 0; |
andrewboyson | 0:b4b170ce93a4 | 202 | } |
andrewboyson | 0:b4b170ce93a4 | 203 | static void logcomms() |
andrewboyson | 0:b4b170ce93a4 | 204 | { |
andrewboyson | 0:b4b170ce93a4 | 205 | static int wasbusy = 0; |
andrewboyson | 0:b4b170ce93a4 | 206 | if (!OneWireBusy() && wasbusy) |
andrewboyson | 0:b4b170ce93a4 | 207 | { |
andrewboyson | 0:b4b170ce93a4 | 208 | LogF("1-wire | send:"); |
andrewboyson | 0:b4b170ce93a4 | 209 | for (int i = 0; i < sendlen; i++) LogF(" %02x", send[i]); |
andrewboyson | 0:b4b170ce93a4 | 210 | LogF(" | recv:"); |
andrewboyson | 0:b4b170ce93a4 | 211 | for (int i = 0; i < recvlen; i++) LogF(" %02x", recv[i]); |
andrewboyson | 0:b4b170ce93a4 | 212 | LogF("\r\n"); |
andrewboyson | 0:b4b170ce93a4 | 213 | } |
andrewboyson | 0:b4b170ce93a4 | 214 | wasbusy = OneWireBusy(); |
andrewboyson | 0:b4b170ce93a4 | 215 | } |
andrewboyson | 0:b4b170ce93a4 | 216 | void DeviceInit() |
andrewboyson | 0:b4b170ce93a4 | 217 | { |
andrewboyson | 0:b4b170ce93a4 | 218 | DS18B20Init(); |
andrewboyson | 0:b4b170ce93a4 | 219 | } |
andrewboyson | 0:b4b170ce93a4 | 220 | int DeviceMain() |
andrewboyson | 0:b4b170ce93a4 | 221 | { |
andrewboyson | 0:b4b170ce93a4 | 222 | |
andrewboyson | 0:b4b170ce93a4 | 223 | if (OneWireTrace) logcomms(); |
andrewboyson | 0:b4b170ce93a4 | 224 | |
andrewboyson | 0:b4b170ce93a4 | 225 | int r = handlestate(); if (r) return -1; |
andrewboyson | 0:b4b170ce93a4 | 226 | |
andrewboyson | 0:b4b170ce93a4 | 227 | return 0; |
andrewboyson | 0:b4b170ce93a4 | 228 | } |