DIY智能插座(二) -- C51单片机编码

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lonely_geek/article/details/52186164

  插座的通断是通过单片机来控制,结合蓝牙POS机做透传,即可直接通过蓝牙来控制继电器。
  
  51单片机代码比较简单,放出完整代码。

#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  //错误码

/*定义四路开关控制引脚*/
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关闭

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

猜你喜欢

转载自blog.csdn.net/lonely_geek/article/details/52186164