-
Notifications
You must be signed in to change notification settings - Fork 1
/
temp-sensors.c
301 lines (276 loc) · 9.41 KB
/
temp-sensors.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
/**
* @file temp-sensors.c
* @brief DS18B20 Temp Sensor Communication Example with Maxim OneWire interface
* @author Tal G.
* @license MIT License
* @details This code demonstrates non-blocking temperature measurement with multiple DS18B20 one-wire sensors.
*/
#include "ch32v003fun.h"
#include "ch32v003_GPIO_branchless.h"
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include "OneWire.c"
#define TEMP_READ_DELAY (FUNCONF_SYSTEM_CORE_CLOCK/32) // roughly one second
// Constants for states
#define FIND_SENSOR 0
#define VALIDATE_ADDRESS 1
#define PRINT_SENSOR_TYPE 2
#define REQUEST_TEMPERATURE 3
#define WAIT_FOR_SENSOR_READ 4
#define READ_TEMPERATURE_DATA 5
#define PRINT_TEMPERATURE_DATA 6
// Function prototypes
/**
* @brief Initializes the hardware
*/
void initializeHardware();
/**
* @brief Find the next DS18x20 sensor on the one-wire bus.
* @param address The 8-byte address of the found sensor.
* @return True if a sensor is found, false otherwise.
*/
bool findNextSensor(uint8_t address[8]);
/**
* @brief Validate the CRC of the sensor's address.
* @param address The 8-byte address of the sensor.
* @return True if the CRC is valid, false otherwise.
*/
bool validateAddressCRC(uint8_t address[8]);
/**
* @brief Print the type of DS18x20 sensor based on its address.
* @param address The 8-byte address of the sensor.
*/
void printSensorType(uint8_t address[8]);
/**
* @brief Start a temperature conversion on the DS18x20 sensor.
* @param address The 8-byte address of the sensor.
*/
void sendTemperatureRequest(uint8_t address[8]);
/**
* @brief Read temperature data from the DS18x20 sensor.
* @param address The 8-byte address of the sensor.
* @param data The array to store the temperature data.
* @return True if the data is successfully read, false otherwise.
*/
bool readTemperatureData(uint8_t address[8], uint8_t data[9]);
/**
* @brief Validate the CRC of the temperature data.
* @param data The temperature data.
* @return True if the CRC is valid, false otherwise.
*/
bool validateDataCRC(uint8_t data[9]);
/**
* @brief Convert raw temperature data to Celsius
* @param data The temperature data.
* @param address The sensor address, used to calculate the type ( address[0] == 0x10 for DS18S20, otherwise DS18B20/DS1822).
* @return The temperature in raw format.
*/
float convertRawDataToCelsius(uint8_t address[8], uint8_t data[9]);
/**
* @brief Print the temperature data.
* @param address The 8-byte address of the sensor.
* @param raw The raw temperature data.
*/
void printTemperatureData(uint8_t address[8], float celsius);
/**
* @brief Initializes the hardware
* This function initializes the hardware for temperature sensor communication on pin C4
*/
void setup() {
GPIO_port_enable(GPIO_port_C);
GPIO_pinMode(GPIOv_from_PORT_PIN(GPIO_port_C, 4), GPIO_pinMode_O_pushPull, GPIO_Speed_50MHz);
printf("Starting up..\n\n");
printf("Looking for temperature sensors..\n");
}
/**
* @brief Main loop for processing received data and serial communication.
* This function is the main loop that performs temperature measurements using DS18B20 sensors.
*/
uint32_t startTime = 0;
int state = FIND_SENSOR;
uint8_t address[8];
uint8_t data[9];
float temperatureInC;
int loop() {
switch (state) {
case FIND_SENSOR:
if (!findNextSensor(address)) {
printf("----\nLooking for temperature sensors..\n");
Delay_Ms(250); // Not strictly needed, but slows down search loop when no sensors are found.
OneWireResetSearch();
state = FIND_SENSOR;
} else {
state = VALIDATE_ADDRESS;
}
break;
case VALIDATE_ADDRESS:
if (!validateAddressCRC(address)) {
printf("Sensor found, but it responded with an invalid address. Skipping.\n");
state = FIND_SENSOR;
} else {
state = REQUEST_TEMPERATURE;
}
break;
case REQUEST_TEMPERATURE:
sendTemperatureRequest(address);
state = WAIT_FOR_SENSOR_READ;
break;
case WAIT_FOR_SENSOR_READ:
// Delay for roughly one second between
// asking for temperature and later reading it.
if(startTime >= TEMP_READ_DELAY) {
state = READ_TEMPERATURE_DATA;
startTime = 0;
} else {
startTime++;
state = WAIT_FOR_SENSOR_READ;
}
break;
case READ_TEMPERATURE_DATA:
// The temp sensors use a slow data rate. The read
// can take a few hundred milliseconds, so it will
// disrupt time critical stuff like multiplexing a display.
if (!readTemperatureData(address, data)) {
printf("Failed to recieve temperature data.\n");
state = FIND_SENSOR;
} else {
temperatureInC = convertRawDataToCelsius(address, data);
state = PRINT_TEMPERATURE_DATA;
}
break;
case PRINT_TEMPERATURE_DATA:
printSensorType(address);
printTemperatureData(address, temperatureInC);
state = FIND_SENSOR;
break;
}
// More features, background tasks, etc can be added here.
return 0;
}
/**
* @brief Entry point of the program.
* This function initializes the system and sets up the main loop for temperature measurements.
*/
int main() {
SystemInit();
setup();
while (1) {
loop();
}
}
// Function definitions
/**
* @brief Find the next DS18x20 sensor on the one-wire bus.
* @param address The 8-byte address of the found sensor.
* @return True if a sensor is found, false otherwise.
* This function searches for the next DS18x20 sensor on the one-wire bus.
*/
bool findNextSensor(uint8_t address[8]) {
if (!OneWireSearch(address, true)) {
return false;
}
return true;
}
/**
* @brief Validate the CRC of the sensor's address.
* @param address The 8-byte address of the sensor.
* @return True if the CRC is valid, false otherwise.
* This function validates the CRC of the sensor's address to ensure it's correct.
*/
bool validateAddressCRC(uint8_t address[8]) {
if (OneWireCrc8(address, 7) != address[7]) {
return false;
}
return true;
}
/**
* @brief Print the type of DS18x20 sensor based on its address.
* @param address The 8-byte address of the sensor.
* This function prints the type of DS18x20 sensor based on its address.
*/
void printSensorType(uint8_t address[8]) {
switch (address[0]) {
case 0x10:
printf("DS18S20 "); // or old DS1820
break;
case 0x28:
printf("DS18B20 ");
break;
case 0x22:
printf("DS1822 ");
break;
default:
printf("Device is not a DS18x20 family device.\n");
break;
}
}
/**
* @brief Start a temperature conversion on the DS18x20 sensor.
* @param address The 8-byte address of the sensor.
* This function initiates a temperature conversion on the DS18x20 sensor.
*/
void sendTemperatureRequest(uint8_t address[8]) {
OneWireReset();
OneWireSelect(address);
OneWireWrite(0x44, 0); // start conversion, with no parasite power on at the end
}
/**
* @brief Read temperature data from the DS18x20 sensor.
* @param address The 8-byte address of the sensor.
* @param data The array to store the temperature data.
* @return True if the data is successfully read, false otherwise.
* This function reads temperature data from the DS18x20 sensor and validates it.
*/
bool readTemperatureData(uint8_t address[8], uint8_t data[9]) {
OneWireReset();
OneWireSelect(address);
OneWireWrite(0xBE, 0); // Read Scratchpad
for (uint8_t i = 0; i < 9; i++) {
data[i] = OneWireRead();
}
if (OneWireCrc8(data, 8) != data[8]) {
return false;
}
return true;
}
/**
* @brief Convert raw temperature data to Celsius
* @param data The temperature data.
* @param address The sensor address, used to calculate the type ( address[0] == 0x10 for DS18S20, otherwise DS18B20/DS1822).
* @return The temperature in celsius.
* This function converts the sensors temperature data to Celsius based on the sensor type.
*/
float convertRawDataToCelsius(uint8_t address[8], uint8_t data[9]) {
int16_t raw = (data[1] << 8) | data[0];
if (address[0] == 0x10 ) {
raw = raw << 3; // 9 bit resolution default
if (data[7] == 0x10) {
raw = (raw & 0xFFF0) + 12 - data[6];
}
} else {
uint8_t cfg = (data[4] & 0x60);
if (cfg == 0x00) raw = raw & ~7; // 9 bit resolution, 93.75 ms
else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
// default is 12 bit resolution, 750 ms conversion time
}
return (float)(raw / 16.0);
}
/**
* @brief Print the temperature data.
* @param address The 8-byte address of the sensor.
* @param raw The raw temperature data.
* This function prints the temperature data in Celsius and Fahrenheit.
*/
void printTemperatureData(uint8_t address[8], float celsius) {
float fahrenheit = (celsius * 1.8 + 32.0);
printf("0x");
for (uint8_t i = 0; i < 8; i++) {
printf("%02X", address[i]);
}
printf(": %d", (int)celsius);
printf("C, ");
printf("%d", (int)fahrenheit);
printf("F\n");
}