GD32入门到实战22-红外NEC通信协议
目录
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 = 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();
}
}