基于STM32f103c8t6的红外接收发送

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_45529757/article/details/102737948


本实验是我在学习过程中做的,之所以分享出来,也是为了回报我在学习中给我的帮助人和文章,有什么问题可以留言

原理

(1)红外发送

1. 红外工作原理

红外通信是利用950nm近红外波段的红外线作为传递信息的媒体,
即通信信道。 发送端采用脉时调制(PPM) 方式, 将二进制数字信号调制成某一频率的脉冲序列, 并驱动红外发射管以光脉冲的形式发送出去;
接收端将接收到的光脉转换成电信号, 再经过放大、 滤波等处理后送给解调电路进行解调, 还原为二进制数字信号后输出。 简而言之, 红外通信的实质就是对二进制数字信号进行调制与解调,
以便利用红外

信道进行传输, 红外通信接口就是针对红外信道的调制解调器。

载波:38KHz

2. 红外信号

在这里插入图片描述

3. 红外物理部分

红外发送头 + 红外接收头、红外接收管

红外接收头:滤除载波 – 二进制信号

红外接收管:接收载波

4. 红外通信协议

编码:NEC 、 RC5

1. 数字量
NEC

扫描二维码关注公众号,回复: 7616517 查看本文章

数据 0 :560us低电平 + 560us高电平

数据 1 :560us低电平 + 1690us高电平

2. 数据帧格式

在这里插入图片描述

引导码:9ms低电平

  • 4.5ms高电平

重复引导码:9ms低+2.25ms高 –110ms发送一次

在这里插入图片描述

(2) 红外接收

如何解析红外编码?
1. 外部中断
–边沿检测 – 时间:定时器
2. 定时器的输入捕获

美的 解析
14120
4494 引导码
4420 引导码
588
1604 1
575
501 0
566
5215 分割码
4498 引导码
4398 引导码
588
1571
589

引导码:不一样 2000 ~ 9500

数据码:有浮动 450 ~ 700

1500 ~ 1800

分割码 5000 ~ 5400

数据解析过程:
在这里插入图片描述

程序

// A code block
#include "ir.h"
_IR ir={.count=0,.overflag=0};
int second=0;
void IR_Config(void)
{
  TIM2_Config(72,20000);  //20ms
  TIM1_Config(72,26,13);  //38KHz  50%
  sFLASH_ReadBuffer((u8 *)&ir,0x60000,sizeof(ir));
  if(*(uint8_t *)&ir!=0xff)
  {
    second=ir.frequency;
    IR_Display();
  }
}

void TIM2_Config(uint16_t psc,uint16_t arr)
{
 //PB3
 GPIO_InitTypeDef GPIO_InitStruct;
 TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
 TIM_ICInitTypeDef TIM_ICInitStruct;
 NVIC_InitTypeDef NVIC_InitStruct;
 
 
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO,ENABLE);
 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
 
 GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//关闭JATG,启用SWD
 GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2,ENABLE);//将TIM2_CH2映射到PB3
 
 GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;
 GPIO_InitStruct.GPIO_Pin=GPIO_Pin_3;
 GPIO_Init(GPIOB,&GPIO_InitStruct);
 //定时器TIM2配置
 TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV2;
 TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;
 TIM_TimeBaseInitStruct.TIM_Period=arr-1;
 TIM_TimeBaseInitStruct.TIM_Prescaler=psc-1;
 TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);
 //输入捕获
 TIM_ICInitStruct.TIM_Channel=TIM_Channel_2;//通道2
 TIM_ICInitStruct.TIM_ICFilter=0x00;//不使用滤波器
 TIM_ICInitStruct.TIM_ICPolarity=TIM_ICPolarity_Falling;//下降沿捕获
 TIM_ICInitStruct.TIM_ICPrescaler=TIM_ICPSC_DIV1;//不分频
 TIM_ICInitStruct.TIM_ICSelection=TIM_ICSelection_DirectTI;// IC2
 TIM_ICInit(TIM2,&TIM_ICInitStruct);
 
 
 TIM_ITConfig(TIM2,TIM_IT_CC2|TIM_IT_Update,ENABLE);
 
 NVIC_InitStruct.NVIC_IRQChannel=TIM2_IRQn;
 NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
 NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=0;
 NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;
 NVIC_Init(&NVIC_InitStruct);
 
 TIM_Cmd(TIM2,ENABLE);
}

//PA8  -- TIM1_CH1  
//38KHz载波    -- 分频 72  -- 1M  --重装载值 -- 26 
void TIM1_Config(u16 psc,u16 arr,u16 ccr)
{ 
 GPIO_InitTypeDef GPIO_InitStruct;
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_TIM1,ENABLE);
 //配置PA8 为复用推挽输出
 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
 GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; 
 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8;
 GPIO_Init(GPIOA,&GPIO_InitStruct);  //GPIO初始化
 
 TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
 TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV2;
 TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
 TIM_TimeBaseInitStruct.TIM_Period = arr-1;//重装载值
 TIM_TimeBaseInitStruct.TIM_Prescaler = psc-1;//分频值
 TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;
 TIM_TimeBaseInit(TIM1,&TIM_TimeBaseInitStruct);


 TIM_OCInitTypeDef TIM_OCInitStruct;
 TIM_OCInitStruct.TIM_Pulse = ccr;//比较值
 TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM2;//PWM2模式
 TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High; //极性:高
 TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;//比较输出使能
 TIM_OCInitStruct.TIM_OCIdleState = TIM_OCIdleState_Set; //空闲为高,对极性反转起作用
 
 TIM_OC1Init(TIM1,&TIM_OCInitStruct);
 
 TIM_CtrlPWMOutputs(TIM1,ENABLE);//主输出使能
 
 TIM_Cmd(TIM1,DISABLE);
}

uint16_t ir_buff[1024]; //存放捕获的计数器的值
uint16_t ir_count=0; //保存边沿的个数
void TIM2_IRQHandler(void)
{
 uint16_t i=0;
 static uint16_t count = 0;
 if(TIM_GetITStatus(TIM2,TIM_IT_Update))//更新中断
 {
  TIM_ClearFlag(TIM2,TIM_FLAG_Update); //清中断
  if(count>40)
  {
  
//   for(i=0;i<count;i++)
//   {
//    printf("%d\r\n",ir_buff[i]);
//   }
   ir_count=count;
   irrun[1] = 2000; //启动时间点
   count = 0;
   ir.overflag = 1;
  }
 }
 if(TIM_GetITStatus(TIM2,TIM_IT_CC2))//捕获中断
 {
  TIM_ClearFlag(TIM2,TIM_FLAG_CC2); //清中断
  ir_buff[count++]=TIM_GetCapture2(TIM2);
  TIM2->CCER ^= (1<<5);     //极性反转,输入/捕获通道2输出极性
  TIM_SetCounter(TIM2,0); //计数器清零
 }
}
/*
比较函数封装
time1 -- 要检测的数据
time2 -- 标准数据
range1 -- 下限
range2 -- 上限
*/
uint32_t guide=0;
uint8_t sign=0;
uint8_t Time_Judge(uint16_t time1,uint16_t time2,uint16_t range1,uint16_t range2)
{
 if(time1 > (time2-range1) && time1 < (time2+range2))
  return 1;
 else 
  return 0;
}

void IR_Bootcode(void)
{
 sign=0;
 for(++guide;guide<ir.count;guide++)
 {
  if(Time_Judge(ir_buff[guide],4500,2000,5000)) //2500~9500
  {
   ir.ir_boot.boot_time[second][ir.ir_boot.boot_len[second]]=ir_buff[guide];
   ir.ir_boot.boot_len[second]++;
   sign=1;
   printf("%d\r\n",ir_buff[guide]);
  }
  else
  {
   break;
  }
 }
}

void IR_Datacode(void)
{
 sign=0;
 for(guide+=1;guide<ir.count;guide+=2)
 {
  if(Time_Judge(ir_buff[guide],560,200,200))
  {
   ir.irdata[second][ir.datalen[second]/8] &=~ (1<<(7-ir.datalen[second]%8));
   ir.datalen[second]++;
   sign=3;
  }
  else if(Time_Judge(ir_buff[guide],1690,200,200))
  {
   ir.irdata[second][ir.datalen[second]/8] |= (1<<(7-ir.datalen[second]%8));
   ir.datalen[second]++;
   sign=2;
  }
  else
  {
   break;
  }
 }
}

void IR_Cutcode(void)
{
 if(Time_Judge(ir_buff[guide],5200,500,500))
 {
  ir.ir_boot.cut_time=ir_buff[guide];
  second=1;
  printf("%d\r\n",ir_buff[guide]);
 }
}

void IR_empty(void)
{
 memset(&ir,0,sizeof(ir));
 second=0;
 guide=0; 
 sign=0;
}

void IR_Transformation(uint8_t a)
{
 guide=0;
 second=0;
 irrun[1] = 0xffffffff;
 if((ir.overflag ==1)&&(a==1))
 {
  memset(&ir,0,sizeof(ir));
  ir.count = ir_count;
  for(u8 i=0;i<second+1;i++)
  {
  
   IR_Bootcode();
   IR_Datacode();
   IR_Cutcode();
   if((sign==0)||(ir.datalen[i]/8!=6))
   {
    IR_empty();
    return;
   }
   ir.frequency=second;
  }
  ir.count = 0;
  ir.overflag = 0;
  sign=0;
  IR_Display();
  sFLASH_EraseSector(0x060000);//擦除器擦除第6块
  sFLASH_WriteBuffer((uint8_t *)&ir,0x060000,sizeof(ir));//写缓存区
 }
 IR_empty();
}

void IR_Display(void)
{
 u32 i=0,j=0;
 for(j=0;j<second+1;j++)
 {
  //打印引导码
  printf("第%d次引导码\r\n",j+1);
  for(i=0;i<ir.ir_boot.boot_len[j];i++)
  {
   printf("%d\t",ir.ir_boot.boot_time[j][i]);
  }
  printf("\r\n");
  printf("第%d次数据\r\n",j+1);
  for(i=0;i<ir.datalen[j]/8;i++)
  {
   printf("%d\t",ir.irdata[j][i]);
  }
  printf("\r\n");
  if((second!=0)&&(sign==0))
  {
   printf("分割码\r\n");
   printf("%d\r\n",ir.ir_boot.cut_time);
   sign=1;
  }
  printf("\r\n");
 }
}

void IR_Bootsend(void)
{
 for(guide=0;guide<ir.ir_boot.boot_len[second];guide++)
 {
  IR_38KHz(sign);
  sign=!sign;
  Delay_nus(ir.ir_boot.boot_time[second][guide]);
 }
 for(guide=0;guide<ir.datalen[second]/8;guide++)
 {
  for(u32 i=0;i<8;i++)
  {
   IR_38KHz(sign);
   sign=!sign;
   Delay_nus(520);
   IR_38KHz(sign);
   sign=!sign;
   if(ir.irdata[second][guide]&(1<<(7-i)))
   {
    Delay_nus(1500);
   }
   else
    Delay_nus(520);
  }
 }
 IR_38KHz(sign);
 sign=!sign;
 Delay_nus(520);
 IR_38KHz(sign);
 sign=!sign;
 Delay_nus(ir.ir_boot.cut_time);
 second=1;
} 

void IR_Sendout(void)
{
 sign=1;
 second=0;
 for(u32 i=0;i<second+1;i++)
 {
  IR_Bootsend();
 }
 printf("发送完成\r\n");
 printf("\r\n");
}

注:
我这里用的是小米手机的手机红外遥控器里的美的空调测试的,用的是NEC协议。每一个产品数据码不一样,引导码分割码也不一样,所以具体情况需要自己测试

猜你喜欢

转载自blog.csdn.net/qq_45529757/article/details/102737948