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; //清除傳送旗號
}
}
限會員,要發表迴響,請先登入


