USART—串口通讯

本章中主要讲解的是串口异步通讯,异步通讯中由于没有时钟信号, 所以两个通讯设备之间需要约定好波特率,即每个码元的长度,以便对信号进行解码 。

串口通讯的一个数据包从起始信号开始,直到停止信号结束。数据包的起始信号由一
个逻辑 0 的数据位表示,而数据包的停止信号可由 0.511.5 2 个逻辑 1 的数据位表示,
只要双方约定一致即可。

STM32 芯片具有多个 USART 外设用于串口通讯,它是 Universal Synchronous
Asynchronous Receiver and Transmitter 的缩写,即通用同步异步收发器可以灵活地与外部设
备进行全双工数据交换。有别于 USART,它还有具有 UART 外设(Universal Asynchronous
Receiver and Transmitter),它是在 USART 基础上裁剪掉了同步通信功能,只有异步通信。
简单区分同步和异步就是看通信时需不需要对外提供时钟输出,我们平时用的串口通信基
本都是 UART

STM32 USART 输出的是 TTL 电平信号,若需要 RS-232 标准的信号可使用
MAX3232 芯片进行转换。

①功能引脚
TX:发送数据输出引脚。
RX:接收数据输入引脚。
SW_RX:数据接收引脚,只用于单线和智能卡模式,属于内部引脚,没有具体外部引
脚。
nRTS:请求以发送(Request To Send)n 表示低电平有效。如果使能 RTS 流控制,当
USART 接收器准备好接收新数据时就会将 nRTS 变成低电平;当接收寄存器已满时,
nRTS 将被设置为高电平。该引脚只适用于硬件流控制。

nCTS:清除以发送(Clear To Send)n 表示低电平有效。如果使能 CTS 流控制,发送
器在发送下一帧数据之前会检测 nCTS 引脚,如果为低电平,表示可以发送数据,如果为
高电平则在发送完当前数据帧之后停止发送。该引脚只适用于硬件流控制。
SCLK:发送器时钟输出引脚。这个引脚仅适用于同步模式。
USART 引脚在 STM32F429IGT6 芯片具体发布见表 20-3

 

应用型编程,先会使用,有需要再去解析内部实现:

int main(void)
{    
  /*初始化USART 配置模式为 115200 8-N-1,中断接收*/
  Debug_USART_Config();
    
    /* 发送一个字符串 */
    Usart_SendString( DEBUG_USART,"这是一个串口中断接收回显实验\n");
    printf("这是一个串口中断接收回显实验\n");
    
  while(1)
    {    
        
    }    
}

 

void Debug_USART_Config(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  USART_InitTypeDef USART_InitStructure;
        
  RCC_AHB1PeriphClockCmd(DEBUG_USART_RX_GPIO_CLK|DEBUG_USART_TX_GPIO_CLK,ENABLE);

  /* 使能 USART 时钟 */
  RCC_APB2PeriphClockCmd(DEBUG_USART_CLK, ENABLE);
  
  /* GPIO初始化 */
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;  
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  
  /* 配置Tx引脚为复用功能  */
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_PIN  ;  
  GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);

  /* 配置Rx引脚为复用功能 */
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_PIN;
  GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
  
 /* 连接 PXx 到 USARTx_Tx*/
  GPIO_PinAFConfig(DEBUG_USART_RX_GPIO_PORT,DEBUG_USART_RX_SOURCE,DEBUG_USART_RX_AF);

  /*  连接 PXx 到 USARTx__Rx*/
  GPIO_PinAFConfig(DEBUG_USART_TX_GPIO_PORT,DEBUG_USART_TX_SOURCE,DEBUG_USART_TX_AF);
  
  /* 配置串DEBUG_USART 模式 */
  /* 波特率设置:DEBUG_USART_BAUDRATE */
  USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
  /* 字长(数据位+校验位):8 */
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  /* 停止位:1个停止位 */
  USART_InitStructure.USART_StopBits = USART_StopBits_1;
  /* 校验位选择:不使用校验 */
  USART_InitStructure.USART_Parity = USART_Parity_No;
  /* 硬件流控制:不使用硬件流 */
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  /* USART模式控制:同时使能接收和发送 */
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  /* 完成USART初始化配置 */
  USART_Init(DEBUG_USART, &USART_InitStructure); 
    
  /* 嵌套向量中断控制器NVIC配置 */
    NVIC_Configuration();
  
    /* 使能串口接收中断 */
    USART_ITConfig(DEBUG_USART, USART_IT_RXNE, ENABLE);
    
  /* 使能串口 */
  USART_Cmd(DEBUG_USART, ENABLE);
}

从上面的红色部分我们可以知道,和往常一样,开启时钟是第一步,尤其注意的是引脚复用调用的函数,注意是GPIO_Pinsource而不是GPIO_Pin.

在编写程序的时候,首先参考官方固件库,然后谨记编程要点,比如什么时钟应该开启,引脚功能如何配置,是否有复用模式,中断是否需要配置。这需要我们熟悉外设挂载在哪个总线上,已及总线的最高时钟,这些都知道以后,固件库编程是很快速的。至于固件库的具体实现,也是很有参考价值的,但是如果你手上还有很多需要学习的东西,可以暂时不管固件库底层如何实现,先完成基本设计,再慢慢深入。这是一个长期累积的过程。

 串口调试助手,不勾选发送模式,默认是以字符的方式发送。

编程时需要用到的固件库函数

要使用printf重定向,需要重写fputc函数,并且在keil中勾选使用微库。

 NOTE:

STM32默认就是小端模式:

The processor can access data words in memory in little-endian format or big-endian 
format. It always accesses code in little-endian format.
Note:
Little-endian is the default memory format for ARM processors.

 在发送一个字节8位模式时,是从高位开始向低位传输的:

但是,要是我们想要发送一个16位的数据,是先发送高8位呢还是低8位?通过参考历程可以看出,是先发送的高8位,再发送低8位。

那么为什么要先发送高8位再发送底八位呢?

例如一个16位数据0x1234;在寄存器中是高位在前,低位在后的(stm32默认小端模式)。

二进制 0001  0010   0011   0100;

要想把这一串二进制以8位一次的方式发送,如果我们先发送低8位,再发送高8位,最后出来将会是0x3412,所以,我们应该先发送高位再发送低位。

重要寄存器,解释为什么发送接收库函数要那么去写:

//接收库函数

//发送库函数

首先,这是中断服务函数调用的,首先调用接收函数,能进接收中断,所以肯定有数据发来单片机接收到了,此时把DR寄存器的值得低9位(在我们的历程中使用的8位,到底是9位还是8位要看M的设置),这个值返回出来,确实应该是接收函数。但是,为什么像DR中写入数据,就是发送了?刚开始我也不理解,但是参看参考手册之后,发现,写数据倒DR寄存器中会硬件触发标志,这样,内核可以知道你是接收还是发送。

发送端:

7. USART_DR 寄存器中写入要发送的数据(该操作将清零 TXE 位)。为每个要在单缓
冲区模式下发送的数据重复这一步骤。
8. USART_DR 寄存器写入最后一个数据后,等待至 TC=1。这表明最后一个帧的传送已
完成。禁止 USART 或进入暂停模式时需要此步骤,以避免损坏最后一次发送

接收端:

 

 这样,读DR寄存器,会产生一些硬件标志置位,所以内核可以知道是否接收完成,向DR寄存器写数据,也会产生一些硬件标志位,这样内核就知道是否发送发送完成。

嵌入式开发,离不开和芯片手册折腾,但是这又是必备技能,而且这里STMF4还是中文参考手册,更多时候,我们开发是英文手册,更加困难,所以,软件程序员,必须熟练运用英语和数学。

posted @ 2017-06-23 16:57  Crystal_Guang  阅读(8797)  评论(0编辑  收藏  举报