前言:
本博客仅在应用函数指针与回调函数相关的知识,通过实践巩固所学知识,也是对相关知识点的回顾。
函数指针与回调函数:1-6 GD32函数指针与回调函数-CSDN博客
目录
前言:
1.0 程序架构思想
2.0 构建串口结构体
3.0 结构体数组
4.0 GPIO初始化
5.0 串口初始化
6.0 中断服务函数
7.0 打印输出重定向
8.0 函数指针变量
9.0 注册回调函数
10.0 回调函数讲解
11.0 灯的编号与状态
12.0 判断数据完整性
13.0 CRC校验
14.0 LED处理函数
15.0 Usb2Com任务处理函数
16.0 USART应用初始化
17.0 usb2com_drv.c
18.0 usb2com_app.c
19.0 main.c
后记:
1.0 程序架构思想
2.0 构建串口结构体
typedef struct
{uint32_t uartNo; // 表示串口USART0rcu_periph_enum rcuUart; // 串口时钟rcu_periph_enum rcuGpio; // GPIO时钟uint32_t gpio; // 对应的GPIO口uint32_t txPin; // 串口发送端引脚uint32_t rxPin; // 串口接收端引脚uint32_t irq; // 串口中断
}UartLxInfo_t;
3.0 结构体数组
static UartLxInfo_t g_uartLxInfo = // 结构体数组,存放结构体参数值
{USART0, RCU_USART0, RCU_GPIOA, GPIOA, GPIO_PIN_9, GPIO_PIN_10, USART0_IRQn
};
参数具体含义参考定义
4.0 GPIO初始化
static void Usb2ComGpioInit(void) // GPIO时钟初始化
{rcu_periph_clock_enable(g_uartLxInfo.rcuGpio);gpio_init(g_uartLxInfo.gpio, GPIO_MODE_AF_PP, GPIO_OSPEED_10MHZ, g_uartLxInfo.txPin);gpio_init(g_uartLxInfo.gpio, GPIO_MODE_IPU, GPIO_OSPEED_10MHZ, g_uartLxInfo.rxPin);
}
5.0 串口初始化
static void Usb2ComUartInit(uint32_t baudRate)
{rcu_periph_clock_enable(g_uartLxInfo.rcuUart); // 使能串口时钟usart_deinit(g_uartLxInfo.uartNo); // 复位串口usart_baudrate_set(g_uartLxInfo.uartNo, baudRate); // 设置波特率usart_transmit_config(g_uartLxInfo.uartNo, USART_TRANSMIT_ENABLE); // 使能串口发送usart_receive_config(g_uartLxInfo.uartNo, USART_RECEIVE_ENABLE); // 使能串口接收usart_interrupt_enable(g_uartLxInfo.uartNo, USART_INT_RBNE); // 使能串口中断nvic_irq_enable(g_uartLxInfo.irq, 0, 0); // 中断使能usart_enable(g_uartLxInfo.uartNo); // 串口使能
}
6.0 中断服务函数
void USART0_IRQHandler(void)
{if (usart_interrupt_flag_get(g_uartLxInfo.uartNo, USART_INT_FLAG_RBNE) != RESET){usart_interrupt_flag_clear(g_uartLxInfo.uartNo, USART_INT_FLAG_RBNE);uint8_t uData = (uint8_t)usart_data_receive(g_uartLxInfo.uartNo);pPrcoUartDataFunc(uData);}
}
7.0 打印输出重定向
int fputc(int ch, FILE *f)
{usart_data_transmit(g_uartLxInfo.uartNo, (uint8_t)ch);while(usart_flag_get(g_uartLxInfo.uartNo, USART_FLAG_TBE) == RESET);return ch;
}
8.0 函数指针变量
static void (*pPrcoUartDataFunc)(uint8_t data); // 函数指针变量,保存应用层回调函数地址
9.0 注册回调函数
void regUsb2ComCb(void(*pFunc)(uint8_t data))
{pPrcoUartDataFunc = pFunc;
}
10.0 回调函数讲解
usb2com_app.c
/**
***********************************************************************
包格式:帧头0 帧头1 数据长度 功能字 LED编号 亮/灭 异或校验数据0x55 0xAA 0x03 0x06 0x00 0x01 0xFB
***********************************************************************
*/
#define FRAME_HEAD_0 0x55
#define FRAME_HEAD_1 0xAA
#define CTRL_DATA_LEN 3
#define PACKET_DATA_LEN (CTRL_DATA_LEN + 4)
#define FUNC_DATA_IDX 3
#define LED_CTRL_CODE 0x06
#define MAX_BUF_SIZE 20
static uint8_t g_rcvDataBuf[MAX_BUF_SIZE];
static bool g_pktRcvd = false;
11.0 灯的编号与状态
typedef struct
{uint8_t ledNo;uint8_t ledState;
}LedCtrlInfo_t;
12.0 判断数据完整性
static void ProcUartData(uint8_t data)
{static uint8_t index = 0;g_rcvDataBuf[index++] = data;switch (index){case 1:if (g_rcvDataBuf[0] != FRAME_HEAD_0){index = 0;}break;case 2:if (g_rcvDataBuf[1] != FRAME_HEAD_1){index = 0;}break;case PACKET_DATA_LEN:g_pktRcvd = true;index = 0;break;default:break;}
}
13.0 CRC校验
/**
***********************************************************
* @brief 对数据进行异或运算
* @param data, 存储数组的首地址
* @param len, 要计算的元素的个数
* @return 异或运算结果
***********************************************************
*/
static uint8_t CalXorSum(const uint8_t *data, uint32_t len)
{uint8_t xorSum = 0;for (uint32_t i = 0; i < len; i++){xorSum ^= data[i];}return xorSum;
}
14.0 LED处理函数
注:该函数调用LED处理函数,对LED灯进行点亮和熄灭操作,使用三元运算符
/**
***********************************************************
* @brief LED控制处理函数
* @param ctrlData,结构体指针,传入LED的编号和状态
* @return
***********************************************************
*/
static void CtrlLed(LedCtrlInfo_t *ctrlData)
{ctrlData->ledState != 0 ? TurnOnLed(ctrlData->ledNo) : TurnOffLed(ctrlData->ledNo);
}
15.0 Usb2Com任务处理函数
void Usb2ComTask(void)
{if (!g_pktRcvd){return;}g_pktRcvd = false;if (CalXorSum(g_rcvDataBuf, PACKET_DATA_LEN - 1) != g_rcvDataBuf[PACKET_DATA_LEN - 1]){return;}if (g_rcvDataBuf[FUNC_DATA_IDX] == LED_CTRL_CODE){CtrlLed((LedCtrlInfo_t *)(&g_rcvDataBuf[FUNC_DATA_IDX + 1]));}
}
16.0 USART应用初始化
/**
***********************************************************
* @brief USB转串口应用初始化函数
* @param
* @return
***********************************************************
*/
void Usb2ComAppInit(void)
{regUsb2ComCb(ProcUartData);
}
17.0 usb2com_drv.c
#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>
#include "gd32f30x.h"typedef struct
{uint32_t uartNo; // 表示串口USART0rcu_periph_enum rcuUart; // 串口时钟rcu_periph_enum rcuGpio; // GPIO时钟uint32_t gpio; // 对应的GPIO口uint32_t txPin; // 串口发送端引脚uint32_t rxPin; // 串口接收端引脚uint32_t irq; // 串口中断
}UartLxInfo_t;static UartLxInfo_t g_uartLxInfo = // 结构体数组,存放结构体参数值
{USART0, RCU_USART0, RCU_GPIOA, GPIOA, GPIO_PIN_9, GPIO_PIN_10, USART0_IRQn
};static void (*pPrcoUartDataFunc)(uint8_t data); // 函数指针变量,保存应用层回调函数地址static void Usb2ComGpioInit(void) // GPIO时钟初始化
{rcu_periph_clock_enable(g_uartLxInfo.rcuGpio);gpio_init(g_uartLxInfo.gpio, GPIO_MODE_AF_PP, GPIO_OSPEED_10MHZ, g_uartLxInfo.txPin);gpio_init(g_uartLxInfo.gpio, GPIO_MODE_IPU, GPIO_OSPEED_10MHZ, g_uartLxInfo.rxPin);
}void regUsb2ComCb(void(*pFunc)(uint8_t data))
{pPrcoUartDataFunc = pFunc;
}static void Usb2ComUartInit(uint32_t baudRate)
{rcu_periph_clock_enable(g_uartLxInfo.rcuUart); // 使能串口时钟usart_deinit(g_uartLxInfo.uartNo); // 复位串口usart_baudrate_set(g_uartLxInfo.uartNo, baudRate); // 设置波特率usart_transmit_config(g_uartLxInfo.uartNo, USART_TRANSMIT_ENABLE); // 使能串口发送usart_receive_config(g_uartLxInfo.uartNo, USART_RECEIVE_ENABLE); // 使能串口接收usart_interrupt_enable(g_uartLxInfo.uartNo, USART_INT_RBNE); // 使能串口中断nvic_irq_enable(g_uartLxInfo.irq, 0, 0); // 中断使能usart_enable(g_uartLxInfo.uartNo); // 串口使能
}void Usb2ComDrvInit(void)
{Usb2ComGpioInit();Usb2ComUartInit(115200);
}void USART0_IRQHandler(void)
{if (usart_interrupt_flag_get(g_uartLxInfo.uartNo, USART_INT_FLAG_RBNE) != RESET){usart_interrupt_flag_clear(g_uartLxInfo.uartNo, USART_INT_FLAG_RBNE);uint8_t uData = (uint8_t)usart_data_receive(g_uartLxInfo.uartNo);pPrcoUartDataFunc(uData);}
}int fputc(int ch, FILE *f)
{usart_data_transmit(g_uartLxInfo.uartNo, (uint8_t)ch);while(usart_flag_get(g_uartLxInfo.uartNo, USART_FLAG_TBE) == RESET);return ch;
}
18.0 usb2com_app.c
#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>
#include "usb2com_drv.h"
#include "led_drv.h"/**
***********************************************************************
包格式:帧头0 帧头1 数据长度 功能字 LED编号 亮/灭 异或校验数据0x55 0xAA 0x03 0x06 0x00 0x01 0xFB
***********************************************************************
*/
#define FRAME_HEAD_0 0x55
#define FRAME_HEAD_1 0xAA
#define CTRL_DATA_LEN 3
#define PACKET_DATA_LEN (CTRL_DATA_LEN + 4)
#define FUNC_DATA_IDX 3
#define LED_CTRL_CODE 0x06
#define MAX_BUF_SIZE 20
static uint8_t g_rcvDataBuf[MAX_BUF_SIZE];
static bool g_pktRcvd = false;typedef struct
{uint8_t ledNo;uint8_t ledState;
}LedCtrlInfo_t;static void ProcUartData(uint8_t data)
{static uint8_t index = 0;g_rcvDataBuf[index++] = data;switch (index){case 1:if (g_rcvDataBuf[0] != FRAME_HEAD_0){index = 0;}break;case 2:if (g_rcvDataBuf[1] != FRAME_HEAD_1){index = 0;}break;case PACKET_DATA_LEN:g_pktRcvd = true;index = 0;break;default:break;}
}/**
***********************************************************
* @brief 对数据进行异或运算
* @param data, 存储数组的首地址
* @param len, 要计算的元素的个数
* @return 异或运算结果
***********************************************************
*/
static uint8_t CalXorSum(const uint8_t *data, uint32_t len)
{uint8_t xorSum = 0;for (uint32_t i = 0; i < len; i++){xorSum ^= data[i];}return xorSum;
}/**
***********************************************************
* @brief LED控制处理函数
* @param ctrlData,结构体指针,传入LED的编号和状态
* @return
***********************************************************
*/
static void CtrlLed(LedCtrlInfo_t *ctrlData)
{ctrlData->ledState != 0 ? TurnOnLed(ctrlData->ledNo) : TurnOffLed(ctrlData->ledNo);
}/**
***********************************************************
* @brief USB转串口任务处理函数
* @param
* @return
***********************************************************
*/
void Usb2ComTask(void)
{if (!g_pktRcvd){return;}g_pktRcvd = false;if (CalXorSum(g_rcvDataBuf, PACKET_DATA_LEN - 1) != g_rcvDataBuf[PACKET_DATA_LEN - 1]){return;}if (g_rcvDataBuf[FUNC_DATA_IDX] == LED_CTRL_CODE){CtrlLed((LedCtrlInfo_t *)(&g_rcvDataBuf[FUNC_DATA_IDX + 1]));}
}/**
***********************************************************
* @brief USB转串口应用初始化函数
* @param
* @return
***********************************************************
*/
void Usb2ComAppInit(void)
{regUsb2ComCb(ProcUartData);
}
19.0 main.c
#include <stdint.h>
#include <stdio.h>
#include "gd32f30x.h"
#include "led_drv.h"
#include "key_drv.h"
#include "systick.h"
#include "usb2com_drv.h"
#include "usb2com_app.h"
#include "delay.h"static void DrvInit(void)
{SystickInit();LedDrvInit();KeyDrvInit();DelayInit();Usb2ComDrvInit();
}
static void AppInit(void)
{Usb2ComAppInit();
}int main(void)
{ DrvInit();AppInit();while (1){Usb2ComTask();//DelayNms(1000);}
}
后记:
注:基于本人回顾理解,仅供学习参考