sujingliang 发表于 2025-6-13 09:42

【灵动微电子MM32F0121测评】2、串口打印&接收不定长UART消息

本文目标实现MM32F0121的串口收发功能。并且使用空闲中断(IDLE)方式实现了接收不定长UART消息。

1、整理下评测用程序
主函数调用评测demo函数
int main(void)
{

    PLATFORM_Init();

                EVAL_Demo();
    while (1)
    {
    }
}
DEMO函数中根据EVAL_DEMO定义决定运行哪个DEMO
void EVAL_Demo(void)
{
        switch(EVAL_DEMO)
        {
                case 1:
                        GPIO_LED_Toggle_Sample();
                        break;
                case 2:
                        UART_Sample();
                        break;
       
        }
}/*
* 1:LED
* 2:UART
*/

#define EVAL_DEMO 2

本例中EVAL_DEMO定义为2

2、PLATFORM_Init修改
因为需要自己处理UART,所以将PLATFORM_Init中UART初始化部分注释掉,只保留LED初始化部分
void PLATFORM_Init(void)
{
    PLATFORM_InitDelay();

    //PLATFORM_InitConsole(115200);

    PLATFORM_InitLED();

    //PLATFORM_PrintInfo();
}

3、增加个uart_demo.c负责uart相关处理

1)USART初始化
使用USART1,TX:PB6,RX:PB7,
使用USART1的原因是USART1和板载调试器已相连,不用外接串口工具
USART1配置为双向收发
USART_IT_PE、USART_IT_ERR、USART_IT_IDLE、USART_IT_RXNE中断使能
USART_IT_IDLE使能用于实现接收不定长UART消息
void USART_Configure(uint32_t Baudrate)
{
   GPIO_InitTypeDefGPIO_InitStruct;
    NVIC_InitTypeDefNVIC_InitStruct;
    USART_InitTypeDef USART_InitStruct;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

    USART_StructInit(&USART_InitStruct);
    USART_InitStruct.USART_BaudRate   = Baudrate;
    USART_InitStruct.USART_WordLength = USART_WordLength_8b;
    USART_InitStruct.USART_StopBits   = USART_StopBits_1;
    USART_InitStruct.USART_Parity   = USART_Parity_No;
    USART_InitStruct.USART_Mode       = USART_Mode_Rx | USART_Mode_Tx;
    USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_Init(USART1, &USART_InitStruct);

   
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);

    GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_0);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_0);

    GPIO_StructInit(&GPIO_InitStruct);
    GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_6;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;
    GPIO_InitStruct.GPIO_Mode= GPIO_Mode_AF_PP;
    GPIO_Init(GPIOB, &GPIO_InitStruct);

    GPIO_StructInit(&GPIO_InitStruct);
    GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_7;
    GPIO_InitStruct.GPIO_Mode= GPIO_Mode_FLOATING;
    GPIO_Init(GPIOB, &GPIO_InitStruct);

    NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelPriority = 0;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);

    USART_ITConfig(USART1, USART_IT_PE, DISABLE);
    USART_ITConfig(USART1, USART_IT_ERR, DISABLE);
               
          USART_ITConfig(USART1, USART_IT_CTS, DISABLE);
    USART_ITConfig(USART1, USART_IT_TC, DISABLE);       
                USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);
                USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
               
    USART_Cmd(USART1, ENABLE);
}

2)定义收发数据处理数据结构

typedef struct
{
    uint8_t Buffer;//缓冲
    uint8_t Length;   //最大长度
    uint8_t CurrentCount;//当前缓冲指针位置
    uint8_t CompleteFlag;//完成标志
} USART_RxTx_TypeDef;


volatile USART_RxTx_TypeDef USART_RxStruct;
volatile USART_RxTx_TypeDef USART_TxStruct;


3)USART接收处理函数

函数中Length参数为要接收数据的长度,此函数对USART_RxStruct进行了初始化,然后通过
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);使能接收中断
void USART_RxData_Interrupt(uint8_t Length)
{
    uint8_t i = 0;

    for (i = 0; i < Length; i++)
    {
      USART_RxStruct.Buffer = 0;
    }

    USART_RxStruct.Length = Length;
    USART_RxStruct.CurrentCount = 0;
    USART_RxStruct.CompleteFlag = 0;

    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
}4)USART发送处理函数
Buffer发送数据指针,Length为发送数据长度
USART_ITConfig(USART1, USART_IT_TXE, ENABLE);使能发送中断
void USART_TxData_Interrupt(uint8_t *Buffer, uint8_t Length)
{
    uint8_t i = 0;

    for (i = 0; i < Length; i++)
    {
      USART_TxStruct.Buffer = Buffer;
    }

    USART_TxStruct.Length = Length;
    USART_TxStruct.CurrentCount = 0;
    USART_TxStruct.CompleteFlag = 0;

    USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
}


4、中断处理函数(mm32f0120_it.c)

void USART1_IRQHandler(void)
{
       uint8_t RxData = 0;

                               
        if ((RESET != USART_GetITStatus(USART1, USART_IT_PE)) ||
      (RESET != USART_GetITStatus(USART1, USART_IT_ERR)))
    {
      USART_ReceiveData(USART1);
    }
                       

    if (RESET != USART_GetITStatus(USART1, USART_IT_RXNE))
    {
      RxData = USART_ReceiveData(USART1);

      if (0 == USART_RxStruct.CompleteFlag)
      {
                                       
            USART_RxStruct.Buffer = RxData;
                                                PLATFORM_LED_Toggle(LED2);
                                               
      }
                       
    }

               
                if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)
                {
                               
                                // 检测到空闲中断,表示一帧数据接收完成
                               USART_ReceiveData(USART1); // 读取数据寄存器清除中断
                           USART_ClearITPendingBit(USART1, USART_IT_IDLE);
                               
                                // 处理接收到的完整消息
                                // ...
                        if(USART_RxStruct.CurrentCount>0){
                                        USART_ITConfig(USART1, USART_IT_IDLE, DISABLE);
                                        USART_RxStruct.CompleteFlag = 1;
                                        PLATFORM_LED_Toggle(LED1);
                                        USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);
                        }
                }
               
    if (RESET != USART_GetITStatus(USART1, USART_IT_TXE))
    {
      if (0 == USART_TxStruct.CompleteFlag)
      {
            USART_SendData(USART1, USART_TxStruct.Buffer);

            if (USART_TxStruct.CurrentCount == USART_TxStruct.Length)
            {
                USART_TxStruct.CompleteFlag = 1;

                USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
            }
      }
    }
}通过前面定义可知USART_IT_PE、USART_IT_ERR、USART_IT_IDLE、USART_IT_RXNE、USART_IT_TXE都会导致进入中断
1、USART_IT_PE (奇偶校验错误中断)、USART_IT_ERR (错误中断)
这两个中断主要处理一些错误情况。
2、USART_IT_RXNE处理接收数据,每接收一个字节,保存在缓冲的CurrentCount所指位置
3、USART_IT_TXE处理发送数据,在USART_IT_TXE使能并且CompleteFlag标识为发送完成情况下,按字节发送缓冲中的数据,当达到Length长度时,设置发送完成标识,设置USART_IT_TXE失能。
4、USART_IT_IDLE (空闲中断)
当检测到总线空闲(接收到一帧数据后,总线保持高电平超过一个完整数据帧时间)触发。

先清除中断标识:
USART_ReceiveData(USART1); // 读取数据寄存器清除中断
USART_ClearITPendingBit(USART1, USART_IT_IDLE);



没有接收到数据时也会进入USART_IT_IDLE中断,所以先判断一下USART_RxStruct.CurrentCount>0,保证是在USART_IT_RXNE中断之后触发的USART_IT_IDLE中断。
实行失能USART_IT_IDLE中断,设置接收数据完成标志CompleteFlag,失能USART_IT_RXNE
if(USART_RxStruct.CurrentCount>0){
        USART_ITConfig(USART1, USART_IT_IDLE, DISABLE);
        USART_RxStruct.CompleteFlag = 1;
        PLATFORM_LED_Toggle(LED1);
        USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);
}



5、写个DEMO运行一下
因为在platform.c以及对USART1做了printf重定义所以可以直接用printf
void Welcome_Info(void)
{
        printf("请输入你的选择:\r\n");
        printf("=========================\r\n");
        printf("【1】:显示Hello 5次\r\n");
        printf("【2】:显示不定长UART接收\r\n");
        printf("【help】:显示本内容\r\n");
        printf("【其他输入】:输入内容串口回显\r\n");
}
回显函数Echo_Back:就是在接收到非命令的RX串口数据后,将原数据通过TX发送回去,使用中断方式,通过USART_TxStruct.CompleteFlag判断是否完成:
void Echo_Back(void)
{
        USART_TxData_Interrupt((uint8_t *)USART_RxStruct.Buffer, USART_RxStruct.CurrentCount);
        while(USART_TxStruct.CompleteFlag!=1){};

}

RX接收后处理函数:
收到1,显示5次“Hello 21ic, Hello MM32F0121”
收到2,显示“输入2显示:这是不定长UART接收DEMO”
收到help,显示Welcome_Info()打印内容
收到其他,原数据回显
void Process_Input(void)
{
        int i;
        if(USART_RxStruct.CurrentCount==3){
                if(USART_RxStruct.Buffer=='1'){
                        printf("输入1显示hello信息:\r\n");
                        for(i=0;i<5;i++)
                                {
                                        USART_TxData_Interrupt((uint8_t *)"Hello 21ic, Hello MM32F0121\r\n",29);
                                        PLATFORM_DelayMS(500);
                                }
               
                }else if(USART_RxStruct.Buffer=='2'){
                        USART_TxData_Interrupt((uint8_t *)"输入2显示:这是不定长UART接收DEMO\r\n",35);
                }else{
                        Echo_Back();
                }
               
        }else if(strstr((char*)USART_RxStruct.Buffer,"help"))
        {
                Welcome_Info();       
        }else{
                Echo_Back();
        }
        USART_RxData_Interrupt(255);
        USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);
}UART_Sample
void UART_Sample(void)
{
       
        USART_RxStruct.CompleteFlag = 0;
USART_TxStruct.CompleteFlag = 1;
        USART_Configure(115200);
       
        printf("【MM32F0121开发板评测】2、串口打印\r\n");
        Welcome_Info();
       
        USART_RxData_Interrupt(255);
        while(1)
        {
               
                if (1== USART_RxStruct.CompleteFlag&&USART_RxStruct.CurrentCount>0)
    {
                        USART_RxStruct.CompleteFlag=0;
                        Process_Input();
    }
        }
}

6、运行



letchgo 发表于 2025-6-22 17:37

请教一下为什么我一直进if (RESET != USART_GetITStatus(USART1, USART_IT_IDLE))这个空闲中断条件,配置也搞成和你文档中一样了,串口助手没有发数据也一直进
页: [1]
查看完整版本: 【灵动微电子MM32F0121测评】2、串口打印&接收不定长UART消息