382 lines
11 KiB
C++
382 lines
11 KiB
C++
/*
|
||
*
|
||
* 基于 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"
|
||
|
||
#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);
|
||
|
||
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(); // 喂狗
|
||
|
||
/*
|
||
if (1 == CH4()) {
|
||
printf("Kitchen danger (fire) alarm detects CH4!!!\n");
|
||
light_flashing();
|
||
_HC_12("Kitchen danger (fire) alarm detects CH4!!!\n");
|
||
}
|
||
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;
|
||
}
|