打印
[其他]

MM32F013x——UART 单线半双工通信

[复制链接]
2022|9
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
在上一次的灵动微课堂中和大家分享过MM32F013x上实现UART极性取反的功能应用,本文再来介绍一下MM32F013x上实现UART单线半双工的功能应用。UART单线半双工简介
在使用数字舵机通讯时所用到的通信方式为UART通信,但舵机只有三根接线,除去VCC和GND,只有一条通信线,也就是说要实现双向通信,只能使用单线半双工模式。在单线半双工模式下,TX 和 RX 引脚在芯片内部互连。

使用特权

评论回复
沙发
两只袜子|  楼主 | 2021-5-25 16:43 | 只看该作者
01 配置流程
单线半双工模式是通过设置UART_SCR寄存器的HDSEL位,在这个模式里UART_SCR 寄存器的SCEN位必须保持清零状态。

在单线半双工模式下,TX和RX引脚在芯片内部互联,使用控制位”HALF DUPLEX SEL”(UART_SCR 中的 HDSEL 位) 选择半双工和全双工通信。

注意
当选择单线半双工模式时RX 不再被使用,当有数据需要发送的时候IO才会被UART驱动,没有数据传输时TX总是被释放,所以使用单线半双工需要外部加上拉。

除此之外通讯上和正常的UART模式类似。由于是单线半双工同一时刻总线上只能有一个节点发送,所以需要软件协议层去管理线上冲突防止多个设备同时发送,当 TXEN 位被设置时,只要数据一写到数据寄存器上,发送就继续。

使用特权

评论回复
板凳
两只袜子|  楼主 | 2021-5-25 16:44 | 只看该作者
02 UART_SCR寄存器描述
配置UART_SCR 的HDSEL为1
UART_SCR 寄存器的SCEN位清

使用特权

评论回复
地板
两只袜子|  楼主 | 2021-5-25 16:45 | 只看该作者
初始化UART1
从官网上下载MM32F013x例程,里面有UART普通模式的配置,在这个基础上我们直接调用UART_HalfDuplexCmd(UART1,ENABLE);函数接口将串口配置成单线半双工模式,然后IO口初始化只需要配置PA9 TX即可,如下:

void UART1_NVIC_Init(u32 baudrate)
{
    UART_InitTypeDef UART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_APB2PeriphclockCmd(RCC_APB2Periph_UART1, ENABLE);
    RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE);

    //UART1 NVIC
    NVIC_InitStructure.NVIC_IRQChannel = UART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    //Baud rate
    UART_Structinit(&UART_InitStructure);
    UART_InitStructure.BaudRate = baudrate;
    //The word length is in 8-bit data format.
    UART_InitStructure.WordLength = UART_WordLength_8b;
    UART_InitStructure.StopBits = UART_StopBits_1;
    //No even check bit.
    UART_InitStructure.Parity = UART_Parity_No;
    //No hardware data flow control.
    UART_InitStructure.HWFlowControl = UART_HWFlowControl_None;
    UART_InitStructure.Mode = UART_Mode_Rx | UART_Mode_Tx;
    UART_Init(UART1, &UART_InitStructure);        

    UART_HalfDuplexCmd(UART1,ENABLE);  //Half Duplex Enable
    UART_ITConfig(UART1, UART_IT_RXIEN, ENABLE);   

    UART_Cmd(UART1, ENABLE);

    GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_1);

    //UART1_TX   GPIOA.9
    GPIO_StructInit(&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
}功能验证测试UART单线半双工功能测试我们现在拿两个MM32F0133的板子一个做主机一个做从机进行单线收发测试,主机先发送一包数据给从节点,当从节点收到这包数据后再把这包数据发回给主机,然后主机和从机两个板子PA9短接到一起,外部在加一个4.7K上拉电阻。

使用特权

评论回复
5
两只袜子|  楼主 | 2021-5-25 16:46 | 只看该作者
主机函数处理:

uint8_t txbuff[10]= {0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA};
s32 main(void)
{
    CONSOLE_Init(115200);//UART2 printf打印
    UART1_NVIC_Init(115200);
    printf("UART Half Duplex TX Test \r\n");
    UART1_Send_Group(txbuff,sizeof(txbuff));
    printf("TX Data: ");
    for(index=0;index<10;index++)
    {
        printf(" %x ",txbuff[index]);
    }   
    printf("\r\n");        
    while(1)
    {            
       IF(gUartRxSta == 1) //收到一包数据
       {
           gUartRxSta = 0;        
           printf("RX Data: ");            
           for(index=0;index<10;index++)
           {
               printf(" %x ",Rx_buff[index]);
           }                    
               printf("\r\n");                              
               memset(Rx_buff,0x00,10);                    
        }
    }
    //return 0;
}
主机UART的中断服务函数里面,将接从机发送的数据存放在Rx_buff里面,当收到一包数据后通过printf打印到串口,和原始发送的数据进行对比。

void UART1_IRQHandler(void)
{
   u8 recvbyte;
   // Send packet
   if (UART_GetITStatus(UART1, UART_IT_TXIEN) != RESET)
   {
      UART_ClearITPendingBit(UART1, UART_IT_TXIEN);
   }
   // Recv packet
   if (UART_GetITStatus(UART1, UART_ISR_RX) != RESET)
   {
      UART_ClearITPendingBit(UART1, UART_ISR_RX);
      recvbyte = UART_ReceiveData(UART1);
      Rx_buff[rx_cnt] = recvbyte;
      rx_cnt++;
      if(rx_cnt == 10)
      {
         gUartRxSta = 1;                 
         rx_cnt = 0;
      }
   }
}

使用特权

评论回复
6
两只袜子|  楼主 | 2021-5-25 16:47 | 只看该作者
从机函数处理:

s32 main(void)
{
   CONSOLE_Init(115200);//UART2 printf打印
   UART1_NVIC_Init(115200);
   printf("UART Half Duplex RX Test\r\n");   
   while(1)
   {            
      if(gUartRxSta == 1)//收到一包数据
      {
         gUartRxSta = 0;
         UART1_Send_Group(Rx_buff,10);
         memset(Rx_buff,0x00,10);
      }  
   }
   //return 0;
}

使用特权

评论回复
7
两只袜子|  楼主 | 2021-5-25 16:49 | 只看该作者
从机UART的中断服务函数里面,将接主机发送的数据存放在Rx_buff里面,当收到一包数据后通过单线半双工这个串口发送回去。

void UART1_IRQHandler(void)
{
    u8 recvbyte;
    // Send packet
    if (UART_GetITStatus(UART1, UART_IT_TXIEN) != RESET)
    {
        UART_ClearITPendingBit(UART1, UART_IT_TXIEN);
    }
    // Recv packet
    if (UART_GetITStatus(UART1, UART_ISR_RX) != RESET)
    {
        UART_ClearITPendingBit(UART1, UART_ISR_RX);
        recvbyte = UART_ReceiveData(UART1);
        Rx_buff[rx_cnt] = recvbyte;
        rx_cnt++;
        if(rx_cnt == 10)
        {
            gUartRxSta = 1;
            rx_cnt = 0;
        }
    }
}

使用特权

评论回复
8
两只袜子|  楼主 | 2021-5-25 16:50 | 只看该作者
观察测试结果:

然后我们通过主机UART2 的printf打印可以看到主机TX Data 和从机返回的RX Data数据是一样的。


再看看下图逻辑分析仪抓取的逻辑波形,可以也可以看到主机发送的波形和从机返回的波形数据是一样的。





使用特权

评论回复
9
单片小菜| | 2021-5-26 22:35 | 只看该作者
感谢楼主普及基础知识。

使用特权

评论回复
10
andygirl| | 2021-6-17 21:14 | 只看该作者
还真没这么用过,这是芯片资源压缩到极致了才这样用吧

使用特权

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

本版积分规则

2038

主题

7364

帖子

10

粉丝