树莓派3使用wiringPI,模拟空调开关,实现空调遥控
1.背景
由于树莓派3无法安装LIRC,所以决定直接使用IO模拟NEC,对红外遥控进行捕获,存储,以及发送
前言
使用的板子是树莓派3,红外接收管为HS0038B,发射管为TSAL6200,对应的空调是海尔,遥控用的是手机模拟遥控
一、NEC是啥
红外协议,建议百度
二、处理思路
1.原理图
使用树莓派的P17作为发射脚,P18作为接收脚,调用树莓派3.3V作为发射电源,5V作为红外接收电源,限流电阻100R,发射电流最大为3.3*10=33mA
PCB绘制后长这样,注意mos管的封装,之前画错了。
如果觉得麻烦,可以直接飞线,用杜邦线/面包板直连,实验成功后再弄板子
2.代码流程
2.1.头文件
#ifndef TEST_H
#define TEST_H
#include <time.h>
#include <sys/time.h>
#include <fstream>
#include <map>
#include <iterator>
#define test_printf(format,...) do{ \
printf("LINE:%d "format,__LINE__,##__VA_ARGS__); \
}while(0);
#define RECV_PINNUM 1 //gpio 18
#define SEND_PINNUM 0 //gpio 17
#define LOADWAVE(PIN,TL,TH) \
digitalWrite((PIN),HIGH); \
delayMicroseconds((TL)); \
digitalWrite((PIN),LOW); \
delayMicroseconds((TH));
#define LOADWAVECS(PIN,TL,TH,TIMES) \
for(int ts=0;ts<(int)((TIMES));ts++){ \
LOADWAVE(PIN,TL,TH) \
}
class NECWave{
public:
NECWave(){
LowTimeUs = 0;
HightTimeUs = 0;
};
int LowTimeUs;
int HightTimeUs;
};
void test(int choice,string filePath);
void initNecINPins(int inPin);
void initNecOUTPins(int outPin);
NECWave catchSignalWave(int inPin); //捕获单个上升下降
void catchlirc(int inPin,vector<NECWave> &NecTimeCat,string savePath); //捕获总函数
int caculateDepTime(struct timeval startT,struct timeval endT); // 计算时间差值
void sendWave(int outPin,vector<NECWave> NecTimeCat,string ifilePath); //发送捕获的NecTimeCat
void VtNECWave2File(string path,vector<NECWave> NecTimeCat);
void File2VtNECWave(string path,vector<NECWave> &NecTimeCat);
#endif
源文件
#include "test.h"
#include "wiringPi.h"
#define OVERTIME_SECOND_NUM 15 //最大超时时间
#define LOADWAVELEVEL 0.35 //占空比(反)
#define LOADFREQ 38000 //载波频率
void test(int choice,string filePath)
{
vector<NECWave> NecTimeCat;
test_printf("test funs\r\n");
//initNecPins(RECV_PINNUM,SEND_PINNUM);
wiringPiSetup();
if(choice == 0){
initNecINPins(RECV_PINNUM);
catchlirc(RECV_PINNUM,NecTimeCat,filePath);
}else if(choice==1){
initNecOUTPins(SEND_PINNUM);
sendWave(SEND_PINNUM,NecTimeCat,filePath);
}else if(choice==2){
wiringPiSetup();
pinMode(RECV_PINNUM,INPUT);
pinMode(SEND_PINNUM,INPUT); //输出设置为输入
}else{
cout<<"Err filename"<<endl;
}
}
void initNecINPins(int inPin)
{
pinMode(inPin,INPUT);
}
void initNecOUTPins(int outPin)
{
pinMode(outPin,OUTPUT);
digitalWrite(outPin,HIGH);
}
void VtNECWave2File(string path,vector<NECWave> NecTimeCat)
{
ofstream ofs;
ofs.open(path,ios::out|ios::binary);
if(!ofs){
cout<<exec("pwd")<<endl;
printf("Err fileOpen write in path:%s\r\n",path.c_str());
return ;
}
for(int num =0 ;num<NecTimeCat.size();num++){
ofs.write((char*)&NecTimeCat[num].LowTimeUs,4);
ofs.write((char*)&NecTimeCat[num].HightTimeUs,4);
//ofs<<NecTimeCat[num].LowTimeUs;
//ofs<<NecTimeCat[num].HightTimeUs;
}
ofs.close();
}
void File2VtNECWave(string path,vector<NECWave> &NecTimeCat)
{
char buff[4];
ifstream ifs;
ifs.open(path,ios::in|ios::binary);
if(!ifs){
cout<<exec("pwd")<<endl;
printf("Err fileOpen read in path:%s\r\n",path.c_str());
return ;
}
while(!ifs.eof()){
NECWave NecTwave;
//ifs>>buff;
ifs.read(buff,4);
NecTwave.LowTimeUs = *((int *)buff);
//ifs>>buff;
ifs.read(buff,4);
NecTwave.HightTimeUs = *((int *)buff);
if(ifs.eof()){
break;
}
//ifs>>NecTwave.LowTimeUs;
//ifs>>NecTwave.HightTimeUs;
NecTimeCat.push_back(NecTwave);
}
ifs.close();
}
void catchlirc(int inPin,vector<NECWave> &NecTimeCat,string savePath)
{
bool flag=false;
double val;
int index = 0;
//NECWave singleWave;
int usCountsLow,usCountsHIGH;
struct timeval startT,endT;
test_printf("start catch\r\n");
int cntTs = 0;
while(1){
NECWave singleWave = catchSignalWave(inPin);
if(singleWave.LowTimeUs==0 && singleWave.HightTimeUs==0){
if(index==0){
test_printf("End wave Or Over time!\r\n");
break;
}else{
test_printf("recv data\r\n");
break;
}
}
if(singleWave.HightTimeUs > OVERTIME_SECOND_NUM*1000000){ // Second
test_printf("OVER TIME BREAK\r\n");
break;
}
if(abs(singleWave.LowTimeUs- singleWave.HightTimeUs)>100000){ //100ms
if(index==0){
continue;
}
test_printf("END TIME BREAK\r\n");
cout<<"LowTimeUs:"<<singleWave.LowTimeUs<<endl;
cout<<"HightTimeUs:"<<singleWave.HightTimeUs<<endl;
index++;
singleWave.HightTimeUs = 4000;
NecTimeCat.push_back(singleWave);
break;
}
if(index==0){
if(singleWave.HightTimeUs>400){
flag = true;
}else{
if(cntTs==3){
break;
}
cout<<"Times"<<endl;
cout<<"LowTimeUs:"<<singleWave.LowTimeUs<<endl;
cout<<"HightTimeUs:"<<singleWave.HightTimeUs<<endl;
delay(1000);
cntTs ++;
index = 0;
}
}
if(flag==true){
index++;
NecTimeCat.push_back(singleWave);
}
}
if(flag==true){
for(int num=0;num<NecTimeCat.size();num++){
test_printf("num:%d Low=%d Hight=%d\r\n",num,NecTimeCat[num].LowTimeUs,\
NecTimeCat[num].HightTimeUs);
}
VtNECWave2File(savePath,NecTimeCat);
}else{
printf("unfound signal in\r\n");
}
}
NECWave catchSignalWave(int inPin)
{
NECWave singleWave;
struct timeval startT,endT,OverTime,OverTst;
again:
gettimeofday(&OverTst,NULL);
while(digitalRead(inPin)==HIGH){
gettimeofday(&OverTime,NULL);
if((OverTime.tv_sec-OverTst.tv_sec)>OVERTIME_SECOND_NUM){ //连续持续两秒的NEC不存在!
printf("cattime over1!\r\n");
return singleWave;
}
}
gettimeofday(&startT,NULL); //获取起始时间 下降沿时刻
while(digitalRead(inPin)==LOW);
gettimeofday(&endT,NULL); //获取结束时间 上升沿时刻
singleWave.LowTimeUs = caculateDepTime(startT,endT);
if(singleWave.LowTimeUs<450){
goto again;
}
while(digitalRead(inPin)==HIGH){
gettimeofday(&OverTime,NULL);
if((OverTime.tv_sec-OverTst.tv_sec)>(OVERTIME_SECOND_NUM+1)){ //连续持续两秒的NEC不存在!
printf("cattime over2!\r\n");
singleWave.LowTimeUs = 0;
singleWave.HightTimeUs = 0;
return singleWave;
}
}
gettimeofday(&startT,NULL); //获取起始时间 下降沿
#if 0
while(digitalRead(inPin)==LOW);
gettimeofday(&endT,NULL); //获取结束时间
singleWave.HightTimeUs = caculateDepTime(startT,endT);
#else
singleWave.HightTimeUs = caculateDepTime(endT,startT);
#endif
return singleWave;
}
int caculateDepTime(struct timeval startT,struct timeval endT)
{
int usCountsStart,usCountsEnd;
usCountsStart = startT.tv_sec * 1000000 + startT.tv_usec;
usCountsEnd = endT.tv_sec * 1000000 + endT.tv_usec;
return (usCountsEnd - usCountsStart);
}
void sendWave(int outPin,vector<NECWave> NecTimeCat,string ifilePath) //发送捕获的NecTimeCat
{
File2VtNECWave(ifilePath,NecTimeCat);
for(int num=0;num<NecTimeCat.size();num++){
test_printf("num:%d Low=%d Hight=%d\r\n",num,NecTimeCat[num].LowTimeUs, \
NecTimeCat[num].HightTimeUs);
}
vector<int> loadcycleVts;
int index=0;
float fPeriodUs = 1000000 / LOADFREQ;
uint32_t u32PeriodUs = fPeriodUs;
uint32_t u32LoadHeightTime = u32PeriodUs * LOADWAVELEVEL;
uint32_t u32LoadLowTime = u32PeriodUs - u32LoadHeightTime;
uint32_t loadcycleTs;
cout<<"load Wave HeightTimeUs"<<u32LoadHeightTime<<endl;
cout<<"load Wave LowTimeUs"<<u32LoadLowTime<<endl;
for(auto wavePtr=NecTimeCat.begin();wavePtr!=NecTimeCat.end();wavePtr++){
loadcycleTs = (wavePtr->LowTimeUs+u32PeriodUs) / u32PeriodUs; //预先把轮次获取 除法吃时间
loadcycleVts.push_back(loadcycleTs);
}
for(auto wavePtr=NecTimeCat.begin();wavePtr!=NecTimeCat.end();wavePtr++){
if(1){
loadcycleTs = loadcycleVts[index];
LOADWAVECS(outPin,u32LoadLowTime,u32LoadHeightTime,loadcycleTs);
}else{
delayMicroseconds(wavePtr->LowTimeUs);
}
digitalWrite(outPin,LOW);
delayMicroseconds(wavePtr->HightTimeUs - u32PeriodUs*3);
index++;
}
digitalWrite(outPin,HIGH);
}
main文件
#include <public.h>
#include <tool.h>
#include <test.h>
int main(int argc,char *argv[])
{
cout<<"main funs"<<endl;
cout<<exec("pwd")<<endl;
if(argc<2){
printf("less args\r\n");
printf("para as : ./run.sh \"-s\" \"../data/outfile.bin\"\r\n");
printf("para as : ./run.sh \"-r\" \"../data/outfile.bin\"\r\n");
printf("para as : ./run.sh \"rest\" \" \"\r\n");
//#define DEBUG
#ifndef DEBUG
// test("../data/open.txt","../data/open.txt");
#else
// test("./data/open.txt","./data/open.txt");
#endif
}else{
string fsname="";
printf("filename= %s para = %s\r\n",argv[2],argv[1]);
if(!strcmp(argv[1],"-r")){
fsname.assign(argv[2]);
test(0,fsname);
}else if(!strcmp(argv[1],"-s")){
fsname.assign(argv[2]);
test(1,fsname);
}else if(!strcmp(argv[1],"rest")){
test(2,fsname);
}else{
cout << " err io files "<<endl;
}
}
return 0;
}
简要说明
传参0 “-r”,捕获红外遥控通信,参数1 表示捕获到的红外文件存储路径;
传参0 “-s”,将存储的文件转换为红外发射出去,参数1 表示红外文件路径
传参0"-rest",复位
./bin/wiringPi_T1 "-r" "./data/open.bin" \\读取捕获红外,存入open.bin
./bin/wiringPi_T1 "-s" "./data/open.bin" \\发射红外文件open.bin
总结
1.红外发射的管子最小电流需要在20mA左右,不可以直接使用树莓派的IO直接驱动
2.红外接收器,默认高电平自带38KHz的载波信号.无载波信号,红外接收器无法接收到载波.
3.如果一直无法成功通信,那么可以做自收自发测试,用树莓派的红外发射器发射,再用树莓派的红外接收器接收. 比对时间
4.归根结底,还是由于有的树莓派不支持lirc_rpi,需要更换版本啥的,很麻烦
5.单片机实现原理大致差不多.
6.树莓派实现了这个功能有啥用
(1)夏/冬天天下班前半小时可以提前开空调
(2)每天/周,周期性的开关空调(空调频繁开关不节约电费,详情自个百度)
(3)加装一个温度传感器,可以进行闭环温度调控.