STM32F4驱动NEC协议的红外接收头

发布者:DataExplorer最新更新时间:2019-06-29 来源: eefocus关键字:STM32F4  NEC协议  红外接收头 手机看文章 扫描二维码
随时随地手机看文章

    红外遥控是一种无线、非接触式控制技术,具有抗干扰能力强、传输可靠、价格便宜、功耗低、易实现等优点。被很多的家用电器所采用。目前常用的红外遥控器协议有NEC协议(PWM脉冲宽度调制)、Philips RC5协议(PPM脉冲位置调制)。红外遥控分为发射端与接收端,发射端是以调制的方式发射数据,就是把数据和一定频率的载波进行“与操作”。调制载波频率一般为30KHz到60KHz之间。


    NEC协议的特点:8位地址和8位命令长度


                               为提高可靠性每次传输有地址码、地址码反码,键码、键码反码等用来检验


                                通过脉冲之间的时间间隔来实现信号的调制


                                38KHz载波频率


                                逻辑0的周期为1.12ms,逻辑1的周期为2.25ms


     

      NOTE:一个逻辑1传输需要2.25ms(560us脉冲+1680us低电平),一个逻辑0传输需要1.125ms(560us脉冲+560us低电平),而遥控接收头在收到脉冲的时候为低电平,在没有脉冲的时候为高电平,这样我们在接收头接收到的信号为:逻辑1(560us的低电平+1680us高电平),逻辑0(560us低电平+560us高电平)。


   

        NOTE:上图为NEC协议的数据格式:引导码、地址码(用户码)、地址反码(用户反码)、键码、键码反码。引导码由9ms高电平+4.5ms低电平组成。数据按照低位在前,高位在后的顺序发送,反码的作用就是用来校验数据的准确性。如果一帧数据发送完毕后,还没有松开按键,则遥控器发送重复码,不会再发送引导码、地址码、键码了。(重复码由9ms低电平+2.5ms高电平+0.56ms低电平+97.94ms高电平组成)。如果接收到重复码,可以使用一个变量来计算按键按下的次数。


         了解到这些俺们就可以用STM32来驱动红外接收头了,通过使用STM32的输入捕获功能来测量高电平的脉宽,从而来判断遥控器发送过来的数据。以下是硬件连接图:



   接下来就来看看我们的软件部分:                                                                                                                                  


       首先我们先初始化GPIO、定时器、捕获、NVIC中断优先级等功能:一定要记得将GPIO设置为复用映射模式


/*==========================================================================


 #

 # 函 数 名:void Remote_Init(void)

 # 功能描述:初始化红外遥控所使用到的GPIO和外设

 # 输入参数:无

 # 输出参数:无

 # 返 回 值:无

 # 说    明:用到多少个中断源就需要初始化多少个NVIC

 #

==========================================================================*/

void Remote_Init(void)

GPIO_InitTypeDef GPIO_InitStruct;

TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;

TIM_ICInitTypeDef TIM_ICInitStruct;

NVIC_InitTypeDef NVIC_InitStruct;

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);


GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_8;

GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_AF; //复用模式

GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;  //推挽输出

GPIO_InitStruct.GPIO_PuPd  = GPIO_PuPd_UP; //上拉

GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;

GPIO_Init(GPIOA, &GPIO_InitStruct);

GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_TIM1); //将PA8映射到TIM1

TIM_TimeBaseInitStruct.TIM_Prescaler = 167; //预分频系数

TIM_TimeBaseInitStruct.TIM_Period    = 10000; //预装载值

TIM_TimeBaseInitStruct.TIM_CounterMode   = TIM_CounterMode_Up; //向上计数模式

TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; //不分频

TIM_TimeBaseInit(TIM1, &TIM_TimeBaseInitStruct);

TIM_ICInitStruct.TIM_Channel  = TIM_Channel_1;

TIM_ICInitStruct.TIM_ICFilter = 0x03; //IC1F=0003 8个定时器时钟周期滤波,连续采集8次都是高电平才有效

TIM_ICInitStruct.TIM_ICPolarity  = TIM_ICPolarity_Rising;

TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入不分频

TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上

TIM_ICInit(TIM1, &TIM_ICInitStruct);

TIM_ITConfig(TIM1, TIM_IT_Update | TIM_IT_CC1, ENABLE); //使能定时器溢出和捕获中断

TIM_Cmd(TIM1, ENABLE); //使能定时器

NVIC_InitStruct.NVIC_IRQChannel = TIM1_CC_IRQn; 

NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;

NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;

NVIC_InitStruct.NVIC_IRQChannelSubPriority =3;

NVIC_Init(&NVIC_InitStruct);

NVIC_InitStruct.NVIC_IRQChannel = TIM1_UP_TIM10_IRQn;

NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;

NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;

NVIC_InitStruct.NVIC_IRQChannelSubPriority =2;

NVIC_Init(&NVIC_InitStruct);


      初始化有关外设之后,我们就可以在捕获中断里面获取高电平的脉宽了,通过获取高电平持续的时间从而来判断发送过来的是引导码还是重复码以及用户码、键码的信息。在捕获到高电平后要马上设置为低电平捕获并清空计数器,在捕获到低电平后读取计数器的值然后设置为高电平捕获。注意:我们只需要捕获高电平持续的时间就可以了,低电平持续的时间则忽略。


//RmtStatu按键信息的标志位:[7]:引导码标志位,[6]:获取按键的所有信息标志位,

//[5]:保留,[4]:捕获到高电平标志位,[3:0]:定时器溢出的次数

u8 RmtStatu =0;   

u32 RmtSDA =0; //按键的地址码、键码

u16 RmtTime =0; //高电平持续时间

u8 RmtCnt =0; //按键连按的次数

/*==========================================================================

 #

 # 函 数 名:void TIM1_CC_IRQHandler(void) 

 # 功能描述:捕获中断服务函数,通过捕获到高电平的时间来得到按键引导码、地址码、键码、重复码等

 # 输入参数:无

 # 输出参数:无

 # 返 回 值:无

 # 说    明:无

 #

==========================================================================*/

void TIM1_CC_IRQHandler(void)

{

  if(TIM_GetITStatus(TIM1, TIM_IT_CC1) == SET)

if(REMOTE_IN)

TIM_OC1PolarityConfig(TIM1, TIM_OCPolarity_Low); //设置为低电平捕获

TIM_SetCounter(TIM1,0); //清空计数器

RmtStatu |=0x10;   //标记已经捕获到高电平

else 

{

RmtTime = TIM_GetCapture1(TIM1);  //完成一次捕获,获取高电平持续的时间

TIM_OC1PolarityConfig(TIM1, TIM_OCPolarity_High); //设置为高电平捕获

if(RmtStatu & 0x10)

{  

if(RmtStatu & 0x80)

{

if(RmtTime >300 && RmtTime <800)   //逻辑0,560us高电平

{

RmtSDA <<=1;

RmtSDA |=0;

}else if(RmtTime >1400 && RmtTime <1800) //逻辑1,1680us高电平

{

RmtSDA <<=1;

RmtSDA |=1;

}else if(RmtTime >2300 && RmtTime <2700) //重复码,2500us高电平

{

RmtCnt++;   //重复码,计算按键按下的次数

RmtStatu &=0xF0;

}

}

else if(RmtTime >4300 && RmtTime <4700) //引导码,4500us高电平

//printf("rn接收到引导码rn");

RmtStatu |=1<<7; //接收到引导码

RmtCnt =0; 

}

}

RmtStatu &= ~(1<<4); //清除捕获到高电平标志

}

}

TIM_ClearITPendingBit(TIM1,TIM_IT_CC1);

}


/*=========================================================================

 #

 # 函 数 名:void TIM1_UP_TIM10_IRQHandler(void) 

 # 功能描述:定时器中断服务函数,在中断里面判断是否完成按键信息的采集,每10ms溢出

 # 输入参数:无

 # 输出参数:无

 # 返 回 值:无

 # 说    明:在获取按键信息的的过程中不会产生计数器溢出中断,因为我们在捕获到高电平后都将计数器清0

 #

==========================================================================*/

void TIM1_UP_TIM10_IRQHandler(void)

{

if(TIM_GetITStatus(TIM1,TIM_IT_Update) == SET) 

if(RmtStatu & 0x80)

RmtStatu &= ~0x10;     //清除捕获到高电平标志

if((RmtStatu & 0x0f) == 0x00) RmtStatu |= 1<<6;    //如果是第一次进入中断就标记完成按键信息的采集

    if((RmtStatu & 0x0f) <14) RmtStatu ++;

else 

{

RmtStatu &= ~(1<<7); //清除引导标识

RmtStatu &= 0xf0;  //清空计数器

}

  }

 }

  TIM_ClearITPendingBit(TIM1,TIM_IT_Update);

}


/*==========================================================================

 #

 # 函 数 名:u8 Remote_Scan(void)

 # 功能描述:如果已经获取到了按键的全部信息,就校验地址码、地址反码和键码、键码反码,如果比

 # 对成功就返回键值,否则就认为没有按键按下

 # 输入参数:无

 # 输出参数:无

 # 返 回 值:KeyValue:0,没有按键按下

 # 其他,按键的键值

 # 说    明:无

 #

==========================================================================*/

u8 Remote_Scan(void)

u8 KeyValue =0;

u8 t1,t2;

if(RmtStatu & (1<<6))  //判断是否已经获取到了按键全部的信息

t1= RmtSDA >>24;

t2= RmtSDA >>16;

printf("%drn",t1);  //打印用户码、用户码反码到串口助手显示

printf("%drn",t2);

if(t1 == (u8)~t2) 

//printf("rn地址码比对正确rn");

t1 =RmtSDA >>8;

t2 =RmtSDA;

printf("%drn",t1); //打印键码、键码反码到串口助手显示

printf("%drn",t2);

if(t1 ==(u8)~t2) 

{

KeyValue = t1; 

//printf("rn键码比对正确rn");

}

}

if((KeyValue == 0) || ((RmtStatu & 0x80)==0))  //没有按键按下时

{

RmtStatu &= ~(1<<6); //清除按键全部信息标识

RmtCnt =0;

RmtSDA =0;

}

 }

 return KeyValue;


}


       在调试程序的过程中,由于是新建的工程,忘记了把System_stm32f4xx.c文件里的PLL第一级分频系数M修改为8(#define PLL_M 8)和stm32f4.h里面的外部时钟HSE_VALUE值修改为8MHz(#define HSE_VALUE((uint_32_t)8000000))了,导致捕获高电平脉宽的时候,计时器的值不准确,从而导致获取的信息不正确,在调了一上午之后才找出问题,心情是既高兴又坎坷啊,竟然犯了这么傻逼的错误。还有这是哥第一次写博客,感觉很新鲜、很好玩,也有很多不足之处,在以后写的时候会好好改正。希望能通过这种操作来加深一下记忆,分享下写程序过程中遇到的快乐&难题。


关键字:STM32F4  NEC协议  红外接收头 引用地址:STM32F4驱动NEC协议的红外接收头

上一篇:STC51入门笔记 第十一节:使用DS12C887时钟芯片设计高精度时钟
下一篇:STM32学习之路(七---红外遥控)

推荐阅读最新更新时间:2024-11-04 20:21

STM32F40xxx 与 STM32F41xxx Flash结构详解
硬件平台:STM32F4 DISCOVERY开发板 型号:MB997A或MB997C 主芯片型号:STM32F405xx, STM32F407xx, STM32F415xx, 或 STM32F417xx 主要参考文档: (1)PM0081 STM32F40xxx and STM32F41xxx Flash programming manual.pdf (2)STM32F407 datasheet.pdf 做为嵌入式方面的开发人员,拿到一个芯片后,我们首先看它的参数指标,有多少多少容量的RAM,多少多少容量的Flash。当然,前提是芯片自带这两个模块。 今天我们只研究Flash的结构:) (一)声明 STM32F405xx
[单片机]
<font color='red'>STM32F4</font>0xxx 与 <font color='red'>STM32F4</font>1xxx Flash结构详解
STM32F407多通道ADC采样程序
注意STM32F407在进行AD采样时,如果引脚是浮空的,这个时候采集到的电压并不是0 1 ADC引脚的初始化 void Lsens_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE); //使能GPIOF时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6; GPIO_InitStructure.GPIO_Mode = GP
[单片机]
<font color='red'>STM32F4</font>07多通道ADC采样程序
第14章 STM32F429的电源,复位和时钟系统
14.1 初学者重要提示 电源管理部分涉及到的各种低功耗方式会在后面章节中为大家讲解,当前阶段仅需了解低功耗属于电源管理部分即可。 14.2 电源 电源是系统稳定运行的根本,主要分为以下几个知识点,电源供电、供电监控、电源管理和低功耗。当前阶段主要了解电源供电和硬件上电时序。 14.2.1 电源供电 学习STM32F429的电源供电,往往被一堆电源标识Vdd,Vdda,Vcap,Vss等搞迷糊,这些标识整明白了,电源供电部分也就理解了,首先看下面的框图: 这些常用标识的解释如下: 对于电源供电部分了解了这些知识点就够用。 14.2.2 电源去耦电容的选择 每个电源对 (VDD/VSS, VDDA/VSSA ..
[单片机]
第14章 <font color='red'>STM32F4</font>29的电源,复位和时钟系统
STM32F429芯片带FIFO的DMA传输实现过程
STM32系列芯片都内置DMA外设,其中很多系列的DMA配备了FIFO。这里以STM32F429芯片及开发板为例,演示一下带FIFO的DMA传输实现过程。 大致情况是这样的,我用TIMER1通道1的比较事件触发DMA,将内存数据写进UART5的数据发送寄存器DR,并将UART5的TX/RX脚物理短接,同时开启UART5的DMA接收模式,即DMA将UART5接收到的数据写到指定的接收内存区。下面重点介绍UART5的DMA方式的接收过程。 首先使用STM32CubeMx完成基本配置。 下面是关于TIM1的相关配置,使用通道1的比较事件触发DMA,将内存数据写入UART的发送数据寄存器。为什么还要搞个定时器来触发,其中一个原因是
[单片机]
<font color='red'>STM32F4</font>29芯片带FIFO的DMA传输实现过程
STM32F407上移植emwin
环境: 主机:WIN8 开发环境:MDK5.13 emwin版本:STemWinLibrary522 mcu: stm32f407VGT6 开发板:安富莱STM32-X3 TFT型号:艾蓝2.8寸TFT,主控芯片:ILI9325 说明: 在STM32F407上移植emwin,驱动屏幕接口为FSMC 移植步骤: 1.MDK新建文件结构: 2.GUIConf.c文件修改 a)增加宏定义: #define GUI_NUMBYTES (1024 * 80) #define GUI_BLOCKSIZE 0x80 b)GUI_X_Config(void)函数中增加语句
[单片机]
<font color='red'>STM32F4</font>07上移植emwin
基础——STM32F4的GPIO模式
stm32的GPIO的配置模式包括: 1. 模拟输入; 2. 浮空输入; 3. 上拉输入; 4. 下拉输入; 5. 开漏输出; 6. 推挽输出; 7. 复用开漏输出; 8. 复用推挽输出 1.模拟输入 从上图我们可以看到,我觉得模拟输入最重要的一点就是,他不经过输入数据寄存器,所以我们无法通过读取输入数据寄存器来获取模拟输入的值,我觉得这一点也是很好理解的,因为输入数据寄存器中存放的不是0就是1,而模拟输入信号不符合这一要求,所以自然不能放进输入数据寄存器。该输入模式,使我们可以获得外部的模拟信号。 2.浮空输入 该输入状态,我的理解是,它的输入完全由外部决定,我觉得在数据通信中应该可以使用该模式。应为在数
[单片机]
基础——<font color='red'>STM32F4</font>的GPIO模式
测试STM32F4 EVNETOUT
看到很多管脚都可以配置成EVENTOUT,刚好有个管脚要想要输出一个高电平脉冲,测试了一下: 环境:STM32F407, IAR 7.4, STM32CubeF4 GPIO配置代码: GPIO_InitStruct.Pin = GPIO_PIN_10; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_PULLDOWN; GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; GPIO_InitStruct.Alternate = GPIO_AF15_EVENTOUT; HAL_GPIO_Init(GPIOB
[单片机]
测试<font color='red'>STM32F4</font> EVNETOUT
STM32F429-DISCO上手,stm32cubeMX与IAR学习,中断及Printf
stm32f429及stm32f439已经带有LTDC控制器,意味着可以输出RGB888及RGB565的图像信号,这与以往的单片机CPU8080接口LCD有很大不同,也是入手STM32F429-DISCO的原因,价格不贵,mouser上不含税150,淘宝180,非常适合学习。 STM推出了一个叫STM32CUBEMX的软件,可以用来配置将要用到的模块,配置时钟树,输出源文件,相当给力。(不过貌似也有童鞋说坑,个人觉得挺好用的) 芯片选型后 配置JTAG(SWD),一个HSE(8MHz),两个GPIO_OUT,一个GPIO_IRQ(都是板子上有的东西) 配置时钟树,有问题的会自动标成红色,特别要记下的就是SYSCL
[单片机]
<font color='red'>STM32F4</font>29-DISCO上手,stm32cubeMX与IAR学习,中断及Printf
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved