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

串口通讯的一个数据包从起始信号开始,直到停止信号结束。数据包的起始信号由一
个逻辑 0 的数据位表示,而数据包的停止信号可由 0.5、 1、 1.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()
{ }
}
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还是中文参考手册,更多时候,我们开发是英文手册,更加困难,所以,软件程序员,必须熟练运用英语和数学。

USART—串口通讯的更多相关文章

  1. 第20章 USART—串口通讯—零死角玩转STM32-F429系列

    第20章      USART—串口通讯 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fi ...

  2. 第20章 USART—串口通讯

    本章参考资料:<STM32F76xxx参考手册>USART章节. 学习本章时,配合<STM32F76xxx参考手册>USART章节一起阅读,效果会更佳,特别是涉及到寄存器说明的 ...

  3. STM32F10x 学习笔记6(USART实现串口通讯 2)

    这次讲讲利用串口收发中断来进行串口通讯.STM32 上为每个串口分配了一个中断.也就是说无论是发送完成还是收到数据或是数据溢出都产生同一个中断.程序需在中断处理函数中读取状态寄存器(USART_SR) ...

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

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

  5. 串口(USART)通信-串口通讯协议简介

    物理层:规定通讯系统中具有机械.电子功能部分的特性,确保原始数据在物理媒体的传输.其实就是硬件部分. 协议层:协议层主要规定通讯逻辑,统一收发双方的数据打包.解包标准.其实就是软件部分. 简单来说物理 ...

  6. CC2530学习路线-基础实验-串口通讯发送字符串(4 未完待续)

    目录 1. 前期预备知识 1.1 串口通讯电路图 1.2 实验相关寄存器 1.2 常用波特率设置 本章未完待续..... 原来写的文章已经丢失了,只能找到这一小部分,看什么时候有时间再补上. 1. 前 ...

  7. Arduino 串口通讯参考笔记 - Serial 类库及相关函数介绍

    声明: 本ID发布的所有文章及随笔均为原创,可随意转载,单转载文章必须注明作者 aiyauto 及包含原文出处地址 http://www.cnblogs.com/aiyauto/p/7071712.h ...

  8. 【STM32H7教程】第29章 STM32H7的USART串口基础知识和HAL库API

    完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第29章       STM32H7的USART串口基础知识和 ...

  9. STM32—串口通讯详解

    串口通讯目录 物理层 协议层 USART简介 开发板与上位机的连接 代码讲解: 一.初始化结构体 二.NVIC配置中断优先级 三.USART配置函数讲解 四.传输数据的函数: 1.发送一个字节 2.发 ...

随机推荐

  1. Endnote在latex中的应用的两种方法

    从endnote中向latex文档批量插入参考文献的两种方法 一.若是latex模板中参考文献编写的命令是: \begin{thebibliography} \bibitem{lab1}LIU M L ...

  2. Mybatis数据库操作的返回值

    mybatis配置 <!-- 配置mybatis --> <bean id="sqlSessionFactory" class="org.mybatis ...

  3. Linux音频驱动简述

    一.数字音频 音频信号是一种连续变化的模拟信号,但计算机仅仅能处理和记录二进制的数字信号.由自然音源得到的音频信号必须经过一定的变换,成为数字音频信号之后,才干送到计算机中作进一步的处理. 数字音频系 ...

  4. iOS:导航条滚动透明度随着tableView的滚动而变化

    来源:HelloYeah 链接:http://www.jianshu.com/p/b8b70afeda81 下面这个界面有没有觉得很眼熟.打开你手里的App仔细观察,你会发现很多都有实现这个功能.比如 ...

  5. Git系列四之在本地服务器搭建gitlab仓库管理

    1.Git仓库管理 现在本地已经创建了git仓库,又在gitlab上创建了一个git仓库,并且让这两个仓库进行远程同步,这样gitlab仓库既可以备份也可以与他人协作管理远程仓库以及根据需要推送或拉取 ...

  6. Java内存缓存

    1.缓存为什么要存在 应用服务器资源是有限的,数据库每秒中接受请求的次数也是有限的.如果利用有限的资源来提供尽可能大的吞吐量呢,一个办法:减少计 算量,缩短请求流程(减少网络io或者硬盘io),这时候 ...

  7. java中return的作用

    脑补一下基础的东西,return的用法. return的常用作用有以下两种第一种用法是返回参数所用的关键字,假如一个有返回值的方法执行完了之后需要返回一个参数,示例: public string fu ...

  8. 【笔记】js Array.prototype.slice.call(arguments) 将函数的参数转换为数组方法的见解

    我们知道函数里面的参数实际上是一个以数组形式储存的对象 但它并非一个数组 如果我们要将它转换为数组可以调用Array.prototype.slice() 这个方法 分析一下这个方法: Array.pr ...

  9. Python 类变量 实例变量

    类变量: ​ 是可在类的所有实例之间共享的值(也就是说,它们不是单独分配给每个实例的).例如下例中,num_of_instance 就是类变量,用于跟踪存在着多少个Test 的实例. 实例变量: 实例 ...

  10. Sphinx-安装和配置

    本例是在Linux下, 环境 CentOS6.5 + PHP5.6.8 + MySQL5.6.13 + Sphinx2.3.1-beta 到官网下载对应环境的安装包, 按照官方文档指定步骤进行安装 第 ...