最近项目需要增加一个控制机器运行的紧急遥控,参考了一个大神的博客,然后我们选择了这样的遥控器和一个315M模块,实现遥控器的按键控制。
首先介绍一下315M模块。315M是指频率为315MHz,还有433M也是比较常用的。其中它使用的芯片是EV1527型,EV1527 每帧数据由 24 个数据位组成,前 20 位为地址码,对于一个芯片来说,地址位的内容是固定的,是出厂前就预制好的,并且理论上每个芯片的地址码是唯一的。后面 4 位为按键码,对应芯片上的K0-K3 4 根数据线,数据线的状态不同,按键码就不同。 具体可以参考链接,我这里只是记录解析。
我们将模块通上电,在它的Data引脚出现无规律的波形。然后按下遥控器之后,芯片会接受到遥控器的信号,出现有规律的波形,如下图。(看着是不是显得头大了?)
根据前者参考资料里了解到,每个帧由24 个数据位组成,前20位是固定不变的地址位,后4位为按键位。在数据位之前,还有一个同步脉冲。我们需要捕获到同步脉冲之后,检测地址数据和按键数据。
同时数据位的“1”和“0”是由高低电平宽度(脉冲宽度)的比例决定的。如果高电平宽度为低电平宽度的 3 倍,就表示逻辑“1”,反过来如果低电平为高电平宽度的 3 倍,就表示逻辑“0”。同步脉冲高电平和低电平的比例固定为 4:124。
我们按下遥控器按键后,检测315M的Data引脚,同时将示波器定住放大如图所示。可以看到有很长一段低电平,此时是它的同步码过程,我们需要检测同步码过程。我们首先检测同步码前面一个的一个脉冲宽度,这个脉冲宽度基本上是遥控器的频率基数(每个遥控器可能脉冲宽度不一样)。将示波器放大,从示波器上看出此时脉冲宽度约为360us,那么CLK频率约为90us。(如果不把示波器放大的话,可能结果CLK可能为100us,影响误差)
那么这样就好办了,我们用stm32定时器定时产生90us的中断,来检测Data引脚的高低电平来检测0或者1。(16个CLK中,若12个为高则为1;若12个为低则为0)。然后在找到同步码后,检测地址码,接着解析按键码。然后判断两次接收的按键码一致,认为按键按下了。
代码如下:
BSP_315M.h
#ifndef __BSP_315M_H__
#define __BSP_315M_H__
#include "stm32f10x.h"
#include "delay.h"
#include "usart.h"
#ifdef __cplusplus
extern "C" {
#endif
void EV1527_Init(void);
void TIM1_NVIC_Init(void);
void TIM1_Mode_Init(void);
void TIM1_UP_IRQHandler(void);
uint32_t GetAddr_315M(void); //获取设备地址
uint8_t GetKey_315M(void); //获取1527M按键号
void Rst_rf_data(void); //调用GetKey_315M()函数后将rf_data置为零
#ifdef __cplusplus
}
#endif
#endif
BSP_315M.c
#include "BSP_315M.h"
//*******************数据定义区*********************************//
uint8_t RF;//接口电平
uint8_t a_code1, a_code2, a_code3; //第一次遥控编码
uint8_t rf_ok1;//第一次遥控编码赋值成功
uint8_t b_code1, b_code2, b_code3; //第二次遥控编码
uint8_t rf_ok2;//第二次遥控编码赋值成功
uint8_t t_code1, t_code2, t_code3; //临时遥控编码
uint8_t last_state;//上一个编码,0为低,1为高
uint8_t hh_w,ll_w;//高低电平宽度
uint8_t flag_syn;//同步码标志位,置1表示已经收到同步码,置0表示未收到同步码
uint8_t rf_data[3]; //最后收到的遥控编码
uint8_t ma_x; //接收到第几位编码
uint16_t s; // 收到第一个码和第二个码之间不能超过s个周期
uint8_t rf_ok=1;
//*************************************************************//
void EV1527_Init() //EV1527
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStruct);
TIM1_Mode_Init();
TIM1_NVIC_Init();
}
void TIM1_NVIC_Init()
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void TIM1_Mode_Init()
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
//((1+71)/72M))*(1+89)=90us
TIM_TimeBaseStructure.TIM_Period = 89;
TIM_TimeBaseStructure.TIM_Prescaler = 71;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
TIM_ClearFlag(TIM1, TIM_FLAG_Update);
TIM_ITConfig(
TIM1,
TIM_IT_Update | TIM_IT_Trigger,
ENABLE
);
NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM1, ENABLE);
}
void TIM1_UP_IRQHandler(void)
{
if(TIM_GetITStatus(TIM1, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM1, TIM_IT_Update);
RF = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13);
//printf("%d", RF);
//接收到低电平,ll_w自加,上一状态设为低电平
if (!RF){
ll_w++;
last_state = 0;
//printf("low!\r");
}
//接收到高电平,hh_w自加
//所有的同步码最后一位,每个编码的最后一位都是由低变为高的。
else {
hh_w++;
//如果上一状态为低电平,即由低变为高的上升沿
//printf("hh_w =%d!\r\n", hh_w);
if (!last_state)
{
//printf("ll_w =%d!\r\n", ll_w);
//如果未接收到同步码,判断同步码的开始时刻
if (((hh_w>=1)&&(hh_w<=5))&&((ll_w>=90)&&(ll_w<=140))){
flag_syn = 1 ;
ma_x = 0;
t_code1=0; t_code2=0; t_code3=0; //初始化
//printf("\r\n\r\n");
}
//如果已接收到了同步码并且接到3个CLK的位0
else if ((flag_syn)&&((ll_w >= 7)&&(ll_w <= 14))){
ma_x++;
//printf("L\r\n");
//如果接收的码大于了23个
if(ma_x>23){
//rf_ok1接收未完成
if(!rf_ok1){
//第一次接收的编码标志
a_code1=t_code1;
a_code2=t_code2;
a_code3=t_code3;
// 可以解码了
rf_ok1=1;
flag_syn=0;
//计时开始
s=1000;
}
//如果rf_ok1接收成功,将数据存到第二组
else{
b_code1=t_code1;
b_code2=t_code2;
b_code3=t_code3;
rf_ok2=1;
flag_syn=0;
}
}
}
else if ((flag_syn)&&((ll_w>=2)&& (ll_w<=6))) {
//printf("H\r\n");
switch (ma_x)
{
case 0 : { t_code1=t_code1 | 0x80; break;}
case 1 : { t_code1=t_code1 | 0x40;break; }
case 2 : { t_code1=t_code1 | 0x20;break; }
case 3 : { t_code1=t_code1 | 0x10;break; }
case 4 : { t_code1=t_code1 | 0x08;break; }
case 5 : { t_code1=t_code1 | 0x04;break; }
case 6 : { t_code1=t_code1 | 0x02;break; }
case 7 : { t_code1=t_code1 | 0x01;break; }
case 8 : { t_code2=t_code2 | 0x80;break; }
case 9 : { t_code2=t_code2 | 0x40;break; }
case 10: { t_code2=t_code2 | 0x20;break; }
case 11: { t_code2=t_code2 | 0x10;break; }
case 12: { t_code2=t_code2 | 0x08;break; }
case 13: { t_code2=t_code2 | 0x04;break; }
case 14: { t_code2=t_code2 | 0x02;break; }
case 15: { t_code2=t_code2 | 0x01;break; }
case 16: { t_code3=t_code3 | 0x80;break; }
case 17: { t_code3=t_code3 | 0x40; break; }
case 18: { t_code3=t_code3 | 0x20;break; }
case 19: { t_code3=t_code3 | 0x10;break; }
case 20: { t_code3=t_code3 | 0x08;break; }
case 21: { t_code3=t_code3 | 0x04;break; }
case 22: { t_code3=t_code3 | 0x02;break; }
case 23: { t_code3=t_code3 | 0x01;
if(!rf_ok1)
{
a_code3=t_code3;
a_code2=t_code2;
s=100;
}
else
{
b_code3=t_code3;
b_code2=t_code2;
b_code1=t_code1;
}
flag_syn=0;
break;
}
}
ma_x++;
}
else{ ma_x=0; flag_syn=0;t_code3=0;t_code2=0; t_code1=0;ll_w=0; }
ll_w=0;hh_w=1;
}
last_state=1;
//printf("ma_x = %d", ma_x);
}
if(rf_ok1)
{
//printf("ok1\r\n");
s--;
if(!s) rf_ok1=0;
if(rf_ok2) {
if((a_code1==b_code1)&&(a_code2==b_code2)&&(a_code3==b_code3)){
rf_ok=1;
rf_ok1=0;
rf_ok2=0;
}
else{
rf_ok=0;
rf_ok1=0;
rf_ok2=0;
}
}
}
if((rf_ok))
{ //printf("ok2\r\n");
TIM_ITConfig(TIM1, TIM_IT_Update, DISABLE);
rf_ok=0;
rf_data[0]=a_code1;
rf_data[1]=a_code2;
rf_data[2]=a_code3;
//printf("rf_data[2] =%d\r\n",rf_data[2]);
TIM_ITConfig(TIM1 , TIM_IT_Update, ENABLE);
}
}
}
uint32_t GetAddr_315M(){
uint32_t result = ((rf_data[0] << 16) + (rf_data[1] << 8) + (rf_data[2] & 0xF0) )>> 4;
//printf("%d\r\n",result);
return result;
}
uint8_t GetKey_315M(){
uint8_t result = (rf_data[2] & 0x0F);
//printf("result = %d\r\n",result);
return result;
}
void Rst_rf_data(){
rf_data[2]= 0x00;
}
mian.c
#include "BSP_315M.h"
int main(void)
{
SystemInit();//系统初始化
delay_init(72); //延时初始化
EV1527_Init();
while(1)
{
tmp = GetKey_315M();
if(tmp == 0x08){
//定义你自己的按键A函数
Rst_rf_data();
}
if(tmp == 0x04){
//定义你自己的按键B函数
Rst_rf_data();
}
if(tmp == 0x02){
//定义你自己的按键C函数
Rst_rf_data();
}
}
}