1、USART的主要特性

  1)名称:串行异步通信接口

  2)全双工、异步通信

  3)发送和接收速率最高可达4.5MBits/s

  4)可编程数据长度8或9bits

  5)可配置的停止位:支持1或2位停止位

  6)单线半双工通信

  7)使用DMA(直接存储器访问)可配置多缓冲通信

  8)支持独立的发送和接收

  9)发送确认标志:接收缓冲区慢、发送缓冲空、发送结束标志

  10)奇偶控制:传输奇偶位、检查接收数据的奇偶

  11)四个错误检测标志:溢出错误、噪声错误、帧错误、奇偶错误

  12)10个带中断源标志:发送数据寄存器为空、发送完成、接收数据寄存器满、溢出错误、噪声错误、帧错误、奇偶错误。。。

  13)如果没有发生地址匹配,多处理器通信进入静音模式

  14)从静音模式中唤醒

2、关于帧格式

  1)起始位

  2)一个数据字(8或9位) 最开始输出的是低位

  3)停止位表示传输完成    停止位有0.5、1、1.5、2位

  4)这个接口使用一个分数波特率发生器:12位尾数和4位小数

  5)一个状态寄存器(USART_SR)

  6)数据寄存器(USART_DR)

  7)波特率寄存器(USART_BRR):12位尾数和4位小数

  8)一个保证时间寄存器(USART_GTRP) 主要是在智能卡模式下

3、USART特性描述

  1)数据发送字长可以选择为8位或9位,这个由USART_CR1寄存器决定

  2)在开始位时,TX引脚为低;在结束位时,TX引脚为高

  3)空闲帧

  4)中断帧

  5)设置发送使能位(TE)后,会发送一个空闲帧

4、可配置的停止位

  1)停止位的位数控制寄存器2的12/13位来控制

  2)默认停止位是1位 还有2位、0.5位、1.5位用于其他模式

  3)空闲帧传输时包括停止位

  4)中断帧是10或11个低比特+停止位   不会传输超过11个低位的比特

5、编程的步骤

  1)通过将USART_CR1寄存器的UE位写1使能USART

  2)写USART_CR1的M位来确定字长

  3)配置USART_CR2寄存器确定停止位的长度

  4)如果要进行多缓冲区通信时,在USART_CR3寄存器中配置DMA使能。

       就如同多缓冲区通信那样配置DMA。

  5)配置USART_BRR寄存器确定波特率

  6)配置USART_CR1寄存器的TE位为1,使其在第一次数据发送时发送空闲帧

  7)将要发送的数据写在USART_DR寄存器中(这样会清除TXE位)。

     在单缓冲区中发送数据就重复这个操作。

  8)将最后一个数据写进USART_DR寄存器后,等待TC=1。

     这个可以保证最后一帧传输完了。

     这个操作是有必要的,因为当USART被禁止或者进入停机模式时,可以避免

最后一帧被打断。

6、单字节通信

  1)每当数据被写进数据寄存器后,TXE位都会被清掉。

  2)TXE位由硬件设置,并且它可以保证:

  a.数据已经从TDR转移到移位寄存器,并且数据发送已经开始了

  b.TDR寄存器为空

  c.下一个数据可以写在USART_DR寄存器中而不需要覆盖先前的数据。

  3)如果TXEIE位被设置为1,这个位将产生一个中断。

  4)当进行传输时,对USART_DR寄存器的写指令将数据存储在TDR寄存器中,并且在传输完成时数据会被复制到移位寄存器中。

  5)当没有发生传输时,对USART_DR寄存器的写指令直接将数据存储在移位寄存器中,传输开始,并且TXE位立刻被置1。

  6)如果在停止位后发送一帧数据,并且TXE位被设置了,TC位就会变高。

     如果USART_CR1寄存器中的TCIE位被设置了,就会产生一个中断。

  7)在把最后一个数据写进USART_CR1时,若要禁用USRAT或让微控制器进入

        低功耗模式时必须等待TC=1。

  8)TC位可通过如下的软件方法进行清除

    a.读一下USART_SR寄存器

    b.写一下USART_DR寄存器

    c.TC位也可以通过写0来清除。这种清除方式仅仅建议在多缓冲通信的时候使用。

7、关于接收

  1)USART可以接收8位或9位的数据,这取决于USART_CR1寄存器的M位。

  2)在USART中,当检测到一个特定的样本序列时,起始位被检测到。

  3)在USART接收的过程中,数据首先在RX引脚上在最低有效位上移动。

    在这种模式下,USART_DR寄存器由内部总线和接收移位寄存器中间的缓冲区(RDR)组成。

  

8、接收程序编写过程

  1)通过将USART_CR1寄存器的UE位写1使能USART。

  2)写USART_CR1寄存器的M位确定接收字的长度。

  3)写USART_CR2寄存器确定停止位。

  4)如果要进行多缓冲区通信,在USART_CR3寄存器中使能DMA。

  5)写USART_BRR配置接收波特率。

  6)在USART_CR1寄存器中将RE写为1,这样可以在接收的过程中搜索起始位。

9、当接收到一个字符时

  1)RXNE位被设置为1。它表示移位寄存器的内容被转移到RDR寄存器中。换句话说,数据被接受了并且可以读数据了。

  2)如果RXNE位被置位了就会产生一个中断。

  3)如果在接收的过程中如果检测到帧错误、噪声或溢出错误,错误标志位就被置位了。

  4)在多缓冲区模式中,每接收一个字节后,RXNE就被置位,DMA读取数据寄存器后就会把位清掉。

  5)在单缓冲模式下,通过软件读取USART_DR寄存器可以清除RXNE位。通过写0也可以清除RXNE标志位。在接收下一个字符之前必须要清除RXNE标志位以避免溢出错误。

  6)在接收数据的过程中,RE位不能被重置。在接收的过程中,如果RE位被禁用的话,当前接收的字节会中止。

10、分割字符

  当接收一个分割字符时,USART将其作为帧错误处理。

11、空闲字符

12、溢出错误

  当在接收一个字符时,如果RXNE位没有被清除就会产生溢出错误。在RXNE位没有被清除之前,数据不能从移位寄存器转移至RDR寄存器。

13、当产生溢出中断时

  1)ORE位会被置位

  2)RDR寄存器里的内容会丢失。当读USART_DR寄存器时,以前的数据还是可用的。

  3)移位寄存器会被覆盖。在这之后,接收到的数据都会丢失。

  4)如果设置了RXNEIE位或者同时设置了EIE和DMA位,就会产生一个中断。

  5)先对USART_SR寄存器进行一个读操作,然后对USART_DR寄存器进行一个读操作,ORE位就会被清除掉。

  6)如果ORE位被置位,表示至少有一个数据丢失了。这里有两种可能性:

    a)如果RXNE=1,最后的有效数据将存储在接收寄存器RDR中,并且可以读取。

    b)如果RXNE=0。

14、噪声错误

15、帧错误

16、在接收期间可配置的停止位

17、分数波特率发生器

  1)发送和接收的波特率会被设置为相同的值,波特率值由USARTDIV的尾数和分数编程。

  

  2)USARTDIV的值由USART_BRR寄存器配置。

18、如何从USART_BRR寄存器获取USARTDIV的值

  例子1:

  关于波特率误差的计算

  误差=(计算的波特率 - 期望波特率)/期望波特率

19、串口接收对时钟偏差的容忍

  只有总系统时钟的偏差比USART接收的偏差小时,USART的异步接收才能正常工作。

20、多机通信

21、空闲线检测

  当RWU位被写为1时,USART进入静音模式。

22、地址符号检测

  在这种模式下,如果MSB=1,字节将被认为是地址,否则被认为数据。

23、奇偶控制

  

27.3.8 局域互联网络模式(LIN)

27.3.9 USART 同步模式

27.3.10 单线半双工通信

27.3.13 使用DMA进行连续通信

27.4 USART 中断

27.5 USART 模式配置

27.6 USART 寄存器    寄存器一般都是32位

  1)Status register(USART_SR)状态寄存器

  2)Data register(USART_DR)数据寄存器

  3)Baud rate register(USART_BRR)波特率寄存器

  4)Control register 1(USART_CR1)控制寄存器1

  5)Control register 2(USART_CR2)控制寄存器2

  6)Control register 3(USART_CR3)控制寄存器3

  7)Guard time and prescaler register(USART_GTPR)保护时间和预分频寄存器

  8)USART寄存器图

关键的函数:

1、void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)

这个函数主要用来处理中断

2、UART_Receive_IT(huart);

这个函数在被包含在HAL_UART_IRQHandler(UART_HandleTypeDef *huart)函数里

这个函数首先判断数据字长是8位还是9位

疑问:

函数是怎么进入HAL_UART_IRQHandler(UART_HandleTypeDef *huart)这个函数

//=======================编程相关===============================//

1、在初始化一个串口时,先初始化与MCU无关的串口协议,再初始化与MCU相关的串口引脚

2、初始化一个外设,无非要初始化两方面的内容:一方面是相关协议;另一方面就是引脚相关了。

//========================串口发送程序===========================//

1、串口发送程序中很重要的一个寄存器是DR(数据寄存器)

从图中可以看出数据的流向

1)首先把数据往DR里写

2)DR里的数据先转移到TDR(发送数据寄存器)中

3)TDR的数据再转移到Transmit Shfit Register中

4)Transmit Shfit Register的数据最后通过TX口发送出去

//====================串口接收程序=======================//

1、我认为最关键的一点是:找到接收程序的入口

  1)接收程序的入口函数是USART1_IRQHandler函数

  2)在main函数里没有USART1_IRQHandler函数,如何才能进入该函数呢?

  3)在启动文件里已经配置了向量表,向量表里存储的内容便是中断或异常程序的入口地址。

     当发生与USART1相关的异常或中断时,PC指针就会移到USART1_IRQHandler函数的入口地址,执行相关程序。

2、第二个关键点是:理清楚USART1_IRQHandler函数里的一层层函数嵌套关系

3、串口接收中断程序中有一个关键函数

/**
* @brief Receives an amount of data in non blocking mode.
* @note When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
* the received data is handled as a set of u16. In this case, Size must indicate the number
* of u16 available through pData.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @param pData Pointer to data buffer (u8 or u16 data elements).
* @param Size Amount of data elements (u8 or u16) to be received.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
/* Check that a Rx process is not already ongoing */
if (huart->RxState == HAL_UART_STATE_READY)
{
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
} /* Process Locked */
__HAL_LOCK(huart); huart->pRxBuffPtr = pData;
huart->RxXferSize = Size;
huart->RxXferCount = Size; huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->RxState = HAL_UART_STATE_BUSY_RX; /* Process Unlocked */
__HAL_UNLOCK(huart); /* Enable the UART Parity Error Interrupt */
__HAL_UART_ENABLE_IT(huart, UART_IT_PE); /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */
__HAL_UART_ENABLE_IT(huart, UART_IT_ERR); /* Enable the UART Data Register not empty Interrupt */
__HAL_UART_ENABLE_IT(huart, UART_IT_RXNE); return HAL_OK;
}
else
{
return HAL_BUSY;
}
}

有了这个函数才会开启中

//接收程序遇到的第二个问题

串口在接收的过程中只能接收一次

原因:在中断结束后,还是要再次设置接收中断函数

HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)

而且这个函数放的位置也有讲究

/**
* @brief This function handles USART1 global interrupt.
*/
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */ /* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
while(HAL_UART_GetState(&huart1) != HAL_UART_STATE_READY);
while(HAL_UART_Receive_IT(&huart1, huart1_RxBuffer, ) != HAL_OK);
/* USER CODE END USART1_IRQn 1 */
}

以上两条语句参考的是正点原子程序

另外在接收和发送程序的过程中,最好加一些延时,不然会卡住。

STM32F103之USART学习记录的更多相关文章

  1. STM32F103之定时器学习记录

    /==============翻译STM32F103开发手册定时器部分========================/ 14 高级控制计时器(TIM1和TIM8) 14.1 TIM1和TIM8介绍 ...

  2. STM32F103之DMA学习记录

    /================翻译STM32F103开发手册DMA章节===========================/ 13 DMA(Direct memory access) 13.1 ...

  3. STM32F103之ADC学习记录

    1.问题 1)10位ADC的误差是多少? 首先要分清分辨率与精度的区别. 10cm的尺子,有100个等分刻度,则该尺子的分辨率为1mm. 但不能说这把尺子的精度是1mm. 在冬天,尺子会热胀冷缩,依然 ...

  4. STM32F103之GPIO学习记录

    9 GPIO:通用I/O口 AFIO:可供选择的I/O口 9.1 GPIO功能描述 每一个通用的I/O口都有: 两个32位的配置寄存器(配置寄存器低和配置寄存器高): 两个32位的数据寄存器(输入数据 ...

  5. STM32F103之I2C学习记录

    26.3.1  模式选择 该外设可以在以下四种模式之一 1)从机发送模式 2)从机接收模式 3)主机发送模式 4)主机接收模式 IIC协议时序 MSB:Most Significant Bit(最高有 ...

  6. Quartz 学习记录1

    原因 公司有一些批量定时任务可能需要在夜间执行,用的是quartz和spring batch两个框架.quartz是个定时任务框架,spring batch是个批处理框架. 虽然我自己的小玩意儿平时不 ...

  7. Java 静态内部类与非静态内部类 学习记录.

    目的 为什么会有这篇文章呢,是因为我在学习各种框架的时候发现很多框架都用到了这些内部类的小技巧,虽然我平时写代码的时候基本不用,但是看别人代码的话至少要了解基本知识吧,另外到底内部类应该应用在哪些场合 ...

  8. Apache Shiro 学习记录4

    今天看了教程的第三章...是关于授权的......和以前一样.....自己也研究了下....我觉得看那篇教程怎么说呢.....总体上是为数不多的精品教程了吧....但是有些地方确实是讲的太少了.... ...

  9. UWP学习记录12-应用到应用的通信

    UWP学习记录12-应用到应用的通信 1.应用间通信 “共享”合约是用户可以在应用之间快速交换数据的一种方式. 例如,用户可能希望使用社交网络应用与其好友共享网页,或者将链接保存在笔记应用中以供日后参 ...

随机推荐

  1. PLSQL无法连接(不存在或找不到oci.dll)

    问题说明:新系统安装plsql后,连接不上Oracle,连接时出现过两种报错 1.找不到OCI.dll文件 2.不能初始化OCI.dll文件,即OCI.dll文件错误 解决方案 plsql连接Orac ...

  2. html中多选框变单选框

    就是一个小js,直接上代码 $("input[name='checkboxlist']").each(function () { if (this.checked &&am ...

  3. EF CodeFirst配置领域类

    当我们不想使用EF的默认约定时,可以手动配置领域类,但还是推荐少配置,Simple is best! 两种配置方式: 1.Data Annotation Attributes[数据注解特性]  数据注 ...

  4. [一本通学习笔记] 字典树与 0-1 Trie

    字典树中根到每个结点对应原串集合的一个前缀,这个前缀由路径上所有转移边对应的字母构成.我们可以对每个结点维护一些需要的信息,这样即可以去做很多事情. #10049. 「一本通 2.3 例 1」Phon ...

  5. Learn from Niu 2020.1.13

    观念: 1. 把可视化的东西拾起来, 毕竟是做那个出身的. 2. 可视化里面时序数据,时空数据一直都是非常重要的. 3. know your data永远是最重要的一步, 我想更好的方式是,数据驱动, ...

  6. 【转】mathnet 使用方法介绍

    转载自:http://blog.csdn.net/c914620529/article/details/50393223 在C#中使用mathnet,需要利用using引入相关类 矩阵运算的相关类: ...

  7. Docker里面运行.net core

    详细可以参考微软官方文档:https://docs.microsoft.com/zh-cn/aspnet/core/host-and-deploy/docker/building-net-docker ...

  8. 在Linux服务器上安装Python3.7

    我的Linux版本是CentOS 6,自带2.7版本的Python.源码安装和系统中默认存在的Python不冲突. 1.在Python官网下载源码包,进入官网https://www.python.or ...

  9. php设计模式之工厂方法实例代码

    实现不修改原代码,扩展新功能 <?php header("Content-type:text/html;charset=utf-8"); /** * db接口 * 实现连接数 ...

  10. CentOS7网络配置:静态IP和DHCP

    1.打开并编辑网络配置文件:/etc/sysconfig/network-scripts/ifcfg-ens33 [root@localhost network-scripts]# vim ifcfg ...