轉(zhuǎn)自嵌入式ARM
學(xué)號(hào)16020311003? 姓名:楊虎成
【嵌牛導(dǎo)讀】多嘗試自己動(dòng)手用嵌入式解決問題
【嵌牛鼻子】嵌入式在大部分電氣中有很大的作用
【嵌牛提問】嵌入式系統(tǒng)在電子元件中如何工作
【嵌牛正文】
智能插座遠(yuǎn)程控制電器很好玩群井!如果你有嵌入式單片機(jī)基礎(chǔ),你也可以自己動(dòng)手做一個(gè)...
——————————————————
自己DIY用的零件清單(大部分都是手頭拆機(jī)的):
1)STC51系列單片機(jī)(淘寶上幾塊錢就能買到毫胜,自己純手工焊了一塊板子)
2)中央空調(diào)控制面板上拆的繼電器书斜,有四路,剛好可以控制四個(gè)插座
3)藍(lán)牙POS機(jī)(淘寶上一毛錢包郵很多酵使,我這款叫“開店寶”)荐吉,用于做藍(lán)牙串口透傳
4)廢舊插座一個(gè)
由于普通插座都是共火線和共零線,為了實(shí)現(xiàn)四路單獨(dú)控制口渔,需要改造插座样屠,將四個(gè)插孔的火線分開,然后與四路繼電器相連缺脉,
整個(gè)控制流:手機(jī)APP –> 藍(lán)牙POS –> 51單片機(jī) –> 繼電器 –> 插座
手機(jī)APP通過藍(lán)牙發(fā)送數(shù)據(jù)到藍(lán)牙POS痪欲,藍(lán)牙POS作為一個(gè)藍(lán)牙透傳設(shè)備,將控制指令數(shù)據(jù)通過串口發(fā)送給單片機(jī)攻礼,單片機(jī)通過GPIO口來控制繼電器业踢,最終實(shí)現(xiàn)對插座的控制。(其實(shí)該藍(lán)牙POS是個(gè)STM32單片機(jī)礁扮,可以無需51單片機(jī)知举,直接將STM32的GPIO引出來去控制瞬沦,如果你動(dòng)手能力強(qiáng)的話,鑒于自己動(dòng)手能力一般雇锡,焊接不好那么細(xì)的芯片引腳蛙埂,所以干脆拿了個(gè)51單片機(jī)來中轉(zhuǎn)一下)。
下面奉上代碼:
插座的通斷是通過單片機(jī)來控制遮糖,結(jié)合藍(lán)牙POS機(jī)做透傳绣的,即可直接通過藍(lán)牙來控制繼電器。
51單片機(jī)代碼比較簡單欲账,放出完整代碼屡江。
#include <stc89c5xrc.h>
#include <string.h>
#define FOSC 22118400L //定義晶振頻率
#define BAUD 115200? //定義波特率
#define SMOD? 1
#define RX_BUFF_SIZE 64
#define ERR_CODE_RSP 0xD0? //錯(cuò)誤碼
/*定義四路開關(guān)控制引腳*/
sbit PLUG_1 = P2^4 ;
sbit PLUG_2 = P2^7? ;
sbit PLUG_3 = P2^6 ;
sbit PLUG_4? = P2^5 ;
unsigned char rx_buff[RX_BUFF_SIZE] = {0}; //串口接收緩沖區(qū)
volatile unsigned char rx_count = 0; //接收計(jì)數(shù)器
volatile unsigned char pos = 0;? ? //讀取計(jì)數(shù)器,記錄當(dāng)前讀取字節(jié)數(shù)?
volatile unsigned char msg_code = 0x00;? //存儲(chǔ)控制碼
volatile unsigned char status_code = 0x70;? //存儲(chǔ)狀態(tài)碼
/** 串口發(fā)送 **/
void byte_send(unsigned char ch)
{
? ? SBUF = ch ;
? ? while(!TI);
? ? TI = 0;
}
/** 判斷緩存是否有數(shù)據(jù)可讀取 **/
unsigned char is_rx_buffer_empty(void)
{
? ? return !(rx_count - pos);
}
/** 讀緩沖區(qū)一個(gè)字節(jié) **/
unsigned char uart_read(void)
{
? ? unsigned char c;
? ? c = rx_buff[pos++];
? ? if(rx_count == pos){
? ? ? ? rx_count = pos = 0;
? ? }?
? ? return c;
}
/** 消息處理 **/
/** 簡單起見赛不,就用了一個(gè)字節(jié)做控制碼
? ? bit0 ~ bit3: 分別對應(yīng)四路開關(guān)惩嘉,置0為關(guān),置為1為開
? ? bit4 ~ bit8: 作為參數(shù)類型(0x06:查詢開關(guān)狀態(tài) 0x07:設(shè)置開關(guān)狀態(tài))
**/
void msg_process(void)
{
? ? if(is_rx_buffer_empty()) //如果設(shè)計(jì)成多個(gè)字節(jié)作為控制碼踢故,此處要改為while循環(huán)
? ? ? ? return;
? ? msg_code = uart_read();
? ? switch((msg_code & 0xF0) >> 4)
? ? {
? ? ? ? case 0x6:? //Get the status
? ? ? ? ? ? msg_reply(status_code);
? ? ? ? ? ? break;
? ? ? ? case 0x7:? //Set and get status
? ? ? ? ? ? PLUG_1 = msg_code & 0x01 ;
? ? ? ? ? ? PLUG_2 = (msg_code & 0x02) >> 1 ;
? ? ? ? ? ? PLUG_3 = (msg_code & 0x04) >> 2 ;
? ? ? ? ? ? PLUG_4 = (msg_code & 0x08) >> 3 ;
? ? ? ? ? ? status_code = msg_code; //保存本次處理結(jié)果
? ? ? ? ? ? msg_reply(status_code);
? ? ? ? ? ? break;
? ? ? ? default:? //Err code
? ? ? ? ? ? msg_reply(ERR_CODE_RSP);? ? ? ?
? ? }
}
/** 消息響應(yīng) **/
void msg_reply(unsigned char msg)
{
? ? //byte_send(':');//unknow reason
? ? delay(1500);
? ? byte_send(msg);
? ? byte_send(':'); //將':'作為間隔符文黎,藍(lán)牙POS收到該符號(hào),才認(rèn)為一條數(shù)據(jù)接收完畢
}
/** 串口初始化 **/
void uart_init(void)
{
? ? SCON = 0x50 ;
? ? TMOD = 0x20 ;
? ? PCON |= 0x80 ;? ? //set smod
? ? TH1 = TL1 = 256 - FOSC*(SMOD+1)/32/12/BAUD ;
? ? TR1 = 1;
? ? ES = 1 ;
? ? EA = 1 ;
}
/** 串口中斷處理 **/
void? serial() interrupt 4? using 1
{
? ? if(RI)
? ? {
? ? ? ? RI = 0;
? ? ? ? if(rx_count > RX_BUFF_SIZE)
? ? ? ? ? ? rx_count = 0;
? ? ? ? rx_buff[rx_count++] = SBUF ;
? ? }
}
/** 主函數(shù) **/
void main(void)
{
? ? P2 = 0x00;
? ? uart_init();
? ? while(1)
? ? {
? ? ? msg_process();
? ? }
}
消息處理函數(shù)殿较,一定要放在主循環(huán)中耸峭,有的開發(fā)者習(xí)慣在中斷響應(yīng)函數(shù)中做消息處理,容易導(dǎo)致串口數(shù)據(jù)丟失淋纲。中斷中一定只做簡單的處理劳闹,本代碼中只是將中斷接收到的數(shù)據(jù)存到數(shù)組中。
測試:
假設(shè)當(dāng)前開關(guān)狀態(tài)為: 0101
用串口助手輸入16進(jìn)制:
輸入:0x60 返回:0x75 0x3A //查詢當(dāng)前開關(guān)狀態(tài)洽瞬,0x3A為’:’對應(yīng)16進(jìn)制ASCII碼
輸入:0x77 返回:0x77 0x3A //設(shè)置開關(guān)0本涕、開關(guān)1、開關(guān)2 開伙窃,開關(guān)3關(guān)閉
操作成功后菩颖,會(huì)聽見繼電器開啟、閉合的聲音为障,可以用萬用表測量是否導(dǎo)通或者切斷晦闰。