**
万和燃气热水器加装遥控功能
**
家中使用一台12L万和牌的燃气热水器,由于使用燃气和废气排放的原因,热水器本身安装在厨房内,而热水使用又在卫生间,所以原先未加装遥控的情况下,热水器的开关和调节要么事先设定好,要么需要家人协助,很不方便.于是便考虑自己加装一个遥控,这样在使用热水器时,在卫生间就可以观察且操控热水器,很是方便!
万和12L热水器
控制面板
1.原控制面板控制原理分析
1.1 控制面板的PCB板
- 拆开热水器外罩后,控制面板就安装在面罩背面的一个盒子中,下面就是面板的PCB正反面的样子,如果加入遥控,需要先搞清楚其原理和信号.看来不能省事,先把原理图画出来才行.
PCB正面
PCB背面,上面的标记可以对照本人画的原理图就可以知道其含义
好在单面PCB分析起来并不麻烦~
1.2 原控制面板的原理图
原控制面板原理图,所有元件参数及标记均与图片上原控制板一致,红色圆圈标记就是前面图上标记的位置,这也是我们需要采用的信号点.
PCB走线也与原板尽可能保持一致,避免原理及信号出错.
1.3 信号分析
原理图比较简单,通过原理图分析,可以得出以下信息
a.面板采用一块74HC164作为串转并的LED驱动芯片,所以要获取温度信息只要读取这个BCD码串就行;
b.按键信号是通过各自的分压电阻将+5V电压进行风压后,将分压信号传回主机的MCU去的;遥控改装也很简单,在标记处并入开关信号即可;
c.需要注意的是,原机的十位数的BCD码的DP(小数点位)并没有给LED显示使用,因为不需要,而是把这个位给了面板的绿色LED工作指示灯用(DIG1),用于指示燃气热水器是否在"燃烧"状态;这个在BCD码串再解码时需注意.
d.蜂鸣器回路无用.
1.4 遥控接口信号考虑
采集的BCD码串,对应:黄:CODE 紫:CP 绿:SM1(SM2波形相同,只不过相对SM1正好差一个节拍,个位和十位轮换显示的区别)
所以:
a.温度端口是5V信号,一般MCU都可以接受,无需隔离;
b.按键输入最好需要用光耦隔离一下,避免冲击之类的事情.
2. 遥控改装的思路
2.1 设计
其实只要理解原控制板原理,改装遥控应该就比较简单,可以根据自己擅长的方案进行改装.下面分享一下本人的改装方案,仅供大家参考.
a.接收端(也就是与热水器本体连接的这一端)使用一个MCU,用于接收遥控器发来的控制信号,并把温度信号传给遥控端;
b.自然需要一个通讯模块,什么类型都行esp8266,24L01,CC1101都行,手边有或者自己用的熟的就行,本人用来一对CC1101,够用就行;
c.接收端最好有两个SPI可用,因为BCD解码和无线通讯可能要各用一个,当然,能自己手搓一个SPI口一个也行-
d.遥控端的MCU最好能带TFT的屏,这样可以DIY比较好看的界面,还有,原先热水器是有一些报警信息的,原面板只能通过BCD码串在两个数码管以E0~E7来显示,其具体含义除非看说明书才能知道含义,一般用户不太会理解这些信息.有了屏,就可以实时读取或观察到这些信息,避免出现问题.
这张纸在热水器前面罩背面贴住,很"贴心"!
2.2 接收端简图
接收端原理图简化版,偷懒画了主要的控制端口,原理并不复杂,改装时每个人具体不尽相同,所以参考即可.图上不清楚可留言.说明一下:
a.使用了一块STM32F103C8T6 的现成板子,非常普通,很好找,用了一块CC1101做通讯,用了一块四路光耦做信号隔离;
b.做了一个小接口插头,这样可以快速与原面板引出的信号进行对接,开发和调试也比较方便,板子的电源也可以直接取用原控制板上的5V;
c.CC1101用了一个SPI口,BCD解码用了一个SPI口.
实物照片比较糊,当初没想留照的…
天线自己重绕了一下,没调好的时候以为天线问题,后来发现和天线无关,也懒得焊回去了,反正可以用,也看不见.
2.3 发射端(遥控端)
遥控端也是找了一块原先用过的板子,MCU是STM32F030C8T6,可以挂一块TFT,把原先的SPI接一个CC1101即可,也是直接用,下面是原理简图示意:
a.另一面接了一块TFT液晶屏,使用SPI接CC1101时注意避开这些端口
b.使用3个GPIO输入按键指令
使用废PCB做个壳子,用起来没问题,这是冷机待机状态.字体是绿色
这是热机待机状态,字体是蓝色
加热燃烧状态,字体是黄色.关机或冷机超时后或息屏并进入休眠状态,主机送电后会唤醒遥控端,另外停止加热超时后也会发出停机指令,避免忘记关机造成浪费!
3.控制程序分析
3.1 接收端需要注意的地方
BCD码串的解码是接收端MCU的一项主要任务.通过波形分析,可以得到下面的码串:
u8 smgduan[16]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};//0~F 温度BCD码数据
这里需要注意的是,燃烧时十位数的BCD码和上面有所区别,最高位"bit7"被置位为 “0”,表示当前处于"燃烧"的状态(正如前面提到过的).因此,需要将此状态正确解码出来并加以利用.另外,也应同时考虑到"故障"码的解码.完整的解码程序如下:
u8 smgduan[16]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};//0~F 温度BCD码数据
/************************************************
函数名称 : decoding
功 能 : 用于翻译解释来自端口的8段BCD码串,结果为对应的数字
其中小数点的码位(bit7)在控制中被设计为点火状态位
中间包含点火状态的解码,如果BCD码点火状态为"0",则进行自动关机倒计时
参 数 : 无
返 回 值 : 计算的温度值,点火状态,关机倒计时计数
作 者 : huangxu
*************************************************/
u8 decoding(void) //解码
{
u8 i,tmp0=0,tmp1=0,decode; //温度个位和温度十位,最终返回的温度计算值
if(0!=BCD) //首先进行非"0"判断,判断是否是BCD码
{
for(i=0;i<15;i++) //进行查表转换,因为包含错误码解码,所以需进行全码解码
{
if ((BCD&0xFF)==smgduan[i]) //温度十位,此时是待机编码
{
tmp0=i; //进行对应位数刷新,码位即对应的真实数值
stop_time--; //停机倒计时
WorkSta=11; //待机状态 未点火"11"
}
else if (((BCD&0xFF)==(smgduan[i]&0x7F))) //点火时编码,因编码DP位借用给工作指示灯,所以工作时温度十位的编码bit7为"0"
{
tmp0=i; //进行对应位数刷新
stop_time=1200; //复归停机计时 约10 分钟
WorkSta=22; //点火状态 最低位置"22"
}
if (((BCD>>8)&0xFF)==smgduan[i]) //温度个位
{
tmp1=i;
}
}
decode = 10*tmp0 + tmp1; //获取实际的温度值
}
else
{
WorkSta= 0; //未启动状态"00",另外一种情况未通电有遥控端进行判断,"00"默认已通电未启动状态
decode = 0; //无温度值返回"0"
}
return decode;
}
因为BCD码解码是被动接受(来自于主机MCU),所以应使用对应SPI端口的中断来"采集"温度数据.并考虑设置采集"窗口",在采集结束后关闭SPI中断,这样可以避免连续的SPI中断导致遥控端来的指令无法执行.
//中断服务程序
void SPI2_IRQHandler(void)
{
if (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_IT_RXNE) == SET)
{
BCD = SPI_I2S_ReceiveData(SPI2); //采集BCD数据
/* 清除接收中断 */
SPI_I2S_ClearITPendingBit(SPI2, SPI_I2S_IT_RXNE);
}
}
在主循环中加入如下采集窗口:
__enable_irq(); // 开启总中断,采集新的温度设定值
delay_ms(20 ); //注意取值<1864 数据接收指示 慢闪两次
led_flashing( ); //
delay_ms(20 ); //注意取值<1864
led_flashing( ); //
__disable_irq(); // 关闭总中断
这样就避免MCU进程被SPI中断拴住的局面,避免死机.
关于CC1101的驱动,本人也是"拿来主义",没有太多的改动,当然"坑"也是有的,前面调试的时候,动不动就"死机",无线通讯信号偶有波动,这边立马躺尸.真是无可奈何!后来经过排查,发现标准例程中确实有问题,通讯过程当中一旦信号波动,丢失,即可进入死等状态,具体修改位置如下:(****处)
/**
* @brief :CC1101发送接收模式设置
* @param :
* @Mode:TX_MODE,发送模式 RX_MODE,接收模式
* @note :无
* @retval:寄存器状态
*/
void CC1101_Set_Mode( CC1101_ModeType Mode )
{
uint16_t l_RxWaitTimeout = 0;
if( Mode == TX_MODE ) //发送模式
{
CC1101_Write_Reg( CC1101_IOCFG0,0x46 );
CC1101_Write_Cmd( CC1101_STX );
}
else if( Mode == RX_MODE ) //接收模式
{
CC1101_Write_Reg(CC1101_IOCFG0,0x46);
CC1101_Write_Cmd( CC1101_SRX );
}
while( 0 != CC1101_GET_GDO0_STATUS( )) //等待发送 或 接收开始
{ //*****此处新加入了超时等待防止信号波动时无应答死机
delay_ms( 1 );
if( 1000 == l_RxWaitTimeout++ )
{
l_RxWaitTimeout = 0;
CC1101_Init( );
break;
}
}
}
另外,CC1101要注意地址和同步字段的问题.
以上实现的MCU是STM32F103C8T6.
3.2 发射端(遥控端)需注意的地方
遥控端实际上大多数时间处于接收状态,主要用于接收来自设备端的温度信号,仅在需要对热水器进行调节时才发送相应指令.
因此,对于遥控端来讲,处理好接收到的信息是一项主要任务,因为信息的显示是由TFT屏完成的,所以代码并不具有通用性,暂时就不贴了,但是有几点还是要注意到:
a.可以使用解码后的故障码>=0xE0,而正常温度不会大于99的区别,进行温度信号和故障信号的甄别;如下参考:
if (temp_now<140) //此处依据温度值,选择显示信息.如果小于140(对应于故障信息码"E0"~"E7"转换后的值),正常显示
{
FRONT_COLOR=WorkColor[RxBuffer[1]/11];BACK_COLOR=BLACK;
LCD_Show64Num(66,60, temp_now,2,64,0x40); //当前温度显示
BACK_COLOR=WHITE;FRONT_COLOR=~BACK_COLOR; //画笔颜色 背景色
}
else //错误信息显示,温度值大于140,表示为故障码状态
{
FRONT_COLOR=WHITE;BACK_COLOR=BLACK;
switch (RxBuffer[0]-140) //按照信息进行显示
{
case 0: //24字体宽度16,最多21字符/行
LCD_ShowString(0,100,tftlcd_data.width,tftlcd_data.height,16,"IN WATER SENCE ERROR!"); //E0 进水传感器故障
break;
case 1:
LCD_ShowString(0,100,tftlcd_data.width,tftlcd_data.height,16," FLAMEOUIT! "); //E1 熄火
break;
case 2:
LCD_ShowString(0,100,tftlcd_data.width,tftlcd_data.height,16,"THERMOCOUPLE PROTECT!"); //E2 热电偶保护
break;
case 3:
LCD_ShowString(0,100,tftlcd_data.width,tftlcd_data.height,16,"FLUE / WIND PRESSURE!"); //E3 烟道或风压
break;
case 4:
LCD_ShowString(0,100,tftlcd_data.width,tftlcd_data.height,16," FAN OR DRIVE ERROR! "); //风机或驱动电路
break;
case 5:
LCD_ShowString(0,100,tftlcd_data.width,tftlcd_data.height,16," TOO HOT! "); //过热保护
break;
case 6:
LCD_ShowString(0,100,tftlcd_data.width,tftlcd_data.height,16,"OUT WATER SENCE ERROR"); //出水温度传感器
break;
case 7:
LCD_ShowString(0,100,tftlcd_data.width,tftlcd_data.height,16," GAS SELECT ERROR! "); //气体选择开关错误
break;
default :
break;
}
b.注意区分几种工况下的区别:
1.热水器端断电;
2.热水器带电,但并未启动;
3.热水器启动,但并未燃烧;
4.热水器处于"燃烧"状态;
5.热水器"燃烧"后超过一段时间,又没有任何操作.
基本考虑到这五种工况后,程序就比较完整了.
c. 一段休眠待机代码:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE); //时钟必须要开启
PWR_BackupAccessCmd(ENABLE);
// PWR_WakeUpPinCmd(PWR_WakeUpPin_1,ENABLE);
PWR_ClearFlag(PWR_FLAG_WU);
PWR_EnterSTANDBYMode();
这段代码放在合适位置可以实现遥控端待机休眠.
以上代码使用STM32F030C8T6实现.
4.其他
遥控与原有的操作面板操作并无冲突,相互独立,即使遥控通道出现问题,也不会影响到原有按键的正常操作和热水器的使用!
本来准备上一段视频演示使用情况,但没有搞明白平台视频上传的操作,暂时先放弃.
接收端和遥控端全套源码附后.
https://download.csdn.net/download/weixin_43022857/89359350