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-17 10:55

STM32 IO口双向问题
如果需要使用一个GPIO既要用作输入也要用作输出的,可以将该引脚配置为Output-OpenDrain, 同时在引脚上连接一个上拉电阻,可将它用作(准)双向输入输出口。 输出时: GPIOx- ODR =输出值; 输入时: 读时先输出高电平(否则有可能因先前低电平输出锁死IO口为低电平),然后读. GPIOx- ODR = 0xFFFF; 变量 = GPIOx- IDR;
[单片机]
<font color='red'>STM32</font> IO口双向问题
STM32开发环境】Linux下开发stm32(四) | 固件库工程开发
st官方固件库是在寄存器操作之上的,但是使用寄存器操作的话,需要注意的地方很多,需要对照参考手册一个一个赋值,稍有不慎便会出错,所以固件库将外设的初始化封装成初始化结构体,将外设的操作封装在函数中,将寄存器赋值的操作都封装起来,我们只需要调用API就可以,这样一来既提高了开发效率,也减少了代码量,如果还不能在MDK里熟练使用固件库编程,建议先补基础~接下来,我们在上一节寄存器工程的基础上,添加固件库,使用固件库进行开发。 1.创建固件库工程 将上一节的寄存器工程复制过来,改名为03-template-lib,然后再其中创建如下目录结构,便于工程管理: startup:存放启动文件 cmsis:stm32固件库中的cmsi
[单片机]
【<font color='red'>STM32</font>开发环境】Linux下开发<font color='red'>stm32</font>(四) | 固件库工程开发
stm32 浮点数问题
由于我后面的课题需要涉及较多的浮点运算,只熟悉f103,它不带FPU,所以软件浮点算法就显得很重要了。这几天在做些小研究和测试。 今天又仔细研读了谭浩强的C语言书的数据类型章节,上面有说到c编译系统总将float类型转换成double类型来进行浮点运算,然而一般应用中7位有效数字的占32位的float类型已基本满足需求,若转为16位有效数字64位double类型岂不是没什么必要?速度岂不是会降低? 今天将原子哥的内部温度传感器实验的浮点运算的代码作了个小小的改动,却是大大的改善,结果如下: 温度计算公式原代码为: temp=(1.43-temp)/0.0043+25; // 这句产生的代码量为1584字节改为单精度: te
[单片机]
STM32 SPI NRF24L01复习整理
/********** mySpi.h****************/ #ifndef __MY_SPI_H #define __MY_SPI_H #include stm32f10x.h #include stdio.h #define SPI1_CSN_HIGH() GPIO_SetBits(GPIOA,GPIO_Pin_1); #define SPI1_CSN_LOW() GPIO_ResetBits(GPIOA,GPIO_Pin_1); #define SPI2_CSN_HIGH() GPIO_SetBits(GPIOB,GPIO_Pin_12); #define SPI2_CSN_LOW() GPIO
[单片机]
IIC (STM32)
IIC(Inter-Integrated Circuit) 总线是一种由 PHILIPS 公司开发的 两线式串行总线 高速 IIC 总线一般可达 400kbps 以上。 IIC信号时序图 IIC 总线在传送数据过程中共有三种类型信号,开始信号、结束信号和应答信号。 开始信号: SCL 为高电平时,SDA 由高电平向低电平跳变,开始传送数据。 SCL = 1 SDA = 1 SDA = 0 结束信号: SCL 为高电平时,SDA 由低电平向高电平跳变,结束传送数据。 SCL = 1 SDA = 0 SDA = 1 应答信号: 每发送一个字节(8个bit),一个字节传输的8个时钟后的第九个时钟期间 接收
[单片机]
IIC (<font color='red'>STM32</font>)
一文读懂STM32之独立看门狗/窗口看门狗的原理
一、独立看门狗 STM32的独立看门狗由内部专门的40Khz低速时钟驱动,即使主时钟发生故障,它也仍然有效。 看门狗的原理:单片机系统在外界的干扰下会出现程序跑飞的现象导致出现死循环,看门狗电路就是为了避免这种情况的发生。看门狗的作用就是在一定时间内(通过定时计数器实现)没有接收喂狗信号(表示MCU已经挂了),便实现处理器的自动复位重启(发送复位信号)。 在键值寄存器(IWDG_KR)中写入0xCCCC,开始启用独立看门狗;此时计数器开始从其复位值0xFFF递减计数。当计数器计数到末尾0x000时,会产生一个复位信号(IWDG_RESET)。无论何时,只要键寄存器IWDG_KR中被写入0xAAAA,IWDG_RLR中的值就会被
[单片机]
一文读懂<font color='red'>STM32</font>之独立看门狗/窗口看门狗的原理
spi 设置speed
//SPI 速度设置函数 //SpeedSet: //SPI_SPEED_2 2分频 (SPI 12M --sys 24M) //SPI_SPEED_8 8分频 (SPI 3M --sys 24M) //SPI_SPEED_16 16分频 (SPI 1.5M --sys 24M) //SPI_SPEED_256 256分频 (SPI 905.6K --sys 24M) void SPI1_SetSpeed(u8 SpeedSet) { SPI1- CR1&=0XFFC7;//Fsck=Fcpu/256 if(SpeedSet==SPI_SPEED_2)//二分频 { SPI1- CR
[单片机]
基于PC的数字电视方案
引言 数字电视作为继黑白电视、彩色电视后的第三代电视技术,已开始在发达国家普及。我国的数字电视标准已经颁布,为我国数字电视的普及扫清了技术障碍。目前基本上有两种数模一体化电视解决方案,第一种是在现有的逐行电视电路的基础上增加数字解码电路的方案,这类方案在数字电视发展的初期被采用,它的集成度低、成本高,但开发周期短;第二种是专用单芯片方案,这是目前被广泛采用的主流,它的功能十分强大,极具成本优势,但开发难度较大。本文提出第三种基于PC的数字电视方案,它的功能灵活多变,能满足未来3C发展需要。 基本原理 本文主要介绍在PC上如何实现数字电视接收。 目前我国处在数字电视发展的初期阶段,数字和模拟信号并存,因此本方案还必须在PC的
[家用电子]
小广播
设计资源 培训 开发板 精华推荐

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

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

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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