前面的文章中我们已经知道如何获取遥控器的红外编码,以及通过单片机重放红外信号,来遥控空调。但是这样是远远不够的,要想让家电智能起来,我们需要把模块接入一些高级点的系统中,比如树莓派,然后通过Linux系统来控制红外发射。下面我们将介绍如何使用Linux与红外模块交互。
1.通信协议的制定
就目前而言,模块与外界通信的渠道只有串口可以使用,所以我们决定使用串口与树莓派进行通信。但是只要制定好双方通信的协议,两者才能合理正确地通信,不然就像你说英语我说中文,鸡同鸭讲。
通信协议采用比较简单的方式,包括起始位
,数据个数
,数据
三个部分组成。
起始位
:占一个字节,用来标识报文的开始,数值为0x2B数据个数
:占一个字节,用来标识之后数据的数量,最大为0XFF,即后面的数据最长为255个数据
:传输的有效载荷,实际的数据
举个例子
2B 03 11 22 33
有效数据位 11 22 33
2.单片机端解析报文
单片机端需要在串口接收中断中根据协议来处理报文,处理的代码如下。
/*用来标识是否正在使用缓存区*/
bit buf_empty = 0;
/*报文起始位有效,接收后续报文*/
bit rec_start = 0;
/*该则报文接收到的数据个数*/
unsigned char rec_counter = 0;
/*该则报文需要接收的数据个数*/
unsigned char rec_sum = 0;
/*需要处理的数据个数*/
unsigned char snd_sum = 0;
/*接收缓存区*/
unsigned char idata recv_buff[MAX_BUF];
/*protocol: | start | byte count | byte0 | byte1 | ...*/
void Uart_Isr() interrupt 4 using 1
{
/*receive data*/
if (RI && buf_empty)
{
unsigned char ch = SBUF;
RI = 0;
/*normal bytes*/
if(rec_start && rec_sum != 0)
{
recv_buff[rec_counter++] = ch;
}
/*the amount of all bytes*/
if(rec_start && 0 == rec_sum)
{
snd_sum = rec_sum = ch;
}
/*start byte*/
if(!rec_start && DATA_PREFIX == ch)
{
rec_start = 1;
}
if(MAX_BUF == rec_counter || (rec_sum != 0 && rec_sum <= rec_counter))
{
/*buff is full*/
rec_counter = 0;
buf_empty = 0;
rec_sum = 0;
rec_start = 0;
}
}
/*send data*/
if (TI)
{
TI = 0;
busy = 0;
}
}
3.树莓派端报文发送程序
树莓派端需要实现串口的读写即可,代码如下。
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <termios.h>
#define MAX_SIZE 256
void init_series(int fd)
{
struct termios t ;
tcgetattr( fd , &t) ;
t.c_cflag &=~CSIZE ;
t.c_cflag &=~CSTOPB;
t.c_cflag |= CREAD ;
t.c_cflag |= CLOCAL ;
t.c_cflag &= ~CRTSCTS;
t.c_cflag |= CS8;
cfsetispeed( &t , B9600);
cfsetospeed( &t , B9600);
tcflush( fd , TCIOFLUSH);
tcsetattr( fd , TCSANOW ,&t);
}
/*这里没有写协议封装函数*/
char air_on[] = {0x2B, 104, 01, 01, 00, 00, 00, 00, 01, 01, 01, 01, 01, 00, 01, 00, 00, 01, 00, 00, 00, 00, 00, 01, 01, 01, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 01, 00, 01, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 01, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 01, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 01, 00, 01, 00, 00, 00, 00, 00, 01, 01, 01, 01, 01, 00, 00, 00};
char air_off[] = {0x2B, 104, 01, 01, 00, 00, 00, 00, 01, 01, 01, 01, 01, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 01, 01, 01, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 01, 00, 01, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 01, 00, 01, 00, 00, 00, 00, 00, 01, 01, 01, 01, 00, 00, 01, 00};
int main(int argc, char **argv)
{
int fd ;
int count ;
char *buff_send = NULL;
if(argc <2)
{
printf("please input args!\n");
return 0;
}
fd = open("/dev/ttyUSB0" , O_RDWR | O_NOCTTY );
if(fd<0)
{
printf("open series error\n");
return 0 ;
}
init_series(fd);
switch(argv[1][0])
{
case 'n':
case 'N': buff_send = air_on; break;
case 'f':
case 'F': buff_send = air_off; break;
default: break;
}
if(buff_send != NULL)
{
write(fd , buff_send , 104+2);
}
close(fd);
return 0 ;
}
OK啦,现在可以通过Linux来控制空调啦!但是这样貌似还不是很方便,如果想远程通过手机来控制的话可能会更方便,后面的文章将介绍搭建简单的物联网云平台,然后将手机和树莓派接入云平台实现远程控制空调。