STM32红外串口接收

发布者:心想的45号最新更新时间:2021-12-20 来源: eefocus关键字:STM32  接收 手机看文章 扫描二维码
随时随地手机看文章

1.NEC协议

现有的红外遥控包括两种方式: PWM(脉冲宽度调制)和PPM(脉冲位置调制)。

两种形式编码的代表分别为NEC 和 PHILIPS的RC-5、RC-6以及将来的RC-7。


PWM(脉冲宽度调制):以发射红外载波的占空比代表"0”和"1"。为了节省能量,一般情况下,发射红外载波的时间固定,通过改变不发射载波的时间来改变占空比。例如常用的电视遥控器,TOSHIBA的TC9012,其引导码为载波发射4. 5ms,不发射4.5ms,其"0"为载波发射0.56ms,不发射0.565ms,其"1"为载波发射0.56ms,不发射1.69ms。


PPM(脉冲位置调制)∶以发射载波的位置表示"0"和"1"。从发射载波到不发射载波为"0",从不发射载波到发射载波为"1"。其发射载波和不发射载波的时间相同,都为0.68ms,也就是每位的时间是固定的。


2.电路图:三条线,VCC 、GND、DATA

在这里插入图片描述

3.通信协议图,总共4*8=32位数据。

在这里插入图片描述

4.地址码,持续时间1690us为数据"1",持续时间560us为数据"0"。

他们低电平部分560us相同,可以省略判断,直接根据高电平持续时间来判断是数据0还是数据1。


通过测量不同的高电平持续时间,就能够知道当前的信号是引导码、比特0、比特1。

地址码
在这里插入图片描述

思路:


红外发射头发射红外,相当于按下按键,变为高电平。 红外发射头停止发射,相当于松开按键,变为高电平,默认的时候是高电平。

所以采用外部中断来触发。


5.代码


#include "stm32f4xx.h"

#include "stm32f4xx_gpio.h"

#include "stm32f4xx_rcc.h"

#include "stm32f4xx_usart.h"

#include "stdio.h"


static GPIO_InitTypeDef  GPIO_InitStructure;

static USART_InitTypeDef USART_InitStructure;

static NVIC_InitTypeDef NVIC_InitStructure;

static EXTI_InitTypeDef    EXTI_InitStructure;


static volatile uint8_t g_ir_data[4]={0};

static volatile uint32_t g_ir_event=0;



//重定义fputc函数 

int fputc(int ch, FILE *f)

{

USART_SendData(USART1,ch);

while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);  

return ch;

}   


void delay_us(uint32_t nus)

{

uint32_t temp;      

SysTick->LOAD =SystemCoreClock/8/1000000*nus; //时间加载    

SysTick->VAL  =0x00;        //清空计数器

SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //使能滴答定时器开始倒数  

do

{

temp=SysTick->CTRL;

}while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达   

SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器

SysTick->VAL =0X00;        //清空计数器 

}


void delay_ms(uint16_t nms)

{     

uint32_t temp;    

SysTick->LOAD=SystemCoreClock/8/1000*nms; //时间加载(SysTick->LOAD为24bit)

SysTick->VAL =0x00;            //清空计数器

SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;    //能滴答定时器开始倒数 

do

{

temp=SysTick->CTRL;

}while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达   

SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;    //关闭计数器

SysTick->VAL =0X00;        //清空计数器       




void USART1_Init(uint32_t baud)

{

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //使能GPIOA时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); //使能USART1时钟

 

//串口1对应引脚复用映射

GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); //GPIOA9复用为USART1

GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); //GPIOA10复用为USART1

//USART1端口配置

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; //GPIOA9与GPIOA10

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用功能

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度50MHz

GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出

GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉

GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA9,PA10


//USART1 初始化设置

USART_InitStructure.USART_BaudRate = baud; //波特率设置

USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字长为8位数据格式

USART_InitStructure.USART_StopBits = USART_StopBits_1; //一个停止位

USART_InitStructure.USART_Parity = USART_Parity_No; //无奇偶校验位

USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件数据流控制

USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式

USART_Init(USART1, &USART_InitStructure); //初始化串口1

USART_Cmd(USART1, ENABLE);  //使能串口1 

USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //开启相关中断


//Usart1 NVIC 配置

NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //串口1中断通道

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3; //抢占优先级3

NVIC_InitStructure.NVIC_IRQChannelSubPriority =3; //子优先级3

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能

NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器

}



void ir_init(void)

{


/* GPIOA硬件时钟使能 */

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

/* Enable SYSCFG clock ,使能系统配置时钟*/

RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);



/* 配置PA8引脚为输入模式  */

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //第8根引脚

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; //输入模式,能够检测外部电平状态

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //GPIO最大的速度为100MHz

GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //不需要上下拉电阻

GPIO_Init(GPIOA, &GPIO_InitStructure);

/* Configure EXTI Line8 ,配置外部中断控制线8*/

EXTI_InitStructure.EXTI_Line = EXTI_Line8; //使能外部中断控制线8

EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //中断模式

EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发,能够检测到红外信号的到达

EXTI_InitStructure.EXTI_LineCmd = ENABLE; //中断控制线使能,让它工作

EXTI_Init(&EXTI_InitStructure);

/* Connect EXTI Line8 to PA8 pin */

SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource8);


/* Enable and set EXTI Line8 Interrupt to the lowest priority ,使能并设置外部中断控制线8中断,优先级是最低*/

NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn; //外部中断控制线9_5触发中断

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F; //抢占优先级为0xF

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F; //响应优先级为0xF

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //允许外部中断控制线9_5触发中断

NVIC_Init(&NVIC_InitStructure);



}



int main(void)

LED_Init();


//系统定时器初始化,时钟源来自HCLK,且进行8分频,

//系统定时器时钟频率=168MHz/8=21MHz

SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); 

//设置中断优先级分组2

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

//串口1,波特率115200bps,开启接收中断

USART1_Init(115200);

ir_init();

while(1)

{


if(g_ir_event)

{

printf("ir data:%02X%02X%02X%02Xrn",g_ir_data[0],g_ir_data[1],g_ir_data[2],g_ir_data[3]);

g_ir_event=0;

}

}

}

//分析红外信号,总结出规律,通过测量不同的高电平持续时间,就能够知道当前的信号是引导码、比特0、比特1

uint8_t IR_PluseHighTime(void)

{

uint8_t t=0;

//高电平

while(PAin(8) == 1)

{

t++;

delay_us(20);

//超时溢出

if(t > 250)

return t;

}


return t;

}



void EXTI9_5_IRQHandler(void)

{

uint8_t t=0,ir_vaild=0,ir_bit=0;

uint32_t ir_data=0,ir_bit_cnt=0;

//检查当前外部中断控制线8是否触发中断

if(EXTI_GetITStatus(EXTI_Line8) != RESET)

{

//添加代码

while(1)

{

//若出现高电平,就进行测量

if(PAin(8)==1)

{

t = IR_PluseHighTime();

//当前信号是非法信号

if(t >=250)

break;

//判断当前信号是引导码

if(t>=200 && t<250) //4ms ~ 5ms

{

ir_vaild=1;

continue;

}

//收到bit1

else if(t>=60 && t<90) //1.2ms~1.8ms

{

ir_bit = 1;

}

//收到bit0

else if(t>=10 && t<50)  //0.2ms ~ 1 ms

{

ir_bit = 0;

}

//获取bit数据

if(ir_vaild)

{

ir_data|=ir_bit< }

ir_bit_cnt++;

if(ir_bit_cnt >=32)

{

g_ir_data[0] = (uint8_t)((ir_data>>24)&0xFF);

g_ir_data[1] = (uint8_t)((ir_data>>16)&0xFF);

g_ir_data[2] = (uint8_t)((ir_data>>8)&0xFF);

g_ir_data[3] = (uint8_t)(ir_data&0xFF);


//进行数据校验判断,检查当前接收到的红外数据是否正确

if(g_ir_data[0] == (0xFF - g_ir_data[1]))

{

if(g_ir_data[2] == (0xFF - g_ir_data[3]))

{

g_ir_event = 1;

}

}

break;


}

}

}

/* Clear the EXTI line 8 pending bit,清空中断标志位,就代表说我已经完成中断处理 */

EXTI_ClearITPendingBit(EXTI_Line8);

}

}


void USART1_IRQHandler(void)                //串口1中断服务程序

{

uint8_t d;


if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断

{

d = USART_ReceiveData(USART1);

关键字:STM32  接收 引用地址:STM32红外串口接收

上一篇:STM32的ADC转换(普通模式)
下一篇:STM32电源管理—实现低功耗

推荐阅读最新更新时间:2024-11-13 08:20

STM32之中断与事件---中断与事件的区别
这张图是一条外部中断线或外部事件线的示意图,图中信号线上划有一条斜线,旁边标志19字样的注释,表示这样的线路共有19套.图中的蓝色虚线箭头,标出了外部中断信号的传输路径,首先外部信号从编号1的芯片管脚进入,经过编号2的边沿检测电路,通过编号3的或门进入中断挂起请求寄存器,最后经过编号4的与门输出到NVIC中断检测电路,这个边沿检测电路受上升沿或下降沿选择寄存器控制,用户可以使用这两个寄存器控制需要哪一个边沿产生中断,因为选择上升沿或下降沿是分别受2个平行的寄存器控制,所以用户可以同时选择上升沿或下降沿,而如果只有一个寄存器控制,那么只能选择一个边沿了. 按下来是编号3的或门,这个或门的另一个输入是软件中断/事件寄存器,从这
[单片机]
<font color='red'>STM32</font>之中断与事件---中断与事件的区别
STM32 IO口位带操作
M4中有4GB的访问空间,访问空间有两个比较重要的地址,寄存器映射地址,又叫别名地址(范围32MB),寄存器地址(范围1MB,固定的) 使用库函数对IO引脚操作比较费时间,需要进行现场保护和现场恢复操作,不能一步到位。使用位带操作能够一步到位,方便快捷。 每个端口都有对应的寄存器地址,查看库函数可以看到对寄存器的的操作。 如: void GPIO_ToggleBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) { /* Check the parameters */ assert_param(IS_GPIO_ALL_PERIPH(GPIOx)); GPIOx- ODR ^= GP
[单片机]
stm32的ucosII加上ucGUI学习
一、学会使用Keil调试工具。 单步调试,跳过函数,跳出函数 可以快速定位到程序的bug位置 二、系统板级驱动要加载需要的函数 三、怎么一步步根据具体需要添加系统功能 程序开发过程 1、加入所用到的封装库 2、写板级驱动BSP 包括GPIO配置 时钟配置 所用到的各种初始化函数用同一的void BSP_Init(void)函数调用 3、编写stm32f10x_it.c文件,设置中断服务函数 4、建立任务,包括定义任务名(函数名),堆栈空间(一个数组),任务优先级(一个宏定义) 5、任务优先级的选择,不合理的优先级,会导致程序无法正常运行,例如有7个任务,界面任务,触摸任务,三个L
[单片机]
STM32----FLASH掉电保存动态平衡方案
stm32是支持对自身Flash(code区)进行读写的。所以,在某些需要掉电保存的场合,我们可以利用这一特性节省一个外部的Flash或者EEPROM,对数据进行保存。 但是,如果需要经常性的保存数据,就会对固定地址的Flash进行频繁的擦写,大大损耗Flash的寿命。在这种时候,就需要用到动态平衡的方法进行处理了。原理: 一、Flash擦写寿命 根据网上查阅的资料,单个NOR Flash地址的寿命,是受擦写次数的影响的。再具体一点,单个地址上的每个位,分别独立。比如0x08011000这个地址,共有8个bit,假设我一直令这个地址的数据循环为0x01与0x00。那么bit0位就会一直被擦写。循环几万次后bit
[单片机]
STM32 串口使用
stm32串口功能比较强大,但仅仅使用串口来说,是很简单的 我们要做的事 1.使能串口时钟 2.复位串口 3.设置串口波特率 4.设置数据长度,停止位 5.收发使能 6.串口使能 1 int main() 2 { 3 u8 buf; 4 sysclk_init(9); 5 6 RCC- APB2ENR|=1 14; //串口使能 7 8 RCC- APB2RSTR|=1 14; 9 RCC- APB2RSTR&=~(1 14);//复位串口,不复位会出错 10 USART1- BRR=0x1D4C;//设置波特率 11 USART1- CR1|=0x
[单片机]
“看门狗“VS“打狗棒”,谁胜谁负?(STM32篇)—MCU抗干扰实验系列专题(3)
在上两期文章和视频中,为了公平起见,所有的MCU使用的是同一个工程程序,(不同的MCU,时钟和GPIO的配置略有不同,使用宏定义区分MCU),除了使用滴答时钟和基本GPIO操作外,没有任何抗干扰手段,全靠MCU内部自身的抗干扰能力进行的测试。结果,只有芯源CW32MCU没有彻底死机外,其它均有死机现象。 这种死机现象,在我们实际开发产品时,是禁止发生的。为了对付这种干扰,除了硬件上有些技术对策,那软件上又有些什么呢? 当然是我们最熟悉的看门狗了。“看门狗”这个神器在“古老的年代”51时期,那是没有的,需要在外面加一个“昂贵”的芯片来实现。当然,现在新时代,所有的ARM MCU基本上都标配了看门狗外设。 看门狗是啥,我们来看一下
[单片机]
“看门狗“VS“打狗棒”,谁胜谁负?(<font color='red'>STM32</font>篇)—MCU抗干扰实验系列专题(3)
STM32】1-LED 使用GPIO点灯
前言 本文用于记录学习过程,因个人水平有限,如有错误还请批评指正。 一、目的 使用STM32进行点灯实验 二、使用器材 1、keil 5 2、Proteus 三、Proteus仿真电路 元件包含: 1、STM32F103R6 2、LED-BIRG 3、POWER 4、RES(电阻) 四、keil 5操作 1、芯片选择 2、新建工程的勾选 3、添加main.c文件 五、main.c中的代码 #include stm32f10x.h void delay_ms(int32_t ms);//延时函数声明 int main() { uint8_t k;//LED亮灭计数 /*L
[单片机]
【<font color='red'>STM32</font>】1-LED 使用GPIO点灯
STM32 通用底层函数集锦, 自用
#include xustm32.h #include xucommon.h //#define COM_DEBUG #include xudebug.h //-------------------- STM32通用函数集锦 --------------------------------------------------- #if 0 HardFault_Handler PROC ; EXPORT HardFault_Handler ; B . IMPORT hard_fault_handler_c TST LR, #4 ITE EQ
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved