# 22.01_UART-发送数据

## 测试步骤

1. 初始化串口波特兰 115200
2. 串口数据长度8位 停止位1位 MSL 关闭校验
3. 串口发送数据0x50

## 实测数据

## 参考代码

22.01_UART_Send.c

    /**
     * @brief UART-发送数据
     * @details
     * 1. 初始化串口波特兰 115200
     * 2. 串口数据长度8位 停止位1位 MSL 关闭校验
     * 3. 串口发送数据0x50
     */
    #include "lks32mc09x_lib.h"
    volatile int baud = 115200;    // 设定波特率
    volatile int refbaud = 115200; // 实际波特率
    volatile int sendflg = 0;      // 设定波特率
    volatile int data = 0xa0;      // 要发送的数据
    int main(void)
    {
        __disable_irq();
        SYS_WR_PROTECT = 0x7a83;
        SYS_CLK_CFG = 0x1ff;
        SYS_WR_PROTECT = 0;
        UART_InitTypeDef UART_InitType;
        UART_StructInit(&UART_InitType);
        UART_InitType.BaudRate = baud;                 ///< 波特率
        UART_InitType.WordLength = UART_WORDLENGTH_8b; ///< 数据长度
        UART_InitType.StopBits = UART_STOPBITS_1b;     ///< 停止位长度
        UART_InitType.FirstSend = UART_FIRSTSEND_MSB;  ///< 发送数据大小端设置
        UART_InitType.ParityMode = UART_Parity_NO;     ///< 奇偶校验
        UART_InitType.MultiDropEna = 0;                ///< 使能Multi-drop, 0:Disable 1:Enable
        UART_InitType.Bit9Value = 0;                   ///< Multi-drop Master模式时, 第9个数据位值
        UART_InitType.DUPLEX = 0;                      ///< 双工选择, 0:全双工 1:半双工
        UART_InitType.Match485Addr = 0;                ///< 用作485通信时的匹配地址
        UART_InitType.IRQEna = 0;                      ///< 中断使能寄存器
        UART_InitType.DMARE = 0;                       ///< DMA 请求使能
        UART_InitType.RXD_INV = 0;                     ///< 接收电平取反
        UART_InitType.TXD_INV = 0;                     ///< 发送电平取反
        UART_Init(UART0, &UART_InitType);
        GPIO_Config(GPIO0, GPIO_PinSource_0, GPIO_Mode_OUT, GPIO_AF_UART);
        for (;;)
        {
            refbaud = UART_SetBaud(UART0, baud);
            if (sendflg)
            {
                UART_SendData(UART0, data);
                sendflg = 0;
            }
        }
    }

## 使用到的库函数

库函数部分代码

    #define GPIO_AF_I2C 6
    #define REG_RESET(reg,mask) reg &= ~(mask)
    #define REG_SET(reg,mask) reg |= (mask)
    #define REG_WRITE(reg,mask) reg = (mask)
    #define SYS SYS0
    #define SYS0 ((SYS_TypeDef *)(SYS_BASE))
    #define SYS_CLK_CFG_CLK_DIV_MASK (uint32_t)(0xFF << SYS_CLK_CFG_CLK_DIV_POS)
    #define SYS_CLK_CFG_CLK_DIV_POS 0
    #define SYS_CLK_CFG_CLK_SEL_MASK (uint32_t)(0x3 << SYS_CLK_CFG_CLK_SEL_POS)
    #define SYS_CLK_CFG_CLK_SEL_POS 8
    #define SYS_MODULE_GPIO BIT11
    #define SYS_MODULE_UART0 BIT12
    #define SYS_MODULE_UART1 BIT13
    #define SYS_MODULE_UART2 BIT14
    #define UART0 ((UART_TypeDef *)UART0_BASE)
    #define UART1 ((UART_TypeDef *)UART1_BASE)
    #define UART2 ((UART_TypeDef *)UART2_BASE)
    #define UART_FIRSTSEND_LSB 0
    /**
     * @brief GPIO功能配置结构体句柄
     */
    typedef struct GPIO_InitTypeDef {
        uint32_t GPIO_Pin;
        GPIO_Mode_TypeDef GPIO_Mode;
        GPIO_PuPd_TypeDef GPIO_PuPd;
        uint32_t GPIO_PODEna;
        uint32_t GPIO_PFLT;
    };
    /**
     * @brief GPIO模式选择枚举
     */
    typedef enum GPIO_Mode_TypeDef {
        GPIO_Mode_IN = 0,
        GPIO_Mode_OUT = 1,
        GPIO_Mode_ANA = 2,
        GPIO_Mode_IO = 3,
    }} {enum_name};
    /// UART 初始化结构体定义
    typedef struct UART_InitTypeDef {
        uint32_t BaudRate;
        uint8_t WordLength;
        uint8_t StopBits;
        uint8_t FirstSend;
        UART_ParityMode ParityMode;
        uint8_t MultiDropEna;
        uint8_t Bit9Value;
        uint8_t DUPLEX;
        uint16_t Match485Addr;
        uint16_t IRQEna;
        uint8_t DMARE;
        uint8_t RXD_INV;
        uint8_t TXD_INV;
        uint8_t ABD_EN;
        uint8_t LBDL;
        uint8_t LIN_EN;
        uint8_t CK_EN;
    };
    /**
     * @brief  GPIO配置函数
     * @param  GPIOx: GPIO端口
     * @param  GPIO_PinSource: GPIO引脚
     * @param  mode: GPIO模式
     * @param  GPIO_AF_x: GPIO复用功能选择
     */
    void GPIO_Config(GPIO_TypeDef *GPIOx, uint32_t GPIO_PinSource, GPIO_Mode_TypeDef mode, uint32_t GPIO_AF_x)
    {
        GPIO_PinAFConfig(GPIOx, GPIO_PinSource, GPIO_AF_x);
        GPIO_InitTypeDef GPIO_InitStructure;
        GPIO_StructInit(&GPIO_InitStructure);
        GPIO_InitStructure.GPIO_Pin  = 1 << GPIO_PinSource;
        GPIO_InitStructure.GPIO_Mode = mode;
        if (GPIO_AF_x == GPIO_AF_I2C)
        {
            GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
        }
        else
        {
            __NOP();
        }
        GPIO_Init(GPIOx, &GPIO_InitStructure);
    }
    /**
     * @brief 初始化GPIO
     * @param GPIOx GPIO模块指针
     * @param GPIO_InitStruct 指向包含初始化参数的GPIO_InitTypeDef结构体
     */
    void GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_InitStruct)
    {
        // 使能GPIO时钟
        SYS_ModuleClockCmd(SYS_MODULE_GPIO, ENABLE);

        // 配置引脚模式
        if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IN)
        {
            GPIOx->PIE |= GPIO_InitStruct->GPIO_Pin;  // 打开输入使能
            GPIOx->POE &= ~GPIO_InitStruct->GPIO_Pin; // 关闭输出使能
            GPIOx->PUE &= ~GPIO_InitStruct->GPIO_Pin; // 关闭上拉使能
        }
        else if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_OUT)
        {
            GPIOx->PIE &= ~GPIO_InitStruct->GPIO_Pin; // 关闭输入使能
            GPIOx->POE |= GPIO_InitStruct->GPIO_Pin;  // 使能输出
        }
        else if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IO)
        {
            GPIOx->PIE |= GPIO_InitStruct->GPIO_Pin; // 使能输入
            GPIOx->POE |= GPIO_InitStruct->GPIO_Pin; // 使能输出
        }
        else // GPIO_Mode_ANA
        {
            GPIOx->PIE &= ~GPIO_InitStruct->GPIO_Pin; // 关闭输入使能
            GPIOx->POE &= ~GPIO_InitStruct->GPIO_Pin; // 关闭输出使能
            GPIOx->PUE &= ~GPIO_InitStruct->GPIO_Pin; // 关闭上拉使能
        }

        if (GPIO_InitStruct->GPIO_PuPd == GPIO_PuPd_UP)
        {
            GPIOx->PUE |= GPIO_InitStruct->GPIO_Pin; // 使能上拉
        }
        else
        {
            GPIOx->PUE &= ~GPIO_InitStruct->GPIO_Pin; // 关闭上拉
        }
        // 配置开漏使能
        if (GPIO_InitStruct->GPIO_PODEna)
        {
            GPIOx->PODE |= GPIO_InitStruct->GPIO_Pin;
        }
        else
        {
            GPIOx->PODE &= ~GPIO_InitStruct->GPIO_Pin;
        }

        // 配置滤波使能
        if (GPIO_InitStruct->GPIO_PFLT)
        {
            GPIOx->PFLT |= GPIO_InitStruct->GPIO_Pin;
        }
        else
        {
            GPIOx->PFLT &= ~GPIO_InitStruct->GPIO_Pin;
        }
    }
    /**
     * @brief 初始化GPIO结构体为默认值
     * @param GPIO_InitStruct 指向要初始化的GPIO_InitTypeDef结构体
     */
    void GPIO_StructInit(GPIO_InitTypeDef *GPIO_InitStruct)
    {
        for (int i = 0; i < sizeof(GPIO_InitTypeDef); i++)
        {
            ((uint8_t *)GPIO_InitStruct)[i] = 0;
        }
    }
    /**
     * @brief 初始化UART模块
     * @param UARTx UART模块指针
     * @param UART_InitStruct 初始化结构体指针
     */
    void UART_Init(UART_TypeDef *UARTx, UART_InitTypeDef *UART_InitStruct)
    {
        // 使能UART模块时钟
        if (UARTx == UART0)
        {
            SYS_ModuleClockCmd(SYS_MODULE_UART0, ENABLE);
        }
        else if (UARTx == UART1)
        {
            SYS_ModuleClockCmd(SYS_MODULE_UART1, ENABLE);
        }
        else if (UARTx == UART2)
        {
            SYS_ModuleClockCmd(SYS_MODULE_UART2, ENABLE);
        }

        UART_SetBaud(UARTx, UART_InitStruct->BaudRate);
        // 配置UART控制寄存器
        UARTx->CTRL = (UART_InitStruct->DUPLEX << 7) |
                      (UART_InitStruct->LIN_EN << 6) |
                      (UART_InitStruct->MultiDropEna << 5) |
                      (UART_InitStruct->CK_EN << 4) |
                      (UART_InitStruct->ParityMode << 3) |
                      (UART_InitStruct->FirstSend << 2) |
                      (UART_InitStruct->StopBits << 1) |
                      (UART_InitStruct->WordLength);

        // 配置中断使能寄存器
        UARTx->IE = UART_InitStruct->IRQEna;

        // 配置DMA请求使能寄存器
        UARTx->RE = UART_InitStruct->DMARE;

        // 配置IO极性
        UARTx->IOC =
            (UART_InitStruct->LBDL << 6) |   ///< LIN同步段检测长度 0:10bits 1:11bits
            (UART_InitStruct->ABD_EN << 4) | ///< LIN波特率自适应使能
            (UART_InitStruct->TXD_INV << 1) |
            (UART_InitStruct->RXD_INV) |
            0;
        UARTx->IF = 0x3ff;
    }
    /**
     * @brief 初始化UART结构体为默认值
     * @param UART_InitStruct 初始化结构体指针
     */
    void UART_StructInit(UART_InitTypeDef *UART_InitStruct)
    {
        for (int i = 0; i < sizeof(UART_InitTypeDef); i++)
        {
            ((uint8_t *)UART_InitStruct)[i] = 0;
        }

        // 默认配置
        UART_InitStruct->WordLength   = UART_WORDLENGTH_8b;
        UART_InitStruct->StopBits     = UART_STOPBITS_1b;
        UART_InitStruct->FirstSend    = UART_FIRSTSEND_LSB;
        UART_InitStruct->ParityMode   = UART_Parity_NO;
        UART_InitStruct->MultiDropEna = DISABLE;
        UART_InitStruct->DUPLEX       = 0; // 全双工
    }
    /**
     * @brief 发送数据
     * @param UARTx UART模块指针
     * @param n 要发送的数据
     */
    void UART_SendData(UART_TypeDef *UARTx, uint32_t n)
    {
        UARTx->BUFF = n & 0xFF;
        while ((UARTx->STT & BIT0) == 0)
        {
            // 等待发送完成
        }
    }
    /**
     * @brief 数字模块时钟使能
     * @param nModule 模块编号
     * @param state 使能或禁用状态
     */
    void SYS_ModuleClockCmd(uint32_t nModule, uint8_t state)
    {
        REG_WRITE(SYS0->PROTECT, 0x7a83);
        if (state)
        {
            REG_SET(SYS0->CLK_FEN, nModule);
        }
        else
        {
            REG_RESET(SYS0->CLK_FEN, nModule);
        }
        REG_WRITE(SYS0->PROTECT, 0);
    }
    /**
     * @brief 获取当前MCU时钟
     * @return 当前MCU时钟频率
     */
    uint32_t SYS_ReadMcuClk(void)
    {
        uint32_t clk    = 96000000;
        uint32_t clkdiv = (SYS_CLK_CFG & SYS_CLK_CFG_CLK_DIV_MASK) >> SYS_CLK_CFG_CLK_DIV_POS;
        uint32_t clksel = (SYS_CLK_CFG & SYS_CLK_CFG_CLK_SEL_MASK) >> SYS_CLK_CFG_CLK_SEL_POS;
        switch (clksel) //  0: HRC 1: PLL 2: LRC
        {
            case 0: // HRC
                clk = 8000000;
                break;
            case 1: // PLL
                switch (clkdiv)
                {
                    case 0xff: // 96M
                        clk = 96000000;
                        break;
                    case 0x55: // 48M
                        clk = 48000000;
                        break;
                    case 0x11: // 24M
                        clk = 24000000;
                        break;
                    case 0x01: // 12M
                        clk = 12000000;
                        break;
                    case 0x00: // 12M
                        clk = 12000000;
                        break;
                    default: // 逐位计算
                        clk = 0;
                        for (int i = 0; i < 8; i++)
                        {
                            if (clkdiv & (1 << i))
                            {
                                clk += 12000000;
                            }
                            else
                            {
                                __NOP();
                            }
                        }
                        break;
                }
                break;
            case 2: // LRC
                clk = 32000;
                break;
            default:
                break;
        }
        return clk;
    }
    /**
     * @brief 设置波特率
     * @param UARTx UART模块
     * @param Baud 波特率范围
     * @return 实际波特率（不考虑时钟误差）
     */
    uint32_t UART_SetBaud(UART_TypeDef *UARTx, uint32_t Baud)
    {
        uint32_t uartclk = SYS_ReadMcuClk() / (SYS->CLK_DIV2 + 1); // 串口的时钟频率
        uint32_t div     = uartclk / Baud - 1;
        if (div > 0xffff)
        {
            div = 0xffff;
        }
        else
        {
            __NOP();
        }
        UARTx->DIVL = div & 0xFF;
        UARTx->DIVH = (div & 0xFF00) >> 8;
        Baud        = uartclk / (div + 1);
        return Baud;
    }
    /**
     * @brief 配置GPIO引脚复用功能
     * @param GPIOx GPIO模块指针
     * @param GPIO_PinSource 引脚源
     * @param GPIO_AF 复用功能选择
     */
    void GPIO_PinAFConfig(GPIO_TypeDef *GPIOx, uint32_t GPIO_PinSource, uint32_t GPIO_AF)
    {
        uint8_t offset;
        uint8_t pins = GPIO_PinSource >> 2;
        offset       = ((GPIO_PinSource & 0x3) * 4);
        switch (pins)
        {
            case 0:
                GPIOx->F3210 = (GPIOx->F3210 & ~(0xf << offset)) | (GPIO_AF << offset);
                break;
            case 1:
                GPIOx->F7654 = (GPIOx->F7654 & ~(0xf << offset)) | (GPIO_AF << offset);
                break;
            case 2:
                GPIOx->FBA98 = (GPIOx->FBA98 & ~(0xf << offset)) | (GPIO_AF << offset);
                break;
            case 3:
                GPIOx->FFEDC = (GPIOx->FFEDC & ~(0xf << offset)) | (GPIO_AF << offset);
                break;
            default:
                break;
        }
    }