目录
红外原理
数据码
引导码
连发码
配置捕获引脚
使能引脚时钟
配置定时器
使能定时器时钟
配置输入捕获
中断优先级分组
配置定时器4中断
定时器中断使能
使能定时器
重写定时器中断服务函数
清空定时器中断标志位
例程
例程说明
main.h
main.c
HongWai.h
HongWai.c
红外原理
红外信号的组成:引导码、地址码、地址反码、键码、键反码、连发码(可有可无)
红色:引导码
橙色:地址码
蓝色:地址反码
绿色:键码
白色:键反码
灰色:连发码
数据码
560us的低电平+560us的高电平=数据“0”
560us的低电平+1690us的高电平=数据“1”
引导码
9ms的低电平+4.5ms的高电平=引导码
连发码
9ms的低电平+2.25ms的高电平=连发码
配置捕获引脚
红外接收继续自己搭建电路,红外接收头的输出引脚必须要接到芯片的时钟引脚上。
配置引脚号
配置引脚速度
配置引脚的模式
引脚初始化
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时钟
配置定时器
根据对应的引脚定时器配置对应的定时器。
配置第一次时钟分频
配置计数模式
配置重载值
配置预分频系数
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时钟
配置输入捕获
配置捕获通道
配置输入滤波器
配置捕获方式
配置输入/捕获预分频器
配置捕获/比较选择,映射关系?
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中断
配置中断源
配置抢占优先级
配置子优先级
定时器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引脚
}