在GD32E230上如何接收红外码值(NEC协议)

该代码展示了如何在GD32单片机上使用外部中断和定时器处理红外遥控信号。通过检测下降沿时间间隔来区分逻辑0和逻辑1,从而解码红外信号。当接收到特定时间间隔的信号时,代码会判断是开始信号、重复信号还是数据信号。
摘要由CSDN通过智能技术生成

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,以及触发信号的到来。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Teleger

你的支持是我前进的方向

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值