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

[复制链接]
 楼主| sujingliang 发表于 2025-6-13 09:42 | 显示全部楼层 |阅读模式
本文目标实现MM32F0121的串口收发功能。并且使用空闲中断(IDLE)方式实现了接收不定长UART消息。

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

  3.     PLATFORM_Init();

  4.                 EVAL_Demo();
  5.     while (1)
  6.     {
  7.     }
  8. }
DEMO函数中根据EVAL_DEMO定义决定运行哪个DEMO
  1. void EVAL_Demo(void)
  2. {
  3.         switch(EVAL_DEMO)
  4.         {
  5.                 case 1:
  6.                         GPIO_LED_Toggle_Sample();
  7.                         break;
  8.                 case 2:
  9.                         UART_Sample();
  10.                         break;
  11.        
  12.         }
  13. }
/*
* 1:LED
* 2:UART
*/

#define EVAL_DEMO 2

本例中EVAL_DEMO定义为2

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

  4.     //PLATFORM_InitConsole(115200);

  5.     PLATFORM_InitLED();

  6.     //PLATFORM_PrintInfo();
  7. }


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消息
  1. void USART_Configure(uint32_t Baudrate)
  2. {
  3.    GPIO_InitTypeDef  GPIO_InitStruct;
  4.     NVIC_InitTypeDef  NVIC_InitStruct;
  5.     USART_InitTypeDef USART_InitStruct;

  6.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

  7.     USART_StructInit(&USART_InitStruct);
  8.     USART_InitStruct.USART_BaudRate   = Baudrate;
  9.     USART_InitStruct.USART_WordLength = USART_WordLength_8b;
  10.     USART_InitStruct.USART_StopBits   = USART_StopBits_1;
  11.     USART_InitStruct.USART_Parity     = USART_Parity_No;
  12.     USART_InitStruct.USART_Mode       = USART_Mode_Rx | USART_Mode_Tx;
  13.     USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  14.     USART_Init(USART1, &USART_InitStruct);

  15.    
  16.     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);

  17.     GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_0);
  18.     GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_0);

  19.     GPIO_StructInit(&GPIO_InitStruct);
  20.     GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_6;
  21.     GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;
  22.     GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_AF_PP;
  23.     GPIO_Init(GPIOB, &GPIO_InitStruct);

  24.     GPIO_StructInit(&GPIO_InitStruct);
  25.     GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_7;
  26.     GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_FLOATING;
  27.     GPIO_Init(GPIOB, &GPIO_InitStruct);

  28.     NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;
  29.     NVIC_InitStruct.NVIC_IRQChannelPriority = 0;
  30.     NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
  31.     NVIC_Init(&NVIC_InitStruct);

  32.     USART_ITConfig(USART1, USART_IT_PE, DISABLE);
  33.     USART_ITConfig(USART1, USART_IT_ERR, DISABLE);
  34.                
  35.           USART_ITConfig(USART1, USART_IT_CTS, DISABLE);
  36.     USART_ITConfig(USART1, USART_IT_TC, DISABLE);       
  37.                 USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);
  38.                 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
  39.                
  40.     USART_Cmd(USART1, ENABLE);
  41. }


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

typedef struct
{
    uint8_t Buffer[255];//缓冲
    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);使能接收中断
  1. void USART_RxData_Interrupt(uint8_t Length)
  2. {
  3.     uint8_t i = 0;

  4.     for (i = 0; i < Length; i++)
  5.     {
  6.         USART_RxStruct.Buffer[i] = 0;
  7.     }

  8.     USART_RxStruct.Length = Length;
  9.     USART_RxStruct.CurrentCount = 0;
  10.     USART_RxStruct.CompleteFlag = 0;

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

  4.     for (i = 0; i < Length; i++)
  5.     {
  6.         USART_TxStruct.Buffer[i] = Buffer[i];
  7.     }

  8.     USART_TxStruct.Length = Length;
  9.     USART_TxStruct.CurrentCount = 0;
  10.     USART_TxStruct.CompleteFlag = 0;

  11.     USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
  12. }



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

  1. void USART1_IRQHandler(void)
  2. {
  3.          uint8_t RxData = 0;

  4.                                
  5.         if ((RESET != USART_GetITStatus(USART1, USART_IT_PE)) ||
  6.         (RESET != USART_GetITStatus(USART1, USART_IT_ERR)))
  7.     {
  8.         USART_ReceiveData(USART1);
  9.     }
  10.                        

  11.     if (RESET != USART_GetITStatus(USART1, USART_IT_RXNE))
  12.     {
  13.         RxData = USART_ReceiveData(USART1);

  14.         if (0 == USART_RxStruct.CompleteFlag)
  15.         {
  16.                                        
  17.             USART_RxStruct.Buffer[USART_RxStruct.CurrentCount++] = RxData;
  18.                                                 PLATFORM_LED_Toggle(LED2);
  19.                                                
  20.         }
  21.                        
  22.     }

  23.                
  24.                 if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)
  25.                 {
  26.                                
  27.                                 // 检测到空闲中断,表示一帧数据接收完成
  28.                                  USART_ReceiveData(USART1); // 读取数据寄存器清除中断
  29.                            USART_ClearITPendingBit(USART1, USART_IT_IDLE);
  30.                                
  31.                                 // 处理接收到的完整消息
  32.                                 // ...
  33.                         if(USART_RxStruct.CurrentCount>0){
  34.                                         USART_ITConfig(USART1, USART_IT_IDLE, DISABLE);
  35.                                         USART_RxStruct.CompleteFlag = 1;
  36.                                         PLATFORM_LED_Toggle(LED1);
  37.                                         USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);
  38.                         }
  39.                 }
  40.                
  41.     if (RESET != USART_GetITStatus(USART1, USART_IT_TXE))
  42.     {
  43.         if (0 == USART_TxStruct.CompleteFlag)
  44.         {
  45.             USART_SendData(USART1, USART_TxStruct.Buffer[USART_TxStruct.CurrentCount++]);

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

  49.                 USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
  50.             }
  51.         }
  52.     }
  53. }
通过前面定义可知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
  1. void Welcome_Info(void)
  2. {
  3.         printf("请输入你的选择:\r\n");
  4.         printf("=========================\r\n");
  5.         printf("【1】:显示Hello 5次\r\n");
  6.         printf("【2】:显示不定长UART接收\r\n");
  7.         printf("【help】:显示本内容\r\n");
  8.         printf("【其他输入】:输入内容串口回显\r\n");
  9. }
回显函数Echo_Back:就是在接收到非命令的RX串口数据后,将原数据通过TX发送回去,使用中断方式,通过USART_TxStruct.CompleteFlag判断是否完成:
  1. void Echo_Back(void)
  2. {
  3.         USART_TxData_Interrupt((uint8_t *)USART_RxStruct.Buffer, USART_RxStruct.CurrentCount);
  4.         while(USART_TxStruct.CompleteFlag!=1){};

  5. }


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


6、运行

tutieshi_640x588_20s.gif

letchgo 发表于 2025-6-22 17:37 | 显示全部楼层
请教一下为什么我一直进if (RESET != USART_GetITStatus(USART1, USART_IT_IDLE))这个空闲中断条件,配置也搞成和你文档中一样了,串口助手没有发数据也一直进
您需要登录后才可以回帖 登录 | 注册

本版积分规则

84

主题

146

帖子

3

粉丝
快速回复 在线客服 返回列表 返回顶部

84

主题

146

帖子

3

粉丝
快速回复 在线客服 返回列表 返回顶部