5a96a696b1
- 펌웨어(program), C# 대시보드(TestProgram), 시뮬레이터(Simulator), 프로토콜/문서(Protocol, doc) 전체를 단일 저장소로 통합 - program 폴더의 별도 git 저장소를 제거하고 통합 저장소에 흡수 - 빌드 산출물(program/build, bin/obj, *.o/.elf/.bin/.hex 등) .gitignore 처리 - 사내 Synology NAS Git 원격 연결 예정 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1246 lines
39 KiB
C
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);
|
|
}
|
|
|