STM32
直播中

名士流

8年用户 892经验值
私信 关注
[问答]

串口半双工具有什么功能?

串口半双工具有什么功能?

回帖(1)

刘莉

2021-12-3 15:11:05
一、串口半双工




  • stm32的串口支持全双工使用,即数据可双向同时传递,特点是有Rx和Tx两根数据线。这很好,可以满足大部分需要的
  • 有些特殊场合,我们需要使用半双工,比如驱动某些数字舵机。这时数据也是双向传递,但是同一时刻只允许一个方向的数据进行传递。这种情况下只用到Tx这一根数据线。stm32的串口也支持半双工
  • 数据手册中对串口的半双工功能有以下描述:




  • 注意:


    • 开启半双工后Rx引脚不在使用
    • Tx引脚应配置为开漏拉高
    • USART1~USART6都支持半双工
    • TE为1时是发送使能,注意这个不会被硬件封锁。换句话说只要TE为1,串口就一直处于发送状态不能接受。查看手册CR1寄存器部分:





      可以看出:我们可以通过操作TE和RE位,配置串口处于仅发送或仅接受的状态



二、示例代码
1. 串口配置:
配置和普通的没啥区别,不同处在于Rx不用配了;Tx配为开漏拉高;使用库函数void USART_HalfDuplexCmd操作HDSEL位使能或失能半双工模式


void USART1_Half_Configuration(void)  
{  
          GPIO_InitTypeDef GPIO_InitStructure;  
          USART_InitTypeDef USART_InitStructure;   
          NVIC_InitTypeDef NVIC_InitStructure;
       
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //使能GPIOA时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能USART1时钟
       
        GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); //GPIOA9复用为USART1
       
          GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;  //开漏上拉
          GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;         
          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;  
          GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;  
          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
          GPIO_Init(GPIOA, &GPIO_InitStructure);  




          USART_InitStructure.USART_BaudRate = 115200;  
        USART_InitStructure.USART_WordLength = USART_WordLength_8b;  
          USART_InitStructure.USART_StopBits = USART_StopBits_1;  
          USART_InitStructure.USART_Parity = USART_Parity_No;  
          USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;  
          USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;  
        //USART_InitStructure.USART_Mode = USART_Mode_Rx ;
          USART_Init(USART1,&USART_InitStructure);  
          USART_HalfDuplexCmd(USART1, ENABLE);          //注意这个,启动半双工模式


          USART_Cmd(USART1,ENABLE);  
        USART_ClearFlag(USART1, USART_FLAG_TC);
        USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启相关中断
       
        //Usart1 NVIC 配置
          NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中断通道
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//抢占优先级3
        NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;                //子优先级3
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                        //IRQ通道使能
        NVIC_Init(&NVIC_InitStructure);        //根据指定的参数初始化VIC寄存器、
       
}  


2. 串口模式切换
操作串口CR1寄存器的TE位和RE位即可,不妨使用宏的形式


#define readOnly(x)        x->CR1 |= 4;        x->CR1 &= 0xFFFFFFF7;                //串口x配置为只读,CR1->RE=1, CR1->TE=0
#define sendOnly(x)        x->CR1 |= 8;        x->CR1 &= 0xFFFFFFFB;                //串口x配置为只写,CR1->RE=0, CR1->TE=1


3. 一个简单的应用示例
USART1和USART2配置为半双工,从USART2发给USART1数据1开始,收到后将数据加一发给对方。
连线:PA9 - PD5
debug观察res1和res2交替递增
以下展示部分示例代码:


//主函数部分
int main(void)
{
        u16 times=0;  
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
        delay_init(168);                                //延时初始化
        LED_Init();                                 
        USART1_Half_Configuration();        //串口1配置为半双工
        USART2_Half_Configuration();        //串口2配置为半双工
       
        sendOnly(USART2);                                //USART2只写
        readOnly(USART1);                                //USART1只读
        USART_SendData(USART2,1);                //USART2先发给USART1
        while(1)
        {
                times++;
                if(times%30==0)LED0=!LED0;        //闪烁LED,提示系统正在运行.
                delay_ms(10);   
        }
}


//接收中断服务函数部分,完成数据互相发送
u8 Res1;        //debug观察
void USART1_IRQHandler(void)               
{
       
        if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  
        {
                Res1 = USART_ReceiveData(USART1);
                readOnly(USART2);
                sendOnly(USART1);
                USART_SendData(USART1,Res1+1);        //USART1发给USART2
        }
}


u8 Res2;        //debug观察
void USART2_IRQHandler(void)                       
{
        if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
        {
                Res2 = USART_ReceiveData(USART2);
                readOnly(USART1);
                sendOnly(USART2);
                USART_SendData(USART2,Res2+1);        //USART2发给USART1
  }
}


可以在github下载完整源码:完整源码,此程序在正点原子stm32f407平台测试通过
举报

更多回帖

发帖
×
20
完善资料,
赚取积分