【STM32F4系列】【自制库】读取并模拟遥控插座的遥控器

news/2025/3/19 13:41:51/

目录

需求分析

信号分析

载波类型寻找

信号获取

解码

思路

初始化

GPIO

外部中断

定时器

 解释

代码

发送 

思路

初始化

代码

成品


需求分析

前段时间入手了一个遥控插座,因为要在两处控制它,懒得拿着遥控器到处跑,因此萌生了复制一个遥控器的想法

信号分析

载波类型寻找

这是遥控器

可以很明显的发现,这是一个射频遥控

常用的射频遥控的载波有两种,315MHz和433MHz,而且一般使用的是ASK/OOK

即根据选定频率的信号的幅值来判断是0还是1

个人开发者买不起信号分析仪,因此我选择购买315MHz和433MHz的接收模块配合逻辑分析仪来判断是哪个频率的信号

这里推荐购买超外差接收模块,淘宝上就有,价格一般在2元左右

超外差的模块效果比超再生的好很多

本质上这些射频模块就是将据有指定频率的射频信号转换为高低电平输出

这个遥控设备使用的是433MHz的载波

信号获取

这是我接收到的信号

注意:当没有任何有效数据输入时,模块也会输出信号

这是因为在正常的空间中会存在大量的干扰,就行幻听一样

红色方块就是幻听,蓝色方块的是接收的信号 

这是信号的放大

我们可以按照这样分为两种码

因为这是厂家自定义的协议,我也不清楚应该如何正确的分

 

这个码型高电平部分多,因此认为是1码 

这个码型低电平部分多,因此认为是0码 

最后一个码字结束之后会有一个占位码

两组信号之间间隔8ms左右

解码

思路

可以看出,0码和1码的时间长度相同,都是由高电平开始,低电平结束

1码的高电平持续时间长,0码的高电平持续时间短

因此我们可以在接收到上升沿之后隔一段时间读取高低电平,比如读取上升沿后500us的电平,高为1,低为0

理论上在中断中不能占用长时间,这边给2个方案,

1.在中断中使用延迟,然后将其的中断优先级调低,比所有使用的中断低即可

2.新开一个定时器,当需要计时时打开定时器,定时器中断时回到解码函数,读取电平高低

本文选用方案1

初始化

根据上文的思路,我们需要初始化的有,GPIO,外部中断(设置为上升沿),定时器(用于计数校验)

GPIO

之前文章介绍过,传送门,需要设置为输入模式,设置为上拉浮空输入

头文件(RF_433M.h)

// GPIO
#define RF_Read_GPIO_RCC RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE)
#define RF_Read_GPIOx GPIOB
#define RF_Read_GPIO_Pin GPIO_Pin_0

C文件(RF_433M.c)

// 读取,GPIO初始化
void RF_Read_GPIO_init(void)
{GPIO_InitTypeDef GPIO_Initstruct;             //声明GPIO初始化结构体RF_Read_GPIO_RCC;                             //打开GPIO时钟GPIO_Initstruct.GPIO_Mode = GPIO_Mode_IN;     //输入模式GPIO_Initstruct.GPIO_OType = GPIO_OType_OD;   //开漏输入模式GPIO_Initstruct.GPIO_Pin = RF_Read_GPIO_Pin;  //引脚GPIO_Initstruct.GPIO_PuPd = GPIO_PuPd_UP;     //上拉模式GPIO_Initstruct.GPIO_Speed = GPIO_High_Speed; //高速模式GPIO_Init(RF_Read_GPIOx, &GPIO_Initstruct);   //初始化GPIO
}

外部中断

设置为上升沿触发,传送门,并设置较低的中断优先级

头文件(RF_433M.h)

//外部中断
#define RF_Read_EXIT_Link SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOB, EXTI_PinSource0)
#define RF_Read_EXIT_Pin EXTI_Line0
#define RF_Read_EXIT_IRQn EXTI0_IRQn
#define RF_Read_EXIT_Priority_1 3
#define RF_Read_EXIT_Priority_2 2
#define RF_Read_EXTI_IRQHandler EXTI0_IRQHandler

C文件(RF_433M.c)

//读取,外部中断初始化
void RF_Read_EXTI_init(void)
{EXTI_InitTypeDef EXTI_Initstruct;                      //创建外部中断初始化结构体RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); //打开时钟RF_Read_EXIT_Link;                                     //将GPIO与外部中断连接EXTI_Initstruct.EXTI_Line = RF_Read_EXIT_Pin;          //配置的是外部中断EXTI_Initstruct.EXTI_LineCmd = ENABLE;                 //使能EXTI_Initstruct.EXTI_Mode = EXTI_Mode_Interrupt;       //选择中断模式EXTI_Initstruct.EXTI_Trigger = EXTI_Trigger_Rising;    //上升沿模式EXTI_Init(&EXTI_Initstruct);                           //初始化外部中断
}
//读取,配置NVIC
void RF_Read_EXTI_NVIC(void)
{NVIC_InitTypeDef NVIC_Initstruct;                                            //声明NVIC初始化结构体NVIC_Initstruct.NVIC_IRQChannel = RF_Read_EXIT_IRQn;                         //配置的外部中断0NVIC_Initstruct.NVIC_IRQChannelCmd = ENABLE;                                 //使能NVIC_Initstruct.NVIC_IRQChannelPreemptionPriority = RF_Read_EXIT_Priority_1; //主优先级NVIC_Initstruct.NVIC_IRQChannelSubPriority = RF_Read_EXIT_Priority_2;        //副优先级NVIC_Init(&NVIC_Initstruct);                                                 //初始化外部中断0的NVIC
}

定时器

定时器是作为校验使用的,为方便我们将分频后的频率设置为1MHz,传送门

头文件(RF_433M.h)

//定时器
#define RF_Read_TIM_RCC RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE)
#define RF_Read_TIM_TIMx TIM3
#define RF_Read_TIM_IRQn TIM3_IRQn
#define RF_Read_TIM_Priority_1 2
#define RF_Read_TIM_Priority_2 2
#define RF_Read_TIM_IRQHandler TIM3_IRQHandler

C文件(RF_433M.c)

//读取,定时器初始化
void RF_Read_TIM_init(void)
{TIM_TimeBaseInitTypeDef TIM_Init_Struct;              //声明定时器初始化结构体NVIC_InitTypeDef NVIC_Init_Struct;                    //声明NVIC初始化结构体RF_Read_TIM_RCC;                                      //打开时钟TIM_Init_Struct.TIM_ClockDivision = TIM_CKD_DIV1;     //滤波器不分频TIM_Init_Struct.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式//每次中断触发时间=[(TIM_Period+1)*(TIM_Prescaler+1)/(SystemCoreClock)] (s)TIM_Init_Struct.TIM_Prescaler = 84 - 1;TIM_Init_Struct.TIM_Period = 0xffff - 1;TIM_Init_Struct.TIM_RepetitionCounter = 0;             //高级定时器特有,这里写0就行TIM_TimeBaseInit(RF_Read_TIM_TIMx, &TIM_Init_Struct);  //调用函数初始TIM_ITConfig(RF_Read_TIM_TIMx, TIM_IT_Update, ENABLE); //启用溢出中断NVIC_Init_Struct.NVIC_IRQChannel = RF_Read_TIM_IRQn;                         //中断名称NVIC_Init_Struct.NVIC_IRQChannelCmd = ENABLE;                                //使能NVIC_Init_Struct.NVIC_IRQChannelPreemptionPriority = RF_Read_TIM_Priority_1; //主优先级1NVIC_Init_Struct.NVIC_IRQChannelSubPriority = RF_Read_TIM_Priority_2;        //副优先级1NVIC_Init(&NVIC_Init_Struct);                                                //初始化NVICTIM_Cmd(RF_Read_TIM_TIMx, ENABLE);                                           //打开定时器
}

 解释

 因为设备会存在幻听,因此在信号发送的时候会有提前发送一段无意义的信号(也可以认为是第一个数据无效)

因此我们可以在这里进行一个延迟检测,只有大于8ms的才会送入进行解码

避免无意义的延迟

这个红色箭头是第一个码位,在前面8ms以上的位置会存在一个上升沿,大于8ms的延迟后会进入解码,

为了编程方便,我们将第一个码字和后面的码字分开进行解码

这个上升沿后延迟一段时间读取第一个码位高低

在第二个红色箭头所指上升沿,需要计算上次上升沿到此的时间做校验,之后再等待500us

后读取电平高低

重复次操作,当写满1Byte时会将其存入解码的数组中,再继续读取,直到全部读取完毕

代码

为了方便,我们将数据的长度作为宏定义

头文件(RF_433M.h)

#define RF_Rean_Len 3
extern u8 RF_READ_OK;                //解码成功标志
extern u8 RF_READ_data[RF_Rean_Len]; //接收的数据

C文件(RF_433M.c)

u8 RF_READ_OK = 0;                  //解码成功标志
u8 RF_READ_ins = 0;                 //状态指示
u8 RF_READ_i = 0;                   //循环
u8 RF_READ_j = 0;                   //循环
u32 RF_READ_time = 0;               //计算时间
u8 RF_READ_data[RF_Rean_Len] = {0}; //数据
u8 RF_READ_Zj = 0;
void RF_READ_decode(void)
{if (RF_READ_ins == 0) //初始化 检测到下降沿{TIM_SetCounter(RF_Read_TIM_TIMx, 0);RF_READ_ins = 1;}else if (RF_READ_ins == 1){RF_READ_time = TIM_GetCounter(RF_Read_TIM_TIMx);             //计算从上次电平到此时间if (RF_READ_time > 8000 - 500 && RF_READ_time < 8000 + 2000) //数据码送入前的延迟{TIM_SetCounter(RF_Read_TIM_TIMx, 0);RF_READ_ins = 2; //开始解码}else{RF_READ_ins = 0; //复位}for (int i = 0; i < RF_Rean_Len; i++)RF_READ_data[i] = 0;if (RF_READ_ins == 2) //解码第一位码{Delay_us(600);if (GPIO_ReadInputDataBit(RF_Read_GPIOx, RF_Read_GPIO_Pin) == 1){RF_READ_Zj = 1;}else if (GPIO_ReadInputDataBit(RF_Read_GPIOx, RF_Read_GPIO_Pin) == 0){RF_READ_Zj = 0;}RF_READ_j = 0;RF_READ_i = 1;}}else if (RF_READ_ins == 2) //解码后面的{RF_READ_time = TIM_GetCounter(RF_Read_TIM_TIMx); //计算时间做验证TIM_SetCounter(RF_Read_TIM_TIMx, 0);if (RF_READ_time > 1050 - 500 && RF_READ_time < 1050 + 500) // 1.05ms左右{Delay_us(600);                                                   //延迟if (GPIO_ReadInputDataBit(RF_Read_GPIOx, RF_Read_GPIO_Pin) == 1) //判断这个时刻电平高低{                                                                //低RF_READ_Zj <<= 1;RF_READ_Zj |= 0x01;}else if (GPIO_ReadInputDataBit(RF_Read_GPIOx, RF_Read_GPIO_Pin) == 0){ //高RF_READ_Zj <<= 1;RF_READ_Zj &= 0xFE;}RF_READ_i++;if (RF_READ_i >= 8) // 8位数据写完 换行{RF_READ_i = 0;RF_READ_data[RF_READ_j] = RF_READ_Zj;RF_READ_Zj = 0;RF_READ_j++;}}else{RF_READ_ins = 0;RF_READ_Zj = 0;}if (RF_READ_j >= RF_Rean_Len) // 24位数据写完 完成标志写1 复位{RF_READ_j = 0;RF_READ_i = 0;RF_READ_OK = 1;RF_READ_ins = 0;RF_READ_Zj = 0;}}
}

发送 

思路

首先发送几个前置信号,用于消除幻听,之后按数据发送高低电平即可,最后别忘记补上占位码

初始化

只需要GPIO初始化即可,上拉开漏输出

头文件(RF_433M.h)

//发送
#define RF_Send_GPIO_RCC RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE)
#define RF_Send_GPIOx GPIOA
#define RF_Send_GPIO_Pin GPIO_Pin_0

C文件(RF_433M.c)

// 发送初始化
void RF_Send_init(void)
{GPIO_InitTypeDef GPIO_Initstruct;             //声明GPIO初始化结构体RF_Send_GPIO_RCC;                             //打开GPIO时钟GPIO_Initstruct.GPIO_Mode = GPIO_Mode_OUT;    //输入模式GPIO_Initstruct.GPIO_OType = GPIO_OType_OD;   //开漏输入模式GPIO_Initstruct.GPIO_Pin = RF_Send_GPIO_Pin;  //引脚0GPIO_Initstruct.GPIO_PuPd = GPIO_PuPd_UP;     //上拉模式GPIO_Initstruct.GPIO_Speed = GPIO_High_Speed; //高速模式GPIO_Init(RF_Send_GPIOx, &GPIO_Initstruct);   //初始化GPIO
}

代码

C文件(RF_433M.c)

void RF_WRITE_send_1(void) //发1
{GPIO_SetBits(RF_Send_GPIOx, RF_Send_GPIO_Pin);Delay_us(755);GPIO_ResetBits(RF_Send_GPIOx, RF_Send_GPIO_Pin);Delay_us(305);
}
void RF_WRITE_send_0(void) //发0
{GPIO_SetBits(RF_Send_GPIOx, RF_Send_GPIO_Pin);Delay_us(305);GPIO_ResetBits(RF_Send_GPIOx, RF_Send_GPIO_Pin);Delay_us(755);
}
void RF_WRITE_send_before(void) //发送诱导波后延迟
{RF_WRITE_send_1();RF_WRITE_send_0();RF_WRITE_send_1();GPIO_ResetBits(RF_Send_GPIOx, RF_Send_GPIO_Pin);Delay_ms(8);
}
void RF_WRITE_send_after(void) //发送结束波
{GPIO_SetBits(RF_Send_GPIOx, RF_Send_GPIO_Pin);Delay_us(305);GPIO_ResetBits(RF_Send_GPIOx, RF_Send_GPIO_Pin);Delay_ms(8);
}
void RF_Send(u8 *Dat, u8 Len) //发送1次
{u8 zj;RF_WRITE_send_before();for (int i = 0; i < Len; i++){zj = Dat[i];for (int j = 0; j < 8; j++){if (zj & 0x80){RF_WRITE_send_1();}else{RF_WRITE_send_0();}zj <<= 1;}}RF_WRITE_send_after();
}

成品

GitHubhttps://github.com/HZ1213825/STM32F4_RF_Socket_Ctrl/settings

CSDNhttps://download.csdn.net/download/m0_57585228/85603025

链接:百度网盘
提取码:4g5p 

433m遥控解码和发送


http://www.ppmy.cn/news/235525.html

相关文章

学习型红外遥控器硬件结构说明

本篇文章上接&#xff1a;智能家居中红外遥控芯片分析比较 2 硬件结构 学习型红外遥控器由红外一体化接收电路、 反相器、温度传感器、AT89C52单片机、红外发送电路、E PROM存储器、键盘及 LCD显示器和数据通信模块组成&#xff0c;如图 1所示。 图 1 遥控器硬件结构框 图 (…

【测试】更新红外遥控信号读取,用示波器抓取红外遥控器NEC信号

最近群里有问红外信号采集相关问题&#xff0c;我以为他问arduino&#xff0c;原来他问米思齐&#xff0c;然后我居然忘了之前我用米思齐也试过。今天再把资料整理一下&#xff0c;备战新项目。 红外遥控器应用非常广泛&#xff0c;大部分家电都使用它来控制 &#xff0c;具有价…

红外线遥控器解码原理

红外线遥控是目前使用最广泛的一种通信和遥控手段。由于红外线遥控装置具有体积小、功耗低、功能强、成本低等特点&#xff0c;因而&#xff0c;继彩电、录像机之后&#xff0c;在录音机、音响设备、空凋机以及玩具等其它小型电器装置上也纷纷采用红外线遥控。工业设备中&#…

APM 学习 13 --- ArduPilot 遥控器 RC 发射器和接收器

英文原文地址&#xff1a; https://ardupilot.org/copter/docs/common-pixhawk-and-px4-compatible-rc-transmitter-and-receiver-systems.html#common-pixhawk-and-px4-compatible-rc-transmitter-and-receiver-systems 本文概述了可与 ArduPilot 自动驾驶仪配合使用的 RC 发…

ipone=遥控器?

苹果准备发布一款新软件平台并借此进入物联网领域&#xff0c;该平台可以让iPhone变成一台遥控器&#xff0c;控制灯具、安全系统和其他家电设备。 据知情人士透露&#xff0c;苹果将于6月2日在旧金山召开今年的全球开发者大会&#xff0c;届时它将发布其智能家居技术&#xff…

2021-2027中国绞盘遥控器市场现状及未来发展趋势

2021-2027中国绞盘遥控器市场现状及未来发展趋势 本报告研究中国市场绞盘遥控器的生产、消费及进出口情况&#xff0c;重点关注在中国市场扮演重要角色的全球及本土绞盘遥控器生产商&#xff0c;呈现这些厂商在中国市场的绞盘遥控器销量、收入、价格、毛利率、市场份额等关键指…

如何在新的Apple TV遥控器上调整触摸灵敏度

If you have recently purchased the latest Apple TV with the new touch sensitive remote, then you probably have dealt with the much-loathed text-entry method. If you’re having problems with it, then they may be alleviated by adjusting the remote’s sensiti…

树莓派c语言小车红外,用家里旧的红外遥控器控制树莓派小车

原标题:用家里旧的红外遥控器控制树莓派小车 001 前言 红外遥控是一种无线、非接触控制技术,在工业控制、航空航天、家电等领域都得到了广泛应用。大部分的电视的遥控器,空调遥控器就都是红外遥控。在baidu上检索了树莓派小车的各种控制方案,没有找到红外遥控的控制方案。所…