/* * * 基于 Raspberry Pico 的厨房危险(火灾)报警 * 使用 DS18B20温度传感器 * 使用 CH4 N55A甲烷气体传感器(进口) * 使用 PASCO2V01 CO2二氧化碳传感器模块(进口模块暂时买不到!) * 使用 MH-Z14B CO2二氧化碳传感器模块(国产)(0 - 5000ppm) * 使用 ME2_CO CO一氧化碳传感器模块(国产) * * Date: 20240103 * */ #include "MAIN.hpp" #include "DTH11.hpp" #include "HC-12.hpp" #include "ZC13.hpp" extern "C" { #include "WIFI.h" } #ifndef PICO_DEFAULT_LED_PIN #warning pio/hello_pio example requires a board with a regular LED #define PICO_DEFAULT_LED_PIN 25 #endif static inline bool uart_rx_program_available(PIO pio, uint sm) { return !pio_sm_is_rx_fifo_empty(pio, sm); } // 闪烁LED static void light_flashing() { gpio_init(PICO_DEFAULT_LED_PIN); gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); gpio_put(PICO_DEFAULT_LED_PIN, 1); sleep_ms(100); gpio_put(PICO_DEFAULT_LED_PIN, 0); sleep_ms(100); return; } int wifi() { if (cyw43_arch_init()) { printf("failed to initialise\n"); return 1; } cyw43_arch_enable_sta_mode(); printf("Connecting to Wi-Fi...\n"); if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 30000)) { printf("failed to connect.\n"); return 1; } else { printf("Connected.\n"); } cyw43_arch_deinit(); return 0; } // 获取主板温度 float read_onboard_temperature() { adc_init(); adc_set_temp_sensor_enabled(true); adc_select_input(4); // Input 4 is the onboard temperature sensor. /* 12-bit conversion, assume max value == ADC_VREF == 3.3 V */ const float conversionFactor = 3.3f / (1 << 12); float adc = (float)adc_read() * conversionFactor; float tempC = 27.0f - (adc - 0.706f) / 0.001721f; //printf("Onboard temperature %.02f°C %.02f°F\n", tempC, (tempC * 9 / 5 + 32)); return tempC; } // 温度传感器 float DS18B20() { float TEMPERATURE = -1; One_wire one_wire(DS18B20_PIN); one_wire.init(); rom_address_t address { }; one_wire.single_device_read_rom(address); /* printf("Device Address: %02x%02x%02x%02x%02x%02x%02x%02x\n", address.rom[0], address.rom[1], address.rom[2], address.rom[3], address.rom[4], address.rom[5], address.rom[6], address.rom[7]); */ one_wire.convert_temperature(address, true, false); TEMPERATURE = one_wire.temperature(address); //printf("Temperature: %3.1f°C\n", one_wire.temperature(address)); return TEMPERATURE; } // 甲烷气体传感器 int CH4() { int CH4_TRUE = 0; gpio_init(PICO_DEFAULT_LED_PIN); gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); gpio_init(CH4_PIN); // 设置 GP14 引脚作为输入引脚 gpio_set_dir(CH4_PIN, GPIO_IN); if (gpio_get(CH4_PIN) == 1) { CH4_TRUE = 1; } sleep_ms(100); return CH4_TRUE; } // CO2 static uint16_t MH_Z14B(int *MH_Z14B_DATA_IS_OK) { // 初始化UART uart_init(UART1, BAUD_RATE); gpio_set_function(UART1_TX_PIN, GPIO_FUNC_UART); gpio_set_function(UART1_RX_PIN, GPIO_FUNC_UART); uart_set_hw_flow(UART1, false, false); uart_set_format(UART1, DATA_BITS, STOP_BITS, PARITY); // 0x86 读气体浓度值 uint8_t CMD[9] = { 0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79 }; uart_write_blocking(UART1, CMD, 9); sleep_ms(200); // 读取 uint8_t CO2_DATA[9] = { 0 }; uart_read_blocking(UART1, CO2_DATA, 9); // CO2 浓度 uint16_t CO2_CONC = (256 * CO2_DATA[2]) + CO2_DATA[3]; // 校验 uint8_t CHECKSUM = (0xFF - (CO2_DATA[1] + CO2_DATA[2] + CO2_DATA[3] + CO2_DATA[4] + CO2_DATA[5] + CO2_DATA[6] + CO2_DATA[7])) + 1; if (CO2_DATA[8] == CHECKSUM && CO2_DATA[1] == 0x86) { //printf("CHECKSUM: %X = %X\n", CO2_DATA[8], CHECKSUM); //printf("CO2 Concentration: %d ppm\n", CO2_CONC); *MH_Z14B_DATA_IS_OK = 1; } /* else { // 校准传感器 零点 (ZERO) uint8_t ZERO[] = { 0XFF, 0X01, 0X87, 0X00, 0X00, 0X00, 0X00, 0X00, 0X78 }; uart_write_blocking(UART1, ZERO, 9); sleep_ms(200); // 校准传感器 跨度点 (SPAN) uint8_t SPAN[] = { 0XFF, 0X01, 0X88, 0X07, 0XD0, 0X00, 0X00, 0X00, 0XA0 }; uart_write_blocking(UART1, SPAN, 9); sleep_ms(200); *MH_Z14B_DATA_IS_OK = 0; printf("CO2 concentration reading failed!\n"); } */ return CO2_CONC; } // CO static uint16_t ME2_CO(int IS_ANSWER, int *ME2_CO_DATA_IS_OK) { // 初始化UART uart_init(UART0, BAUD_RATE); gpio_set_function(UART0_TX_PIN, GPIO_FUNC_UART); gpio_set_function(UART0_RX_PIN, GPIO_FUNC_UART); uart_set_hw_flow(UART0, false, false); uart_set_format(UART0, DATA_BITS, STOP_BITS, PARITY); if (IS_ANSWER == 1) { // 应答模式 uint8_t _ANSWER[9] = { 0xFF, 0x01, 0x78, 0x41, 0x00, 0x00, 0x00, 0x00, 0x46 }; uart_write_blocking(UART0, _ANSWER, 9); sleep_ms(100); } // 读取 uint8_t CO_DATA[9] = { 0 }; uart_read_blocking(UART0, CO_DATA, 9); // CO 浓度 uint16_t CO_CONC = (256 * CO_DATA[4]) + CO_DATA[5]; // 校验 uint8_t CHECKSUM = (0xFF - (CO_DATA[1] + CO_DATA[2] + CO_DATA[3] + CO_DATA[4] + CO_DATA[5] + CO_DATA[6] + CO_DATA[7])) + 1; if (CO_DATA[8] == CHECKSUM && CO_DATA[1] == 0x04) { //printf("CHECKSUM: %X = %X\n", CO_DATA[8], CHECKSUM); //printf("CO Concentration: %d ppm\n", CO_CONC); *ME2_CO_DATA_IS_OK = 1; } else { *ME2_CO_DATA_IS_OK = 0; } return CO_CONC; } // 433MHZ 无线电发送数据到服务器端(Raspberry pico W WiFi 暂时不实现) int _433_MHZ(unsigned long val) { const uint RADIO_TRANSMIT_PIN = _433_MHZ_PIN; // 433发射模块引脚 const uint PULSE_LENGTH = 169; // set this to PULSELENGTH RECIEVED const uint REPEAT_TRANSMIT = 4; // set this to whatever works best for you. // 重复发送 const uint PROTOCOL = 1; // set this to PROTOCOL RECIEVED const uint BIT_LENGTH = 24; // set this to BIT LENGTH RECIEVED gpio_init(RADIO_TRANSMIT_PIN); RCSwitch mySwitch = RCSwitch(); mySwitch.enableTransmit(RADIO_TRANSMIT_PIN); mySwitch.setProtocol(PROTOCOL); mySwitch.setPulseLength(PULSE_LENGTH); mySwitch.setRepeatTransmit(REPEAT_TRANSMIT); mySwitch.send(val, BIT_LENGTH); sleep_ms(10); return 0; } // 简单编码通过433MHZ发送 int addDigit(int number, int digit) { char TEMP[BUFER] = { 0 }; snprintf(TEMP, sizeof(TEMP), "%d%d%d", digit, number, digit); return atoi(TEMP); } // 核心0发送数据到核心1, 核心1判断是否有数据到来. static void core1_main() { while (1) { multicore_fifo_push_blocking(CH4()); watchdog_update(); sleep_ms(1000); } return; } int main(int argc, char *argv[]) { stdio_init_all(); sleep_ms(1000); if (cyw43_arch_init()) { DEBUG_printf("failed to initialise\n"); return 1; } cyw43_arch_enable_sta_mode(); printf("Connecting to Wi-Fi...\n"); if (cyw43_arch_wifi_connect_timeout_ms("root", "@aixiao.19960623", CYW43_AUTH_WPA2_AES_PSK, 30000)) { printf("failed to connect.\n"); return 1; } else { printf("Connected.\n"); } while (1) { run_tcp_client_test(); sleep_ms(3000); } cyw43_arch_deinit(); return 0; } /* int main(int argc, char *argv[]) { stdio_init_all(); sleep_ms(1000); set_sys_clock_khz(250000, true); int FIFO_ = -1; float TEMPERATURE = -1; float ONBOARD_TEMPERATURE = -1; uint16_t CO2_DATA = -1; uint16_t CO_DATA = -1; int MH_Z14B_DATA_IS_OK = 0; int ME2_CO_DATA_IS_OK = 0; // core1 multicore_reset_core1(); multicore_launch_core1(core1_main); if (watchdog_caused_reboot()) { // 判断是否从看门狗启动或者正常启动 printf("Rebooted by Watchdog!\n"); } else { printf("Clean boot\n"); } watchdog_enable(8300, 1); // 8秒检测是否重新加载看门狗计数器. (不更新计数器则重启硬件, 最高8秒) watchdog_start_tick(12); _HC_12_INIT(); ZC13_INIT(); while (1) { watchdog_update(); // 喂狗 // RP2040温度 ONBOARD_TEMPERATURE = read_onboard_temperature(); if (ONBOARD_TEMPERATURE != -1) { printf("Onboard temperature %.02f°C %.02f°F\n", ONBOARD_TEMPERATURE, (ONBOARD_TEMPERATURE * 9 / 5 + 32)); //_433_MHZ(addDigit(ONBOARD_TEMPERATURE, SIGN_RP2040)); char ONBOARD_TEMPERATURE_TEMP[BUFER] = { 0 }; sprintf(ONBOARD_TEMPERATURE_TEMP, "Onboard temperature %.02f°C %.02f°F\n", ONBOARD_TEMPERATURE, (ONBOARD_TEMPERATURE * 9 / 5 + 32)); _HC_12(ONBOARD_TEMPERATURE_TEMP); } watchdog_update(); // 喂狗 // CH4 FIFO_ = multicore_fifo_pop_blocking(); if (FIFO_ == 1) { printf("Kitchen danger (fire) alarm detects CH4!!!\n"); light_flashing(); FIFO_ = -1; //_433_MHZ(addDigit(4, SIGN_CH4)); } watchdog_update(); // 喂狗 // DS18B20 TEMPERATURE = DS18B20(); if (TEMPERATURE != -1) { if (TEMPERATURE >= 10) { printf("Temperature: %.3f°C\n", TEMPERATURE); } //_433_MHZ(addDigit(TEMPERATURE, SIGN_DS18B20)); if (TEMPERATURE != 85) { char TEMPERATURE_TEMP[BUFER] = { 0 }; sprintf(TEMPERATURE_TEMP, "Temperature: %.3f°C\n", TEMPERATURE); _HC_12(TEMPERATURE_TEMP); TEMPERATURE = -1; } } watchdog_update(); // 喂狗 // ZC13 CH4 传感器 char CH4_DATA[BUFER] = { 0 }; sprintf(CH4_DATA, "CH4 Concentration: %d\n", ZC13("ZC05")); _HC_12(CH4_DATA); watchdog_update(); // 喂狗 // ME2_CO CO // 50 ppm(百万分之一):长时间暴露可能会导致头痛、恶心、疲劳等不适症状。 // 200 ppm:短时间暴露可能会导致轻微的头痛、疲劳和呼吸困难。 // 800 ppm:短时间暴露可能会导致头晕、恶心和死亡。 // 1600 ppm:短时间暴露可能会导致昏迷、危及生命。 CO_DATA = ME2_CO(0, &ME2_CO_DATA_IS_OK); if (CO_DATA != -1 && ME2_CO_DATA_IS_OK == 1) { printf("CO Concentration: %d ppm\n", CO_DATA); //_433_MHZ(addDigit(CO_DATA, SIGN_CO)); char CO_DATA_TEMP[BUFER] = { 0 }; sprintf(CO_DATA_TEMP, "CO Concentration: %d ppm\n", CO_DATA); _HC_12(CO_DATA_TEMP); } watchdog_update(); // 喂狗 // MH_Z14B CO2 CO2_DATA = MH_Z14B(&MH_Z14B_DATA_IS_OK); if (CO2_DATA != -1 && MH_Z14B_DATA_IS_OK == 1) { printf("CO2 Concentration: %d ppm\n", CO2_DATA); //_433_MHZ(addDigit(CO2_DATA, SIGN_CO2)); char CO2_DATA_TEMP[BUFER] = { 0 }; sprintf(CO2_DATA_TEMP, "CO2 Concentration: %d ppm\n", CO2_DATA); _HC_12(CO2_DATA_TEMP); } printf("\r\n"); watchdog_update(); // 喂狗 sleep_ms(5000); watchdog_update(); // 喂狗 } return 0; } */