diff --git a/8ch_temp_hum_v0.2.ino b/8ch_temp_hum_v0.2.ino new file mode 100644 index 0000000..603c092 --- /dev/null +++ b/8ch_temp_hum_v0.2.ino @@ -0,0 +1,139 @@ +// 16ch Temp&Hum +// by WANG Yanqi +// Created 4 Jan 2024 + +#include + +unsigned long previousMillis = 0; +unsigned long currentMillis = 0; +const long interval = 1000; +const uint8_t addr_hub[] = {0x70, 0x72}; +const uint8_t addr_sen = 0x44; +const int size_hub = sizeof(addr_hub)/sizeof(addr_hub[0]); +uint8_t data[6]; +uint8_t data_crc[2]; +float temp; +float hum; + +float fun_temp(float raw); +float fun_hum(float raw); +uint8_t crc8(const uint8_t* data, size_t length); + +void setup() { + + Wire.begin(); + Serial.begin(9600); + delay(5000); + // Go through all the hubs + for (int i = 0; i < size_hub; i++) { + // Go through 8 ch. in a hub + for (uint8_t ch = 0b00000001; ch != 0; ch = ch << 1) { + // Open the ch. + Wire.beginTransmission(addr_hub[i]); + Wire.write(ch); + Wire.endTransmission(); + // Soft reset sens + Wire.beginTransmission(addr_sen); + Wire.write(0x30); + Wire.write(0xA2); + Wire.endTransmission(); + delay(100); + } + // Close all the ch. + Wire.beginTransmission(addr_hub[i]); + Wire.write(0); + Wire.endTransmission(); + } +} + +void loop() { + // Get the current number of milliseconds since the program started + currentMillis = millis(); + if (currentMillis - previousMillis >= interval) { + // Go through all the hubs + for (int i = 0; i < size_hub; i++) { + // Go through 8 ch. in a hub + for (uint8_t ch = 0b00000001; ch != 0; ch = ch << 1) { + // Open the ch. + Wire.beginTransmission(addr_hub[i]); + Wire.write(ch); + Wire.endTransmission(); + read_sen(addr_sen, data); + // Check temp + data_crc[0] = data[0]; + data_crc[1] = data[1]; + if (crc8(data_crc, sizeof(data_crc)) == data[2]) { + temp = fun_temp((data[0] << 8) | data[1]); + // Serial.print(temp); + } else { + temp = NAN; + // temp = (data[0] << 8) | data[1]; + // Serial.print(temp, BIN); + } + // Serial.print(","); + // Check hum + data_crc[0] = data[3]; + data_crc[1] = data[4]; + if (crc8(data_crc, sizeof(data_crc)) == data[5]) { + hum = fun_hum((data[3] << 8) | data[4]); + // Serial.print(hum); + } else { + hum = NAN; + // hum = (data[3] << 8) | data[4]; + // Serial.print(hum, BIN); + } + // Print data + Serial.print(temp); + Serial.print(","); + Serial.print(hum); + if (i != size_hub-1 || ch != 0b10000000) { + Serial.print(";"); + } + } + // Close all the ch. + Wire.beginTransmission(addr_hub[i]); + Wire.write(0); + Wire.endTransmission(); + } + Serial.print("\n"); + previousMillis = currentMillis; + } +} + +void read_sen(uint8_t addr, uint8_t* data) { + // Clock stretching, high repeatability + Wire.beginTransmission(addr); + Wire.write(0x2C); + Wire.write(0x06); + Wire.endTransmission(); + Wire.requestFrom(addr, 6); + for (int i = 0; i < 6; i++) { + data[i] = Wire.read(); + } +} + +uint8_t crc8(const uint8_t* data, size_t length) { + uint8_t crc = 0xFF; // Start with 0xFF for initialization + for (size_t i = 0; i < length; ++i) { + crc ^= data[i]; // XOR byte into least sig. byte of crc + for (uint8_t j = 8; j; --j) { // Loop over each bit + if (crc & 0x80) { // If the uppermost bit is 1... + crc = (crc << 1) ^ 0x31; // ... shift left and XOR with the polynomial + } else { + crc <<= 1; // Otherwise, just shift left + } + } + } + // No final XOR + return crc; +} + +float fun_temp(float raw) { + float temp = -45.0 + 175.0 * raw / 65535; + return temp; +} + +float fun_hum(float raw) { + float hum = 100.0 * raw / 65535; + return hum; +} \ No newline at end of file diff --git a/Cover.jpeg b/Cover.jpeg new file mode 100644 index 0000000..88b7ea4 Binary files /dev/null and b/Cover.jpeg differ diff --git a/FPC.jpeg b/FPC.jpeg new file mode 100644 index 0000000..275d0ee Binary files /dev/null and b/FPC.jpeg differ diff --git a/Monitor.py b/Monitor.py new file mode 100644 index 0000000..e078aa5 --- /dev/null +++ b/Monitor.py @@ -0,0 +1,111 @@ +# pip install pyserial matplotlib pandas + +import serial +import matplotlib.pyplot as plt +import pandas as pd +from matplotlib.widgets import Button +from datetime import datetime + +max_points = 20 # Number of points to display on the graph +data = { + 'Timestamp': [], + **{f'Temp{i+1}': [] for i in range(16)}, + **{f'Hum{i+1}': [] for i in range(16)} +} + +# Initialize plots +plt.ion() +fig, (ax_temp, ax_hum) = plt.subplots(2, 1, figsize=(15, 10)) + +# Set plot titles and labels +ax_temp.set_title('Temperature') +ax_temp.set_xlabel('Time') +ax_temp.set_ylabel('Temperature (°C)') + +ax_hum.set_title('Humidity') +ax_hum.set_xlabel('Time') +ax_hum.set_ylabel('Humidity (%)') + +# Global flag to control the data collection +collecting_data = False +exit_flag = False + +# Button callback functions +def start_button_callback(event): + global collecting_data + collecting_data = True + +def exit_button_callback(event): + global exit_flag + exit_flag = True + +# Create the buttons +ax_start_button = plt.axes([0.7, 0.05, 0.1, 0.075]) +ax_exit_button = plt.axes([0.81, 0.05, 0.1, 0.075]) + +start_button = Button(ax_start_button, 'Start') +start_button.on_clicked(start_button_callback) + +exit_button = Button(ax_exit_button, 'Exit') +exit_button.on_clicked(exit_button_callback) + +# Display the plot window +plt.show(block=False) + +# Wait here until 'Start' button is pressed +while not collecting_data: + plt.pause(0.1) # Use a short pause to handle UI events + if exit_flag: + plt.close(fig) + raise SystemExit + +# Main loop +try: + # Set up the serial connection (adjust the COM port as needed) + ser = serial.Serial('/dev/cu.usbmodem14101', 9600, timeout=1) + while not exit_flag: + line = ser.readline().decode('utf-8').strip() + if line: + try: + # Split the line into groups and then into temperature and humidity values + groups = line.split(';') + if len(groups) == 16: + timestamp = datetime.now().strftime('%H:%M:%S') + data['Timestamp'].append(timestamp) + temps = [] + hums = [] + for i, group in enumerate(groups): + temp, hum = map(float, group.split(',')) + temps.append(temp) + hums.append(hum) + data[f'Temp{i+1}'].append(temp) + data[f'Hum{i+1}'].append(hum) + + # Update temperature graph with latest 20 points + ax_temp.clear() + ax_temp.set_title('Temperature') + ax_temp.set_xlabel('Time') + ax_temp.set_ylabel('Temperature (°C)') + for i in range(16): + ax_temp.plot(data['Timestamp'][-max_points:], data[f'Temp{i+1}'][-max_points:], label=f'Temp{i+1}') + + # Update humidity graph with latest 20 points + ax_hum.clear() + ax_hum.set_title('Humidity') + ax_hum.set_xlabel('Time') + ax_hum.set_ylabel('Humidity (%)') + for i in range(16): + ax_hum.plot(data['Timestamp'][-max_points:], data[f'Hum{i+1}'][-max_points:], label=f'Hum{i+1}') + + plt.pause(0.5) + except ValueError as e: + print(f"Could not convert data to float: {line}, error: {e}") +except KeyboardInterrupt: + plt.ioff() +finally: + # Save the data to a CSV file + df = pd.DataFrame(data) + csv_filename = 'arduino_data.csv' + df.to_csv(csv_filename, index=False) + print(f"Data saved to '{csv_filename}'") + ser.close() \ No newline at end of file diff --git a/launch.json b/launch.json new file mode 100644 index 0000000..7e4253b --- /dev/null +++ b/launch.json @@ -0,0 +1,8 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + "version": "0.2.0", + "configurations": [ + + ] +}