这两天折腾CTS/RTS硬件流控,看到说232协议的CTS/RTS只是用来做半双工换向使用的。正好手头上有块stm32的板子,看了看stm32的Usart,竟然发现支持的是单线半双工。232里面毕竟4根线,支持半双工也是各自独立地物理信道(大胆猜测,回头回顾一下以前草草使用的双线485,看看它的半双工)。第一次注意到。之所以引起我的兴趣,是因为,我好奇stm32的单线半双工有2点。

  第一:有啥用。结果上网一搜,还真有人用它来控制AX-12数字舵机。

  第二:怎么实现的。我印象中stm32的io口是需要配置方向的。单线半双工需要两端即当输入又当输出。操作不当很容易把IO口的mos管烧掉啊。

  于是折腾了半天。最后确实调通了。管子也没烧。

  参考手册上关于这块,很简单说的。

  单线半双方模式通过设置USART_CR3寄存器的HDSEL位选择。在这个模式里,下面的位必须保持清零状态:
    ● USART_CR2寄存器的LINEN和CLKEN位
    ● USART_CR3寄存器的SCEN和IREN位
  USART可以配置成遵循单线半双工协议。在单线半双工模式下,TX和RX引脚在芯片内部互连。使用控制位”HALF DUPLEX SEL”(USART_CR3中的HDSEL位)选择半双工和全双工通信。
  当HDSEL为’1’时
    ● RX不再被使用
    ● 当没有数据传输时,TX总是被释放。因此,它在空闲状态的或接收状态时表现为一个标准I/O口。这就意味该I/O在不被USART驱动时,必须配置成悬空输入(或开漏的输出高)
  除此以外,通信与正常USART模式类似。由软件来管理线上的冲突(例如通过使用一个中央仲裁器)。特别的是,发送从不会被硬件所阻碍。当TE位被设置时,只要数据一写到数据寄存器上,发送就继续。

基本上比较模糊,但是也能猜出个大概。也就是双方的USart通过TX-Tx相连。而且Tx管脚IO状态设置成悬空输入(或开漏的输出高)。这个地方其实出现了个问题,因为手册第9章GPIO配置的地方明确写道:

Tx管脚在用作半双工模式时,GPIO应该设为推挽复用输出。所以这个悬空输入其实是有问题的。因为手册上写道:

当I/O端口配置为输入时:

● 输出缓冲器被禁止

● 施密特触发输入被激活

● 根据输入配置(上拉,下拉或浮动)的不同,弱上拉和下拉电阻被连接

● 出现在I/O脚上的数据在每个APB2时钟被采样到输入数据寄存器

● 对输入数据寄存器的读访问可得到I/O状态

也就是说输出根本输出不来。所以这里使用复用推挽输出或者复用开漏输出。我估计很多人就是管脚没配置对所以没调通。。。而且既然一定要外接上拉电阻至3.3V,不仅是开漏输出,复用推挽也是,实践证明,不然通信失败。

开漏输出好理解,加上拉后可以输出正常高低电平,而且stm32的IO口设置成开漏输出后,其实是双向的,这点可以从下图看出。手册上说配置成输出后,采样输入数据寄存器里的值即可得到IO状态。

从图上还可以看到。IO管脚内部是有稳压管的。有的管脚会被稳压到3.3VVDD,有的会被稳压到5V,VDD_FT,所以网上说什么上拉至5V其实指得是在FT管脚上才能实现的,不然再上拉也拉不上去。顶多3.3,再多就烧了。

单向半双工(Half Deplux)的实现也比较简单,代码如下。

int main(void)
{
usart_Configuration(); while(NbrOfDataToRead2--)
{
/* Wait until end of transmit */
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)
{ }
/* Write one byte in the USARTy Transmit Data Register */ USART_SendData(USART1, TxBuffer1[TxCounter1++]);
// GPIO_SetBits(GPIOB,GPIO_Pin_0);
/* Wait the byte is entirely received by USARTz */
while(USART_GetFlagStatus(USART2, USART_FLAG_RXNE) == RESET)
{
}
/* Store the received byte in the RxBuffer2 */
RxBuffer2[RxCounter2++] = USART_ReceiveData(USART2);
//GPIO_SetBits(GPIOB,GPIO_Pin_0);
}
USART_ReceiveData(USART1);
while(NbrOfDataToRead1--)
{
/* Wait until end of transmit */
while(USART_GetFlagStatus(USART2, USART_FLAG_TXE)== RESET)
{
}
/* Write one byte in the USARTz Transmit Data Register */
USART_SendData(USART2, TxBuffer2[TxCounter2++]); /* Wait the byte is entirely received by USARTy */
while(USART_GetFlagStatus(USART1,USART_FLAG_RXNE) == RESET)
{
}
/* Store the received byte in the RxBuffer1 */
RxBuffer1[RxCounter1++] = USART_ReceiveData(USART1);
} /* Check the received data with the send ones */
TransferStatus1 = Buffercmp(TxBuffer1, RxBuffer2, TxBufferSize1);
if(TransferStatus1)
{GPIO_SetBits(GPIOB,GPIO_Pin_0);}
/* TransferStatus = PASSED, if the data transmitted from USARTy and
received by USARTz are the same */
/* TransferStatus = FAILED, if the data transmitted from USARTy and
received by USARTz are different */
TransferStatus2 = Buffercmp(TxBuffer2, RxBuffer1, TxBufferSize2);
if(TransferStatus2)
{GPIO_SetBits(GPIOB,GPIO_Pin_1);}
while ()
{
} //IO配置部分
void Rcc_Configuration(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
} void UsartGPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure; GPIO_PinRemapConfig(GPIO_Remap_USART2, ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_USART1, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure); //Tx1 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
//GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOD, &GPIO_InitStructure);//Tx2 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure); //PB0---LED0
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_Init(GPIOB, &GPIO_InitStructure); //PB1---LED1s } void usart_Configuration(void)
{
USART_InitTypeDef USART_InitStructure; Rcc_Configuration(); UsartGPIO_Configuration(); USART_InitStructure.USART_BaudRate = ;
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_Init(USART1, &USART_InitStructure);
USART_Init(USART2, &USART_InitStructure); USART_HalfDuplexCmd(USART1,ENABLE);
USART_HalfDuplexCmd(USART2,ENABLE); USART_Cmd(USART1, ENABLE);
USART_Cmd(USART2, ENABLE);
}

  最后,but也是我没想明白的地方。为什么设置成复用推挽输出,依旧能通信成功而且没烧掉mos管。这里我猜测,是由于虽然你设置了管脚位推挽输出,但是你也设置了HalfDelpux模式,其实Tx这时候默认其实是输入的。只有在你往发送数据寄存器TDR里面写入数据时,标志位TXE置1,然后由硬件将IO口设置成推挽输出。这样对面Tx仍然是输入,所以能够通信输出,不存在mos管被短路的可能性存在。但是手册上没有更详细的介绍了。所以只能是个人猜测。

Usart的单线半双工模式(stm32F10x系列)的更多相关文章

  1. STM32 uart 单线半双工模式(cube版本)

    STM32 uart 单线半双工模式(cube版本) 1.引言 在某些场合下需要进行三线制串口通信(信号线只有一根),这就要求进行单线半双工的模式进行通信.在这种情况进行数据协议传输的过程中,信号端需 ...

  2. 桥接模式-pattern系列

    git链接 桥接模式 桥梁模式的用意是"将抽象化(Abstraction)与实现化(Implementation)脱耦,使得二者可以独立地变化".这句话有三个关键词,也就是抽象化. ...

  3. Linux模式设计系列( 内核与应用关联思考)

    http://blog.chinaunix.net/uid/20608849/cid-25333-list-2.html

  4. 字符串模式匹配算法系列(二):KMP算法

    算法背景: KMP算法是由Donald Knuth和Vaughan Pratt于1970年共同提出的,而James H.Morris也几乎同时间独立提出了这个算法.因此人们将其称作“克努特-莫里斯-普 ...

  5. 字符串模式匹配算法系列(一):BF算法

    算法背景: BF(Brute Force)算法,是一种在字符串匹配的算法中,比较符合人类自然思维方式的方法,即对源字符串和目标字符串逐个字符地进行比较,直到在源字符串中找到完全与目标字符串匹配的子字符 ...

  6. 字符串模式匹配算法系列(三):Trie树及AC改进算法

    Trie树的python实现(leetcode 208) #!/usr/bin/env python #-*- coding: utf-8 -*- import sys import pdb relo ...

  7. 27. USART, Universal synchronous asynchronous receiver transmitter

    27.1 USART introduction 通用同步异步接收发射机(USART)对需要NRZ异步串行数据格式行业标准的外部设备,提供了一个灵活的全双工数据交换的方法.USART使用分数波特率生成器 ...

  8. STM32F10x 学习笔记5(USART实现串口通讯 1)

    STM32F10x 系列单片机中都包含了USART 模块,所谓USART,就是通用同步异步收发器.通用同步异步收发器(USART)提供了一种灵活的方法与使用工业标准NRZ异步串行数据格式的外部设备之间 ...

  9. (stm32f103学习总结)—USART串口通信

    一. USART简介 USART即通用同步异步收发器,它能够灵活地与外部设备进行全双工 数据交换,满足外部设备对工业标准 NRZ 异步串行数据格式的要求. UART即通用异步收发器,它是在USART基 ...

随机推荐

  1. LDAP与migrationtools 导入系统账号

    1:安装migrationtools yum -y install migrationtools 2:修改配置文件 cd     /usr/share/migrationtools 可以看到很多的文件 ...

  2. 汉诺塔(c++)

    今天看了递归函数,就写个汉诺塔,哈哈.........(每天记录一点点)

  3. TimeQuest学习

    1.物理时钟特性:clock skew(时钟差),jitter(拉动),clock latency(时钟潜伏),这些物理时钟特性又称为uncertainl--非定性,或非理想性. clock skew ...

  4. coreData数据操作

    // 1. 建立模型文件// 2. 建立CoreDataStack// 3. 设置AppDelegate 接着 // // CoreDataStack.swift // CoreDataStackDe ...

  5. 用css伪类制作三角形的三种方法

    在手机上写三角形的时候,我一般都用伪类,刚开始的时候用的图片,但是在现在的手机高清屏幕上,图片容易失真,还是用伪类吧! 第一种:一个90度的“ > ”, 只有线条.(可以做下拉框的箭头之类的) ...

  6. hashMap的数据结构

    HashMap底层实现还是数组,只是数组的每一项都是一条链.

  7. C# 将文件嵌入DLL 。Log4net 配置

    最近在弄使用Log4net记录日志. 将配置文件封装到的DLL中. 封装步骤: 1.将配置文件添加到类库中. 2.在配置文件上右键,选择属性. 3. 此时生成类库.DLL中就存在该配置文件啦.如图: ...

  8. iOS 10 开发 相机相关的适配

    升级 iOS 10 之后目测坑还是挺多的,记录一下吧,看看到时候会不会成为一个系列. 直入正题吧 今天在写 Swift 3 相关的一个项目小小练下手,发现调用相机,崩了.试试看调用相册,又特么崩了.然 ...

  9. .Net判断一个对象是否为数值类型

    这乍一听是个很简单的事,但突然搞起来还真有点无从下手的感觉. 首先当然是通过GetType()方法反射获取其类型信息,然后对其进行分析,但是类型信息Type中并没有简单地给出这么一个属性进行判断. 老 ...

  10. MVC中获取模型属性的Range和StringLength验证特性设置

    MVC中的客户端及服务端模型验证信息都以ModelMetadata类型作为承载,在获得属性的ModelMetadata之后(还不知道怎么获取ModelMetadata的童鞋请自行恶补),我们可以轻松得 ...