zoukankan      html  css  js  c++  java
  • 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,"这是一个串口中断接收回显实验
    ");
        printf("这是一个串口中断接收回显实验
    ");
        
      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还是中文参考手册,更多时候,我们开发是英文手册,更加困难,所以,软件程序员,必须熟练运用英语和数学。

  • 相关阅读:
    死锁
    Notepad++源代码阅读——窗口封装与继承
    Notepad++源代码阅读——窗口元素组织与布局
    选择问题(selection problem)
    插入排序 | 冒泡排序 | 希尔排序 | 堆排序 | 快速排序 | 选择排序 | 归并排序
    编程之美2014---大神与三位小伙伴
    ulimit 修改 open files & core
    tmux手记
    匿名访问windows server 2008 R2 文件服务器的共享
    WINDOWS系统变量
  • 原文地址:https://www.cnblogs.com/yangguang-it/p/7070787.html
Copyright © 2011-2022 走看看