網路城邦
上一篇 回創作列表 下一篇   字體:
HC-05藍牙接收模組的電器遙控:89C52微處理器與HC-05藍牙模組
2016/01/12 21:03:02瀏覽1007|回應0|推薦0

HC-05藍牙接收模組的電器遙控:89C52微處理器與HC-05藍牙模組

  

   在本設計中,主要是利用HC-05藍牙模組負責接收由PC端的藍牙DONGLE所發送出來的指令碼,再經由HC-05藍牙模組的RXD與TXD信號送至STC89C52的UART PORT,之後再由STC89C52的內部程式解碼後去控制指定編碼的繼電器動作,程式中TIMER #0有撰寫一個時鐘程式,此乃利用MCU本身的時基構成的24小時計時程式,由於本身程式做來計時之用時,會有程式計數上的精準誤差的時序問題,所以需實測校正之。

    程式中,在每次時基有秒數進位時,會設定一個顯示旗號,再由主程式送出時間字串給PC端,其格式為@HH:MM:SS 00000\n,最後的5位數是顯示當下已有多少次數接收到遙控的指令碼,此做為將來擴充功能之用。

    指令碼範例#1:RELAY ON/OFF遙控

   3108(hex)    =>RELAY#1動作

   3208(hex)    =>RELAY#2動作

    指令碼範例#2:時間設定指令碼

    543039323008(hex)    =>設定時間為09:20

        第1個byte是0x54(T,時間設定指令碼)

        第2個BYTE是0x30(小時的十位數之ascii碼)

        第3個BYTE是0x39(小時的個位數之ascii碼)

        第4個BYTE是0x32(分鐘的十位數之ascii碼)

        第5個BYTE是0x30(分鐘的十位數之ascii碼)

        第6個BYTE是0x08(尾碼0x08=\n)

    例如可增加遙控電器的定時開啟或關閉功能,或是可調亮度的LED燈,或是如可控制的空調系統,窗簾系統。。等,亦或是火災,煙霧,二氧化碳濃度等警示元件,來經由PC端的智慧中央控制系統進行相關管理,因此後續可撰展的應用與功能,就再加以發揮了。

以下是撰寫的程式

/*-----------------------------------------------

檔案名稱:RS100_52.c

@2016/01/12 89C52 & HC-05 & UART(96,N,1,1)

硬體接腳定義:

89C52 PIN    功能定義

BLUE_LED0    = P1^0;    //LED0 BLUE INDICATOR(秒數指示燈)

RED_LED1    = P2^7;    //LED1 RED INDICATOR(指令接收指示燈)

RXD         = P3^0;    //接至HC-05藍牙模組的TXD腳

TXD         = P3^1; //接至HC-05藍牙模組的RXD腳

Out0        = P3^7;    //RELAY #1(經由RELAY控制電器電源)

Out1        = P3^6;    //RELAY #2

Out2        = P3^5;    //RELAY #3

Out3        = P3^4;    //RELAY #4

軟體指令碼定義:

    指令碼定為為兩個字元,第1個BYTE是欲控制的RELAY繼電器的編碼,第2個BYTE是0x08(等似於/n)為指令碼的結尾碼,切記任何指令碼的第二個位元必須是0x08,才能構成完整指令結構,當接收了第1次時,會令指定的繼電器ON,如再次接收到同一指令碼時,則會讓原先的繼電器ON轉態為OFF,如此達成電器之遙控的功能.

舉例如下:

EX1: 指令碼0x31 0x08 =>指定繼電器#1動作.

    於PC端可使用ACCESSPORT或SSCOM兩種UART傳送軟體來下達遙控指令碼.

------------------------------------------------*/

#include "reg52.h"

#include "stdio.h"

#include "stdlib.h"

#include "string.h"

#include "delay.c"

#include "1602.c"

sbit BLUE_LED0    = P1^0;    //LED0 BLUE INDICATOR

sbit RED_LED1    = P2^7;    //LED1 RED INDICATOR

sbit Out0       = P3^7;    //RELAY #1

sbit Out1       = P3^6;    //RELAY #2

sbit Out2       = P3^5;    //RELAY #3

sbit Out3       = P3^4;    //RELAY #4

/*------------------------------------------------

                整體變數宣告

------------------------------------------------*/

bit Tdisp_flag=0;

bit SetFlag,busy;

unsigned char temp[21];       //LCM Buffer

unsigned xdata Rcv_buf[41];    //RS232 Rcv Buffer

unsigned char AC_ms,AC_sec,AC_min,AC_hours;   //時鐘變數

#define T25ms     46089       //時基25ms

#define BS     0x08        //'\n'

#define FOSC     22118000    //XTAL=22.1194MHZ

#define BAUD     9600        //BAUD RATE=9800

#define RELOAD_COUNT 0xFA     //12T 9600bps

unsigned char Rcv_idx;

unsigned short RCV_num;

/*------------------------------------------------

                  函數聲明

------------------------------------------------*/

void Init_Timer0(void);                  //時鐘計數

void InitUART(void);                 //UART的初始化 96,8,N,1

void Uart_SendStr(unsigned char *s);    //UART送出字串

void Uart_SendByte(unsigned char dat);    //UART送出字元

/*------------------------------------------------

                    主程式

------------------------------------------------*/

void main(void)

{   unsigned char i;

    unsigned char cmd;

    Init_Timer0();      //計時器初始化

    InitUART();

    LCD_Init();         //LCM初始化

    DelayMs(10);        //延遲LCM

    LCD_Clear();        //清除LCM畫面

    SetFlag=0;

    P3=0xff;

    P2=0xff;

    P1=0xff;

    BLUE_LED0=1;

    RED_LED1=1;

    EA=1;               //interupt enable

    ES=1;

    for(i=0;i<41;i++) span="" style="mso-tab-count: 1;" data-mce-style="mso-tab-count: 1;">    {Rcv_buf[i]=0x20;}

    Uart_SendStr("STC89C52+HC_05\r\n Uart1 96,N.1,1 Test !\r\n");

//***********************

    ET1=0;

    TR0=1;

    ET0=1;

//***********************

    RCV_num=0;

    while(1)    //主程式

    {  

        START0:

//***********************      

        if(Tdisp_flag==1)       //判斷顯示旗號

        {    BLUE_LED0=0;        //秒數指示燈 ON

            sprintf(temp,"@ %02d:%02d:%02d %05d\b",(int)AC_hours,(int)AC_min,(int)AC_sec,(short)RCV_num);

            LCD_Write_String(0,0,temp); //顯示時鐘於LCD模組

            if(!RI)

            {  

                Uart_SendStr(temp);    //送出時間值至UART

            }

            Tdisp_flag=0;       //清除顯示旗號

            BLUE_LED0=1;        //秒數指示燈OFF

        }

        if (SetFlag==1)            //判斷是否有藍芽指令接收

        {           

            ES=0;RED_LED1=0;    //DISABLE interrupt,同時點亮接收指示燈

            RCV_num++;          //接收指令次數加一

            sprintf(temp,"%1c%1c%1c%1c",(char)Rcv_buf[0],(char)Rcv_buf[1]);

            LCD_Write_String(0,1,temp); //顯示接收之指令於LCD模組

            RED_LED1=1;         //接收指示燈 OFF       

            cmd=Rcv_buf[0];     //取得指令碼

            switch(cmd)

            {   case 0x31: Out0=~Out0;break;   //指令0x31:RELAY#1動作

                case 0x32: Out1=~Out1;break;   //指令0x32:RELAY#2動作

                case 0x33: Out2=~Out2;break;   //指令0x33:RELAY#3動作

                case 0x34: Out3=~Out3;break;   //指令0x34:RELAY#4動作

                case 0x54:     AC_hours=(int)(Rcv_buf[1]-0x30)*10+(int)(Rcv_buf[2]-0x30);//指令"T":設定時間參數

                            AC_min=(int)(Rcv_buf[3]-0x30)*10+(int)(Rcv_buf[4]-0x30);

                            AC_sec=0;

                            break; 

                default:break;

            }

            DelayMs(10);                       

            Rcv_idx=0;  //接收緩衝器指標歸 0

            SetFlag=0;  //清除接收旗號

            ES=1;       //ENABLE interrupt

        }

        goto START0;

    }

}

/*------------------------------------------------

                計數器 0 的初始化

------------------------------------------------*/

void Init_Timer0(void)               //計數器0的初始化

{

    TMOD  = (TMOD & 0xF0)|0x01;     //設定 Timer 0 to MODE #1 auto load

    TH0=(65536-T25ms)/256;          //時基 25ms

    TL0=(65536-T25ms)%256;

    ET0=1;                            //打開中斷

    TR0=1;                            //啟動 TIMER 0

}

/*------------------------------------------------

    計時器 TIMER0 中斷處理

------------------------------------------------*/

void TIMER0(void) interrupt 1 using 1

{    TH0=(65536-T25ms)/256;                  //設定 TIMER 0 為時鐘時基25ms

    TL0=(65536-T25ms)%256;                  //reload值

    TF0=0;

    AC_ms++;

    if(AC_ms>=40)                           //20ms x 40次 = 1秒

    {    AC_ms=0;AC_sec++;Tdisp_flag=1;      //秒數增加 1,同時時基歸 0.並設定顯示旗號為 1

        if(AC_sec>=60)                      //判斷是否已滿 60秒

        {    AC_sec=0;AC_min++;              //分鐘數增加 1,同時秒數歸 0

            if(AC_min>=60)                  //判斷是否已滿 1分鐘

            {    AC_min=0;AC_hours++;        //已滿 1 小時,分鐘數歸 0

                if(AC_hours>23)    AC_hours=0; //判斷是否已滿24小時, 小時數歸 0

            }

        }

    }      

}

/*------------------------------------------------

    UART #1    初始化

    0xfa    9600,8,N,1 @XTAL=22.1194Mhz

------------------------------------------------*/

void InitUART  (void)

{   TMOD  = (TMOD & 0x0F)|0x20;     // 設定 Timer 1 to MODE #2 auto load

    SCON  = 0x50;                    // 設定 Serial Mode 1

    TH1   = 0xfa;   // TH1:重裝值 9600 串列傳輸速率 晶振 22.118MHz

    TL1   = 0xfa;

    TR1   = 1;      // TR1:  timer 1 打開                     

    EA    = 1;      // 打開總中斷

    ES    = 1;      // 打開串口中斷       

}

/*------------------------------------------------

    UART發送一個位元組

------------------------------------------------*/

void Uart_SendByte(char dat)

{    while(busy);    //判斷傳送旗號是否結束

    busy=1;         //設定傳送旗號

   SBUF=dat;        //送出字元

}

/*------------------------------------------------

    UART發送一個字串

------------------------------------------------*/

void Uart_SendStr(char *s)

{    while(*s!=BS)   // \b 表示字串結束標誌,通過檢測是否字串末尾

    {    Uart_SendByte(*s++);

    }

}

/*------------------------------------------------

    UART 1 中斷程式 (P3^0 & P3^1)

------------------------------------------------*/

void UART_SER (void) interrupt 4    //串列中斷服務程式

{  

    if(RI)                          //判斷是接收中斷產生

    {    Rcv_buf[Rcv_idx]=SBUF;      //讀入緩衝區的值

        Rcv_idx++;

        if(Rcv_buf[Rcv_idx-1]==BS || Rcv_idx>21)    //連續接收16個字元資訊

        {    Rcv_idx=0;

            SetFlag=1;              //接收完成標誌位置1

            ES=0;

        }

       RI=0;                        //標誌位元清零

    }

   if(TI==1)                        //如果是發送標誌位元,清零

    {    TI=0;

        busy=0;                     //清除傳送旗號

    }

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

( 興趣嗜好電腦3C )
回應 推薦文章 列印 加入我的文摘
上一篇 回創作列表 下一篇

引用
引用網址:https://classic-blog.udn.com/article/trackback.jsp?uid=PYANG&aid=43240338