基于STM32f103c8t6的红外接收发送

原理

(1)红外发送

1. 红外工作原理

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

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

载波:38KHz

2. 红外信号

在这里插入图片描述

3. 红外物理部分

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

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

红外接收管:接收载波

4. 红外通信协议

编码:NEC 、 RC5

1. 数字量
NEC

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

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

2. 数据帧格式

在这里插入图片描述

引导码:9ms低电平

  • 4.5ms高电平

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

在这里插入图片描述

(2) 红外接收

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

美的解析
14120
4494引导码
4420引导码
588
16041
575
5010
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协议。每一个产品数据码不一样,引导码分割码也不一样,所以具体情况需要自己测试

本文档的主要内容详细介绍的是直流无刷电机的工作原理的详细资料。主要内容包括了:直流无刷电机的优越性,直流无刷电机的控制结构 ,直流无刷电机的控制原理,P.I.D 控制简介,电机驱动器的保护措施   直流电机具有响应快速、较大的起动转矩、从零转速至额定转速具备可提供额定转矩的性能,但直流电机的优点也正是它的缺点,因为直流电机要产生额定负载下恒定转矩的性能,则电枢磁场与转子磁场须恒维持 90°,这就要藉由碳刷及整流子。碳刷及整流子在电机转动时会产生火花、碳粉因此除了会造成组件损坏之外,使用场合也受到限制。交流电机没有碳刷及整流子,免维护、坚固、应用广,但特性上若要达到相当于直流电机的性能须用复杂控制技术才能达到。现今半导体发展迅速功率组件切换频率加快许多,提升驱动电机的性能。微处理机速度亦越来越快,可实现将交流电机控制置于一旋转的两轴直交坐标系统中,适当控制交流电机在两轴电流分量,达到类似直流电机控制并有与直流电机相当的性能。   此外已有很多微处理机将控制电机必需的功能做在芯片中,而且体积越来越小;像模拟/数字转换器(Analog-to-digital converter,ADC)、脉冲宽度调制(pulse wide modulator,PWM)…等。直流无刷电机即是以电子方式控制交流电机换相,得到类似直流电机特性又没有直流电机机构上缺失的一种应用。
下面是一个基于STM32F103C8T6微控制器和红外传感器控制蜂鸣器的示例代码: ```c #include "stm32f10x.h" #define IR_SENSOR_PIN GPIO_Pin_0 #define IR_SENSOR_PORT GPIOA #define BUZZER_PIN GPIO_Pin_1 #define BUZZER_PORT GPIOA void GPIO_Configuration(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 设置红外传感器引脚为输入模式 GPIO_InitStructure.GPIO_Pin = IR_SENSOR_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入模式 GPIO_Init(IR_SENSOR_PORT, &GPIO_InitStructure); // 设置蜂鸣器引脚为输出模式 GPIO_InitStructure.GPIO_Pin = BUZZER_PIN; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出模式 GPIO_Init(BUZZER_PORT, &GPIO_InitStructure); } int main(void) { GPIO_Configuration(); while (1) { // 检测红外传感器状态 if (GPIO_ReadInputDataBit(IR_SENSOR_PORT, IR_SENSOR_PIN) == Bit_SET) { // 红外传感器检测到物体,开启蜂鸣器 GPIO_SetBits(BUZZER_PORT, BUZZER_PIN); } else { // 红外传感器未检测到物体,关闭蜂鸣器 GPIO_ResetBits(BUZZER_PORT, BUZZER_PIN); } } } ``` 这段代码中,我们使用了STM32的GPIO库来配置红外传感器引脚为输入模式,并设置上拉输入模式。然后,我们将蜂鸣器引脚配置为输出模式,并使用推挽输出模式控制蜂鸣器的开关状态。在主循环中,我们通过读取红外传感器引脚的状态来判断是否检测到物体,从而控制蜂鸣器的开关状态。 请注意,这只是一个简单的示例代码,具体的硬件连接和其他配置可能需要根据你的实际应用进行调整。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值