1-7 GD32函数指针应用

前言:


本博客仅在应用函数指针与回调函数相关的知识,通过实践巩固所学知识,也是对相关知识点的回顾。

函数指针与回调函数:1-6 GD32函数指针与回调函数-CSDN博客


目录

前言:

[1.0 程序架构思想](#1.0 程序架构思想)

[2.0 构建串口结构体](#2.0 构建串口结构体)

[3.0 结构体数组](#3.0 结构体数组)

[4.0 GPIO初始化](#4.0 GPIO初始化)

[5.0 串口初始化](#5.0 串口初始化)

[6.0 中断服务函数](#6.0 中断服务函数)

[7.0 打印输出重定向](#7.0 打印输出重定向)

[8.0 函数指针变量](#8.0 函数指针变量)

[9.0 注册回调函数](#9.0 注册回调函数)

[10.0 回调函数讲解](#10.0 回调函数讲解)

[11.0 灯的编号与状态](#11.0 灯的编号与状态)

[12.0 判断数据完整性](#12.0 判断数据完整性)

[13.0 CRC校验](#13.0 CRC校验)

[14.0 LED处理函数](#14.0 LED处理函数)

[15.0 Usb2Com任务处理函数](#15.0 Usb2Com任务处理函数)

[16.0 USART应用初始化](#16.0 USART应用初始化)

[17.0 usb2com_drv.c](#17.0 usb2com_drv.c)

[18.0 usb2com_app.c](#18.0 usb2com_app.c)

[19.0 main.c](#19.0 main.c)

后记:


1.0 程序架构思想



2.0 构建串口结构体


cpp 复制代码
typedef struct
{
    uint32_t uartNo;            // 表示串口USART0
    rcu_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 结构体数组


cpp 复制代码
static UartLxInfo_t g_uartLxInfo =                   // 结构体数组,存放结构体参数值
{
    USART0, RCU_USART0, RCU_GPIOA, GPIOA, GPIO_PIN_9, GPIO_PIN_10, USART0_IRQn
};

参数具体含义参考定义


4.0 GPIO初始化

cpp 复制代码
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 串口初始化


cpp 复制代码
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 中断服务函数


cpp 复制代码
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 打印输出重定向

cpp 复制代码
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 函数指针变量


cpp 复制代码
static void (*pPrcoUartDataFunc)(uint8_t data);      // 函数指针变量,保存应用层回调函数地址

9.0 注册回调函数


cpp 复制代码
void regUsb2ComCb(void(*pFunc)(uint8_t data))
{
    pPrcoUartDataFunc = pFunc;
}

10.0 回调函数讲解



usb2com_app.c


cpp 复制代码
/**
***********************************************************************
包格式:帧头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 灯的编号与状态

cpp 复制代码
typedef struct
{
    uint8_t ledNo;
    uint8_t ledState;
}LedCtrlInfo_t;

12.0 判断数据完整性


cpp 复制代码
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校验


cpp 复制代码
/**
***********************************************************
* @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灯进行点亮和熄灭操作,使用三元运算符

cpp 复制代码
/**
***********************************************************
* @brief LED控制处理函数
* @param ctrlData,结构体指针,传入LED的编号和状态
* @return 
***********************************************************
*/
static void CtrlLed(LedCtrlInfo_t *ctrlData)
{
    ctrlData->ledState != 0 ? TurnOnLed(ctrlData->ledNo) : TurnOffLed(ctrlData->ledNo);
}

15.0 Usb2Com任务处理函数


cpp 复制代码
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应用初始化


cpp 复制代码
/**
***********************************************************
* @brief USB转串口应用初始化函数
* @param
* @return 
***********************************************************
*/
void Usb2ComAppInit(void)
{
	regUsb2ComCb(ProcUartData);
}

17.0 usb2com_drv.c


cpp 复制代码
#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>
#include "gd32f30x.h"

typedef struct
{
    uint32_t uartNo;            // 表示串口USART0
    rcu_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


cpp 复制代码
#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


cpp 复制代码
#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);
	}
}

后记:

注:基于本人回顾理解,仅供学习参考

相关推荐
析木不会编程1 小时前
【小白51单片机专用教程】protues仿真独立按键控制LED
单片机·嵌入式硬件·51单片机
Uu_05kkq3 小时前
【C语言1】C语言常见概念(总结复习篇)——库函数、ASCII码、转义字符
c语言·数据结构·算法
枯无穷肉5 小时前
stm32制作CAN适配器4--WinUsb的使用
stm32·单片机·嵌入式硬件
不过四级不改名6775 小时前
基于HAL库的stm32的can收发实验
stm32·单片机·嵌入式硬件
嵌入式科普5 小时前
十一、从0开始卷出一个新项目之瑞萨RA6M5串口DTC接收不定长
c语言·stm32·cubeide·e2studio·ra6m5·dma接收不定长
嵌入式大圣5 小时前
单片机UDP数据透传
单片机·嵌入式硬件·udp
A懿轩A5 小时前
C/C++ 数据结构与算法【栈和队列】 栈+队列详细解析【日常学习,考研必备】带图+详细代码
c语言·数据结构·c++·学习·考研·算法·栈和队列
云山工作室6 小时前
基于单片机的视力保护及身姿矫正器设计(论文+源码)
stm32·单片机·嵌入式硬件·毕业设计·毕设
嵌入式-老费6 小时前
基于海思soc的智能产品开发(mcu读保护的设置)
单片机·嵌入式硬件
1 9 J7 小时前
数据结构 C/C++(实验五:图)
c语言·数据结构·c++·学习·算法