本篇博文最后修改时间:2017年04月04日,12:48。
一、简介
本文介绍如何在STM32上使用红外接收头接收红外信号。
其中,红外协议采用为最常见的NEC协议。
二、实验平台
库版本:STM32F10x_StdPeriph_Lib_V3.5.0
编译软件:MDK4.53
硬件平台:STM32开发板(主芯片stm32f103c8t6)
仿真器:JLINK
三、版权声明
博主:甜甜的大香瓜
声明:喝水不忘挖井人,转载请注明出处。
原文地址:http://blog.csdn.NET/feilusia
联系方式:[email protected]
香瓜BLE之CC2541群:127442605
香瓜BLE之CC2640群:557278427
香瓜BLE之Android群:541462902
1、硬件原理
答:
1)接收管元器件
上图的引脚从左到右依次为:OUT(空闲时为高电平,接收到载波时为低电平)、GND、VCC。
电压范围为2.7V~5.5V。
附淘宝链接:
https://detail.tmall.com/item.htm?spm=a1z10.3-b.w4011-3079905380.37.ZS9LXo&id=14265901312&rn=9fa50b1d19ad40efa6f149c454e32cfa&abbucket=14
2)硬件原理图
如上图,红外接收引脚接到PB3,PB3为JTAG使用引脚,因此在代码中要注意将引脚功能切换回普通IO口。
2、本文中红外接收的流程是如何的?
答:
1)配置红外接收引脚PB3为IO上拉中断方式。
2)当红外接收头接收到红外遥控器发出的载波信号时,PB3被拉低,代码进入中断服务函数,并依次判断时序是否满足:引导码、用户码、用户反码、键码、键码反码、停止位。
如果时序正确,则获得键值。如果时序不正确,则将此数据过滤。
六、实验步骤
注:下面的步骤为主要步骤,并不是所有步骤,编译有错误的地方请自行修改。
1、编写并添加红外接收的驱动
1)编写驱动GUA_Infrared_Receiver.c(存放在“……\HARDWARE”)
//******************************************************************************
//name: GUA_Infrared_Receiver.c
//introduce: 红外传感器接收驱动
//author: 甜甜的大香瓜
//email: [email protected]
//QQ group 香瓜单片机之STM8/STM32(164311667)
//changetime: 2016.12.29
//******************************************************************************
#include "stm32f10x.h"
#include "GUA_Infrared_Receiver.h"
#include "GUA_SysTick.h"
/*********************宏定义************************/
#define TRUE 0
#define FALSE 1
//红外接收引脚
//IO
#define GUA_INFRARED_RECEIVER_PORT GPIOB
#define GUA_INFRARED_RECEIVER_PIN GPIO_Pin_3
#define GUA_INFRARED_RECEIVER_RCC RCC_APB2Periph_GPIOB
//中断
#define GUA_INFRARED_RECEIVER_EXTI_LINE EXTI_Line3
#define GUA_INFRARED_RECEIVER_PORTSOURCE GPIO_PortSourceGPIOB
#define GUA_INFRARED_RECEIVER_PINSOURCE GPIO_PinSource3
/*********************外部变量************************/
GUA_U32 gGUA_InfraredReceiver_Data = 0;
/*********************内部函数************************/
static void GUA_Infrared_Receiver_IO_Init(void);
static GUA_U16 GUA_Infrared_Receiver_GetHighLevelTime(void);
static GUA_U16 GUA_Infrared_Receiver_GetLowLevelTime(void);
//******************************************************************************
//name: GUA_Infrared_Receiver_IO_Init
//introduce: 红外接收的IO初始化
//parameter: none
//return: none
//author: 甜甜的大香瓜
//email: [email protected]
//QQ group 香瓜单片机之STM8/STM32(164311667)
//changetime: 2016.12.29
//******************************************************************************
static void GUA_Infrared_Receiver_IO_Init(void)
{
//IO结构体
GPIO_InitTypeDef GPIO_InitStructure;
//失能JTAG和SWD在PB3上的功能使用
GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable, ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
//时钟使能
RCC_APB2PeriphClockCmd(GUA_INFRARED_RECEIVER_RCC | RCC_APB2Periph_AFIO, ENABLE);
//红外接收IO配置
GPIO_InitStructure.GPIO_Pin = GUA_INFRARED_RECEIVER_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GUA_INFRARED_RECEIVER_PORT, &GPIO_InitStructure);
}
//******************************************************************************
//name: GUA_Infrared_Receiver_Exti_Init
//introduce: 红外接收的IO中断初始化
//parameter: none
//return: none
//author: 甜甜的大香瓜
//email: [email protected]
//QQ group 香瓜单片机之STM8/STM32(164311667)
//changetime: 2016.12.29
//******************************************************************************
static void GUA_Infrared_Receiver_Exti_Init(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
//中断配置
EXTI_ClearITPendingBit(GUA_INFRARED_RECEIVER_EXTI_LINE);
GPIO_EXTILineConfig(GUA_INFRARED_RECEIVER_PORTSOURCE, GUA_INFRARED_RECEIVER_PINSOURCE);
EXTI_InitStructure.EXTI_Line = GUA_INFRARED_RECEIVER_EXTI_LINE;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
}
//******************************************************************************
//name: GUA_Infrared_Receiver_Init
//introduce: 红外接收初始化
//parameter: none
//return: none
//author: 甜甜的大香瓜
//email: [email protected]
//QQ group 香瓜单片机之STM8/STM32(164311667)
//changetime: 2016.12.29
//******************************************************************************
void GUA_Infrared_Receiver_Init(void)
{
//初始化IO
GUA_Infrared_Receiver_IO_Init();
//初始化中断配置
GUA_Infrared_Receiver_Exti_Init();
}
//******************************************************************************
//name: GUA_Infrared_Receiver_GetHighLevelTime
//introduce: 红外接收获取高电平维持时间
//parameter: none
//return: nNum:返回20us的个数
//author: 甜甜的大香瓜
//email: [email protected]
//QQ group 香瓜单片机之STM8/STM32(164311667)
//changetime: 2016.12.29
//******************************************************************************
static GUA_U16 GUA_Infrared_Receiver_GetHighLevelTime(void)
{
GUA_U16 nGUA_Num = 0;
//判断是否一直为高电平
while(GPIO_ReadInputDataBit(GUA_INFRARED_RECEIVER_PORT, GUA_INFRARED_RECEIVER_PIN) == Bit_SET)
{
//超时超时溢出
if(nGUA_Num >= 250)
{
return nGUA_Num;
}
//计延时20us的次数
nGUA_Num++;
//延时
GUA_Delay_Us(17);
}
return nGUA_Num;
}
//******************************************************************************
//name: GUA_Infrared_Receiver_GetLowLevelTime
//introduce: 红外接收获取低电平维持时间
//parameter: none
//return: nNum:返回20us的个数
//author: 甜甜的大香瓜
//email: [email protected]
//QQ group 香瓜单片机之STM8/STM32(164311667)
//changetime: 2016.12.29
//******************************************************************************
static GUA_U16 GUA_Infrared_Receiver_GetLowLevelTime(void)
{
GUA_U16 nGUA_Num = 0;
//判断是否一直为低电平
while(GPIO_ReadInputDataBit(GUA_INFRARED_RECEIVER_PORT, GUA_INFRARED_RECEIVER_PIN) == Bit_RESET)
{
//超时超时溢出
if(nGUA_Num >= 500)
{
return nGUA_Num;
}
//计延时20us的次数
nGUA_Num++;
//延时
GUA_Delay_Us(17);
}
return nGUA_Num;
}
//******************************************************************************
//name: GUA_Infrared_Receiver_Process
//introduce: 红外接收的处理函数
//parameter: none
//return: GUA_INFRARED_RECEIVER_OK or GUA_INFRARED_RECEIVER_ERROR
//author: 甜甜的大香瓜
//email: [email protected]
//QQ group 香瓜单片机之STM8/STM32(164311667)
//changetime: 2016.12.29
//******************************************************************************
GUA_U8 GUA_Infrared_Receiver_Process(void)
{
GUA_U16 nGUA_Time_Num = 0;
GUA_U8 nGUA_Data = 0;
GUA_U8 nGUA_Byte_Num = 0;
GUA_U8 nGUA_Bit_Num = 0;
//接收引导码9ms的低电平,过滤无用信号>10ms或<8ms
nGUA_Time_Num = GUA_Infrared_Receiver_GetLowLevelTime();
if((nGUA_Time_Num >= 500) || (nGUA_Time_Num <= 400))
{
return GUA_INFRARED_RECEIVER_ERROR;
}
//接收引导码4.5ms的高电平,过滤无用信号>5ms或<4ms
nGUA_Time_Num = GUA_Infrared_Receiver_GetHighLevelTime();
if((nGUA_Time_Num >= 250) || (nGUA_Time_Num <= 200))
{
return GUA_INFRARED_RECEIVER_ERROR;
}
//接收后4字节数据
for(nGUA_Byte_Num = 0; nGUA_Byte_Num < 4; nGUA_Byte_Num++)
{
//接收每字节8位数据
for(nGUA_Bit_Num = 0; nGUA_Bit_Num < 8; nGUA_Bit_Num++)
{
//接收每bit的前0.56ms的低电平,过滤无用信号>1.2ms或<0.40ms
nGUA_Time_Num = GUA_Infrared_Receiver_GetLowLevelTime();
if((nGUA_Time_Num >= 60) || (nGUA_Time_Num <= 20))
{
return GUA_INFRARED_RECEIVER_ERROR;
}
//接收每bit的后高电平时长:高电平数据,1.68ms(1.2ms~2.0ms),低电平数据,0.56ms(0.2ms~1ms),过滤其他无用信号
nGUA_Time_Num = GUA_Infrared_Receiver_GetHighLevelTime();
if((nGUA_Time_Num >=60) && (nGUA_Time_Num < 100))
{
nGUA_Data = 1;
}
else if((nGUA_Time_Num >=10) && (nGUA_Time_Num < 50))
{
nGUA_Data = 0;
}
else
{
return GUA_INFRARED_RECEIVER_ERROR;
}
//保存数据
gGUA_InfraredReceiver_Data <<= 1;
gGUA_InfraredReceiver_Data |= nGUA_Data;
}
}
return GUA_INFRARED_RECEIVER_OK;
}
2)编写驱动头文件GUA_Infrared_Receiver.h(存放在“……\HARDWARE”)
//******************************************************************************
//name: GUA_Infrared_Receiver.h
//introduce: 红外传感器接收驱动的头文件
//author: 甜甜的大香瓜
//email: [email protected]
//QQ group 香瓜单片机之STM8/STM32(164311667)
//changetime: 2016.12.29
//******************************************************************************
#ifndef _GUA_INFRARED_RECEIVER_H_
#define _GUA_INFRARED_RECEIVER_H_
/*********************宏定义************************/
#ifndef GUA_U8
typedef unsigned char GUA_U8;
#endif
#ifndef GUA_8
typedef signed char GUA_8;
#endif
#ifndef GUA_U16
typedef unsigned short GUA_U16;
#endif
#ifndef GUA_16
typedef signed short GUA_16;
#endif
#ifndef GUA_U32
typedef unsigned long GUA_U32;
#endif
#ifndef GUA_32
typedef signed long GUA_32;
#endif
#ifndef GUA_U64
typedef unsigned long long GUA_U64;
#endif
#ifndef GUA_64
typedef signed long long GUA_64;
#endif
#define GUA_INFRARED_RECEIVER_OK 0
#define GUA_INFRARED_RECEIVER_ERROR 1
#define GUA_INFRARED_RECEIVER_KEY1 0x00FF00FF
#define GUA_INFRARED_RECEIVER_KEY2 0x00FF01FE
#define GUA_INFRARED_RECEIVER_KEY3 0x00FF02FD
#define GUA_INFRARED_RECEIVER_KEY4 0x00FF03FC
/*********************外部变量************************/
extern GUA_U32 gGUA_InfraredReceiver_Data;
/*********************外部函数声明************************/
extern void GUA_Infrared_Receiver_Init(void);
extern GUA_U8 GUA_Infrared_Receiver_Process(void);
#endif
由于发送端自定义了四个按键,因此香瓜在这里将这四个按键键值写在这里,此处可自行修改。
3)工程中添加GUA_Infrared_Receiver.c
4)在MDK设置中添加驱动源文件路径
2、设置NVIC中断优先级(GUA_NVIC.c的GUA_NVIC_Init中)
//红外接收
GUA_NVIC_Config(NVIC_PriorityGroup_2, EXTI3_IRQn, 2, 2, ENABLE);
#include "GUA_Infrared_Receiver.h"
//******************************************************************************
//name: EXTI3_IRQHandler
//introduce: 红外接收的处理函数
//parameter: none
//return: none
//author: 甜甜的大香瓜
//email: [email protected]
//QQ group 香瓜单片机之STM8/STM32(164311667)
//changetime: 2016.11.21
//******************************************************************************
void EXTI3_IRQHandler(void)
{
//红外
if(EXTI_GetITStatus(EXTI_Line3) != RESET)
{
//接收红外数据正确
if(GUA_Infrared_Receiver_Process() == GUA_INFRARED_RECEIVER_OK)
{
function = FUNC_INFRARED_RECEIVER_EVENT;
}
//清除标志位
EXTI_ClearITPendingBit(EXTI_Line3);
}
}
4、在应用层中调用
1)添加头文件(main.c中)
#include "GUA_Infrared_Receiver.h"
//红外接收初始化
GUA_Infrared_Receiver_Init();
①写红外接收处理事件(main.c的main函数中)
//红外接收处理
case FUNC_INFRARED_RECEIVER_EVENT:
{
//键值处理
switch(gGUA_InfraredReceiver_Data)
{
//红外按键1
case GUA_INFRARED_RECEIVER_KEY1:
{
break;
}
//红外按键2
case GUA_INFRARED_RECEIVER_KEY2:
{
break;
}
//红外按键3
case GUA_INFRARED_RECEIVER_KEY3:
{
break;
}
//红外按键4
case GUA_INFRARED_RECEIVER_KEY4:
{
break;
}
//其他
default:
{
break;
}
}
//返回空闲状态
function = FUNC_IDLE_EVENT;
break;
}
//主轮询的宏
#define FUNC_IDLE_EVENT 0x00 //空闲
#define FUNC_INFRARED_RECEIVER_EVENT 0x16 //红外接收处理
七、注意事项
暂无。
八、实验结果
仿真并设置断点在红外接收处理事件中,全速运行。
当遥控器发送0x00FF00FF的键值时,代码会停止在断点处,并且gGUA_InfraredReceiver_Data的值为0x00FF00FF。