智能插座远程控制电器很好玩!如果你有单片机或嵌入式基础,你也可以自己动手做一个

转自嵌入式ARM

学号16020311003  姓名:杨虎成

【嵌牛导读】多尝试自己动手用嵌入式解决问题

【嵌牛鼻子】嵌入式在大部分电气中有很大的作用

【嵌牛提问】嵌入式系统在电子元件中如何工作

【嵌牛正文】

智能插座远程控制电器很好玩!如果你有嵌入式单片机基础,你也可以自己动手做一个...

——————————————————

自己DIY用的零件清单(大部分都是手头拆机的):

1)STC51系列单片机(淘宝上几块钱就能买到,自己纯手工焊了一块板子)

2)中央空调控制面板上拆的继电器,有四路,刚好可以控制四个插座

3)蓝牙POS机(淘宝上一毛钱包邮很多,我这款叫“开店宝”),用于做蓝牙串口透传

4)废旧插座一个

由于普通插座都是共火线和共零线,为了实现四路单独控制,需要改造插座,将四个插孔的火线分开,然后与四路继电器相连,

 

整个控制流:手机APP –> 蓝牙POS –> 51单片机 –> 继电器 –> 插座

手机APP通过蓝牙发送数据到蓝牙POS,蓝牙POS作为一个蓝牙透传设备,将控制指令数据通过串口发送给单片机,单片机通过GPIO口来控制继电器,最终实现对插座的控制。(其实该蓝牙POS是个STM32单片机,可以无需51单片机,直接将STM32的GPIO引出来去控制,如果你动手能力强的话,鉴于自己动手能力一般,焊接不好那么细的芯片引脚,所以干脆拿了个51单片机来中转一下)。


  

下面奉上代码:

插座的通断是通过单片机来控制,结合蓝牙POS机做透传,即可直接通过蓝牙来控制继电器。

  

51单片机代码比较简单,放出完整代码。

#include

#include

#define FOSC 22118400L //定义晶振频率

#define BAUD 115200  //定义波特率

#define SMOD  1

#define RX_BUFF_SIZE 64

#define ERR_CODE_RSP 0xD0  //错误码

/*定义四路开关控制引脚*/

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}; //串口接收缓冲区

volatile unsigned char rx_count = 0; //接收计数器

volatile unsigned char pos = 0;    //读取计数器,记录当前读取字节数 

volatile unsigned char msg_code = 0x00;  //存储控制码

volatile unsigned char status_code = 0x70;  //存储状态码

/** 串口发送 **/

void byte_send(unsigned char ch)

{

    SBUF = ch ;

    while(!TI);

    TI = 0;

}

/** 判断缓存是否有数据可读取 **/

unsigned char is_rx_buffer_empty(void)

{

    return !(rx_count - pos);

}

/** 读缓冲区一个字节 **/

unsigned char uart_read(void)

{

    unsigned char c;

    c = rx_buff[pos++];

    if(rx_count == pos){

        rx_count = pos = 0;

    } 

    return c;

}

/** 消息处理 **/

/** 简单起见,就用了一个字节做控制码

    bit0 ~ bit3: 分别对应四路开关,置0为关,置为1为开

    bit4 ~ bit8: 作为参数类型(0x06:查询开关状态 0x07:设置开关状态)

**/

void msg_process(void)

{

    if(is_rx_buffer_empty()) //如果设计成多个字节作为控制码,此处要改为while循环

        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; //保存本次处理结果

            msg_reply(status_code);

            break;

        default:  //Err code

            msg_reply(ERR_CODE_RSP);       

    }

}

/** 消息响应 **/

void msg_reply(unsigned char msg)

{

    //byte_send(':');//unknow reason

    delay(1500);

    byte_send(msg);

    byte_send(':'); //将':'作为间隔符,蓝牙POS收到该符号,才认为一条数据接收完毕

}

/** 串口初始化 **/

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 ;

    }

}

/** 主函数 **/

void main(void)

{

    P2 = 0x00;

    uart_init();

    while(1)

    {

      msg_process();

    }

}

消息处理函数,一定要放在主循环中,有的开发者习惯在中断响应函数中做消息处理,容易导致串口数据丢失。中断中一定只做简单的处理,本代码中只是将中断接收到的数据存到数组中。

测试:

假设当前开关状态为: 0101

用串口助手输入16进制:

输入:0x60 返回:0x75 0x3A //查询当前开关状态,0x3A为’:’对应16进制ASCII码

输入:0x77 返回:0x77 0x3A //设置开关0、开关1、开关2 开,开关3关闭

操作成功后,会听见继电器开启、闭合的声音,可以用万用表测量是否导通或者切断。

你可能感兴趣的:(智能插座远程控制电器很好玩!如果你有单片机或嵌入式基础,你也可以自己动手做一个)