欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 教育 > 高考 > 1-7 GD32函数指针应用

1-7 GD32函数指针应用

2024/11/30 6:10:25 来源:https://blog.csdn.net/qq_45973003/article/details/144075160  浏览:    关键词:1-7 GD32函数指针应用

前言:


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

函数指针与回调函数: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);}
}

后记:

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

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com