Danger-alarm/SOFTWARE/Source/MAIN.cpp

473 lines
13 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
*
* 基于 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;
}
#define TARGET_SSID "cpyfb-01" // 替换为你要连接的 SSID
#define TARGET_PASSWORD "aa1122334" // 替换为你的 Wi-Fi 密码
static bool is_target_ssid_found = false; // 标志:目标 SSID 是否被找到
// 扫描结果处理函数
static int scan_result(void *env, const cyw43_ev_scan_result_t *result) {
if (result) {
// 输出每个扫描结果的信息
printf("ssid: %-32s rssi: %4d chan: %3d mac: %02x:%02x:%02x:%02x:%02x:%02x sec: %u\n",
result->ssid, result->rssi, result->channel,
result->bssid[0], result->bssid[1], result->bssid[2], result->bssid[3], result->bssid[4], result->bssid[5],
result->auth_mode);
// 检查是否是目标 SSID
if (!is_target_ssid_found && strcmp((const char*)result->ssid, TARGET_SSID) == 0) {
printf("Found target SSID: %s\n", TARGET_SSID);
is_target_ssid_found = true;
}
}
return 0;
}
// 执行 Wi-Fi 扫描
int wifi_scan() {
cyw43_wifi_scan_options_t scan_options = {0};
int err = cyw43_wifi_scan(&cyw43_state, &scan_options, NULL, scan_result);
if (err != 0) {
printf("Failed to start Wi-Fi scan: %d\n", err);
return err;
}
return 0;
}
// 连接 Wi-Fi
int wifi_connect() {
printf("Connecting to Wi-Fi...\n");
if (cyw43_arch_wifi_connect_timeout_ms(TARGET_SSID, TARGET_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 30000)) {
printf("Wi-Fi connection failed.\n");
return -1;
} else {
printf("Wi-Fi connected successfully.\n");
return 0;
}
}
// 主程序
int main(int argc, char *argv[]) {
stdio_init_all();
sleep_ms(3000);
// 初始化 CYW43 模块
if (cyw43_arch_init()) {
printf("CYW43 initialization failed\n");
return 1;
}
cyw43_arch_enable_sta_mode();
// 执行扫描并等待找到目标 SSID
while (!is_target_ssid_found) {
int scan_result_code = wifi_scan();
if (scan_result_code != 0) {
cyw43_arch_deinit();
return 1;
}
sleep_ms(7000); // 每隔 7 秒重新扫描一次
}
// 目标 Wi-Fi 已找到,连接 Wi-Fi
if (wifi_connect() != 0) {
cyw43_arch_deinit();
return 1;
}
// 连接成功,执行 TCP 客户端测试
while (1) {
float ONBOARD_TEMPERATURE = read_onboard_temperature();
printf("Onboard temperature %.02f°C %.02f°F\n", ONBOARD_TEMPERATURE, (ONBOARD_TEMPERATURE * 9 / 5 + 32));
char ONBOARD_TEMPERATURE_TEMP[BUFER] = { 0 };
sprintf(ONBOARD_TEMPERATURE_TEMP, "PICO_W CPU temperature %.02f°C %.02f°F\n", ONBOARD_TEMPERATURE, (ONBOARD_TEMPERATURE * 9 / 5 + 32));
run_tcp_client_test(ONBOARD_TEMPERATURE_TEMP);
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;
}
*/