GD32入门到实战22--红外NEC通信协议
ir_drv.c
红外传输协议地位在前,所以我们可以这样保存数据到数组
假使接收到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 = 1usif(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();}
}