我的賬戶
中國電子DIY

科技成就未來

親愛的游客,歡迎!

已有賬號,請

如尚未注冊?

多圖殺貓,膽小勿入!資料開源

  [復制鏈接]
27778 53
苗條的猩猩 發表于 2016-11-15 14:33:10 | 只看該作者 |只看大圖 |閱讀模式 打印 上一主題 下一主題
本帖最后由 苗條的猩猩 于 2016-11-15 14:33 編輯

好久沒發帖了,本來早就想發這篇帖的,但是怕軟件運行不穩定被人噴,現在已經工作3個多月了,
非常穩定。
本人發帖一向追求原創和圖文并茂,像某些朋友直接從網上復制幾段文字圖片那種事我做不來。
首先,簡單說明下,這是一個4路遙控加按鍵控制的插座,第一路可定時,開啟時間和關閉時間可
獨立定時。定時范圍999(分鐘),四位數碼管顯示。
既然是改裝插座,肯定先要有個現成插座板,于是我從超市買了個帶開關的。

外觀還不錯,主要看中他內部獨立的模組結構,方便改裝。

拆開的樣子,不錯吧?一分錢一分貨,這玩意要40多大洋
我準備在兩頭空缺的區域放置電路板,不過空間太小,有些挑戰。
我采用的是stc的單片機,便宜,哈哈哈哈,推薦配置:
4K以上空間,8—12M晶振,最小io數目22,上拉電阻10K(省電與穩定的平衡點),
首先單片機是5V的,所以要個電源,本來想用阻容降壓,但考慮到要驅動4個繼電器,
怕功率達不到,加上阻容降壓本身不安全不穩定,萬一調試的時候不小心觸電我就掛了。
所以我打算用手機適配器的電路板


但是苯寶寶很快發現一個問題,這電源太大了,放不進插座,但是厚度到是輕薄,要是能把長度變到厚度上就好了。
我發現這對于天生愛思考的我根本不是事,我把所有元件拆了下來,然后抄板,于是有了下面的作品。

這是我根據原來的電路重新設計的電源。

很緊湊有木有?
好了,主角該出場了,當當當當!

這是主板,PLCC封裝89C52.外形經過了我一天兩夜的嚴格設計


這是整合在背面的升壓系統,因為繼電器是12V驅動的,所以要把5V升到12V。

側面來一張。

從汽車主板上拆的12V繼電器。(哥以前是修車的)

繼電器裝好的樣子,用膠水稍微粘下好些。

放入主板和電源的樣子。用泡沫棉固定一下走線方便裝殼,話說這走線有點亂,沒辦法,想線太多。

當當當當!!寫好軟件的成品。
開機后全部繼電器關閉。
第一位數碼管顯示第一路繼電器狀態,第二位數碼管顯示。。。
F表示關閉,n表示接通,第一個按鍵控制第一路,第二個控制。。。。
長按第一個按鍵進入定時界面,這時短按第一個按鍵選擇定時開啟時間還是關閉時間,并由第一個數碼管顯示狀態
第二個按鍵選擇調整個位十位百位,第三個按鍵數字加一,第四個按鍵數據保存,長按第四個按鍵退出并開始定時,
定時過程中,另外三路照常工作,并由小數點顯示狀態。此過程中長按第四個按鍵取消定時并回到初始界面。
看下視頻吧。

原理圖文件開放,要的拿走。

話說我做項目從來不用原理圖,嫌麻煩,這個圖是我為了發帖畫的,全部元件都是臨時建的。
下面是代碼。此代碼不包含紅外接收程序,為的是不想便宜游客,要的留郵箱。



/* 通用頭文件 */
#include <REGX52.H>
#include <intrins.h>
#define SYS_MCLK   (11059387/12)  //系統主時鐘頻率,即振蕩器頻率÷12
/* 數據類型定義 */
typedef  signed    char    int8;    // 8位有符號整型數
typedef  signed    int     int16;   //16位有符號整型數
typedef  signed    long    int32;   //32位有符號整型數
typedef  unsigned  char    uint8;   // 8位無符號整型數
typedef  unsigned  int     uint16;  //16位無符號整型數
typedef  unsigned  long    uint32;  //32位無符號整型數

bit Longkey_f=0;//長按鍵觸發標志

uint8 l=0;           //.....
uint8 e=0;          //.....
uint8 d=0;          //.....

bit  s_onaf=0;//選擇通斷方式
uint8 s_timedi=0;//個位時間調整
uint8 s_timete=0;//十位時間調整
uint8 s_timehu=0;//百位時間調整
uint8 s_loca=0;//個位,十位,百位選擇

uint8 Longkey=0; //界面切換

uint16 varn=0; //保存導通時間的變量(最大值999)
uint16 varf=0;//保存關斷時間的變量(最大值999)
uint16 min=0;

sbit KEY1 = P3^7;  //定義按鍵接口
sbit KEY2 = P3^6;
sbit KEY3 = P3^5;
sbit KEY4 = P3^4;

sbit RELAY_OUT1= P2^0;        //定義繼電器控制輸出接口                                                                                                                                          
sbit RELAY_OUT2= P2^1;                                                                                                                                                  
sbit RELAY_OUT3= P2^2;                                                                                                                                                  
sbit RELAY_OUT4= P2^3;                                                                                                                                                  

uint8 i = 0;
uint8 j = 0;        

uint8 T0RH = 0;    //T0重載值的高字節
uint8 T0RL = 0;    //T0重載值的低字節

unsigned char code LedChar[] = { 0XFA,0X22,0XB9,0XAB,0X63,0XCB,0XDB,0XA2,0XFB,0XEB,0XF2,0XD1,
0xFE,0X26,0XBD,0XAF,0X67,0XCF,0XDF,0XA6,0XFF,0XEF
}; //數碼管顯示字符轉換表        (由于數碼管的段碼引腳我是亂接的,所以取模都是手動計算)
uint8 LedBuff[9] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00,0x00}; //數碼管顯示緩沖區
uint8 pdata out[4] = {0, 0, 0, 0}; //這是啥來著。。。太久了忘記了
const uint8 code KeyCodeMap[6] = { 1,2,3,4,5,6,}; //按鍵值與遙控鍵值映射表
unsigned char Output[2];  //顯示開關狀態的數據緩沖區
extern bit irflag;         //紅外接收標志
extern unsigned char ircode[4];          //接收到的紅外數據
extern void InitInfrared(void);        //紅外接收子函數

/* 定時器T0配置子程序 */
void ConfigTimer0(uint16 ms)
{
    uint32 tmp;

    tmp = (SYS_MCLK*ms)/1000; //計算所需的計數值
    tmp = 65536 - tmp;        //計算定時器重載值
    tmp = tmp + 34;           //補償中斷響應延時造成的誤差   
    T0RH = (uint8)(tmp>>8);   //定時器重載值拆分為高低字節
    T0RL = (uint8)tmp;
    TMOD &= 0xF0;   //清零T0的控制位
    TMOD |= 0x01;   //配置T0為模式1
    TH0 = T0RH;     //加載T0重載值
    TL0 = T0RL;
    ET0 = 1;        //使能T0中斷
    TR0 = 1;        //啟動T0
}

/* 數碼管動態掃描刷新函數,需在定時中斷中調用 */
void LedScan()
{
    static unsigned char i = 0;  //動態掃描索引

    P1 = 0x00;                  //關閉所有段選位,顯示消隱
    P0 = (P0 & 0xF0) | i;       //位選索引值賦值到P1口低3位
    P1 = LedBuff;            //緩沖區中索引位置的數據送到P0口
    if (i < sizeof(LedBuff)-1)  //索引遞增循環,遍歷整個緩沖區
        i++;
    else
        i = 0;
}
void S_pstnu() //時間調整
{
switch (s_loca)   
    {
            case 0:
                         s_timedi++; if(s_timedi>=10){s_timedi=0;};
                                 break;
        case 1:
                         s_timete++; if(s_timete>=10){s_timete=0;};
                                 break;
        case 2:
                     s_timehu++; if(s_timehu>=10){s_timehu=0;};
                                 break;
        case 3:
                         s_loca=0;
                                 break;
        default: break;
    }
}

void timetdw() //個位十位百位數據整合
{
if(s_onaf==1)
    {varn=s_timedi+s_timete*10+s_timehu*100;s_timedi=0;s_timete=0; s_timehu=0;}
else
    {varf=s_timedi+s_timete*10+s_timehu*100;s_timedi=0;s_timete=0; s_timehu=0;}       
}

void KeyAction(unsigned char keycode)        //按鍵值索引
{
if(Longkey==0||Longkey>=2) //界面0和界面2的按鍵值索引
{       
    switch (keycode)   
    {
            case 1:
                               
                                 if( Longkey==0) {RELAY_OUT1=~RELAY_OUT1;}
                         else ;
                                 break;
        case 2:
                         RELAY_OUT2=~RELAY_OUT2;
                                 break;
        case 3:
                     RELAY_OUT3=~RELAY_OUT3;
                                 break;
        case 4:
                         RELAY_OUT4=~RELAY_OUT4;
                                 break;
            case 5:
                         Longkey=1;
                                 break;
            case 6:
                             Longkey=0;
                                 break;
        default: break;
    }
}
if(Longkey==1) //界面1的按鍵值索引
{       
    switch (keycode)   
    {
            case 1:
                         s_onaf=~s_onaf;
                                 break;
        case 2:
                         s_loca++; if(s_loca>=3){s_loca=0;};
                                 break;
        case 3:
                     S_pstnu();
                                 break;
        case 4:
                         timetdw();min=varf;
                                 break;
            case 5:
                         Longkey=1;
                                 break;
            case 6:
                         Longkey=2;
                                 break;
        default: break;
    }
}

}

void Relay() //紅外按鍵索引
{

                            if (ircode[0]==0X01)
                {
                  if (ircode[2]==0X01)
                  {
                     KeyAction(1);  
                  }
                }
                            if (ircode[0]==0X02)
                {
                  if (ircode[2]==0X02)
                  {
                     KeyAction(2);
                  }
                }
                            if (ircode[0]==0X03)
                {
                  if (ircode[2]==0X03)
                  {
                     KeyAction(3);  
                  }
                }
                            if (ircode[0]==0X04)
                {
                  if (ircode[2]==0X04)
                  {
                     KeyAction(4);
                  }
                }
                                    if (ircode[0]==0X05)
                {
                  if (ircode[2]==0X05)
                  {
                     KeyAction(5);
                  }
                }
                               if (ircode[0]==0X06)
                {
                  if (ircode[2]==0X06)
                  {
                     KeyAction(6);
                  }
                }
}
/* 按鍵掃描函數,需在定時中斷中調用,推薦調用間隔1ms */
void KeyScan()
{
static uint16 ft1 = 0;  //按鍵脈沖計數
static uint16 ft2 = 0;
static uint16 ft3 = 0;
static uint16 ft4 = 0;
    if(!KEY1)
        {
          ft1++;
         }

          if(ft1>1050)
                {
                        ft1=1051;
                        if(KEY1)
                        {
                            KeyAction(5);
                         ft1=0;
                }
                        }
          if(ft1>40&&ft1<800)
          {
            if(KEY1)
           {
                 KeyAction(1);
                        ft1=0;
           }
          }

              if(!KEY2)
        {
          ft2++;
         }

          if(ft2>1050)
                {
                        ft2=1051;
                        if(KEY2)
                        {
                            KeyAction(2);
                         ft2=0;
                }
                        }
          if(ft2>40&&ft2<800)
          {
            if(KEY2)
           {
                 KeyAction(2);
                        ft2=0;
           }
          }

              if(!KEY3)
        {
          ft3++;
         }

          if(ft3>1050)
                {
                        ft3=1051;
                        if(KEY3)
                        {
                            KeyAction(3);
                         ft3=0;
                }
                        }
          if(ft3>40&&ft3<800)
          {
            if(KEY3)
           {
                 KeyAction(3);
                        ft3=0;
           }
          }

              if(!KEY4)
        {
          ft4++;
         }

          if(ft4>1050)
                {
                        ft4=1051;
                        if(KEY4)
                        {
                            KeyAction(6);
                         ft4=0;
                }
                        }
          if(ft4>40&&ft4<800)
          {
            if(KEY4)
           {
                 KeyAction(4);
                        ft4=0;
           }
          }

}
void displayt_timing()        //界面2下的開關狀態由位點顯示
{

                                 if(RELAY_OUT2)
                                         {  
                       l=12;
                                          }
                    else        if(!RELAY_OUT2)
                                          {
                                            l=0;
                                          }
                                 if(RELAY_OUT3)
                                         {
                                          e=12;
                                         }
          else  if(!RELAY_OUT3)
                                         {
                                         e=0;
                                         }
                                 if(RELAY_OUT4)
                                         {  
                                        d=12;
                                          }
                 else        if(!RELAY_OUT4)
                                          {
                                          d=0;
                                          }
}
void display() //界面0下的開關狀態由數碼管顯示n和F表示(on and off)
{

                                 if(RELAY_OUT1)
                                         {
                                          i<<=4;
                                          i>>=4;
                                      i|=0XA0;
                                         }
              else  if(!RELAY_OUT1)
                                         {
                                          i<<=4;
                                          i>>=4;
                                      i|=0XB0;
                                         }
                                 if(RELAY_OUT2)
                                         {  
                                          i>>=4;
                                          i<<=4;
                                      i|=0X0A;
                                          }
                    else        if(!RELAY_OUT2)
                                          {
                                          i>>=4;
                                          i<<=4;
                                      i|=0X0B;
                                          }
                                 if(RELAY_OUT3)
                                         {
                                          j<<=4;
                                          j>>=4;
                                      j|=0XA0;
                                         }
          else  if(!RELAY_OUT3)
                                         {
                                          j<<=4;
                                          j>>=4;
                                      j|=0XB0;
                                         }
                                 if(RELAY_OUT4)
                                         {  
                                          j>>=4;
                                          j<<=4;
                                      j|=0X0A;
                                          }
                 else        if(!RELAY_OUT4)
                                          {
                                          j>>=4;
                                          j<<=4;
                                      j|=0X0B;
                                          }
}

void main()
{
P1 = 0X00;  //初始化數碼管全滅

RELAY_OUT1= 0;        //初始化繼電器全關                                                                                                                                          
RELAY_OUT2= 0;                                                                                                                                                  
RELAY_OUT3= 0;                                                                                                                                                  
RELAY_OUT4= 0;

Output[0]=0XBB;        //顯示開關狀態的數據待命在FFFF
Output[1]=0XBB;
InitInfrared();         //初始化紅外接收
ConfigTimer0(1); //定時器給1毫秒初值
EA = 1;                 //總中斷允許
PT0 = 1;        //配置T0中斷為高優先級,啟用本行可消除接收時的閃爍
while(1)
{
  if(Longkey==0)  //界面0  (正常按鍵和遙控)
  {
     display();
           varn=0;
           varf=0;
            min=0;       
  }

if(Longkey==1)         //界面1          (時間調整的顯示處理)
  {
if(s_onaf)
{
i<<=4;
i>>=4;
i|=0XA0;

}
else if(!s_onaf)
{
i<<=4;
i>>=4;
i|=0XB0;
}
                                          j>>=4;
                                          j<<=4;
                                      j|=s_timedi;        //個位顯示數據處理

                                          j<<=4;
                                          j>>=4;
                                      j|=(s_timete<<4);        //十位顯示數據處理

                                          i>>=4;
                                          i<<=4;
                                      i|=s_timehu; //百位顯示數據處理
                                                
  }
   if(Longkey>=2)         //界面2(倒計時的顯示處理)
  {
                displayt_timing();
                                LedBuff[1] = LedChar[Output[0] >> 4];
                            LedBuff[2] = LedChar[min%10+d];
                                LedBuff[8] = LedChar[min/10%10+e];
                                LedBuff[4] = LedChar[min/100%10+l];       
  }


        if (irflag)  //紅外接收功能實時查詢
        {
            irflag = 0;
                   Relay();
                }
        if (Longkey<=1)  //         把界面0和1的顯示數據加載到緩沖區
        {
                                Output[0]=i;
                     Output[1]=j;
            LedBuff[1] = LedChar[Output[0] >> 4];  //第一位
            LedBuff[4] = LedChar[Output[0]&0x0F]; //第二位
            LedBuff[8] = LedChar[Output[1] >> 4]; //第三位
            LedBuff[2] = LedChar[Output[1]&0x0F]; //第四位
                          
        }
}
}
/* T0中斷服務函數,實現系統定時和按鍵掃描 ,數碼管掃描顯示 */
void InterruptTimer0() interrupt 1
{
    static uint8 tmr10s = 0;
    static uint8 tmr100ms = 0;
    static uint8 st = 0;
    static uint16 tin = 0;
        static bit a = 0;
            
    TH0 = T0RH;  //重新加載重載值
    TL0 = T0RL;
    tmr100ms++;  //定時100ms

    if (tmr100ms >= 100)
    {
        tmr100ms = 0;
        tmr10s++;  //定時10s
                //這里可以放標志位控制其他程序,比如不需要頻繁執行的程序     
        if (tmr10s >= 100)
        {
            tmr10s = 0;
                    st++;          //定時一分鐘
                   //這里可以放標志位控制其他程序
                     if (st>=6)
           {
                    st=0;
                        if(Longkey==2&&varn>=0) //檢測到界面2且導通時間不為0進入倒計時       
          {       
                        if(!a)
                                {
                            i<<=4; //狀態置為F         
                i>>=4;
                i|=0XB0;
                                Output[0]=i;
                                }
                        //        min=varf;        按鍵處理時已經賦值,這步不要,不然出錯
                                  tin++; //計時器加1
                            min--; //關斷時間減1
           if (tin>=999) //超程限制,不要也行
           {
                        tin=0;
           }               
        if(varf<=tin&&a==0)        //關斷定時時間到
           {
              tin=0;                 //計時器清0
           varf=0;                 //關斷時間清0,界面0已處理,這里不用也行
           min=varn;         //把導通時間賦值給min
           a=1;                         //執行完后不再進入
           i<<=4;                  //開關顯示狀態切換到n
       i>>=4;
       i|=0XA0;
           Output[0]=i;
           RELAY_OUT1= 1;  //繼電器開啟
        }
                if(varn<=tin&&a==1)         //導通定時時間到
           {
              tin=0;                           //所有有關數據清0,方便下次進入
           varn=0;
           a=0;
           RELAY_OUT1= 0;           //關閉繼電器
           Longkey=0;                  //回到界面0
        }
  }
           }
        }
    }

    KeyScan();   //執行按鍵掃描
LedScan();   //數碼管掃描顯示        
}


再說一遍,要紅外接收程序的留郵箱。
聲明:文章內容為作者“苗條的猩猩”原創,僅作為學習討論使用,嚴禁商業用途。
如需轉載,引用全部或部分內容請注明出處。謝謝各位的配合。
特別鳴謝:1,感謝“中國電子diy之家”論壇提供分享平臺。
2,感謝“宋雪江”老師提供的開源學習視頻。
參與人數 4下載幣 +25 刀幣 +40 收起 理由
黎明之光 + 10 + 10 贊一個!
看門查水表 + 5 + 10 繼電器的線是不是太細了,過流就不好玩了
瘋愛 + 10 支持DIY精神!
diyhome + 10 + 10 支持DIY精神!

查看全部評分總評分 : 下載幣 +25 刀幣 +40

收藏
收藏8
分享
分享
支持
支持0
反對
反對0

精彩評論53

跳轉到指定樓層
2#
GT2014 發表于 2016-11-15 16:07:14 | 只看該作者
支持DIY精神樓主繼續加油,分享好作品
回復

使用道具 舉報

3#
王棟春 發表于 2016-11-15 20:23:12 | 只看該作者
動手能力超強呀           就是程序不能打包開源嗎  
回復

使用道具 舉報

4#
1399109998 發表于 2016-11-15 21:33:26 | 只看該作者
厲害了我的哥竟然用plcc封裝,還有繼電器加光耦隔離了嗎有沒有保護二極管
回復

使用道具 舉報

5#
石頭的旅行 發表于 2016-11-16 09:50:13 | 只看該作者
樓主,網上有賣小米拆機電源模塊的,折疊以后2.5*2.5*2.5,打開以后是5.0*2.5*1.4cm,標稱1A,應該能滿足你的要求。
回復

使用道具 舉報

6#
FSLTKJ 發表于 2016-11-16 13:11:14 | 只看該作者
不錯,謝謝樓主分享+開源。
回復

使用道具 舉報

7#
670712150 發表于 2016-11-16 14:14:07 | 只看該作者
謝謝樓主分享!!
回復

使用道具 舉報

8#
jwb天若有情526 發表于 2016-11-17 09:28:01 | 只看該作者
樓主用的什么東西焊接的電路板  黑不溜秋的  
回復

使用道具 舉報

9#
 樓主| 苗條的猩猩 發表于 2016-11-17 11:50:05 | 只看該作者
jwb天若有情526 發表于 2016-11-17 09:28
樓主用的什么東西焊接的電路板  黑不溜秋的

松香              
回復

使用道具 舉報

10#
漣漪 發表于 2016-11-18 09:39:26 | 只看該作者
感謝樓主分享。                        
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 注冊

本版積分規則

關注0

粉絲6

帖子11

發布主題
最新發布
推薦閱讀
關注我們
中國電子DIY官方微信

客服電話:000-000-0000

客服郵箱:776513803@qq.com

周一至周五 9:00-18:00

公司地址:深圳市南山區美麗灣大廈B座

Powered by Discuz! X3.4@ 2001-2013 Comsenz Inc.