0451-88102248
13836024381
15204677158
 

站内搜索


关键词:


类  型:


汇款账号

当前位置: 主页 > 代码示例 > 智能电扇控制器调速器

智能电扇控制器调速器

作者:志成时间:2011-06-21 15:20来源:哈尔滨汇丰电子 浏览: LOGING....

智能电扇控制器
 
   炎热的夏天开着电扇睡觉是个不错的主意,但是半夜气温回落后从美梦中被吹醒是件糟糕的事情。下面这个小小的制作会提供您两个好办法,
  第一你可以用遥控器方便的关掉电扇,第二你还可以用温度来控制电扇的起停,温度下降后使电扇自动停止。
   功能:A键强制打开电扇,B键强制关闭电扇,D键记录当前的温度为参考控制温度,C进入温度控制模式
   温度控制模式下如果环境温度大于参考控制温度则打开电扇,如果环境温度降到参考控制温度-1℃则关闭风扇。测量温度分辨率(注意不是
  精度,这样的控制不需要太高的精度)0.1℃。
   有了这样一个控制器,在晚上睡觉前按一次D键记录当前温度为参考控制温度,再按一次C键进入温度控制模式,电扇打开,到半夜温度下降1℃
  时电扇自动被关闭,避免了被吹醒。

 

   从电子市场可以很容易的买到如上图所示的遥控组件,它的工作原理大体是这样的:遥控器内有一个编码芯片PT2262,当按一个键时它产生一组
 波形对应这个键的代码,这个波形被调制到315MHz的微波内之后从天线发送出去,而这个接收模块从315MHz的微波内解调出PT2262产生的波形。
 现在我要用单片机将此波形识别,之后执行相应的操作,这个被称为软件解码。

电路原理图    

实物图

学生电扇

    温度传感器使用的是NTC(负温度系数)热敏电阻,它是很常用的测温元件,由于各厂家制作的参数不大相同,这里就不作介绍。关于PT2262在网
 络中介绍的文章很多,要注意的是它所产生的波形从时间上精度不是很大,不能按异步串行通信的思路去解码,另外接收到的波形根据现场环境的不
 同参杂着很多的噪声,为此软件解码PT2262波形对于初学者来讲绝对是一个挑战。
    下面是我在ATTINY26上实现的软件解码程序,ATTINY26使用了内部1MHz的时钟,PT2262每次按键时至少发送4次,不少网络上的文章建议连续接收
 2次再确认,但这个程序只需要接收一次即可。这个小小制作我已经使用了一年多了,至今没有发现误操作等异常现象。

//rf.c PT2262软件解码程序
#include
#include

#include"main.h"

#define KUAN_PLUS_CNT  16
#define ZHAI_PLUS_CNT 2

/*********************************
震荡电阻:Rosc=4.7MOhm
震荡频率:f=2*1000*16/Rosc = 6.81KHz
震荡周期:a=1/f=146.875us
位时间 = 32a = 4700us
窄脉冲时间=4a=587.5us  =7.3次中断
宽脉冲时间=12a=1762.5us =22次中断
同步码低电平宽度=128a-4a=124a=18212.5us = 227次中断
**********************************/

static volatile uint8_t g_bit;  //接收位计数器
static uint8_t g_begin_flag;    //开始标记
static uint8_t g_wait_state;    //等待电平状态
static uint8_t g_plus_code[24];  //脉冲宽度临时记录区
static uint8_t g_h_cnt,g_l_cnt;  //高低电平保持时间计数器
static uint8_t g_prev_h_cnt;    //一次扫描中高电平的计数个数

/*两个脉冲码对应的地址码表格,
两个窄脉冲g_mask_code[0][0]=0 两个宽脉冲g_mask_code[1][1]=1,
一窄一宽脉冲(悬空)g_mask_code[0][1]=2 一宽一窄脉冲非法数据=3*/
static uint8_t g_mask_code[2][2]={{0,2},{3,1}};

void recv_reset(void)
{
  g_bit=0;
  g_wait_state=1;
  g_h_cnt=0;
  g_l_cnt=0;
  g_begin_flag=0;
}

void RFInit(void)
{
  DDRB&=~_BV(PB6);
  PORTB&=~_BV(PB6); 
 
  TCCR0=_BV(CS00);  //不分频
  TCNT0=0; 
  TIMSK=_BV(TOIE0);
 
  recv_reset();
}

//地址码接收定时处理
void recv_ad_bit(uint8_t lv)
{
    if(g_wait_state)  //正在计时检测高电平时间
    {
      if(lv)          //测到高电平
      {
        g_h_cnt++;
        if(g_h_cnt>KUAN_PLUS_CNT)  //高电平保持时间太长
          recv_reset();
        if(g_l_cnt>0)//有过一次低电平噪声
        {
          g_h_cnt++;
          g_l_cnt=0;
        }
      }
      else                //出现了低电平
      {
        if(g_h_cnt < ZHAI_PLUS_CNT) //高电平保持时间不够长
        { recv_reset(); return ; }
        if(g_l_cnt++ > 0)//低电平保持两个周期认为确实检测到低电平
        { 
          g_wait_state=0;    //进入检测低电平状态
          g_prev_h_cnt=g_h_cnt;
          g_h_cnt=0;
        }
      }
    }
    else              //正在计时检测低电平时间
    {
      if(lv)          //出现了高电平
      {
        if(g_l_cnt0)//高电平保持两个周期认为确实检测到高电平
        {
          g_plus_code[g_bit]=(g_prev_h_cnt>8) ? 1:0;  //保存脉冲宽度
          g_wait_state=1;      //进入检测高电平状态 
          g_bit++;
          g_l_cnt=0;
        }
      }
      else             //低电平计数
      {
        g_l_cnt++;
        if(g_l_cnt > KUAN_PLUS_CNT) //低电平保持时间太长
          recv_reset();
        if(g_h_cnt>0)//有过一次高电平噪声
        {
          g_l_cnt++;
          g_h_cnt=0;
        }
      }
    }
}

//同步码接收定时处理
void recv_syn_bit(uint8_t lv)
{
    if(g_wait_state)  //正在计时高电平时间
    {
      if(lv)
      {
        g_h_cnt++;
        if(g_h_cnt>15)
          recv_reset();
      }
      else
      {
        if(g_h_cnt < 2)
        {
          recv_reset();
          return ;
        }
        g_wait_state=0;
      }
    }
    else //正在计时低电平时间
    {
      if(lv)
      {
        if(g_l_cnt<70)
        {
          recv_reset(); return ;
        }
        g_wait_state=1;
        g_bit++;
      }
      else
      {
        g_l_cnt++;
        if(g_l_cnt > 100) //低电平保持时间满足要求
          g_bit++;
      }
    } 
}

//约80us中断一次
ISR(TIMER0_OVF0_vect)
{
  uint8_t lv=0;
 
  TCNT0=175;  //255-80
 
  if(PINB&_BV(PB6))
    lv=1;

  if(g_bit > 24) //接收完一次并没有处理完
    return ;
 
  if((lv==0)&&(g_begin_flag==0))//接收前低电平
    return ;
  g_begin_flag=1;
 
  if(g_bit==24)        //正在接收同步位
    recv_syn_bit(lv); 
  else                //正在接收地址位
    recv_ad_bit(lv);
}

uint8_t RfRecv(uint16_t *addr,uint8_t *key)
{
  uint8_t i,tmp;
  uint32_t ret=0;
 
  if(g_bit<25)
   return 0;
  for(i=0;i<24;i+=2)
  {
    ret<<=2;
    tmp=g_mask_code[g_plus_code[i]][g_plus_code[i+1]];
    ret+=tmp;
    if(tmp>2)   //有非法脉冲码
    {
      recv_reset();
      return 0;
    }
  }
  *key=ret;
  *addr=ret>>8;
  recv_reset();
 
  return 1;
}

主程序文件主要内容如下:

uint8_t g_Mode;//当前模式
uint16_t g_ConfigTmp;//设定温度
uint8_t EEMEM eep_Mode;
uint16_t EEMEM eep_ConfigTemp;
uint16_t g_CurTemp;//当前温度

#define MODE_MANUAL    1      //手动控制模式
#define MODE_TEMP      0      //温度控制模式

/*
  地址码:0xaa46
  a键:0x40
  b键:0x10
  c键:0x04
  d键:0x01
*/

void RFInit(void);
uint8_t RfRecv(uint16_t *addr,uint8_t *key);
void AdcInit(void);
uint8_t AdConvert(uint16_t *val);

void DelayMs(uint16_t t)
{
  uint16_t i;
  for(i=0;i=g_ConfigTmp)
  {
    RELAY_OPEN;
    LED_Y_SET; 
  }
  else
  {
    RELAY_CLOSE;
    LED_Y_CLR;
  } 
}

int main(void)
{
  uint8_t key;
  uint16_t addr;
 
  RELAY_INIT;
  LED_PORT_INIT;
  LED_G_SET;
  LED_Y_CLR;
 
  RFInit();
  AdcInit();
 
  while(AdConvert(&g_CurTemp)==0);//转换完一次
  while(AdConvert(&g_CurTemp)==0);//转换完一次
 
  //装入掉电保持数据
  g_Mode=eeprom_read_byte(&eep_Mode);
  g_ConfigTmp=eeprom_read_word(&eep_ConfigTemp);
  if(g_Mode!=MODE_TEMP)
  {
    RELAY_OPEN;
    LED_Y_SET;   
  }
  else
    EnterTempControlMode();
 
  TCCR1A=0;
  TCCR1B=_BV(CS10)|_BV(CS11)|_BV(CS12)|_BV(CS13);//CK/16384
 
  sei();

  while(1)
  {
    if(RfRecv(&addr,&key))
    {
      if(addr==0x46aa)
      {
        cli();
        switch(key)
        {
          case 0x40: //A 强制打开
            RELAY_OPEN;
            LED_Y_SET;
            LED_G_SET;
            save_mode(MODE_MANUAL);
            break;
          case 0x10://B  强制关闭
            RELAY_CLOSE;
            LED_Y_CLR;
            LED_G_SET;
            save_mode(MODE_MANUAL);
            break;
          case 0x04://C 温度控制模式
            if(g_Mode!=MODE_TEMP)
              EnterTempControlMode();
            save_mode(MODE_TEMP);
            break;
          case 0x01://D 设定当前温度
            if(g_Mode == MODE_TEMP)
            {
              g_ConfigTmp=g_CurTemp;
              eeprom_busy_wait();
              eeprom_write_word(&eep_ConfigTemp,g_CurTemp);
              for(key=0;key<4;key++)
              {
                LED_Y_FLASH;
                DelayMs(200);
              }
            }
            break;
          default:
            break;
          }
          sei();
         }
       }
       if(AdConvert(&g_CurTemp))
       {
         if(g_Mode==MODE_TEMP)
         {
         if(g_CurTemp>=g_ConfigTmp)
         {
            RELAY_OPEN;
            LED_Y_SET; 
         }
         if(g_CurTemp <= (g_ConfigTmp-10))
         {
            RELAY_CLOSE;
            LED_Y_CLR;
         }
         if(TCNT1 > 15)
         {
           TCNT1=0;
           LED_G_FLASH;
         }
      }
    }
  }//while
}

温度检测程序略!!!

发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片

友情链接 所有链接 | 申请加入