目录

GD32入门到实战22-红外NEC通信协议

目录

GD32入门到实战22–红外NEC通信协议

ir_drv.chttps://i-blog.csdnimg.cn/direct/69df56a04fbd49d989453636ded3a820.png

https://i-blog.csdnimg.cn/direct/13208aec7c3a45ffb0e4011c6b80e6f6.png

https://i-blog.csdnimg.cn/direct/d80fa9a943ee4662abddc2edf9cdde23.png

https://i-blog.csdnimg.cn/direct/6a4dd83939844453929b803136be958d.png

https://i-blog.csdnimg.cn/direct/590980183ebe4a0fb0956c456bdc17d5.png

红外传输协议地位在前,所以我们可以这样保存数据到数组

https://i-blog.csdnimg.cn/direct/7d5922be359e4b26bb3d707c6642dd55.png

假使接收到1就»1再|0x80,如果接收到0就»1

新建红外驱动层代码ir_drv.c


#include <stdio.h>  
#include "gd32f30x.h"
#include <stdbool.h>  

static void GpioInit(void) 
{
    rcu_periph_clock_enable(RCU_GPIOC);
    gpio_init(GPIOC,GPIO_MODE_IN_FLOATING,GPIO_OSPEED_10MHZ,GPIO_PIN_6);
}

static void TimerInit()
{
    timer_parameter_struct timerInitPara;
    timer_struct_para_init(&timerInitPara);//给定时器结构体赋初值
    
    /*使能定时器时钟*/
    rcu_periph_clock_enable(RCU_TIMER7);
    /*复位定时器*/
    timer_deinit(TIMER7);
    /*设置预分频值*/
    timerInitPara.prescaler = 120 - 1;//时钟频率为1Mhz,周期为1us
    /*设置自动重装载值*/
    timerInitPara.period = 65535;
    /*初始化定时器*/
    timer_init(TIMER7,&timerInitPara);//给定时器结构体赋初值
    
    timer_ic_parameter_struct icInitPara;
    timer_channel_input_struct_para_init(&icInitPara);
    /*设置上升沿/下降沿捕获*/
    icInitPara.icpolarity = TIMER_IC_POLARITY_FALLING;
    /*设置输入通道*/
    icInitPara.icselection = TIMER_IC_SELECTION_DIRECTTI;
    timer_input_capture_config(TIMER7,TIMER_CH_0,&icInitPara);
    /*使能定时器的捕获中断*/
    timer_interrupt_flag_clear(TIMER7 ,TIMER_INT_FLAG_CH0);//清除中断标志位
    timer_interrupt_enable(TIMER7,TIMER_INT_CH0);
    /*使能定时器中断优先级*/
    nvic_irq_enable(TIMER7_Channel_IRQn, 0, 0);
    /*使能定时器*/
    timer_enable(TIMER7);
}


#define TICK_HEAD_MAX   20000//引导码的最长时间
#define TICK_HEAD_MIN   10000//引导码的最短时间
#define TICK_0_MAX      1800//0的最长时间
#define TICK_0_MIN      500 //0的最短时间
#define TICK_1_MAX      3000//1的最长时间
#define TICK_1_MIN      1800//1的最短时间
static uint8_t g_irCode[4]; //存放数组
static bool g_irCodeFlag = false; //解析到完整的数据
static void ParseIrFrame(uint32_t tickNum)
{
    static bool s_headFlag = false;//表示是否收到
    static uint8_t s_index = 0;//数组索引值
    
    if(tickNum > TICK_HEAD_MIN && tickNum < TICK_HEAD_MAX)//引导码时间是否正常
    {//正常
        s_headFlag = true;
        return;
    }
    if(!s_headFlag)//如果引导码不正常
    {//说明没有解析到引导码
        return;
    }
    if(tickNum > TICK_1_MIN && tickNum < TICK_1_MAX)//1
    {//s_index / 8:s_index为8位数据,整个数据长为32位,
     //s_index0-7存到g_irCode[0];s_index8-15存到g_irCode[1]....
        g_irCode[s_index / 8] >>= 1;
        g_irCode[s_index / 8] |= 0x80;
        s_index++;
    }
    if(tickNum > TICK_0_MIN && tickNum < TICK_0_MAX)//0
    {
        g_irCode[s_index / 8] >>= 1;
        s_index++;
    }
    if(s_index == 32)
    {   //if(g_irCode[2] == (uint8_t)~g_irCode[3])//校验数据反码,两种方法一样
        if((g_irCode[2] & g_irCode[3]) == 0)//按位与
        {//如果相等
            g_irCodeFlag = true;
        }
        else
        {
            g_irCodeFlag = false;
        }            
        s_headFlag = false;//清除接收到标志
        s_index = 0;//数组索引清零
    }
}

/**
***********************************************************
* @brief 获取红外码值
* @param  code,输出,按键码值
* @return 返回是否成功获取按键码值
***********************************************************
*///*code:
bool GetIrCode(uint8_t *code)
{
    if(!g_irCodeFlag)//如果没有解析到完整数据
    {
        return false;
    }
    *code = g_irCode[2];//把数据取到指向的地址
    g_irCodeFlag = false;//把解析完成标志位清零
    return true;
}



void TIMER7_Channel_IRQHandler()
{   
    static uint32_t icValue;//1 = 1us
    if(timer_interrupt_flag_get(TIMER7 , TIMER_INT_FLAG_CH0) == SET)//判断是否产生中断
    {
        timer_interrupt_flag_clear(TIMER7 , TIMER_INT_FLAG_CH0);//清除中断标志位
        icValue = timer_channel_capture_value_register_read(TIMER7, TIMER_CH_0) + 1;//读取计数值
        timer_counter_value_config(TIMER7 , 0);//计数器清零
        ParseIrFrame(icValue);
    }
}


/**
***********************************************************
* @brief 红外接收硬件初始化函数
* @param 
* @return 
***********************************************************
*/
void IrDrvInit()
{
    GpioInit();
    TimerInit();
}

ir_drv.h


#ifndef _IR_DRV_H_
#define _IR_DRV_H_

#include <stdint.h>
#include <stdbool.h>

#define KEY1_CODE   0X45
#define KEY2_CODE   0X46

/**
***********************************************************
* @brief 红外接收硬件初始化函数
* @param 
* @return 
***********************************************************
*/
void IrDrvInit(void);
	
/**
***********************************************************
* @brief 获取遥控按键码值
* @param code,输出,按键码值
* @return 返回是否成功获取到按键码值
***********************************************************
*/
bool GetIrCode(uint8_t *code);

#endif

hmi_app.c


#include <stdint.h>
#include "led_drv.h"
#include "ir_drv.h"
#include <stdio.h>
/**
***********************************************************
* @brief 人机交互任务处理函数
* @param 
* @return 
***********************************************************
*/
void HmiTask(void)
{
	uint8_t keyVal;
    if(!GetIrCode(&keyVal))//如果没有获取到码值
    {
        return;
    }
    printf("ir keyVal is 0x%x.\n",keyVal);
	switch (keyVal)
	{
		case KEY1_CODE:
			TurnOnLed(LED1);
			break;
		case KEY2_CODE:
			TurnOffLed(LED1);
			break;
		default:
			break;
	}
}

main.c


#include <stdint.h>
#include <stdio.h>
#include "led_drv.h"
#include "key_drv.h"
#include "systick.h"
#include "usart_drv.h"
#include "delay.h"
#include "usb2com_app.h"
#include "hmi_app.h"
#include "ir_drv.h"

typedef struct
{
	uint8_t run;                // 调度标志,1:调度,0:挂起
	uint16_t timCount;          // 时间片计数值
	uint16_t timRload;          // 时间片重载值
	void (*pTaskFuncCb)(void);  // 函数指针变量,用来保存业务功能模块函数地址
} TaskComps_t;/*任务调度结构体*/

static TaskComps_t g_taskComps[] =  /*任务调度结构体数组,存放各个业务功能模块调度参数*/
{/*填入各个业务功能模块*/
	{0, 5,   5,   HmiTask},
	{0, 200, 200, usartTask},
	/* 添加业务功能模块 */
};

#define TASK_NUM_MAX   (sizeof(g_taskComps) / sizeof(g_taskComps[0]))
/*用宏定义计算结构体数组的个数*///sizeof(g_taskComps):计算整个数组 g_taskComps 的大小(以字节为单位)。
//sizeof(g_taskComps[0]):计算数组中单个元素的大小(以字节为单位)。
//通过整个数组的大小除以单个元素的大小,得到数组中元素的数量



/*
******************************************
* @brief 任务调度函数(判断所有业务模块的标志位)
* @param 
* @return
********************************************
*/
static void TaskHandler(void)
{
	for (uint8_t i = 0; i < TASK_NUM_MAX; i++)
	{
		if (g_taskComps[i].run)                  // 判断时间片标志
		{
			g_taskComps[i].run = 0;              // 标志清零
			g_taskComps[i].pTaskFuncCb();        // 执行调度业务功能模块
		}
	}
}

/*
******************************************
* @brief 时间片递减函数 1ms-1时间片
* @param 
* @return
********************************************
*/
static void TaskScheduleCb(void)
{
	for (uint8_t i = 0; i < TASK_NUM_MAX; i++)
	{
		if (g_taskComps[i].timCount)
		{
			g_taskComps[i].timCount--;
			if (g_taskComps[i].timCount == 0)
			{
				g_taskComps[i].run = 1;
				g_taskComps[i].timCount = g_taskComps[i].timRload;
			}
		}
	}
}

static void DrvInit(void)
{
	SystickInit();
	LedDrvInit();
	DelayInit();
	UsartDrv_Init();
    IrDrvInit();
}
static void AppInit(void)
{
	TaskScheduleCbReg(TaskScheduleCb);
}

int main(void)
{	
	DrvInit();
	AppInit();

	while (1)
	{
		TaskHandler();
	}
}