Files
HECO2/program/User/My_system.c
T
jeon a502322188 chore: HERV 통합 저장소 재초기화 커밋
손상된 .git 히스토리(missing tree)로 재초기화 후 작업트리 전체 커밋.
.claude/ 만 제외(로컬 에이전트 설정). 구 저장소 백업(.git_corrupt_backup/) 포함.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 09:32:17 +09:00

1246 lines
39 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "Nano100Series.h"
#include "adc.h"
#include "gpio.h"
#include "pwm.h"
#include "timer.h"
#include "uart.h"
#include "sys.h"
#include "clk.h"
#include "EEPROM_Emulate.h"
#include "My_define.h"
void delay_us(uint32_t us)
{
CLK_SysTickDelay(us);
}
void delay_ms(uint32_t ms)
{
while(ms--)
{
delay_us(1000);
}
}
void UART0_Init()//hood
{
/*---------------------------------------------------------------------------------------------------------*/
/* Init UART */
/*---------------------------------------------------------------------------------------------------------*/
SYS_ResetModule(UART0_RST);
UART_Open(UART0, 9600);
UART_EnableInt(UART0, UART_IER_RDA_IE_Msk);
NVIC_EnableIRQ(UART0_IRQn);
}
void UART1_Init()
{
/*---------------------------------------------------------------------------------------------------------*/
/* Init UART */
/*---------------------------------------------------------------------------------------------------------*/
SYS_ResetModule(UART1_RST);
UART_Open(UART1, 115200); // HOMENET_485 : ErvDashboard 바이너리 프로토콜 (115200 N81)
UART_EnableInt(UART1, UART_IER_RDA_IE_Msk);
NVIC_EnableIRQ(UART1_IRQn);
}
void SC0_Init() // to roomcon
{
SCUART_Open(SC0, 1200);
// Enable smartcard receive interrupt
SCUART_ENABLE_INT(SC0, SC_IER_RDA_IE_Msk);
NVIC_EnableIRQ(SC0_IRQn);
}
void SC1_Init() // to display
{
SCUART_Open(SC1, 115200);
// Enable smartcard receive interrupt
SCUART_ENABLE_INT(SC1, SC_IER_RDA_IE_Msk);
NVIC_EnableIRQ(SC1_IRQn);
}
void PowerDownFunction(void)
{
;
}
volatile uint32_t Bldc1_signal = 0, Bldc2_signal = 0;
void GPABC_IRQHandler(void)
{
uint32_t reg;
if(GPIO_GET_INT_FLAG(PA, BIT13))
{
GPIO_CLR_INT_FLAG(PA, BIT13);
CLK->WK_INTSTS = 1; /* clear interrupt status */
Bldc2_signal++;
}
else
{
reg = PA->ISRC; PA->ISRC = reg;
reg = PB->ISRC; PB->ISRC = reg;
reg = PC->ISRC; PC->ISRC = reg;
}
}
void GPDEF_IRQHandler(void)
{
uint32_t reg;
if(GPIO_GET_INT_FLAG(PE, BIT5))
{
GPIO_CLR_INT_FLAG(PE, BIT5);
CLK->WK_INTSTS = 1; /* clear interrupt status */
Bldc1_signal++;
}
else
{
reg = PD->ISRC; PD->ISRC = reg;
reg = PE->ISRC; PE->ISRC = reg;
reg = PF->ISRC; PF->ISRC = reg;
}
}
volatile uint16_t Process_1000ms = 0, Process_333ms = 0,Process_100ms = 0, Process_10ms = 2,Process_5ms = 0;
uint16_t com_roomcon_delay = 0;
uint8_t Rx_homenet_TimeOut, Tx_homenet_TimeOut;
uint16_t InCom_polling_timer = 0;
uint16_t Hood_polling_timer = 0;
uint8_t rx_hood_485_TimeOut = 0;
uint16_t Hood_Conn_Timeout = 0; /* 후드 통신연결 생존 카운터(ms). 유효 응답 수신 시 재충전, 0이면 미연결 */
void TMR0_IRQHandler(void)
{
if(rx_hood_485_TimeOut)rx_hood_485_TimeOut--;
if(Hood_polling_timer)Hood_polling_timer--;
if(Hood_Conn_Timeout)Hood_Conn_Timeout--;
if(InCom_polling_timer)InCom_polling_timer--;
if(Tx_homenet_TimeOut)Tx_homenet_TimeOut--;
if(Rx_homenet_TimeOut)Rx_homenet_TimeOut--;
if(Rx_roomcon_TimeOut)Rx_roomcon_TimeOut--;
if(com_roomcon_delay)com_roomcon_delay--;
if(Process_1000ms)Process_1000ms--;
if(Process_333ms)Process_333ms--;
if(Process_100ms)Process_100ms--;
if(Process_10ms)Process_10ms--;
if(Process_5ms)Process_5ms--;
// clear timer interrupt flag
TIMER_ClearIntFlag(TIMER0);
}
// TIMER_ClearWakeupFlag(TIMER0);
void Timer0_Init(void)
{
TIMER_Open(TIMER0, TIMER_PERIODIC_MODE, 1000); // 1ms -> HZ
// Enable timer interrupt
TIMER_EnableInt(TIMER0);
NVIC_EnableIRQ(TMR0_IRQn);
// Start Timer 0
TIMER_Start(TIMER0);
}
void TMR1_IRQHandler(void)
{
Step_process();
// clear timer interrupt flag
TIMER_ClearIntFlag(TIMER1);
}
void Timer1_Init(void)
{
TIMER_Open(TIMER1, TIMER_PERIODIC_MODE, 1000); // 2ms -> HZ
// Enable timer interrupt
TIMER_EnableInt(TIMER1);
NVIC_EnableIRQ(TMR1_IRQn);
// Start Timer 0
TIMER_Start(TIMER1);
}
void BLDC1_Duty_Change(uint32_t BLDC1_duty) // 0 ~ 10000
{
PWM_ConfigOutputChannel(PWM1, 0, 1000, BLDC1_duty); // BLDC1
}
void BLDC2_Duty_Change(uint32_t BLDC2_duty) // 0 ~ 10000
{
PWM_ConfigOutputChannel(PWM0, 0, 1000, BLDC2_duty); // BLDC2
}
void PWM_Init(void)
{
// PWM0 frequency is 300Hz, duty 50%
PWM_ConfigOutputChannel(PWM0, 0, 1000, 10000); // BLDC2
PWM_ConfigOutputChannel(PWM1, 0, 1000, 10000); // BLDC1
// Enable output of all PWM channels
PWM_EnableOutput(PWM0, 1<<0); // ch0
PWM_EnableOutput(PWM1, 1<<0); //
// Start
PWM_Start(PWM0, 1<<0); // pwm0_ch0
PWM_Start(PWM1, 1<<0);
}
volatile uint8_t ADC_Complete = 0;
void ADC_IRQHandler(void)
{
uint32_t u32Flag;
// Get ADC conversion finish interrupt flag
u32Flag = ADC_GET_INT_FLAG(ADC, ADC_ADF_INT);
if(u32Flag & ADC_ADF_INT)
{
ADC_Complete = 1;
}
ADC_CLR_INT_FLAG(ADC, u32Flag);
}
void ADC_Init(void)
{
// Enable channel 1
ADC_Open(ADC, ADC_INPUT_MODE_SINGLE_END, ADC_OPERATION_MODE_SINGLE_CYCLE, ADC_CH_0_MASK|ADC_CH_1_MASK|ADC_CH_2_MASK|ADC_CH_3_MASK|ADC_CH_4_MASK);
// Set reference voltage to AVDD
ADC_SET_REF_VOLTAGE(ADC, ADC_REFSEL_POWER);
// Power on ADC
ADC_POWER_ON(ADC);
// Enable ADC ADC_IF interrupt
ADC_EnableInt(ADC, ADC_ADF_INT);
NVIC_EnableIRQ(ADC_IRQn);
ADC_START_CONV(ADC);
}
void GPIO_Init(void)
{
GPIO_SetMode(PA, BIT13, GPIO_PMD_INPUT); // BLDC2_FG
GPIO_ENABLE_PULL_UP(PA, BIT13);
GPIO_EnableInt(PA, 13, GPIO_INT_FALLING);
GPIO_SetMode(PA, BIT11, GPIO_PMD_INPUT); // SW
GPIO_SetMode(PE, BIT5, GPIO_PMD_INPUT); // BLDC1_FG
GPIO_ENABLE_PULL_UP(PE, BIT5);
GPIO_EnableInt(PE, 5, GPIO_INT_FALLING);
GPIO_SetMode(PC, BIT7, GPIO_PMD_OUTPUT); //
BUNBAGI_485_DIR = 0;
GPIO_SetMode(PB, BIT6, GPIO_PMD_OUTPUT); //
HOMENET_485_DIR = 0;
GPIO_SetMode(PB, BIT2, GPIO_PMD_OUTPUT); //
HOOD_485_DIR = 0;
GPIO_SetMode(PB, BIT7, GPIO_PMD_OUTPUT); // BLDC_PW
BLDC_PW = 1; // OFF
GPIO_SetMode(PA, BIT5, GPIO_PMD_OUTPUT); // ROOM_PW
UV_PW = 1;
GPIO_SetMode(PA, BIT10, GPIO_PMD_OUTPUT); // STATUS LED
ST_LED = 1;
GPIO_SetMode(PF, BIT2, GPIO_PMD_OUTPUT); // UV
P_UV = 0;
GPIO_SetMode(PA, BIT15|BIT14|BIT6, GPIO_PMD_OUTPUT); // STEP
GPIO_SetMode(PB, BIT3|BIT9|BIT10|BIT12|BIT13|BIT14|BIT15|BIT8, GPIO_PMD_OUTPUT); // STEP
GPIO_SetMode(PC, BIT8|BIT9|BIT10|BIT11|BIT2|BIT3|BIT14|BIT15|BIT6, GPIO_PMD_OUTPUT); // STEP
GPIO_SetMode(PD, BIT15|BIT14|BIT7|BIT6, GPIO_PMD_OUTPUT); // STEP
NVIC_EnableIRQ(GPABC_IRQn);
NVIC_EnableIRQ(GPDEF_IRQn);
/* Enable interrupt de-bounce function and select de-bounce sampling cycle time */
GPIO_SET_DEBOUNCE_TIME(GPIO_DBCLKSRC_HCLK, GPIO_DBCLKSEL_1);
GPIO_ENABLE_DEBOUNCE(PA, BIT12);
GPIO_ENABLE_DEBOUNCE(PE, BIT5);
}
void SYS_Init(void)
{
/* Unlock protected registers */
SYS_UnlockReg();
/* Enable clock source */
CLK_EnableXtalRC(CLK_PWRCTL_LIRC_EN_Msk|CLK_PWRCTL_HIRC_EN_Msk);
/* Waiting for clock source ready */
CLK_WaitClockReady(CLK_CLKSTATUS_LIRC_STB_Msk|CLK_CLKSTATUS_HIRC_STB_Msk);
/* If the defines do not exist in your project, please refer to the related clk.h in the Header folder appended to the tool package. */
/* Set HCLK clock */
CLK_SetHCLK(CLK_CLKSEL0_HCLK_S_HIRC, CLK_HCLK_CLK_DIVIDER(1));
/* Enable IP clock */
CLK_EnableModuleClock(GPIO_MODULE);
CLK_EnableModuleClock(ADC_MODULE);
// CLK_EnableModuleClock(I2C0_MODULE);
// CLK_EnableModuleClock(I2C1_MODULE);
// CLK_EnableModuleClock(PWM0_CH23_MODULE);
CLK_EnableModuleClock(PWM0_CH01_MODULE);
CLK_EnableModuleClock(PWM1_CH01_MODULE);
CLK_EnableModuleClock(ISP_MODULE);
CLK_EnableModuleClock(SC0_MODULE);
CLK_EnableModuleClock(SC1_MODULE);
CLK_EnableModuleClock(SRAM_MODULE);
CLK_EnableModuleClock(TICK_MODULE);
CLK_EnableModuleClock(TMR0_MODULE);
CLK_EnableModuleClock(TMR1_MODULE);
CLK_EnableModuleClock(UART0_MODULE);
CLK_EnableModuleClock(UART1_MODULE);
CLK_EnableModuleClock(WDT_MODULE);
/* Set IP clock */
CLK_SetModuleClock(ADC_MODULE, CLK_CLKSEL1_ADC_S_HIRC, CLK_ADC_CLK_DIVIDER(1));
// CLK_SetModuleClock(PWM0_CH23_MODULE, CLK_CLKSEL1_PWM0_CH23_S_HIRC, MODULE_NoMsk);
CLK_SetModuleClock(PWM0_CH01_MODULE, CLK_CLKSEL1_PWM0_CH01_S_HIRC, MODULE_NoMsk);
CLK_SetModuleClock(PWM1_CH01_MODULE, CLK_CLKSEL2_PWM1_CH01_S_HIRC, MODULE_NoMsk);
CLK_SetModuleClock(SC0_MODULE, CLK_CLKSEL2_SC_S_HIRC, CLK_SC0_CLK_DIVIDER(6));
CLK_SetModuleClock(SC1_MODULE, CLK_CLKSEL2_SC_S_HIRC, CLK_SC1_CLK_DIVIDER(1));
CLK_SetModuleClock(TMR0_MODULE, CLK_CLKSEL1_TMR0_S_HIRC, MODULE_NoMsk);
CLK_SetModuleClock(TMR1_MODULE, CLK_CLKSEL1_TMR1_S_HIRC, MODULE_NoMsk);
CLK_SetModuleClock(UART0_MODULE, CLK_CLKSEL1_UART_S_HIRC, CLK_UART_CLK_DIVIDER(1));
CLK_SetModuleClock(UART1_MODULE, CLK_CLKSEL1_UART_S_HIRC, CLK_UART_CLK_DIVIDER(1));
/* Update System Core Clock */
/* User can use SystemCoreClockUpdate() to calculate SystemCoreClock. */
SystemCoreClockUpdate();
//If the defines do not exist in your project, please refer to the corresponding sys.h in the Header folder appended to the tool package.
SYS->PA_H_MFP = SYS_PA_H_MFP_PA12_MFP_PWM0_CH0 | SYS_PA_H_MFP_PA9_MFP_SC0_DAT | SYS_PA_H_MFP_PA8_MFP_SC0_CLK;
SYS->PA_L_MFP = SYS_PA_L_MFP_PA4_MFP_ADC_CH4 | SYS_PA_L_MFP_PA3_MFP_ADC_CH3 | SYS_PA_L_MFP_PA2_MFP_ADC_CH2 | SYS_PA_L_MFP_PA1_MFP_ADC_CH1 | SYS_PA_L_MFP_PA0_MFP_ADC_CH0;
SYS->PB_H_MFP = SYS_PB_H_MFP_PB11_MFP_PWM1_CH0;
SYS->PB_L_MFP = SYS_PB_L_MFP_PB5_MFP_UART1_TX | SYS_PB_L_MFP_PB4_MFP_UART1_RX | SYS_PB_L_MFP_PB1_MFP_UART0_TX | SYS_PB_L_MFP_PB0_MFP_UART0_RX;
SYS->PC_H_MFP = 0x00000000;
SYS->PC_L_MFP = SYS_PC_L_MFP_PC1_MFP_SC1_DAT | SYS_PC_L_MFP_PC0_MFP_SC1_CLK;
SYS->PD_H_MFP = 0x00000000;
SYS->PD_L_MFP = 0x00000000;
SYS->PE_L_MFP = 0x00000000;
SYS->PF_L_MFP = SYS_PF_L_MFP_PF1_MFP_ICE_CLK | SYS_PF_L_MFP_PF0_MFP_ICE_DAT;
/* Lock protected registers */
SYS_LockReg();
return;
}
volatile uint8_t Run_Mode = 0, Auto_Mode = 0, Fan_Mode = 0;
uint8_t Power_On = 0;
extern signed int Out_Temperature;
extern uint8_t Fan1_Speed, Fan2_Speed;
volatile uint32_t Reserve_timer_sec = 0;
uint16_t Filter_timer_sec = 1800;
volatile uint16_t Filter_timer_clean = 0;
volatile uint16_t Filter_timer_change = 0;
volatile uint16_t Soja_timer_change = 0;
void Reservation_process(void)
{
if(Power_On == 1)// power on - run
{
if(Reserve_timer_sec)Reserve_timer_sec--;
if(Reserve_timer_sec == 1)
{
Power_off_process(1);
}
}
}
uint16_t UV_OnOff_Timer = 0;
void UV_process(void) // 1sec
{
if(Roomcon_connect_mode == 0)
{
UV_OnOff = 0x00;
if((Power_On == 0))
{
UV_OnOff_Timer = 0;
return;
}
if(UV_OnOff_Timer++ >= 3600)UV_OnOff_Timer = 0;
if((Run_Mode == MODE_VENTILATION)||(Run_Mode == MODE_AUTO)||(Run_Mode == MODE_AIRCLEAN))
{
#if(((SPEC_DEVICE_TYPE_INFO&0x0F) == 0x06)||((SPEC_DEVICE_TYPE_INFO&0x0F) == 0x08))//EF1
if(Run_Mode == MODE_AIRCLEAN)
{
if(UV_OnOff_Timer < 1800)
{
UV_OnOff = 0x10;
}
}
#elif((SPEC_DEVICE_TYPE_INFO&0x0F) == 0x04)//EBSN
if(Fan_Mode >= 2)
{
if(UV_OnOff_Timer < 900)
{
UV_OnOff = 0x10;
}
}
#endif
}
}
if(Power_On == 1)
{
if(UV_OnOff == 0x10)
{
if(Fan1_Speed != 0) P_UV = 1;
else P_UV = 0;
}
else
{
P_UV = 0;
}
}
else
{
P_UV = 0;
}
}
extern volatile uint8_t Err_Code;
void Filter_process(void)
{
if(Power_On == 1)
{
if(Filter_timer_sec++ >= 3600)
{
Filter_timer_sec = 0;
if(Filter_timer_clean++ >= 2000)
{
Filter_timer_clean = 2000;
Err_Code |= ERROR_FILTER_CLEAN;
}
if(Filter_timer_change++ >= 4000)
{
Filter_timer_change = 4000;
Err_Code |= ERROR_FILTER_CHANGE;
}
if(Soja_timer_change++ >= 20000)
{
Soja_timer_change = 20000;
Err_Code |= ERROR_SOJA_CHANGE;
}
EEP_Save_Flag = 1;
}
}
if(Filter_Reset_Flag == 1)
{
Filter_Reset_Flag = 0;
if(Filter_Reset_Process() == 1)EEP_Save_Flag = 1;
}
}
uint8_t Sometime_cycle = 0, Pre_Sometime_cycle = 0;
uint8_t Protect_Mode = 0;
uint16_t Sometime_Timer = 0;
uint8_t Sometime_Mode = 0;
uint8_t Sometime_before_speed = 0;
uint8_t Sometime_before_mode = 0;
uint8_t Kijer_Mode = 0;
uint16_t Kijer_Timer = 0;
void Exception_mode_process(void)
{
if(Out_Temperature <= -15)
{
Protect_Mode = 1;
Err_Code |= ERROR_PROTECT;
Sometime_Mode = 0;
Err_Code &= ~ERROR_SOMETIME;
}
else if(Out_Temperature >= -13)
{
Protect_Mode = 0;
Err_Code &= ~ERROR_PROTECT;
}
if((Out_Temperature <= -7)&&(Protect_Mode == 0))
{
if((Power_On == 1)&&(Run_Mode == MODE_AUTO))
{
if(Sometime_Mode == 0)
{
Sometime_Mode = 1;
Err_Code |= ERROR_SOMETIME;
Sometime_Timer = 1800; // 30min
}
}
else
{
Sometime_Mode = 0;
Err_Code &= ~ERROR_SOMETIME;
}
}
if(Out_Temperature >= -5)
{
if(Sometime_Mode == 1)
{
Sometime_Mode = 0;
Err_Code &= ~ERROR_SOMETIME;
}
}
if(Protect_Mode == 1)
{
if(Power_On == 0)
{
return;
}
else
{
Run_Mode = MODE_VENTILATION;
Fan_Mode = 0;
Reserve_timer_sec = 0;
Power_off_process(1);
}
}
else if(Sometime_Mode == 1)
{
if((Power_On == 0)||(Run_Mode != MODE_AUTO))
{
Sometime_Timer = 0;
Pre_Sometime_cycle = Sometime_cycle = 0;
Sometime_Mode = 0;
Err_Code &= ~ERROR_SOMETIME;
return;
}
if(Sometime_Timer > 600) // 600 ~ 1800 -- 20min
{
Sometime_cycle = 1;
Sometime_Timer--;
}
else if(Sometime_Timer > 0) // 600 ~ 0 -- 10min
{
Sometime_cycle = 0;
Sometime_Timer--;
}
else
{
Sometime_cycle = 0;
Sometime_Timer = 1800;
}
if(Sometime_cycle != Pre_Sometime_cycle)
{
if(Sometime_cycle == 1)
{
Run_Mode = MODE_AUTO;
Fan_Mode = 1;
}
else
{
Run_Mode = MODE_AUTO;
Fan_Mode = 0;
}
Pre_Sometime_cycle = Sometime_cycle;
}
}
else
{
Pre_Sometime_cycle = Sometime_cycle = 0;
}
}
//------------------------------------------------
typedef struct {
char name; // 변수 이름 (a, b, c, d)
uint8_t value; // 변수 값
}Var;
Var vars[4] = {
{'1', 0},
{'2', 0},
{'3', 0},
{'4', 0}
};
// 내림차순 정렬 함수
int compare(const void *x, const void *y) {
Var *a = (Var *)x;
Var *b = (Var *)y;
// 값이 큰 순서대로
if (b->value != a->value)
return b->value - a->value;
else
return a->name - b->name; // 값이 같으면 이름 순으로
}
//-----------------------------------------------
uint8_t CO2_quality[7] = {0,};
uint8_t PM2_5_quality[7] = {0,};
uint8_t VOC_quality[7] = {0,};
uint8_t ROOM_air_volume[7] = {0,};
uint16_t volatile CO2_Histeresys = 50;
uint16_t Focus_Mode_RunTime = 0;
uint8_t Focus_Mode = 0;
uint8_t Focus_Air_Volume = 0;
uint8_t Focus_Room_Number = 0;
uint8_t Pre_Ext_Run_Mode = 0;
uint16_t Ext_Run_Mode_Off_Delay = 0;
uint8_t Memory_Hood_Status = 0;
uint8_t RJ_Memory_Run_Mode = 0, RJ_Memory_Fan_Mode = 0;
uint8_t My_Memory_Run_Mode = 0, My_Memory_Fan_Mode = 0;
uint8_t Hood_YeunDong_Enable = 0;
uint8_t Total_CV_Mode_Factot = 0;
uint8_t Total_CVP_Fan_Factor = 0;
/* ============================================================================
* 260428 v.Final 자동 동작로직 (집중/분산) - 제어로직_260428.xlsx (정본)
* 실별 4종 센서를 0~4 단계로 변환 -> 실별 최고단계(Level) -> 부하총점(Score)/dP
* - 풍량 단수 : Score 매핑 (0->0, 1~4->1, 5~8->2, 9~12->3, 13~16->4)
* - dP = 정렬 내림차순[0]-[1] (두번째로 높은 단계, 동점 포함)
* - 댐퍼 : P_max==0 전체대기 / dP>=2 집중(P_max 실만) / 그 외 분산(1단계↑ 실만)
* ==========================================================================*/
/* 공기질 센서 히스테리시스 — 모드별(0=ECO,1=NORMAL,2=TURBO) 오염단계 상한 임계값.
* [preset][4개 상한] = 0/1/2/3단계(좋음/보통/나쁨/매우나쁨)의 상한, 그 초과는 4단계(최악).
* (변경 가능 : HOMENET 프리셋 값 설정으로 갱신) - 기본값은 사양서 표(260613 10p) */
uint16_t Co2_Thr[3][4] = {{1000,1300,1600,2000}, {800,1100,1400,1700}, {700,1000,1300,1600}};
uint16_t Pm25_Thr[3][4] = {{ 20, 38, 60, 86}, { 14, 29, 49, 69}, { 12, 23, 38, 52}};
uint16_t Pm10_Thr[3][4] = {{ 40, 86, 126, 173}, { 28, 66, 102, 138}, { 24, 53, 78, 104}};
uint16_t Voc_Thr[3][4] = {{ 171, 195, 308, 438}, {120, 150, 250, 350}, {103, 120, 192, 263}};
/* 히스테리시스 데드밴드(하강 시) [preset] : CO2,PM2.5,PM10,VOC */
uint16_t Co2_Db[3] = { 50, 50, 30};
uint16_t Pm25_Db[3] = { 2, 2, 2};
uint16_t Pm10_Db[3] = { 5, 5, 5};
uint16_t Voc_Db[3] = { 5, 5, 3};
uint8_t Hyst_Preset = 1; /* 0 ECO / 1 NORMAL / 2 TURBO */
uint8_t Room_Level[7] = {0,}; /* 실별 오염단계 0~4 (1=거실 2=침1 3=침2 4=침3) */
uint8_t Load_Score = 0; /* 부하 총점 0~16 */
uint8_t Auto_P_max = 0; /* 최고 단계 */
uint8_t Auto_dP = 0; /* P_max - P_2nd */
uint8_t Auto_Concentrate = 0; /* 0 분산 / 1 집중 (HOMENET autoState) */
/* 센서별 이전 단계(히스테리시스 데드존 유지용) */
static uint8_t Prev_CO2_Lv[7] = {0,};
static uint8_t Prev_PM25_Lv[7] = {0,};
static uint8_t Prev_PM10_Lv[7] = {0,};
static uint8_t Prev_VOC_Lv[7] = {0,};
/* 센서값 -> 0~4 단계. 하강 시 (임계-데드밴드) 이하라야 내려감. 데드존이면 이전 단계 유지 */
static uint8_t sensor_level(uint16_t v, const uint16_t *T, uint16_t db, uint8_t prev)
{
uint8_t lv = prev;
if (v <= (uint16_t)(T[0] - db)) lv = 0;
else if ((v > T[0]) && (v <= (uint16_t)(T[1] - db))) lv = 1;
else if ((v > T[1]) && (v <= (uint16_t)(T[2] - db))) lv = 2;
else if ((v > T[2]) && (v <= (uint16_t)(T[3] - db))) lv = 3;
else if (v > T[3]) lv = 4;
return lv;
}
/* 부하 총점(0~16) -> 풍량 단수(0~4) */
static uint8_t score_to_stage(uint8_t score)
{
if (score == 0) return 0;
if (score <= 4) return 1;
if (score <= 8) return 2;
if (score <= 12) return 3;
return 4;
}
uint8_t Air_Quality_damper_process(void)
{
uint8_t Tmp_Air_Volume = 0;
uint8_t room_CV_quality = 0, room_CVP_quality = 0;
uint8_t Room_Num = 0;
Tmp_Air_Volume = 0;
if(Force_Damper_Mode == 1)
{
if(Damper_Status_Display & 0x01){Memory_Diffuser_Dmp_Ang_SA[4] = 110;}else{Memory_Diffuser_Dmp_Ang_SA[4] = 0;};
if(Damper_Status_Display & 0x02){Memory_Diffuser_Dmp_Ang_RA[4] = 110;}else{Memory_Diffuser_Dmp_Ang_RA[4] = 0;};
if(Damper_Status_Display & 0x04){Memory_Diffuser_Dmp_Ang_SA[3] = 110;}else{Memory_Diffuser_Dmp_Ang_SA[3] = 0;};
if(Damper_Status_Display & 0x08){Memory_Diffuser_Dmp_Ang_RA[3] = 110;}else{Memory_Diffuser_Dmp_Ang_RA[3] = 0;};
if(Damper_Status_Display & 0x10){Memory_Diffuser_Dmp_Ang_SA[2] = 110;}else{Memory_Diffuser_Dmp_Ang_SA[2] = 0;};
if(Damper_Status_Display & 0x20){Memory_Diffuser_Dmp_Ang_RA[2] = 110;}else{Memory_Diffuser_Dmp_Ang_RA[2] = 0;};
if(Damper_Status_Display & 0x40){Memory_Diffuser_Dmp_Ang_SA[1] = 110;}else{Memory_Diffuser_Dmp_Ang_SA[1] = 0;};
if(Damper_Status_Display & 0x80){Memory_Diffuser_Dmp_Ang_RA[1] = 110;}else{Memory_Diffuser_Dmp_Ang_RA[1] = 0;};
if((Memory_Diffuser_Dmp_Ang_SA[4] != 0)||(Memory_Diffuser_Dmp_Ang_RA[4] != 0))Diffuser_Air_quality[4] = 5;
else Diffuser_Air_quality[4] = 0;
if((Memory_Diffuser_Dmp_Ang_SA[3] != 0)||(Memory_Diffuser_Dmp_Ang_RA[3] != 0))Diffuser_Air_quality[3] = 5;
else Diffuser_Air_quality[3] = 0;
if((Memory_Diffuser_Dmp_Ang_SA[2] != 0)||(Memory_Diffuser_Dmp_Ang_RA[2] != 0))Diffuser_Air_quality[2] = 5;
else Diffuser_Air_quality[2] = 0;
if((Memory_Diffuser_Dmp_Ang_SA[1] != 0)||(Memory_Diffuser_Dmp_Ang_RA[1] != 0))Diffuser_Air_quality[1] = 5;
else Diffuser_Air_quality[1] = 0;
Tmp_Air_Volume = Set_Fan_Mode;
Ext_Run_Mode_Off_Delay = 0;
goto PASS_RETURN;
}
else if((Ext_Run_Mode == 1)&&(Pre_Ext_Run_Mode != 1)) //안심회복 모드
{
Memory_Diffuser_Dmp_Ang_SA[6] = 110;
Memory_Diffuser_Dmp_Ang_SA[5] = 110;
Memory_Diffuser_Dmp_Ang_SA[4] = 110;
Memory_Diffuser_Dmp_Ang_SA[3] = 110;
Memory_Diffuser_Dmp_Ang_SA[2] = 110;
Memory_Diffuser_Dmp_Ang_SA[1] = 110;
Memory_Diffuser_Dmp_Ang_RA[6] = 0;
Memory_Diffuser_Dmp_Ang_RA[5] = 0;
Memory_Diffuser_Dmp_Ang_RA[4] = 0;
Memory_Diffuser_Dmp_Ang_RA[3] = 0;
Memory_Diffuser_Dmp_Ang_RA[2] = 0;
Memory_Diffuser_Dmp_Ang_RA[1] = 0;
Memory_Diffuser_Dmp_Ang_SA[Ext_Select_Room] = 0;
Memory_Diffuser_Dmp_Ang_RA[Ext_Select_Room] = 110;
Diffuser_Air_quality[6] = 5;//ON
Diffuser_Air_quality[5] = 5;//ON
Diffuser_Air_quality[4] = 5;//ON
Diffuser_Air_quality[3] = 5;//ON
Diffuser_Air_quality[2] = 5;//ON
Diffuser_Air_quality[1] = 5;//ON
Tmp_Air_Volume = 2;//3;/////////////// 2026.1.8 전경선...
Command_request_type |= (TYPE_MODE|TYPE_FAN_SPEED);
My_Memory_Run_Mode = Run_Mode;
My_Memory_Fan_Mode = Fan_Mode;
Set_Run_Mode = MODE_VENTILATION;
Set_Fan_Mode = 2;//3; /////////////// 2026.1.8 전경선...
Pre_Ext_Run_Mode = Ext_Run_Mode ;
Pre_Ext_Select_Room = Ext_Select_Room;
goto PASS_VOLUME;
}
else if((Ext_Run_Mode == 2)&&(Pre_Ext_Run_Mode != 2)) //쾌적조리 En
{
Hood_YeunDong_Enable = 1;
Pre_Ext_Run_Mode = Ext_Run_Mode ;
Pre_Ext_Select_Room = Ext_Select_Room;
}
else if((Ext_Run_Mode == 3)&&(Pre_Ext_Run_Mode != 3)) //집중청정 모드
{
Memory_Diffuser_Dmp_Ang_SA[6] = 0;
Memory_Diffuser_Dmp_Ang_SA[5] = 0;
Memory_Diffuser_Dmp_Ang_SA[4] = 0;
Memory_Diffuser_Dmp_Ang_SA[3] = 0;
Memory_Diffuser_Dmp_Ang_SA[2] = 0;
Memory_Diffuser_Dmp_Ang_SA[1] = 0;
Memory_Diffuser_Dmp_Ang_RA[6] = 0;
Memory_Diffuser_Dmp_Ang_RA[5] = 0;
Memory_Diffuser_Dmp_Ang_RA[4] = 0;
Memory_Diffuser_Dmp_Ang_RA[3] = 0;
Memory_Diffuser_Dmp_Ang_RA[2] = 0;
Memory_Diffuser_Dmp_Ang_RA[1] = 0;
Memory_Diffuser_Dmp_Ang_SA[Ext_Select_Room] = 110;
Memory_Diffuser_Dmp_Ang_RA[Ext_Select_Room] = 110;
Diffuser_Air_quality[6] = 0;//OFF
Diffuser_Air_quality[5] = 0;//OFF
Diffuser_Air_quality[4] = 0;//OFF
Diffuser_Air_quality[3] = 0;//OFF
Diffuser_Air_quality[2] = 0;//OFF
Diffuser_Air_quality[1] = 0;//OFF
Diffuser_Air_quality[Ext_Select_Room] = 5;//ON
Tmp_Air_Volume = 2;
Command_request_type |= (TYPE_MODE|TYPE_FAN_SPEED);
My_Memory_Run_Mode = Run_Mode;
My_Memory_Fan_Mode = Fan_Mode;
Set_Run_Mode = MODE_VENTILATION;
Set_Fan_Mode = 2;
Pre_Ext_Run_Mode = Ext_Run_Mode ;
Pre_Ext_Select_Room = Ext_Select_Room;
goto PASS_VOLUME;
}
else if(Ext_Run_Mode == 4) //스마트 수면 모드 (사양서 8p) : 환기 수동·1단 고정, 실별 CO2 기준 댐퍼 개폐
{
if(Pre_Ext_Run_Mode != 4) /* 진입 1회 : 모드/풍량 + 초기상태(거실 CLOSE, 침실1~3 OPEN) */
{
Command_request_type |= (TYPE_MODE|TYPE_FAN_SPEED);
My_Memory_Run_Mode = Run_Mode;
My_Memory_Fan_Mode = Fan_Mode;
Set_Run_Mode = MODE_VENTILATION;
Set_Fan_Mode = 1;
Memory_Diffuser_Dmp_Ang_SA[1] = 0; Memory_Diffuser_Dmp_Ang_RA[1] = 0; /* 거실 CLOSE */
for(Room_Num = 2; Room_Num < 5; Room_Num++) /* 침실1~3 OPEN */
{ Memory_Diffuser_Dmp_Ang_SA[Room_Num] = 110; Memory_Diffuser_Dmp_Ang_RA[Room_Num] = 110; }
Memory_Diffuser_Dmp_Ang_SA[5] = 0; Memory_Diffuser_Dmp_Ang_RA[5] = 0;
Memory_Diffuser_Dmp_Ang_SA[6] = 0; Memory_Diffuser_Dmp_Ang_RA[6] = 0;
Pre_Ext_Run_Mode = Ext_Run_Mode;
Pre_Ext_Select_Room = Ext_Select_Room;
}
/* 매 틱 : 실별 CO2 히스테리시스. CO2 >= 1000 OPEN, <= 800 CLOSE, 그 사이(데드존)는 현재 상태 유지 */
for(Room_Num = 1; Room_Num < 5; Room_Num++)
{
if(SEN66_CO2_value[Room_Num] >= 1000)
{ Memory_Diffuser_Dmp_Ang_SA[Room_Num] = 110; Memory_Diffuser_Dmp_Ang_RA[Room_Num] = 110; }
else if(SEN66_CO2_value[Room_Num] <= 800)
{ Memory_Diffuser_Dmp_Ang_SA[Room_Num] = 0; Memory_Diffuser_Dmp_Ang_RA[Room_Num] = 0; }
if((Memory_Diffuser_Dmp_Ang_SA[Room_Num] != 0)||(Memory_Diffuser_Dmp_Ang_RA[Room_Num] != 0))
Diffuser_Air_quality[Room_Num] = 5;//ON
else
Diffuser_Air_quality[Room_Num] = 0;//OFF
}
Tmp_Air_Volume = 1; /* 1단 고정 */
Ext_Run_Mode_Off_Delay = 0;
goto PASS_VOLUME;
}
else if((Ext_Run_Mode == 0)&&((Pre_Ext_Run_Mode == 1)||(Pre_Ext_Run_Mode == 3)||(Pre_Ext_Run_Mode == 4)))
{
if(Power_On == 1)
{
Command_request_type |= (TYPE_MODE|TYPE_FAN_SPEED);
Set_Run_Mode = My_Memory_Run_Mode;
Set_Fan_Mode = My_Memory_Fan_Mode;
Pre_Ext_Run_Mode = Ext_Run_Mode ;
Pre_Ext_Select_Room = Ext_Select_Room;
}
Ext_Run_Mode_Off_Delay = 0;
}
else if((Ext_Run_Mode == 0)&&(Pre_Ext_Run_Mode == 2))// 쾌적조리(후드연동) 토글 OFF -> 연동 없음(사양 260613 9p 3.1)
{
Hood_YeunDong_Enable = 0;
/* 메이크업 에어 동작중(후드 가동/롤백 유지)이었으면 본래 운전모드/풍량으로 즉시 복귀(롤백 딜레이 없음) */
if((Power_On == 1)&&((Hood_Status != 0)||(Hood_Yeundong_flag != 0)||(Hood_Warming_up_Timer != 0)))
{
Set_Run_Mode = My_Memory_Run_Mode;
Set_Fan_Mode = My_Memory_Fan_Mode;
Command_request_type |= (TYPE_MODE|TYPE_FAN_SPEED);
}
Hood_Yeundong_flag = 0;
Hood_Warming_up_Timer = 0;
Pre_Ext_Run_Mode = Ext_Run_Mode ;
Pre_Ext_Select_Room = Ext_Select_Room;
goto PASS_VOLUME;
}
else if((Ext_Run_Mode != 0)&&(Ext_Run_Mode != 2))
{
Pre_Ext_Run_Mode = Ext_Run_Mode ;
Pre_Ext_Select_Room = Ext_Select_Room;
if(Run_Mode != MODE_AUTO)goto PASS_VOLUME;
}
Total_CV_Mode_Factot = 0;
Total_CVP_Fan_Factor = 0;
for(Room_Num = 1; Room_Num < 6; Room_Num++)
{
uint8_t lc, lp25, lp10, lvc, lvl;
/* 4종 센서 각각 0~4 단계 (모드별 임계 + 하강 히스테리시스) */
lc = sensor_level(SEN66_CO2_value[Room_Num], Co2_Thr[Hyst_Preset], Co2_Db[Hyst_Preset], Prev_CO2_Lv[Room_Num]);
lp25 = sensor_level(SEN66_pm2p5[Room_Num], Pm25_Thr[Hyst_Preset], Pm25_Db[Hyst_Preset], Prev_PM25_Lv[Room_Num]);
lp10 = sensor_level(SEN66_pm10p0[Room_Num], Pm10_Thr[Hyst_Preset], Pm10_Db[Hyst_Preset], Prev_PM10_Lv[Room_Num]);
lvc = sensor_level((uint16_t)SEN66_VOC_value[Room_Num], Voc_Thr[Hyst_Preset], Voc_Db[Hyst_Preset], Prev_VOC_Lv[Room_Num]);
Prev_CO2_Lv[Room_Num]=lc; Prev_PM25_Lv[Room_Num]=lp25; Prev_PM10_Lv[Room_Num]=lp10; Prev_VOC_Lv[Room_Num]=lvc;
/* 실 오염단계 = 4종 중 최고 */
lvl = lc;
if(lp25 > lvl) lvl = lp25;
if(lp10 > lvl) lvl = lp10;
if(lvc > lvl) lvl = lvc;
Room_Level[Room_Num] = lvl;
ROOM_air_volume[Room_Num] = lvl;
if(lvl) Total_CV_Mode_Factot = 1;
/* AUTO 외(수동/바이패스/공청) 및 전원OFF 댐퍼는 여기서 결정.
AUTO 는 집중/분산 판정 후 일괄 처리하므로 여기서 건드리지 않음 */
if(Power_On != 1)
{
Memory_Diffuser_Dmp_Ang_SA[Room_Num] = 0;
Memory_Diffuser_Dmp_Ang_RA[Room_Num] = 0;
Diffuser_Air_quality[Room_Num] = 0;//OFF
Diffuser_Damper_Manual[Room_Num] = 0; /* 전원OFF - 수동 댐퍼 해제 */
}
else if(Run_Mode != MODE_AUTO)
{
/* 환기/공청/바이패스 : 전실 개방. 단, 대시보드 수동 댐퍼(Manual) 실은 위치 유지 */
if(Diffuser_Damper_Manual[Room_Num] == 0)
{
Memory_Diffuser_Dmp_Ang_SA[Room_Num] = 110;
Memory_Diffuser_Dmp_Ang_RA[Room_Num] = 110;
}
Diffuser_Air_quality[Room_Num] = 5;//ON
Tmp_Air_Volume = Diffuser_Fan_Speed[1] = Fan_Mode; //manual
}
else /* MODE_AUTO : 자동 제어 - 수동 댐퍼 해제 */
{
Diffuser_Damper_Manual[Room_Num] = 0;
}
}
if(Power_On != 1)
{
Focus_Mode = 0;
Focus_Mode_RunTime = 0;
Auto_Concentrate = 0;
Tmp_Air_Volume = 0;
}
/* ===== 부하 총점(Score) / P_max / dP : 거실+침실3실(1~4) ===== */
Load_Score = (uint8_t)(Room_Level[1] + Room_Level[2] + Room_Level[3] + Room_Level[4]);
{
uint8_t max1 = 0, max2 = 0, r, v;
/* 260428 v.Final : dP = 정렬 내림차순[0]-[1] (= 두번째로 높은 단계, 동점 포함).
최고단계 실이 2개 이상 동점이면 max2=max1 -> dP=0 -> 분산. 한 실만 확실히(2↑) 나쁠 때만 집중.
예) {0,3,3,0}->분산, {0,3,0,0}->집중, {2,2,1,1}->분산, {4,4,4,4}->분산 */
for(r = 1; r < 5; r++)
{
v = Room_Level[r];
if(v > max1) { max2 = max1; max1 = v; } /* 1·2위 갱신 */
else if(v > max2) { max2 = v; } /* 2위만 갱신(동점 포함) */
}
Auto_P_max = max1;
Auto_dP = (uint8_t)(max1 - max2);
}
if(Run_Mode == MODE_AUTO)
{
/* 자동 = 환기 기반 */
if(Auto_Mode != (MODE_VENTILATION+1))
{
Auto_Mode = MODE_VENTILATION+1;
Command_request_type |= (TYPE_MODE);
}
/* === 댐퍼 개폐 모드 결정 (대기 / 집중 / 분산) === */
if(Auto_P_max == 0) /* 대기 : 전 실 OFF */
{
Auto_Concentrate = 0;
Focus_Mode = 0;
for(Room_Num = 1; Room_Num < 7; Room_Num++)
{
Memory_Diffuser_Dmp_Ang_SA[Room_Num] = 0;
Memory_Diffuser_Dmp_Ang_RA[Room_Num] = 0;
Diffuser_Air_quality[Room_Num] = 0;
}
}
else if(Auto_dP >= 2) /* 집중 : P_max 실만 개방 */
{
Auto_Concentrate = 1;
Focus_Mode = 1;
for(Room_Num = 1; Room_Num < 7; Room_Num++)
{
if((Room_Num < 5) && (Room_Level[Room_Num] == Auto_P_max))
{
Memory_Diffuser_Dmp_Ang_SA[Room_Num] = 110;
Memory_Diffuser_Dmp_Ang_RA[Room_Num] = 110;
Diffuser_Air_quality[Room_Num] = 5;
}
else
{
Memory_Diffuser_Dmp_Ang_SA[Room_Num] = 0;
Memory_Diffuser_Dmp_Ang_RA[Room_Num] = 0;
Diffuser_Air_quality[Room_Num] = 0;
}
}
}
else /* 분산 : 1단계 이상 실만 개방 (260428 : 0단계 좋음 실은 닫음) */
{
Auto_Concentrate = 0;
Focus_Mode = 0;
for(Room_Num = 1; Room_Num < 7; Room_Num++)
{
if((Room_Num < 5) && (Room_Level[Room_Num] >= 1))
{
Memory_Diffuser_Dmp_Ang_SA[Room_Num] = 110;
Memory_Diffuser_Dmp_Ang_RA[Room_Num] = 110;
Diffuser_Air_quality[Room_Num] = 5;
}
else
{
Memory_Diffuser_Dmp_Ang_SA[Room_Num] = 0;
Memory_Diffuser_Dmp_Ang_RA[Room_Num] = 0;
Diffuser_Air_quality[Room_Num] = 0;
}
}
}
/* === 최종 풍량 : 부하 총점 매핑 === */
Tmp_Air_Volume = score_to_stage(Load_Score);
if(Tmp_Air_Volume > 4) Tmp_Air_Volume = 4;
if(Set_Fan_Mode != Tmp_Air_Volume)
{
Set_Fan_Mode = Diffuser_Fan_Speed[1] = Tmp_Air_Volume;
Command_request_type |= (TYPE_FAN_SPEED);
}
}
else
{
Focus_Mode = 0;
Focus_Mode_RunTime = 0;
/* 쾌적조리 메이크업 에어(사양 260613 9p) : 후드 가동중(Hood_Status!=0 / 연동플래그)
전실 급기(SA) 100% 개방, 배기(RA) 닫힘. 풍량은 Hood_process() 가 후드 단수를
추종(1->1,2->2,3->3,4->4,5->4)하여 Set_Fan_Mode 로 반영.
조리 종료 후 잔여 배출(메이크업 유지)은 후드측이 담당 → 후드 OFF 시 즉시 복귀. */
if((Hood_YeunDong_Enable == 1)&&((Hood_Status != 0)||(Hood_Yeundong_flag == 1)))
{
Memory_Diffuser_Dmp_Ang_SA[1] = 110;
Memory_Diffuser_Dmp_Ang_RA[1] = 0;
Memory_Diffuser_Dmp_Ang_SA[2] = 110;
Memory_Diffuser_Dmp_Ang_RA[2] = 0;
Memory_Diffuser_Dmp_Ang_SA[3] = 110;
Memory_Diffuser_Dmp_Ang_RA[3] = 0;
Memory_Diffuser_Dmp_Ang_SA[4] = 110;
Memory_Diffuser_Dmp_Ang_RA[4] = 0;
Diffuser_Air_quality[1] = 5;//ON
Diffuser_Air_quality[2] = 5;//ON
Diffuser_Air_quality[3] = 5;//ON
Diffuser_Air_quality[4] = 5;//ON
}
}
PASS_VOLUME:
if(Tmp_Air_Volume > 4)Tmp_Air_Volume = 4;
if(Focus_Mode_RunTime != 0)
{
if(Tmp_Air_Volume != Focus_Air_Volume)
{
Command_request_type |= (TYPE_FAN_SPEED);
if(Tmp_Air_Volume > Focus_Air_Volume){Set_Fan_Mode = Focus_Air_Volume = Tmp_Air_Volume;}
else {Set_Fan_Mode = Tmp_Air_Volume = Focus_Air_Volume;}
}
}
if(Ext_Run_Mode == 4)
{
if(Tmp_Air_Volume >= 2)Tmp_Air_Volume -= 1;
if(Set_Fan_Mode != Tmp_Air_Volume)
{
Set_Fan_Mode = Diffuser_Fan_Speed[1] = Tmp_Air_Volume;
Command_request_type |= (TYPE_FAN_SPEED);
}
}
/* ===== LED 추종 : 댐퍼 개방→LED ON(9), 닫힘/전원OFF→소등.
수동 LED(CTRL_LED, Diffuser_Led_Manual)는 모든 모드에서 값 유지, 전원OFF 시에만 해제. ===== */
for(Room_Num = 1; Room_Num < 5; Room_Num++)
{
if(Power_On != 1) Diffuser_Led_Manual[Room_Num] = 0; /* 전원OFF - 수동 LED 해제 */
if(Diffuser_Led_Manual[Room_Num]) continue; /* 수동값 유지 */
if((Power_On == 1) && ((Memory_Diffuser_Dmp_Ang_SA[Room_Num] != 0) || (Memory_Diffuser_Dmp_Ang_RA[Room_Num] != 0)))
Light_Bright[Room_Num] = 9;
else
Light_Bright[Room_Num] = 0;
}
PASS_RETURN:
return(Tmp_Air_Volume);
}
uint8_t Air_Quality_color_process(void)
{
uint8_t room_CV_quality = 0, room_PM_quality = 0, total_room_CV_quality = 0, total_room_PM_quality = 0;
uint8_t Room_Num = 0;
total_room_CV_quality = 0;
total_room_PM_quality = 0;
/////////////////////////////////////////////////
return(0);
///////////////////////////////////////////////////
for(Room_Num = 1; Room_Num < 7; Room_Num++)
{
room_CV_quality = 0;
room_PM_quality = 0;
if(SEN66_CO2_value[Room_Num] <= (uint16_t)(m_CO2_Level_1-CO2_Histeresys)) CO2_quality[Room_Num] = 0; // 2025.5.13 himpel
else if((SEN66_CO2_value[Room_Num] > (uint16_t)(m_CO2_Level_1))&&(SEN66_CO2_value[Room_Num] <= (uint16_t)(m_CO2_Level_2-CO2_Histeresys))) CO2_quality[Room_Num] = 0x01;
else if((SEN66_CO2_value[Room_Num] > (uint16_t)(m_CO2_Level_2))&&(SEN66_CO2_value[Room_Num] <= (uint16_t)(m_CO2_Level_3-CO2_Histeresys))) CO2_quality[Room_Num] = 0x02;
else if((SEN66_CO2_value[Room_Num] > (uint16_t)(m_CO2_Level_3))&&(SEN66_CO2_value[Room_Num] <= (uint16_t)(m_CO2_Level_4-CO2_Histeresys))) CO2_quality[Room_Num] = 0x04;
else if(SEN66_CO2_value[Room_Num] > (uint16_t)(m_CO2_Level_4)) CO2_quality[Room_Num] = 0x08;
if(SEN66_pm2p5[Room_Num] <= m_PM2_5_Level_1) PM2_5_quality[Room_Num] = 0;
else if(SEN66_pm2p5[Room_Num] < m_PM2_5_Level_2) PM2_5_quality[Room_Num] = 0x01;
else if(SEN66_pm2p5[Room_Num] < m_PM2_5_Level_3) PM2_5_quality[Room_Num] = 0x02;
else if(SEN66_pm2p5[Room_Num] < m_PM2_5_Level_4) PM2_5_quality[Room_Num] = 0x04;
else PM2_5_quality[Room_Num] = 0x08;
if(SEN66_VOC_value[Room_Num] <= m_VOC_Level_1) VOC_quality[Room_Num] = 0;
else if(SEN66_VOC_value[Room_Num] < m_VOC_Level_2) VOC_quality[Room_Num] = 0x01;
else if(SEN66_VOC_value[Room_Num] <= m_VOC_Level_3) VOC_quality[Room_Num] = 0x02;
else if(SEN66_VOC_value[Room_Num] <= m_VOC_Level_4) VOC_quality[Room_Num] = 0x04;
else VOC_quality[Room_Num] = 0x08;
room_CV_quality = CO2_quality[Room_Num] | VOC_quality[Room_Num];
room_PM_quality = PM2_5_quality[Room_Num];
if(room_CV_quality == 0) //Quality - Good
{
Diffuser_Air_quality[Room_Num] = Memory_Diffuser_Air_quality[Room_Num] = 0;
}
else if(room_CV_quality < 2) //Quality - Normal
{
Diffuser_Air_quality[Room_Num] = Memory_Diffuser_Air_quality[Room_Num] = 5;
}
else if(room_CV_quality < 4) //Quality - Bad
{
Diffuser_Air_quality[Room_Num] = 5;
}
else if(room_CV_quality < 8) //Quality - Bad Bad
{
Diffuser_Air_quality[Room_Num] = Memory_Diffuser_Air_quality[Room_Num] = 5;
}
else //Quality - Very Bad
{
Diffuser_Air_quality[Room_Num] = Memory_Diffuser_Air_quality[Room_Num] = 5;
}
total_room_CV_quality |= room_CV_quality;
total_room_PM_quality |= room_PM_quality;
}
return(0);
}