【WCH蓝牙系列芯片】-基于CH592开发板—多串口协同与 GPIO 复用引脚释放技巧

------------------------------------------------------------------------------------------------------------------------------------

  在CH592芯片开发中,串口通信和引脚复用是最基础。在串口开发中有的时候只需要串口的发送功能,或者是串口的接收功能,这样另一个IO口如果不利用起来就浪费了,这次利用CH592的串口3的PA4和PA5这两个引脚。当PA4做串口接收时,PA5就当普通的GPIO使用;当PA5做串口发送时,PA4就当普通的GPIO使用。

image

1、串口3-PA5做串口发送、PA4做普通GPIO

int main()
{
    uint8_t len;
    uint8_t current_cmd = '0'; // 测试指令,在 '0' 和 '1' 之间切换
    SetSysClock(CLK_SOURCE_PLL_60MHz);
    /* 配置串口1:先配置IO口模式,再配置串口 */
    GPIOA_SetBits(GPIO_Pin_9);
    GPIOA_ModeCfg(GPIO_Pin_8, GPIO_ModeIN_PU);      // RXD-配置上拉输入
    GPIOA_ModeCfg(GPIO_Pin_9, GPIO_ModeOut_PP_5mA); // TXD-配置推挽输出,注意先让IO口输出高电平
    UART1_DefInit();

    //将 PA4 彻底释放为普通 GPIO,推挽输出,
    GPIOA_ModeCfg(GPIO_Pin_4, GPIO_ModeOut_PP_5mA);
    GPIOA_ResetBits(GPIO_Pin_4);                    // 初始默认拉低电平

    GPIOA_SetBits(GPIO_Pin_5);                      // 串口空闲状态为高电平,先拉高避免产生错误起始位
    GPIOA_ModeCfg(GPIO_Pin_5, GPIO_ModeOut_PP_5mA); // PA5 配置为推挽输出,供 UART3 发送使用
//    UART3_DefInit();

    UART3_BaudRateCfg(115200);
    R8_UART3_FCR = (2 << 6) | RB_FCR_TX_FIFO_CLR | RB_FCR_RX_FIFO_CLR | RB_FCR_FIFO_EN;
    R8_UART3_LCR = RB_LCR_WORD_SZ;
    // PA5 只做接收,我们需要清零 RB_IER_TXD_EN,关闭串口对引脚的强制输出驱动
    // 否则 PA5 可能会被内部拉高,导致外部设备发进来的数据无法拉低电平
    R8_UART3_IER |= RB_IER_TXD_EN;
    R8_UART3_DIV = 1;

#if 1 // 测试串口发送字符串
    UART1_SendString(TxBuff, sizeof(TxBuff));
#endif

    while(1)
    {
        // 通过 PA5 (UART3) 发送 1 个字节的数据 ('1' 或 '0')
        R8_UART3_THR = current_cmd;

        // 等待 UART3 数据彻底发送完成 (移位寄存器为空)
        while((R8_UART3_LSR & RB_LSR_TX_ALL_EMP) == 0);

        //根据刚才发出的数据,同步改变 PA4 的电平
        if(current_cmd == '1')
        {
            GPIOA_SetBits(GPIO_Pin_4);   // 发送1,拉高PA4
        }
        else if(current_cmd == '0')
        {
            GPIOA_ResetBits(GPIO_Pin_4); // 发送0,拉低PA4
        }

        // 用 UART1 接收 PA5 发过来的数据
        len = UART1_RecvString(RxBuff);
        if(len == 0)
        {
            // 抓取到了 PA5 发出的信号,通过 PA9 打印
            UART1_SendString((uint8_t *)"UART1 Monitored Data from PA5: ", 31);
            UART1_SendString(RxBuff, len);
            // 打印一下当前 PA4的值
            if(GPIOA_ReadPortPin(GPIO_Pin_4)) {
                UART1_SendString((uint8_t *)" | PA4 is HIGH\r\n", 16);
            } else {
                UART1_SendString((uint8_t *)" | PA4 is LOW\r\n", 15);
            }
        }
        // 切换指令,延时 1 秒,
        if(current_cmd == '1') {
            current_cmd = '0';
        } else {
            current_cmd = '1';
        }
        mDelaymS(1000);
    }
#endif

  在程序中,将PA4为普通 GPIO(做推挽输出),初始化拉低状态。配置PA5也是推挽输出,用作串口发送。关键在于开启 UART3 对 PA5 的强制发送输出驱动 R8_UART3_IER |= RB_IER_TXD_EN;在主循环中间,先通过PA5的发送保持寄存器R8_UART3_THR 直接发送一个字节数据,然后阻塞等待:读取线状态寄存器(LSR),确认发送FIFO和移位寄存器彻底清空,while((R8_UART3_LSR & RB_LSR_TX_ALL_EMP) == 0);

然后根据发出的数据,同步改变 PA4 的电平,用 UART1串口接收传过来的 PA5 数据。

image

2、串口3-PA4做串口接收、PA5做普通GPIO

#if 1
int main()
{
    uint8_t len;
    SetSysClock(CLK_SOURCE_PLL_60MHz);
    /* 配置串口1:先配置IO口模式,再配置串口 */
    GPIOA_SetBits(GPIO_Pin_9);
    GPIOA_ModeCfg(GPIO_Pin_8, GPIO_ModeIN_PU);      // RXD-配置上拉输入
    GPIOA_ModeCfg(GPIO_Pin_9, GPIO_ModeOut_PP_5mA); // TXD-配置推挽输出,注意先让IO口输出高电平
    UART1_DefInit();
    
    // 配置 PA4 为串口接收(上拉输入)
    GPIOA_ModeCfg(GPIO_Pin_4, GPIO_ModeIN_PU);
    UART3_DefInit();
    R8_UART3_IER &= ~RB_IER_TXD_EN;  //关闭 UART3 的发送使能,彻底释放 PA5 的控制权给 GPIO
    // 配置 PA5 为普通 GPIO
    GPIOA_ModeCfg(GPIO_Pin_5, GPIO_ModeOut_PP_5mA);
    GPIOA_ResetBits(GPIO_Pin_5);                    // 测试:拉低 PA5

#if 1 // 测试串口发送字符串
    UART1_SendString(TxBuff, sizeof(TxBuff));
#endif

 // 查询方式:接收数据后发送出去
    while(1)
    {
        len = UART3_RecvString(RxBuff);
        if(len > 0)
        {
            // 判断接收到的第一个字节数据
            // 注意:这里假设您通过串口助手发送的是字符
            if(RxBuff[0] == '1')
            {
                // 如果收到字符 '1',将 PA5 置为高电平
                GPIOA_SetBits(GPIO_Pin_5);
            }
            else if(RxBuff[0] == '0')
            {
                // 如果收到字符 '0',将
                GPIOA_ResetBits(GPIO_Pin_5);
            }
            // 通过 UART1 打印回电脑
            UART1_SendString((uint8_t *)"Received cmd: ", 14);
            UART1_SendString(RxBuff, len);
            UART1_SendString((uint8_t *)"\r\n", 2); // 换行
            // GPIOA_ReadPortPin 返回非 0 表示高电平,返回 0 表示低电平
            if (GPIOA_ReadPortPin(GPIO_Pin_5))
            {
                // 此时 PA5 是高电平
                UART1_SendString((uint8_t *)"PA5 Current State: HIGH (1)\r\n", 29);
            }
            else
            {
                // 此时 PA5 是低电平
                UART1_SendString((uint8_t *)"PA5 Current State: LOW (0)\r\n", 28);
            }
        }
    }
#endif

  在程序中配置PA4为上拉输入,PA5为普通GPIO使用,关键的是关闭 UART3 的发送使能,使用寄存器对 R8_UART3_IER &= ~RB_IER_TXD_EN; 阻断了 UART3 外设对 PA5 物理引脚的映射,这样当PA4作为串口接收时,PA5就是GPIO功能,在主循环中,就用串口3接收串口调试工具发送的数据,并根据接收的数据来改变PA5的GPIO的电平变化。

image

 

posted on 2026-02-27 23:25  凡仕  阅读(102)  评论(0)    收藏  举报