昨天分析了普通io口的使用,和初始化代码流程,回顾一下,首先定义一个配置io口功能的结构体,然后开启时钟,再去配置这个结构体里面的各个成员变量,每个成员变量都有很多种选择,可以看各个成员变量 后面的注释,找到可选的配置即可,把这个结构体配置完了之后,把它扔到hal库提供的io口初始化函数中,另一个参数是ABC。。。中的一个,指定端口。

  同理,操作串口的流程大致和上面叙述的过程差不多,但是串口多了收发数据,中断等等功能。在Cubemx里面配置串口,然后打开工程,跟踪代码,了解详细的过程。首先,串口的初始化代码部分:

    UART_HandleTypeDef UART1_Handler; //UART句柄 

    UART1_Handler.Instance=USART1;            //  指定串口
UART1_Handler.Init.BaudRate=bound; // 波特率
UART1_Handler.Init.WordLength=UART_WORDLENGTH_8B; // 字长为8位数据格式
UART1_Handler.Init.StopBits=UART_STOPBITS_1; // 一个停止位
UART1_Handler.Init.Parity=UART_PARITY_NONE; // 无奇偶校验位
UART1_Handler.Init.HwFlowCtl=UART_HWCONTROL_NONE; // 无硬件流控
UART1_Handler.Init.Mode=UART_MODE_TX_RX; // 收发模式
HAL_UART_Init(&UART1_Handler); // 初始化这个串口

大概过程和配置io口类似,不再细说。但是要进到串口初始化函数中去看一下,发现会调用这个函数,但是这个函数的weak虚函数,虚函数的概念百度一下即可,大概就是用户需要自己重新写他的功能:

HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart)

...
HAL_UART_MspInit(huart);
...

...
__weak void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(huart);
/* NOTE: This function Should not be modified, when the callback is needed,
the HAL_UART_MspInit could be implemented in the user file
*/
}

看一下注释,大意就是与回调有关系,cubemx给做了,看一下:

void HAL_UART_MspInit(UART_HandleTypeDef* huart)
{
GPIO_InitTypeDef GPIO_InitStruct; /**USART1 GPIO Configuration
PA9 ------> USART1_TX
PA10 ------> USART1_RX
*/
GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); HAL_NVIC_SetPriority(USART1_IRQn, , );
HAL_NVIC_EnableIRQ(USART1_IRQn);
}

从代码可以功能:配置io口,刚才的初始化串口函数,只是配置了串口的波特率、数据位等等,但是还没有配置串口所在的引脚,在这里配置,注释很清楚,A9  A10是这个川口的T和R,然后配置速度、复用模式,复用为什么,这个复用说一下。举个例子,如果有的用户想用很多普通io口,不用串口啊、SPI接口啊。有的呢,就用串口和spi接口,那厂家要是想满足这些用户,就要给片上,多加io口,加串口,等等其他的引脚,那么就可能会使脚很多,芯片大或者制造成本高,于是厂家就用100根引脚(407某型号)然后让一些脚有多个功能,既可以干这个也可以做那个,至于到底做什么,用户决定,这样就是脚会少,同时满足大多数用户的需求。片上除了电源等口,剩下的,基本都可以当作普通的io口用,同时也可以做串口、SPI等等功能,这叫复用。刚才说到,我们只配置了串口功能,还没配置这个串口所在的io口为复用,复用为串口。在这个回调初始化中定义了。同时,也配置了,中断优先号,中断使能。

  那么中断怎么用呢?这里我直接参考了正点原子的教程:

    //               串口号         接受缓冲数组      接收量:自己宏定义或者直接写数就行    
HAL_UART_Receive_IT(&huart1, (u8 *)aRxBuffer1, RXBUFFERSIZE1);
//该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量

这个函数放在串口初始化中,就使能了串口接收中断,串口接收到数据,这个函数就把数据放在我们定义的接受缓冲数组中,可能一次过来很多,但是我们只接收RXBUFFERSIZ1个,这个还要配合回中断调用函数,在利用JY901模块收再说,下面再说。如果想深入了解的话,还得进入这个函数去看看,发现他会调用函数:__HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);,其实这是一个宏定义,如下:

#define UART_IT_MASK  ((uint32_t)0x0000FFFFU)
#define __HAL_UART_ENABLE_IT(__HANDLE__, __INTERRUPT__) ((((__INTERRUPT__) >> 28U) == 1U)? ((__HANDLE__)->Instance->CR1 |= ((__INTERRUPT__) & UART_IT_MASK)): \
(((__INTERRUPT__) >> 28U) == 2U)? ((__HANDLE__)->Instance->CR2 |= ((__INTERRUPT__) & UART_IT_MASK)): \
((__HANDLE__)->Instance->CR3 |= ((__INTERRUPT__) & UART_IT_MASK)))

很复杂,如果带参数宏定义,把参数带入进来,然后对比寄存器,配置中断的,这个就不详细写了,其实如果不了解寄存器的话也可用起来的。(刚才分析了一下,感觉这块还是要一步一步的写出来,以后自己看还是很省事的,但是时间紧迫,以后在回过头来补充)。

  那如果发生了中断呢,刚才配置的是USART1_IRQn,我们去查一下他,发现:

DCD     USART1_IRQHandler                 ; USART1  

void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&huart1);
}

串口1的中断处理函数是USART1_IRQHandler,他又调用了HAL_UART_IRQHandler(&huart1):

void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{
...
UART_Receive_IT(huart); //读数据寄存器,并且调用回调函数
....
} static HAL_StatusTypeDef UART_Receive_IT(UART_HandleTypeDef *huart)
{
HAL_UART_RxCpltCallback(huart); // 回调函数,虚函数自己定义
} __weak void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(huart);
/* NOTE: This function Should not be modified, when the callback is needed,
the HAL_UART_TxCpltCallback could be implemented in the user file
*/
}

那么我们接收到了传到串口的数据后我们利用hal库函数也得到了,然后我们想利用一下这些数据做点什么怎么办呢?这个接收中断回调函数就来了,接收到数据后,执行中断函数,中断函数的功能是读取数据寄存器,把数据放在我们指定的数组中,然后调用这个回调函数,我们在这各回调函数中就可以操作这些数据了(读取到了),(但是根据正点院子教程所说,这么做效率不高,入门的话,就这么做就行,毕竟官方的)。

    if(huart->Instance == USART1)//如果是串口1
{
a = aRxBuffer1[];
HAL_UART_Receive_IT(&huart1, (u8 *)aRxBuffer1, RXBUFFERSIZE1);
}

这里要仔细说一下,我这么写是来一个中断,读取一个字节(之前宏的),但是我用的JY901模块是一次发送11个数据,每条11个字节,我就要中断11次,想来效率不高,该进:把RXBUFFERSIZE1定义为11,一条指令包过来11个字节全部存储在aRxBuffer1中,就行了,然后继续接收使能。

  概过程就是这样,这里面并没有发送中断,目前我还没用,只接受就行了,抓紧调四轴。

stm32 HAL库笔记(一)——串口的操作的更多相关文章

  1. stm32 HAL库笔记(零)

    最近在设计四旋翼飞行器,用stm32f407,有三种开发方式可以选择:一.寄存器开发.二:库函数开发.三:HAL库开发,考虑了一下,选择了HAL库,原因如下: 1. 寄存器开发相对较慢,寄存器很多,配 ...

  2. stm32 HAL库笔记(一)——普通IO口

    今天介HAL库操作普通IO口,就是输入/输出. 如果用CubeMX配置io工程,打开以后可以看到如下代码: GPIO_InitTypeDef GPIO_Initure; __HAL_RCC_GPIOB ...

  3. STM32 HAL库详解 及 手动移植

    源: STM32 HAL库详解 及 手动移植

  4. 【书籍连载】《STM32 HAL 库开发实战指南—基于F7》-第一章

    从今天起,每天开始连载一章<STM32 HAL 库开发实战指南—基于F7>.欢迎各位阅读.点评.学习. 第1章  如何使用本书 1.1  本书的参考资料 本书参考资料为:<STM32 ...

  5. STM32 HAL库 UART 串口读写功能笔记

    https://www.cnblogs.com/Mysterious/p/4804188.html STM32L0 HAL库 UART 串口读写功能 串口发送功能: uint8_t TxData[10 ...

  6. STM32 HAL库利用DMA实现串口不定长度接收方法

    参考:https://blog.csdn.net/u014470361/article/details/79206352 我这里使用的芯片是 F1 系列的,主要是利用 DMA 数据传输方式实现的,在配 ...

  7. stm32 hal库串口通信资料汇集

    串口的发送接收函数:HAL_UART_Transmit();串口轮询模式发送,使用超时管理机制.HAL_UART_Receive();串口轮询模式发送,使用超时管理机制.HAL_UART_Transm ...

  8. STM32 HAL库的定时器中断回调函数跟串口中断回调函数

    void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { //添加回调后的程序逻辑 if (htim->Instance == ...

  9. STM32 HAL库使用中断实现串口接收不定长数据

    以前用DMA实现接收不定长数据,DMA的方法接收串口助手的数据,全部没问题,不过如果接收模块返回的数据,而这些数据如果包含回车换行的话就会停止接收,例如接收:AT\r\nOK\r\n,就只能接收到AT ...

随机推荐

  1. JavaScript事件概览

    JavaScript事件 JavaScript是单线程,在同一个时间点,不可能同时运行两个"控制线程". 事件句柄和事件对象 1.注册事件句柄 标准和非标准 var button= ...

  2. C#开发微信门户及应用(33)--微信现金红包的封装及使用

    我在上篇随笔<C#开发微信门户及应用(32)--微信支付接入和API封装使用>介绍为微信支付的API封装及使用,其中介绍了如何配置好支付环境,并对扫码支付的两种方式如何在C#开发中使用进行 ...

  3. PHP-递归扫描目录和删除目录

    (1) 通过递归扫描目录并打印 // php递归扫描目录 function scanMyDir($path){ // 打开目录 $dh = opendir($path); echo '<ul&g ...

  4. MFC各种控件的常见操作(逐步添加中......)

    由于经常切换系统或界面框架进行编程,难免有时会忘记之前的编程函数等等.所有在此自己做一个备份,以防止重新充电带来的痛苦! 1.CButton 1.1 在VC中编程实现按钮的启用(enable)和禁用( ...

  5. [原]TCP/UDP使用细节备忘

    body { font-family: "Microsoft YaHei UI","Microsoft YaHei",SimSun,"Segoe UI ...

  6. 数据的加密传输——单片机上实现TEA加密解密算法

    各位大侠在做数据传输时,有没有考虑过把数据加密起来进行传输,若在串口或者无线中把所要传的数据加密起来,岂不是增加了通信的安全性.常用的加密解密算法比如DES.RSA等,受限于单片机的内存和运算速度,实 ...

  7. 消息机制JMS

    消息机制JMS http://wenku.baidu.com/link?url=5FiNu_HP3lUFKhePmfCUPE09DV_f9-tsQ4NpWtKxHYphxAglzsjg3XSM8Sz6 ...

  8. Codeforces #550 (Div3) - G.Two Merged Sequences(dp / 贪心)

    Problem  Codeforces #550 (Div3) - G.Two Merged Sequences Time Limit: 2000 mSec Problem Description T ...

  9. 「2017 山东一轮集训 Day5」苹果树

    「2017 山东一轮集训 Day5」苹果树 \(n\leq 40\) 折半搜索+矩阵树定理. 没有想到折半搜索. 首先我们先枚举\(k\)个好点,我们让它们一定没有用的.要满足这个条件就要使它只能和坏 ...

  10. ServiceStack.Redis遇到的问题:ServiceStack.Redis.Generic.RedisTypedClient`1”的方法“get_Db”没有实现。

    问题: ServiceStack.Redis.Generic.RedisTypedClient`1”的方法“get_Db”没有实现. 解决方案: step 1::引用的三个 包版本保持一致 Servi ...