最近给家里更换了WIFI控制的卷帘门,原先为单片机与手机通讯,控制遥控器,但最近遥控器坏了,所以查了下卷帘门遥控器的通讯方式,从淘宝买了发射与接收模块,自己把遥控器也集成了。如图:
左图接收,右图发射
每个模块上三个口,GND,VCC,DATA信号线,最后一个孔是装天线的,可以无视。
GND VCC不必多说,3.3V供电的。
DATA信号线就是通讯的基础,如果发射模块下,DATA信号为高电平,那么接收模块上的DATA信号也是高电平,反之低电平也是一样。
当然这是需要433震荡的,所以如果不能“高低高低”的发送震荡似的电平信号,DATA引脚自己就会震荡,示波器单独去测量信号就会变得没有意义。
介绍完硬件,然后是433M的通讯协议:
两者通讯方式是震荡,既然如此,如何表达MCU上的0与1呢?
很简单,在震荡中去取出DATA引脚上的低电平信号时间。如果低电平信号持续时间在0~500us之间,则认为时数据1,如果低电平持续时间在750~1500之间,则认为数据0。
当然,具体时间与数据0和1对应可以自行定义,或者根据自己家的遥控器,卷帘门等设备进行对应。
最后是通讯协议:
为了滤除无意义的震荡信号,所以卷帘门遥控器的通讯协议如下:
1,开始同步信号:发送9ms~14ms之间的低电平信号,认为通讯开始。
2,然后发送24bit的数据信号,如:0x55AAFF即可。
具体遥控器发送的数据是什么意义,我们不管,只要复制下来即可。
下面直接看接收遥控器信号的程式:
1.先定义一个引脚检测DATA信号,这里我用的是PB8,接入接收模块的DATA信号脚上。
#define RF_Dat ((GPIOB->IDR & GPIO_IDR_8)>>8)
引脚配置如下:高速,下拉。
RCC->AHBENR |= RCC_AHBENR_GPIOBEN;
GPIOB->MODER = (GPIOB->MODER & ~GPIO_MODER_MODER8);
GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR8;
GPIOB->PUPDR |= (GPIOB->PUPDR & ~GPIO_PUPDR_PUPDR8) | GPIO_PUPDR_PUPDR8_1;
2.再定义一个定时器,不停的低电平引脚检测时间,以50us为例:
则数据0与1的低电平信号时间如下:
#define _start_us_min 180//同步信号的低电平持续时间,最低值9ms
#define _start_us_max 280//同步信号的低电平持续时间,最高值14ms
#define _num0_us_min 15//数据0,低电平信号持续时间,最低值750us
#define _num0_us_max 30//数据0,低电平信号持续时间,最高值1500us
#define _num1_us_min 0//数据1,低电平信号持续时间,最低值0us
#define _num1_us_max 10//数据1,低电平信号持续时间,最高值500us
定时器配置如下:
RCC->APB1ENR |= 0X00000002;//TIM3
TIM3->ARR = 400;//72M/400/(8+1)=0.01M=50us
TIM3->PSC = 8;
TIM3->CR1 &= 0XFF87;
TIM3->DIER |= 0X0001;//UIE
TIM3->CR1 |= 0X0001;
NVIC->ISER[TIM3_IRQn/32]|=1<<TIM3_IRQn%32;
服务函数如下:
void TIM3_IRQHandler(void)
{
if(TIM3->SR&0X0001)
{
TIM3->SR&=~(1<<0);
soft_count();
}
}
soft_count()便是解码程式,具体内容如下:
void soft_count()//接受码计数函数
{
if(RF_Dat==0) //低电平
{
Low++;//电平持续时间累积。
if(Jump_flag==1)
{Jump_flag = 0}//防误触发,需确认为下降沿
}
else if(RF_Dat==1) //高电平
{
if(Jump_flag == 0)//防误触发,确认为上升沿,则低电平累积时间结束。
{
Jump_flag=1; //上升沿
soft_decode();//对Low的计数长度进行处理。
Low=0;
}
}
}
void soft_decode()//接受码处理函数
{
if(start_flag==0)//处于同步状态中
{
if(( Low > _start_us_min ) && ( Low < _start_us_max )) //同步码的低电平时间长度
{
start_flag=1;//同步结束,开始接收数据
cntint=0;//数据长度
RF_data=0;//数据临时存放地址
}
}
else if((start_flag==1)&&(cntint<24))//接收数据中
{
if(( Low > _num0_us_min ) && ( Low < _num0_us_max )) //数据 0 750~1500us
{
RF_data=RF_data<<1;
cntint++;
}
else if(( Low > _num1_us_min ) && ( Low < _num1_us_max )) //数据 1 0-500us
{
RF_data=RF_data<<1;
RF_data|=1;
cntint++;
}
else
{
start_flag=0;//数据错误,清零重新等待同步信号
cntint=0;
}
}
if(cntint==24)//长度抵达24bit,开始处理
{
cntint=0;
start_flag=0;
dataJ = RF_data;//记下当前数据
RF_data = 0;
}
}
完成上述程式,即可破译433M遥控器的密码了。进入keil调试,然后按下遥控器,就可以看到接收模块接收到的数据内容了。如图:
这一串55AAFF即是遥控器发出来的数据。
破解了遥控器的数据,下面我们再来看看发射程序。
1,先定义脚位,连接发射模块的DATA脚,这里我使用的是PA7,高速,上拉。
RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
GPIOA->MODER = (GPIOA->MODER & ~GPIO_MODER_MODER7) | GPIO_MODER_MODER7_0;
GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR7;
GPIOA->PUPDR |= (GPIOA->PUPDR & ~GPIO_PUPDR_PUPDR7) | GPIO_PUPDR_PUPDR7_0;
GPIOA->BSRR |= 0X1<<7;
2,再定义一个定时器,用于发射低电平的时间计数,这里以50us为例:
#define send0 21//数据0,低电平持续21*50us
#define send1 7//数据1,低电平持续7*50us
配置如下:
RCC->APB1ENR |= 0X00000001;//TIM2
TIM2->ARR = 400;//72M/400/(8+1)=0.01M=50us
TIM2->PSC = 8;
TIM2->CR1 &= 0XFF87;
TIM2->DIER |= 0X0001;//UIE
TIM2->CR1 |= 0X0001;
NVIC->ISER[TIM2_IRQn/32]|=1<<TIM2_IRQn%32;
服务函数如下:
void TIM2_IRQHandler(void)
{
static uint8_t send_dat = 0;
if(TIM2->SR&0X0001)
{
TIM2->SR&=~(1<<0);
if(sflag == 0)
{
send_dat = sendtostart();//发送同步信号,若返回0xff即发送完成
}
if(sflag == 1)
{
send_dat = send_data(0X0055AAFF);//发送数据,若返回0xff即发送完成
}
if(send_dat == 0xff)
{
send_dat = 0;
sflag++;
}
if(sflag>=2 && sflag<200)
{
sflag++;
}
else if(sflag >= 200)
{
sflag=0;//发送完成后,间隔9.9ms后再发送
}
}
}
下面为自己写的发送函数,有兴趣的可以看一看,没有兴趣直接调用即可,这里不再过多赘述。
uint8_t senddata(uint8_t Dbit)
{
static uint8_t cnt = 0;
static uint8_t BIT_Done = 0xFF;
static uint8_t BIT_cnt = 0;
cnt++;
if(BIT_Done==0xff)//空闲
{
BIT_Done = 1;//开始发送
cnt = 0;
if(Dbit == 1)
{
BIT_cnt = 10+send1;
}
else
{
BIT_cnt = 10+send0;
}
BIT_Done = 2;//发送中
}
if(BIT_Done == 2)
{
if(cnt<10)
{
GPIOA->BSRR |= 0X1<<7;
}
else if(cnt < BIT_cnt)
{
GPIOA->BSRR |= 0X1<<23;
}
else
{
GPIOA->BSRR |= 0X1<<7;
BIT_Done = 0xFF;
}
}
return BIT_Done;
}
uint8_t sendtostart()
{
static uint8_t cnt = 0;
static uint8_t BIT_Done = 0xFF;
static uint8_t BIT_cnt = 0;
cnt++;
if(BIT_Done==0xff)//空闲
{
cnt = 0;
BIT_cnt = 10+180;
BIT_Done = 1;//发送中
}
if(BIT_Done == 1)
{
if(cnt<10)
{
GPIOA->BSRR |= 0X1<<7;
}
else if(cnt < BIT_cnt)
{
GPIOA->BSRR |= 0X1<<23;
}
else
{
GPIOA->BSRR |= 0X1<<7;
BIT_Done = 0xFF;
}
}
return BIT_Done;
}
uint8_t send_data(uint32_t data)
{
static uint8_t start = 0xff;
static uint32_t data_back = 0;
static uint8_t data_cnt = 0;
uint8_t bit_done;
uint32_t data_buf = 0;
if(start == 0xff)
{
data_buf = data;
for(uint8_t i = 0;i<24;i++)
{
if(data_buf&0x01)
{
data_back<<=1;
data_back|=1;
}
else
{
data_back<<=1;
}
data_buf>>=1;
}
start = 1;
}
if(start == 1)
{
bit_done = senddata(data_back&0x01);
if(bit_done==0xff)
{
data_back>>=1;
data_cnt++;
}
}
if(data_cnt >32)
{
data_cnt = 0;
start = 0xff;
}
return start;
}
目前已完成遥控器的数据破解,完美替代了自己家中卷帘门的遥控器,将其集成到了自己做的一个wifi控制器上。
#end