基于STM32的利用红外收发机制的人体感应设计

因为网上资料很多,本人在这里只是记录自己学习的过程。具体内容可以参考其他大神的文章。

红外的收发其实和光耦原理差不多。发射端收到数据,发红外光,接收端收到光信号也开始导通,采集Rx信号即可知道发来的数据。电路原理图如下:

 红外解码协议有好多种:有ITT协议、NEC协议、NokiaNRC协议、Sharp协议、SonySIRC协议、PhilipSRC-5协议、PhilipsRC-6协议,等等,此处使用NEC协议。

简单介绍NEC协议;

数据1是560us的低电平,然后再1680us的高电平,周期是2.24ms。数据0是560us的低电平,然后再560us的高电平,周期是1.20ms;

引导码:9ms的低电平,然后在4.5ms的高电平。  重复发数据:9ms的低电平,然后在2.25ms的高电平

 NEC的数据格式如下:1、引导码(9+4.5ms);2、地址码;3、地址反码;4、数据码;5、数据反码;6、结束码(可以加可以不加)

 为了说明清楚,用简易的图片来描述,A之间的距离大小对应是发送0,还是发送1.(其实阴影部分的时间都是一样的,0和1取决于剩下的部分),发送和接收的电平状态是反着的。与原理图可知。接收解析时只需要关心 B的大小即可区分0还是1。即在捕获电平时只需要捕获高电平即可。

NEC原理简单介绍完了。讲下程序的工作原理。 

利用两个定时器,TIM3用来产生PWM,用来做红外的发送载波,一般用38khz, TIM5用来捕获TIM3产生的“”波形”.并从中解析收到的数据。

为什么用38khz,市面上卖的红外接收头大部分是接收38KHZ红外信号的,还有就是38KHZ的940nm波长的红外线可以很好的避免其他光的干扰。

产生38khz的方波就需要配置定时器周期为26us(f=1/T,剩下自己算,注意单位转换)。 TIM_SetCompare4(TIM3,9)//占空比1/3。

发送逻辑0和1,需要us定时器,我用的是TIM2。

void Delay_Timer_Init(void)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

	TIM_TimeBaseStructInit(&TIM_TimeBaseInitStruct);
	TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Down;
	TIM_TimeBaseInitStruct.TIM_Period = 100 - 1;
	TIM_TimeBaseInitStruct.TIM_Prescaler = (84 - 1);
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);

	while ((TIM2->SR & TIM_FLAG_Update) != SET);
	TIM2->SR = (uint16_t)~TIM_FLAG_Update;
}
void Delay_us(uint32_t us_cnt)
{
	TIM2->CNT = us_cnt - 1;
	TIM2->CR1 |= TIM_CR1_CEN;
	while ((TIM2->SR & TIM_FLAG_Update) != SET);
	TIM2->SR = (uint16_t)~TIM_FLAG_Update;
	TIM2->CR1 &= ~TIM_CR1_CEN;

}

用示波器测试过,10us有3us的误差。所以在接收载波的解析时,判断是逻辑0和1,判断高电平的时间要增大范围。

#define NO_CARRIER()	TIM_SetCompare4(TIM3,0)
#define NEC_HEAD		(u16)(4500) //引导码
#define NEC_ZERO 		(u16)(560)  //代表0
#define NEC_ONE			(u16)(1680) //代表1
#define NEC_CONTINUE 	(u16)(2500)


#define NEC_HEAD_MIN (u16)(NEC_HEAD*1.0f) //4500
#define NEC_HEAD_MAX (u16)(NEC_HEAD*1.4f) //6300

#define NEC_ZERO_MIN (u16)(NEC_ZERO*0.7f)
#define NEC_ZERO_MAX (u16)(NEC_ZERO*1.5f)

#define NEC_ONE_MIN (u16)(NEC_ONE*0.7f)
#define NEC_ONE_MAX (u16)(NEC_ONE*1.3f)

附上一张定时器配置通道和引脚分布的截图

数据解析原理:在定时器中断里面检测是否有捕获中断,(定时器初始化时候设置为上升沿触发),当捕获到上升沿时,做标记,清定时计数,然后设置为下降沿,当再次捕获到数据时,读出计数器的值。同时设置为上升沿,为下次捕获高电平做准备。计数器的值就是两次捕获到的一个高电平的时间,通过前面手绘那个图,捕获到到的高电平的时间就是B的长度,根据NEC协议,由时间长短来判断捕获到的是引导码还是逻辑0还是逻辑1.(接收到的逻辑0和1的时间和发送的相反,切记),只有在收到引导码的前提下,才能对数据的内容解析,要不然解析的也是错的。解析完数据,还要解析到结束码,如果没有解析到结束码,这个数据可能是错的,结束码是这一帧数据全部收到的标志(有点像是CRC校验和)。

如何实现人体感应。红外接收,发射分开放置,当人靠近的时候,人把发射的信号反射到接收上面去。当接收到的数据和发射的一致,说明有人靠近了。反之,没人靠近,那就不会接收到数据。

这个项目最恶心有点是,捕获中断设置的是上升沿触发,由红外的原理图可知当没收到数据的时候采集电压那个脚一直是高电平,就会一直进入中断。造成采集高电平的时间有时会出现几us的杂波。因此还需要对这个杂波进行过滤。因为这点被卡了3天,特地写下来记录下。最后送佛送到西,附上完整程序(亲测可用)就不上传了赚积分了,不道德,省的没积分的童鞋蓝瘦。

#include "IR.h"
#include "BSP_CFG.h"
#include "Setup.h"//用到延迟函数(自己写一个吧)

u8 DelayNus = 0;
#define CARRIER_38KHz() TIM_SetCompare4(TIM3,9)//设置PWM占空比.初始化周期27us。
 //第二个参数是输出PWM的高电平的时间  第4通道  PB1输出高电平9us。f=1/T= 0.0370。
 //周期转化为秒也就是37khz
#define NO_CARRIER()	TIM_SetCompare4(TIM3,0)
#define NEC_HEAD		(u16)(4500) //引导码
#define NEC_ZERO 		(u16)(560)  //代表0
#define NEC_ONE			(u16)(1680) //代表1
#define NEC_CONTINUE 	(u16)(2500)


#define NEC_HEAD_MIN (u16)(NEC_HEAD*1.0f) //4500
#define NEC_HEAD_MAX (u16)(NEC_HEAD*1.4f) //6300

#define NEC_ZERO_MIN (u16)(NEC_ZERO*0.7f)
#define NEC_ZERO_MAX (u16)(NEC_ZERO*1.5f)

#define NEC_ONE_MIN (u16)(NEC_ONE*0.7f)
#define NEC_ONE_MAX (u16)(NEC_ONE*1.3f)

#define NEC_CONTINUE_MIN (u16)(NEC_CONTINUE*1.0f)
#define NEC_CONTINUE_MAX (u16)(NEC_CONTINUE*1.3f)


#define  NEC_RX_RCC      RCC_APB2Periph_GPIOA
#define  NEC_TX_RCC      RCC_APB2Periph_GPIOA

#define  NEC_RX_PIN      GPIO_Pin_2//检测电平输入
#define  NEC_TX_PIN      GPIO_Pin_1//电平输出

#define  NEC_RX_PORT     GPIOA
#define  NEC_TX_PORT     GPIOB


#define NEC_TIMER3_PWM_PERIOD				 (72 - 1)
#define NEC_TIMER5_PERIOD				 (72 - 1)


struct  NEC_DATA  NEC_Data;

//输入捕获的一般配置步骤:
//初始化定时器和通道对应IO的时钟。
//初始化IO口,模式为输入,下拉模式:GPIO_Init(); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
//初始化定时器ARR,PSC:TIM_TimeBaseInit();
//初始化输入捕获通道:TIM_ICInit();
//如果要开启捕获中断:TIM_ITConfig(); NVIC_Init();
//使能定时器: TIM_Cmd();
//编写中断服务函数: TIMx_IRQHandler();
//输入捕获整体初始化函数(含步骤1-6)

//**************************************接收部分**************************//
//红外遥控接收初始化 利用定时器5      PA1脚  捕获
void NEC_RX_Configuration(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	TIM_ICInitTypeDef TIM_ICInitStructure; //输入捕获


	RCC_APB2PeriphClockCmd(NEC_RX_RCC, ENABLE); //使能PORT时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);  //TIM5 时钟使能

	GPIO_InitStructure.GPIO_Pin = NEC_RX_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;        // 下拉输入:平时就是0
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(NEC_RX_PORT, &GPIO_InitStructure);    //PA1--CH2

	//初始化定时器5 TIM5
	TIM_TimeBaseStructure.TIM_Period = 50000; //设定计数器自动重装值 最大50ms溢出
	TIM_TimeBaseStructure.TIM_Prescaler = NEC_TIMER5_PERIOD;    //预分频器,1M的计数频率,1us加1.  记一个数的时间T=1/f=1/1M=1us
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx
													//初始化TIM5输入捕获参数
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_3;  // 选择输入端 IC3映射到TI3上
	TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获
	TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上
	TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;    //配置输入分频,不分频 检测了几个上升沿(或者下降沿)才产生一次中断
	TIM_ICInitStructure.TIM_ICFilter = 0x03; //IC3F=0000 配置输入滤波器 不滤波//IC3F=0011 配置输入滤波器 8个定时器时钟周期滤波
	TIM_ICInit(TIM5, &TIM_ICInitStructure); //初始化定时器输入捕获通道

        //中断优先级在别的函数一起初始化了,需要自己移植过来

	TIM_ITConfig(TIM5, TIM_IT_Update | TIM_IT_CC3, ENABLE); //允许更新中断 ,使能CC2IE捕获中断

	TIM_ARRPreloadConfig(TIM5, ENABLE);  //重装载

	TIM_Cmd(TIM5, ENABLE);  //使能定时器5
}

//**************************************发送部分**************************//
void NEC_TX_Configuration(void)     //红外传感器接收头引脚初始化 定时器3  PB1  CH4
{
	GPIO_InitTypeDef GPIO_InitStructure;

	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	TIM_OCInitTypeDef TIM_OCInitStructure;             //输出比较

	RCC_APB2PeriphClockCmd(NEC_TX_RCC, ENABLE);          //使能PORT时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //TIM3 时钟使能

	GPIO_InitStructure.GPIO_Pin = NEC_TX_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;     //复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(NEC_TX_PORT, &GPIO_InitStructure);

	TIM_Cmd(TIM3, DISABLE);
	TIM_ITConfig(TIM3, TIM_IT_Update | TIM_IT_CC4, DISABLE);           //关闭TIM3中断
																	   //不分频,PWM 频率=72000/1894=38Khz//设置自动重装载寄存器周期的值																   //当发送器发送高电平时,实际上发送的是38khz的载波,也就是周期约为26.31us 占空比为1/3(或1/4,有时候可以2/3)的波
	TIM_TimeBaseStructure.TIM_Period = 27; //原来27                          //设定计数器自动重装值 最大27us溢出
	TIM_TimeBaseStructure.TIM_Prescaler = NEC_TIMER3_PWM_PERIOD;                        //预分频器,1M的计数频率,1us加1.
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;         //设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;     //TIM向上计数模式
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;             //设置PWM1模式
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //输出使能
	TIM_OCInitStructure.TIM_Pulse = 0;   // 占空比                //设置捕获比较寄存器的值
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;     //设置有效电平为高电平
	TIM_OC4Init(TIM3, &TIM_OCInitStructure);                      //生效初始化设置
	TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable);             //使能输出比较预装载

	TIM_Cmd(TIM3, ENABLE);
}

void Delay_Timer_Init(void)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

	TIM_TimeBaseStructInit(&TIM_TimeBaseInitStruct);
	TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Down;
	TIM_TimeBaseInitStruct.TIM_Period = 100 - 1;
	TIM_TimeBaseInitStruct.TIM_Prescaler = (84 - 1);
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);

	while ((TIM2->SR & TIM_FLAG_Update) != SET);
	TIM2->SR = (uint16_t)~TIM_FLAG_Update;
}
void Delay_us(uint32_t us_cnt)
{
	TIM2->CNT = us_cnt - 1;
	TIM2->CR1 |= TIM_CR1_CEN;
	while ((TIM2->SR & TIM_FLAG_Update) != SET);
	TIM2->SR = (uint16_t)~TIM_FLAG_Update;
	TIM2->CR1 &= ~TIM_CR1_CEN;

}



void TIM5_IRQHandler(void)
{

	//超时没捕获到,发送中断
	if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET)  //更新中断
	{
	     GPIO_SetBits(GPIOA, GPIO_Pin_8); //led灭

	}
	if (TIM_GetITStatus(TIM5, TIM_IT_CC3) != RESET) //捕获1发生捕获事件
	{
		NEC_Data.flag = 1;

		if (0x00 == NEC_Data.TIM5CH1_CAPTURE_STA)          // 空闲状态
		{
			NEC_Data.TIM5CH1_CAPTURE_STA = 0x01;       //标记捕获到一个上降沿
			NEC_Data.TIM5CH1_CAPTURE_VAL = 0;          //计时时间清0
			TIM_SetCounter(TIM5, 0);
			TIM_OC3PolarityConfig(TIM5, TIM_ICPolarity_Falling);     //CC1P=1 设置为下降沿捕获
		}

		else if (0x01 == NEC_Data.TIM5CH1_CAPTURE_STA)   //在捕获到一个上升沿前提下,如果再捕获下降沿  ,说明捕获到了高电平
		{

			NEC_Data.TIM5CH1_CAPTURE_VAL = TIM_GetCapture3(TIM5); //获取捕获高电平时间

			NEC_Data.TIM5CH1_CAPTURE_STA_H = 0x01; //标记捕获到一个高电平 if(  TIM5CH1_CAPTURE_VAL>300  )
			TIM_OC3PolarityConfig(TIM5, TIM_ICPolarity_Rising); //CC2P=0 设置为上升沿捕获 准备捕获上升沿
		}

	}

	if (NEC_Data.TIM5CH1_CAPTURE_STA_H == 0x01) //如果捕获到一个高电平,判断是否前导码,是前导码。跳出去,

	{
		NEC_Data.TIM5CH1_CAPTURE_STA_H = 0x00;   //不是前导码,判断是否已经捕到前导码,是:判断数据正确性,不是,跳出去

		if (NEC_Data.TIM5CH1_CAPTURE_STA_Head == 0x01) //只有接收到了引导码之后得到的才是数据
		{

			if (NEC_Data.TIM5CH1_CAPTURE_VAL > NEC_ZERO_MIN && NEC_Data.TIM5CH1_CAPTURE_VAL < NEC_ZERO_MAX)  //560为标准值,560us min=392 max=728               实际值为0.68ms
			{
				//红外接收到的数据:0
				NEC_Data.RmtRec <<= 1;                 //左移一位.
				NEC_Data.RmtRec |= 0;                  //接收到0
			}
			else if (NEC_Data.TIM5CH1_CAPTURE_VAL > NEC_ONE_MIN && NEC_Data.TIM5CH1_CAPTURE_VAL < NEC_ONE_MAX)  //1680为标准值,1680us min=1.176ms max=2.148ms    实际值为1.96ms
			{
				//红外接收到的数据:1
				NEC_Data.RmtRec <<= 1;                 //左移一位.
				NEC_Data.RmtRec |= 1;                  //接收到1

			}
			else if (300 < NEC_Data.TIM5CH1_CAPTURE_VAL && NEC_Data.TIM5CH1_CAPTURE_VAL < 8800)      //得到按键键值增加的信息 2500为标准值2.5ms
			{

				NEC_Data.TIM5CH1_CAPTURE_RecFlag = 0x01;
				NEC_Data.TIM5CH1_CAPTURE_STA_Head = 0x00; //准备接受下一帧数据
			}

		}
		else if (NEC_Data.TIM5CH1_CAPTURE_VAL > NEC_HEAD_MIN && NEC_Data.TIM5CH1_CAPTURE_VAL < NEC_HEAD_MAX)       //4500为标准值4.5ms  实测5773 //4500 -6300
		{
			NEC_Data.TIM5CH1_CAPTURE_STA_Head = 0x01;  //标记成功接收到了引导码
											  //跳出去,等待下一个高电平
		}
		NEC_Data.TIM5CH1_CAPTURE_STA = 0x00;                    //空闲状态
	}


	TIM_ClearITPendingBit(TIM5, TIM_IT_Update | TIM_IT_CC3);  //清除中断标志位
}


void NEC_GetValue(u8 *addr, u16 *value)
{
	u8 t1, t2;
	*addr = 0;
	*value = 0;
	if (NEC_Data.TIM5CH1_CAPTURE_RecFlag == 0x01)    //接收到一个数据
	{
		NEC_Data.TIM5CH1_CAPTURE_RecFlag = 0x00;
		t1 = NEC_Data.RmtRec >> 24;             //得到地址码
		t2 = (NEC_Data.RmtRec >> 16) & 0xff;    //得到地址反码
		if (t1 == (u8)~t2)             //检验遥控识别码(ID)及地址
		{
			*addr = t1;
			t1 = 0;
			t2 = 0;
		}
		else
		{*addr = 0; }
		t1 = (NEC_Data.RmtRec >> 8) & 0xff;  //得到数据
		t2 = NEC_Data.RmtRec & 0xff;         //得到数据反码
		if (t1 == (u8)~t2)           //检验数据码及数据反码
		{*value = t1;}
		else
		{*value = 0; }
		NEC_Data.RmtRec = 0;
	}
}


//一个逻辑0的传输需要 1.125ms(560us载波+560us空闲)。
static void NEC_Send_0(void)
{
	CARRIER_38KHz();    //比较值为1/3载波
	Delay_us(560);
	NO_CARRIER();   //不载波
	Delay_us(560);

}
//一个逻辑1传输需要2.25ms(560us载波+1680us空闲)
static void NEC_Send_1(void)
{
	CARRIER_38KHz();    //比较值为1/3载波
	Delay_us(560);
	NO_CARRIER();   //不载波
	Delay_us(1680);

}
//NEC协议格式://引导码:发送一个9ms载波的引导码,之后是4.5ms的空闲,
static void NEC_Send_Head(void)
{

	CARRIER_38KHz();
	Delay_us(9000);        //  实际10.56ms    10us实际13us
	NO_CARRIER();   //不载波 	        0
	Delay_us(4500);          // 实际接收时间在5.24ms

}
//结束码(自己加的)
static void NEC_Send_Tail(void)
{

	CARRIER_38KHz();
	Delay_us(200);
	NO_CARRIER();
	Delay_us(300);    //   2.5<3ms<3.3ms

}
//发送一字节数据
static void NEC_Send_BYTE(u8 value)
{
	u8 i;

	for (i = 0; i < 8; i++)
	{
		if (value & 0x80)
		{
			NEC_Send_1();
		}
		else
		{
			NEC_Send_0();
		}
		value <<= 1;
	}


}
static void NEC_Send_Repeat(u8 count)
{
	u8 i = 0;

	if (count == 0)          //如果没有重复码就直接设置无载波,发射管进行空闲状态
	{
		NEC_Send_Tail();
	}
	else
	{
		for (i; i < count; i++)
		{
			CARRIER_38KHz();
			Delay_us(9000);
			NO_CARRIER();
			Delay_us(2250);
		}

	}


}
//后发送16位地址码(18ms36ms)、8位数据码(9ms18ms)以及8为数据反码。
//(第二个108ms)如果接下来发射重复的数据,可以先发送9ms载波,空闲2.5ms,
//再发射0.56ms载波即可,注意每次发射的间隔时间。
void NEC_Send(u8 addr, u8 value, u8 cnt)

{

	NEC_TX_Configuration();
	NEC_RX_Configuration();
	NEC_Send_Head();                //发送起始码
	NEC_Send_BYTE(addr);            //发送地址码H
	NEC_Send_BYTE(~addr);           //发送地址码L
	NEC_Send_BYTE(value);           //发送命令码H
	NEC_Send_BYTE(~value);          //发送命令码L
	NEC_Send_Repeat(cnt);           //发送重复码

}
void HW_Init(void)
{
	NEC_TX_Configuration();
	NEC_RX_Configuration();
}

//定时器3中断服务程序
void TIM3_IRQHandler(void)
{

	if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) {} //更新中断

	TIM_ClearITPendingBit(TIM3, TIM_IT_Update | TIM_IT_CC3);  //清除中断标志位
}




void  IR_Sensor(u8 Data)
{
	u16 data[1];
	u8 addr[1];
	NEC_Send(0xff, Data, 0);
	NEC_GetValue(addr, data);
	if (*data == Data)
	{
		GPIO_ResetBits(GPIOA, GPIO_Pin_8); //led亮灯
	}

}












#ifndef __IR_H
#define __IR_H
#include "BSP_CFG.h"

//位带操作,实现51类似的GPIO控制功能
//IO口操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr))
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum))
//IO口地址映射
#define GPIOA_ODR_Addr    (GPIOA_BASE+12) //0x4001080C
#define GPIOB_ODR_Addr    (GPIOB_BASE+12) //0x40010C0C
#define GPIOC_ODR_Addr    (GPIOC_BASE+12) //0x4001100C
#define GPIOD_ODR_Addr    (GPIOD_BASE+12) //0x4001140C
#define GPIOE_ODR_Addr    (GPIOE_BASE+12) //0x4001180C
#define GPIOF_ODR_Addr    (GPIOF_BASE+12) //0x40011A0C
#define GPIOG_ODR_Addr    (GPIOG_BASE+12) //0x40011E0C

#define GPIOA_IDR_Addr    (GPIOA_BASE+8) //0x40010808
#define GPIOB_IDR_Addr    (GPIOB_BASE+8) //0x40010C08
#define GPIOC_IDR_Addr    (GPIOC_BASE+8) //0x40011008
#define GPIOD_IDR_Addr    (GPIOD_BASE+8) //0x40011408
#define GPIOE_IDR_Addr    (GPIOE_BASE+8) //0x40011808
#define GPIOF_IDR_Addr    (GPIOF_BASE+8) //0x40011A08
#define GPIOG_IDR_Addr    (GPIOG_BASE+8) //0x40011E08

//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //输出
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //输入

#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //输出
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //输入

#define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  //输出
#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  //输入

#define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  //输出
#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  //输入

#define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //输出
#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //输入

#define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  //输出
#define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  //输入

#define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  //输出
#define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  //输入
#define RDATA 	PAin(1)	 	//红外数据输入脚


struct NEC_DATA
{
  u32 RmtRec  ;                   //红外接收到的数据
u8 TIM5CH1_CAPTURE_STA  ;         //输入捕获状态
u8 TIM5CH1_CAPTURE_STA_H  ;       //捕获到一个高电平
u8 TIM5CH1_CAPTURE_STA_Head  ;    //捕获到一个引导码
u8 TIM5CH1_CAPTURE_RecFlag ;
u16 TIM5CH1_CAPTURE_VAL;          //输入捕获值
u8 flag ;


}   ;

extern void IR_Sensor(u8 Data);
extern void HW_Init(void);
void Delay_Timer_Init(void);
#endif















评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

在嵌入式里摸爬滚打

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

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

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

打赏作者

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

抵扣说明:

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

余额充值