打印
[研电赛技术支持]

GD32函数指针应用

[复制链接]
16|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
1.0 程序架构思想



2.0 构建串口结构体
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 结构体数组
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;
    }
    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;            // 表示串口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
#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;
    }
    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);
        }
}


————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/qq_45973003/article/details/144075160

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

18

主题

58

帖子

0

粉丝