【STM32F103ZET6——库函数】11.捕获红外信号

目录

红外原理

数据码

引导码

连发码

配置捕获引脚

使能引脚时钟

配置定时器

使能定时器时钟

配置输入捕获

中断优先级分组

配置定时器4中断

定时器中断使能

使能定时器

重写定时器中断服务函数

清空定时器中断标志位

例程

例程说明

main.h

main.c

HongWai.h

HongWai.c

红外原理

红外信号的组成:引导码、地址码、地址反码、键码、键反码、连发码(可有可无)

  • 红色:引导码

  • 橙色:地址码

  • 蓝色:地址反码

  • 绿色:键码

  • 白色:键反码

  • 灰色:连发码

数据码

  • 560us的低电平+560us的高电平=数据“0”

  • 560us的低电平+1690us的高电平=数据“1”

引导码

9ms的低电平+4.5ms的高电平=引导码

连发码

9ms的低电平+2.25ms的高电平=连发码

配置捕获引脚

红外接收继续自己搭建电路,红外接收头的输出引脚必须要接到芯片的时钟引脚上

  1. 配置引脚号

  2. 配置引脚速度

  3. 配置引脚的模式

  4. 引脚初始化

void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);//初始化引脚
GPIO_InitTypeDef GPIO;

//配置PB9引脚
GPIO.GPIO_Mode=GPIO_Mode_IPD;//下拉输入
GPIO.GPIO_Pin=GPIO_Pin_9;
GPIO_Init(GPIOB,&GPIO);//初始化PA0引脚

使能引脚时钟

void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//使能PB时钟

配置定时器

根据对应的引脚定时器配置对应的定时器。

  1. 配置第一次时钟分频

  2. 配置计数模式

  3. 配置重载值

  4. 配置预分频系数

void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);

TIM_TimeBaseInitTypeDef DSQ_4;//定时器4

//定时器4配置
DSQ_4.TIM_ClockDivision=TIM_CKD_DIV1;//第一次时钟分频,不分频
DSQ_4.TIM_CounterMode=TIM_CounterMode_Up;//计数模式,向上计数模式
DSQ_4.TIM_Period=10000;//重载值,10ms溢出
DSQ_4.TIM_Prescaler=72-1;//预分频系数,不分频
TIM_TimeBaseInit(TIM4,&DSQ_4);

使能定时器时钟

void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);//使能定时器4时钟

配置输入捕获

  1. 配置捕获通道

  2. 配置输入滤波器

  3. 配置捕获方式

  4. 配置输入/捕获预分频器

  5. 配置捕获/比较选择,映射关系?

void TIM_ICInit(TIM_TypeDef *TIMx,TIM_ICInitTypeDef *TIM_ICInitStruct) ;

TIM_ICInitTypeDef BuHuo4;//捕获4

//PB9 -> TIM4_CH4,输入捕获配置
BuHuo4.TIM_Channel=TIM_Channel_4;//通道4h
BuHuo4.TIM_ICFilter=0x03;//IC1F=0111 配置输入滤波器 8个事件后产生一个输出跳变
BuHuo4.TIM_ICPolarity=TIM_ICPolarity_Rising;//上升沿捕获
BuHuo4.TIM_ICPrescaler=TIM_ICPSC_DIV1;//输入/捕获1预分频器,无预分频器
BuHuo4.TIM_ICSelection=TIM_ICSelection_DirectTI;//捕获/比较1选择,IC1映射到TI1上
TIM_ICInit(TIM4,&BuHuo4);

中断优先级分组

/*
zu_bie:
	NVIC_PriorityGroup_0
	NVIC_PriorityGroup_1
	NVIC_PriorityGroup_2
	NVIC_PriorityGroup_3
	NVIC_PriorityGroup_4
*/
void NVIC_PriorityGroupConfig(zu_bie);

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断优先级分组

配置定时器4中断

  1. 配置中断源

  2. 配置抢占优先级

  3. 配置子优先级

  4. 定时器3中断源使能

void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);//初始化中断

NVIC_InitTypeDef ZhongDuan4;//中断4

//定时器4中断配置
ZhongDuan4.NVIC_IRQChannel=TIM4_IRQn;//定时器4中断
ZhongDuan4.NVIC_IRQChannelCmd=ENABLE;
ZhongDuan4.NVIC_IRQChannelPreemptionPriority=1;//抢占优先级
ZhongDuan4.NVIC_IRQChannelSubPriority=1;//子优先级
NVIC_Init(&ZhongDuan4);

定时器中断使能

void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);

TIM_ITConfig(TIM4,TIM_IT_Update|TIM_IT_CC4,ENABLE);//允许更新中断 ,允许CC4IE捕获中断

使能定时器

void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);

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

重写定时器中断服务函数

        注意:中断服务函数的函数已经固定,重新定义相同名字的函数即可,在定义好的函数里写中断的操作,哪个串口发生中断就得重定义哪个串口中断的函数

void TIM4_IRQHandler(){//定时器4中断服务函数
    if(TIM_GetITStatus(TIM4,TIM_IT_Update)!=RESET){//获取定时器5溢出的中断标志位
        if(YinDaoMa_flag){//已经捕获到引导码
            if(DSQ_YiChu_CiShu<=13){//计算溢出次数
                DSQ_YiChu_CiShu++;
            }
            else{
                YinDaoMa_flag=0;//引导码清零,为下次捕获红外信号做准备
                BuHuo_flag=1;//记为成功捕获一次红外信号
            }
        }
    }
    if(TIM_GetITStatus(TIM4,TIM_IT_CC4)!=RESET){//发生捕获事件
        if(BuHuo_ShangShengYan_flag==0){//第一次捕获到上升沿
            TIM_OC4PolarityConfig(TIM4,TIM_OCPolarity_Low);//配置定时器4通道4的捕获极性,配置为下降沿捕获
            TIM_SetCounter(TIM4,0);//设置定时器4从0开始计数
            BuHuo_ShangShengYan_flag=1;//成功捕获到上升沿
        }
        else{//捕获到下降沿
            GaoDianPing_Time=TIM_GetCapture4(TIM4);//获取定时器4通道4的值,高电平的持续时间
            TIM_OC4PolarityConfig(TIM4,TIM_OCPolarity_High);//配置定时器4通道4的捕获极性,配置为上升沿捕获
            if(BuHuo_ShangShengYan_flag){//完成一次高电平捕获
                if(GaoDianPing_Time>4200&&GaoDianPing_Time<4700){//4500,接收到引导码
                    YinDaoMa_flag=1;
                }
                else if(YinDaoMa_flag){//接收到引导码后,进行对数据处理
                    if(GaoDianPing_Time>300&&GaoDianPing_Time<800){//560us,接收到数据0
                        data=data<<1;
                        data=data|0;
                    }
                    else if(GaoDianPing_Time>1400&&GaoDianPing_Time<1800){//1680us,接收到数据1
                        data=data<<1;
                        data=data|1;
                    }
                    else if(GaoDianPing_Time>2200&&GaoDianPing_Time<2600){//2500us,接收到连发码
                        YinDaoMa_flag=0;//引导码清零,为下次捕获红外信号做准备
                        BuHuo_flag=1;//记为成功捕获一次红外信号
                    }
                }
                BuHuo_ShangShengYan_flag=0;//清零,为下一次捕获上升沿做准备
            }
        }
    }
    TIM_ClearITPendingBit(TIM4,TIM_IT_CC4|TIM_IT_Update);//清除中断标志位
}

清空定时器中断标志位

void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);

TIM_ClearITPendingBit(TIM4,TIM_IT_CC4|TIM_IT_Update);//清除中断标志位

例程

例程说明

捕获红外信号,并进行解码

main.h

#ifndef _MAIN_H_
#define _MAIN_H_

#include "stm32f10x.h"                  // Device header
#include <string.h>
#include <stdio.h>

#include "delay.h"
#include "usart.h"
#include "HongWai.h"

#endif

main.c


#include "main.h"

u8 BuHuo_flag=0;//捕获成功标志位,0:未捕获一次成功;1:捕获1次成功
u8 BuHuo_ShangShengYan_flag=0;//捕获上升沿标志位,0:未捕获到上升沿;1:捕获到上升沿
u8 DSQ_YiChu_CiShu=0;//定时器溢出次数
u16 GaoDianPing_Time=0;//高电平时间
u8 YinDaoMa_flag=0;//引导码标志位,0:没有接收到引导码;1:接收到引导码
u32 data=0;//红外数据

int main() {
    u8 DiZhiMa=0;//地址码
    u8 DiZhiMa_FanMa=0;//地址码反码
    u8 JianMa=0;//键码
    u8 JianMa_FanMa=0;//键码反码
    delay_init();
    HongWai_Init();
    uart_init(115200);
    printf("程序开始运行!!!\n");
    while(1){
        if(BuHuo_flag){//捕获一次成功
            DiZhiMa=(u8)(data>>24);
            DiZhiMa_FanMa=(u8)((data>>16)&0xff);
            JianMa=(u8)(data>>8);
            JianMa_FanMa=(u8)data;
            printf("data:%d  ",data);
            printf("地址码:%d  ",DiZhiMa);
            printf("地址码反码:%d  ",DiZhiMa_FanMa);
            printf("键码:%d  ",JianMa);
            printf("键码反码:%d\n",JianMa_FanMa);
            if(DiZhiMa==(u8)(~DiZhiMa_FanMa)){
                printf("地址码正确!地址码为:%d\n",DiZhiMa);
            }
            else{
                printf("地址码错误!\n");
            }
            if(JianMa==(u8)(~JianMa_FanMa)){
                printf("键码正确!键码为:%d\n",JianMa);
            }
            else{
                printf("键码错误!\n");
            }
            BuHuo_flag=0;//开启下一次捕获
            data=0;//红外数据清零
            BuHuo_ShangShengYan_flag=0;
            DSQ_YiChu_CiShu=0;
            YinDaoMa_flag=0;
        }
    }
}

void TIM4_IRQHandler(){//定时器4中断服务函数
    if(TIM_GetITStatus(TIM4,TIM_IT_Update)!=RESET){//获取定时器5溢出的中断标志位
        if(YinDaoMa_flag){//已经捕获到引导码
            if(DSQ_YiChu_CiShu<=13){//计算溢出次数
                DSQ_YiChu_CiShu++;
            }
            else{
                YinDaoMa_flag=0;//引导码清零,为下次捕获红外信号做准备
                BuHuo_flag=1;//记为成功捕获一次红外信号
            }
        }
    }
    if(TIM_GetITStatus(TIM4,TIM_IT_CC4)!=RESET){//发生捕获事件
        if(BuHuo_ShangShengYan_flag==0){//第一次捕获到上升沿
            TIM_OC4PolarityConfig(TIM4,TIM_OCPolarity_Low);//配置定时器4通道4的捕获极性,配置为下降沿捕获
            TIM_SetCounter(TIM4,0);//设置定时器4从0开始计数
            BuHuo_ShangShengYan_flag=1;//成功捕获到上升沿
        }
        else{//捕获到下降沿
            GaoDianPing_Time=TIM_GetCapture4(TIM4);//获取定时器4通道4的值,高电平的持续时间
            TIM_OC4PolarityConfig(TIM4,TIM_OCPolarity_High);//配置定时器4通道4的捕获极性,配置为上升沿捕获
            if(BuHuo_ShangShengYan_flag){//完成一次高电平捕获
                if(GaoDianPing_Time>4200&&GaoDianPing_Time<4700){//4500,接收到引导码
                    YinDaoMa_flag=1;
                }
                else if(YinDaoMa_flag){//接收到引导码后,进行对数据处理
                    if(GaoDianPing_Time>300&&GaoDianPing_Time<800){//560us,接收到数据0
                        data=data<<1;
                        data=data|0;
                    }
                    else if(GaoDianPing_Time>1400&&GaoDianPing_Time<1800){//1680us,接收到数据1
                        data=data<<1;
                        data=data|1;
                    }
                    else if(GaoDianPing_Time>2200&&GaoDianPing_Time<2600){//2500us,接收到连发码
                        YinDaoMa_flag=0;//引导码清零,为下次捕获红外信号做准备
                        BuHuo_flag=1;//记为成功捕获一次红外信号
                    }
                }
                BuHuo_ShangShengYan_flag=0;//清零,为下一次捕获上升沿做准备
            }
        }
    }
    TIM_ClearITPendingBit(TIM4,TIM_IT_CC4|TIM_IT_Update);//清除中断标志位
}

HongWai.h

#ifndef __HONGWAI_H_
#define __HONGWAI_H_

#include "stdio.h"
#include "sys.h"

void HongWai_Init();//红外初始化

#endif

HongWai.c

//PB9 -> TIM4_CH4

#include "HongWai.h"

void HongWai_Init(){
    TIM_TimeBaseInitTypeDef DSQ_4;//定时器4
    TIM_ICInitTypeDef BuHuo4;//捕获4
    NVIC_InitTypeDef ZhongDuan4;//中断4
    GPIO_InitTypeDef GPIO;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);//使能定时器4时钟
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断优先级分组
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//使能PB时钟

    //定时器4配置
    DSQ_4.TIM_ClockDivision=TIM_CKD_DIV1;//第一次时钟分频,不分频
    DSQ_4.TIM_CounterMode=TIM_CounterMode_Up;//计数模式,向上计数模式
    DSQ_4.TIM_Period=10000;//重载值,10ms溢出
    DSQ_4.TIM_Prescaler=72-1;//预分频系数,不分频
    TIM_TimeBaseInit(TIM4,&DSQ_4);

    //PB9 -> TIM4_CH4,输入捕获配置
    BuHuo4.TIM_Channel=TIM_Channel_4;//通道4
    BuHuo4.TIM_ICFilter=0x03;//IC1F=0111 配置输入滤波器 8个事件后产生一个输出跳变
    BuHuo4.TIM_ICPolarity=TIM_ICPolarity_Rising;//上升沿捕获
    BuHuo4.TIM_ICPrescaler=TIM_ICPSC_DIV1;//输入/捕获1预分频器,无预分频器
    BuHuo4.TIM_ICSelection=TIM_ICSelection_DirectTI;//捕获/比较1选择,IC1映射到TI1上
    TIM_ICInit(TIM4,&BuHuo4);

    TIM_ITConfig(TIM4,TIM_IT_Update|TIM_IT_CC4,ENABLE);//允许更新中断 ,允许CC4IE捕获中断

    //定时器4中断配置
    ZhongDuan4.NVIC_IRQChannel=TIM4_IRQn;//定时器4中断
    ZhongDuan4.NVIC_IRQChannelCmd=ENABLE;
    ZhongDuan4.NVIC_IRQChannelPreemptionPriority=1;//抢占优先级
    ZhongDuan4.NVIC_IRQChannelSubPriority=1;//子优先级
    NVIC_Init(&ZhongDuan4);

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

    //配置PB9引脚
    GPIO.GPIO_Mode=GPIO_Mode_IPD;//下拉输入
    GPIO.GPIO_Pin=GPIO_Pin_9;
    GPIO_Init(GPIOB,&GPIO);//初始化PA0引脚
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

因心,三人水

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值