1.首先要一个带红外接收头的,能接收约38Khz 频率的.
2. 一个GD32的单片机.
看代码,以下代码,有参考链接,此博客具体实现是在硬件STC89C52,8位单片机.
这博客,详细有关资料,介绍的比较详细,这里不多说了。
请看修改后,可运行在GD的代码:
#include "gd32e23x.h"
#include "systick.h"
#include "recvremote.h"
typedef enum{
IR_RECV_INIT = 0x00,
IR_RECV_HEADER = 0x01,
IR_RECV_INFO
}IR_RECV_STATUS;
#define Ir_PIN_GROUP GPIOA
#define Ir_PIN_GPIO GPIO_PIN_7
uint8_t IR_DataFlag = 0;
uint8_t IR_RepeatFlag = 0;
uint8_t IR_GetDataFlag(void) {
if(IR_DataFlag) {
IR_DataFlag = 0;
return 1;
}
return 0;
}
uint8_t IR_GetRepeat(void) {
if(IR_RepeatFlag) {
IR_RepeatFlag = 0;
return 1;
}
return 0;
}
void ir_rx_init(void)
{
rcu_periph_clock_enable(RCU_GPIOA);
/* configure button pin as input */
gpio_mode_set(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN_7);
ir_rx_exit_init();
ir_rx_timer_config();
}
void ir_rx_exit_init(){
/* enable the CFGCMP clock */
rcu_periph_clock_enable(RCU_CFGCMP);
/* enable and set key EXTI interrupt to the specified priority */
nvic_irq_enable(EXTI4_15_IRQn, 0x01);
/* connect key EXTI line to key GPIO pin */
syscfg_exti_line_config(EXTI_SOURCE_GPIOA, EXTI_SOURCE_PIN7);
/* configure key EXTI line */
exti_init(EXTI_7, EXTI_INTERRUPT, EXTI_TRIG_FALLING);
exti_interrupt_flag_clear(EXTI_7);
}
//定时器计时10us
void ir_rx_timer_config(void)
{
/* ----------------------------------------------------------------------------
TIMER13 Configuration:
---------------------------------------------------------------------------- */
timer_oc_parameter_struct timer_ocinitpara;
timer_parameter_struct timer_initpara;
/* enable the peripherals clock */
rcu_periph_clock_enable(RCU_TIMER13);
/* deinit a TIMER */
timer_deinit(TIMER13);
/* initialize TIMER init parameter struct */
timer_struct_para_init(&timer_initpara);
/* TIMER2 configuration */
timer_initpara.prescaler = 71;
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
timer_initpara.counterdirection = TIMER_COUNTER_UP;
timer_initpara.period = 9;
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
timer_init(TIMER13, &timer_initpara);
/* clear channel 0 interrupt bit */
timer_interrupt_flag_clear(TIMER13, TIMER_INT_FLAG_UP);
/* enable the TIMER interrupt */
timer_interrupt_enable(TIMER13, TIMER_INT_UP);
/* enable a TIMER */
nvic_irq_enable(TIMER13_IRQn, 1);
}
volatile uint32_t timer_Count = 0;
IR_RECV_STATUS ir_recv_status = IR_RECV_INIT;
uint32_t IR_Time;
uint8_t IR_pData;
uint8_t IR_Data[4];
void set_timer_count(uint32_t time){
timer_Count = time;
}
uint32_t Get_timer_Count(){
return timer_Count;
}
static void timer13_status(unsigned char flag){
if(flag){
timer_enable(TIMER13);
return;
}
timer_disable(TIMER13);
}
void TIMER13_IRQHandler(void)
{
if(SET == timer_interrupt_flag_get(TIMER13, TIMER_INT_FLAG_UP)){
timer_interrupt_flag_clear(TIMER13, TIMER_INT_FLAG_UP);
timer_Count++;
}
}
static uint8_t IR_AroundNum(uint16_t num,uint16_t compare,uint16_t offset){
return num >= (compare - offset) && num <= (compare + offset);
}
//信号头 9ms + 4.5ms = 13500us 13500/10 = 1350
//repeat 9ms + 2.5ms = 11250 us 1125
//逻辑0 560us+560us= 1120 us 112
//逻辑1 560us+1690us=2250us 225
void ir_recv_logic_process(void){
switch (ir_recv_status)
{
case IR_RECV_INIT://当外部中断首次响应(调用)
set_timer_count(0);//设置计数器初值
timer13_status(1);//开启定时器
ir_recv_status = IR_RECV_HEADER;//接收状态开始置位接收头信息,也就是引导码
break;
case IR_RECV_HEADER:
IR_Time = Get_timer_Count();
set_timer_count(0);
//接收到开始信号
if(IR_AroundNum(IR_Time,1350,30)){
ir_recv_status = IR_RECV_INFO;
//printf("head sianal \r\n");
}else if(IR_AroundNum(IR_Time,1125,30)){
IR_RepeatFlag = 1;
ir_recv_status = IR_RECV_INIT;
}else{
ir_recv_status = IR_RECV_HEADER;
}
//printf("ir_recv_status %d, time=%d \r\n",ir_recv_status,IR_Time);
break;
case IR_RECV_INFO:
IR_Time = Get_timer_Count();
set_timer_count(0);
if(IR_AroundNum(IR_Time,112,30)){//logic 0
IR_Data[IR_pData / 8] &= ~(0x01 << (IR_pData % 8));
IR_pData++;
}else if(IR_AroundNum(IR_Time,225,30)){//logic 1
IR_Data[IR_pData / 8] |= (0x01 << (IR_pData % 8));
IR_pData++;
}else {
IR_pData = 0;
ir_recv_status = IR_RECV_HEADER;
}
if(IR_pData >= 32){
IR_pData = 0;
// 数据校验
if((IR_Data[0]==~IR_Data[1]) && (IR_Data[2]==~IR_Data[3])) {
IR_DataFlag = 1;
}
timer13_status(0);//定时器关闭
ir_recv_status = IR_RECV_INIT;//回到初始状态
}
break;
default:
break;
}
}
void EXTI4_15_IRQHandler(void)
{
if(RESET != exti_interrupt_flag_get(EXTI_7)) {
ir_recv_logic_process();
exti_interrupt_flag_clear(EXTI_7);
}
}
说明: 1. 该代码使用了一个外部中断, 该中断 硬件引脚外接 红外接收头. (可适当连接部分电阻器件)
2. 软件另外部分使用了一个定时器, 单片机可用的定时器即可。主要用在计时,统计下降沿之间的差值,来判断逻辑0和逻辑1,以及触发信号的到来。