昨天分析了普通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. 【情人节选帽子】TCS34725颜色传感器和Python图形界面编程(STM32 HAL库)

    截图 描述: l  STM32 HAL库编程 l  使用模拟IIC通信,方便程序移植 l  Python界面编写,蘑菇头的帽子是什么颜色 l  STM32 HAL库串口通信 l  Python界面使用 ...

  4. STM32 HAL库与标准库的区别_浅谈句柄、MSP函数、Callback函数

    最近笔者开始学习STM32的HAL库,由于以前一直用标准库进行开发,于是发现了HAL库几点好玩的地方,在此分享. 1.句柄在STM32的标准库中,假设我们要初始化一个外设(这里以USART为例)我们首 ...

  5. 【有趣的全彩LED | 编程】用STM32 HAL库让WS2812B为你所动

    一.效果展示 观看演示效果:https://www.bilibili.com/video/BV1dv411Y7x3 使用STM32 HAL库编程 PWM+DMA控制输出,CubeMX生成初始工程 实现 ...

  6. 【春节歌曲回味 | STM32小音乐盒 】PWM+定时器驱动无源蜂鸣器(STM32 HAL库)

    l  STM32通过PWM与定时器方式控制无源蜂鸣器鸣响 l  STM32小音乐盒,歌曲进度条图形显示与百分比显示,歌曲切换 l  编程使用STM32 HAL库 l  IIC OLED界面编程,动画实 ...

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

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

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

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

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

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

随机推荐

  1. 学习笔记CB001:NLTK库、语料库、词概率、双连词、词典

    聊天机器人知识主要是自然语言处理.包括语言分析和理解.语言生成.机器学习.人机对话.信息检索.信息传输与信息存储.文本分类.自动文摘.数学方法.语言资源.系统评测. NLTK库安装,pip insta ...

  2. 【SQL】 借助游标来实现文本的分列与合并

    有时我们会遇到需要把表中个别字段拆分成多条数据或是把多条数据合并到一起的情况.一般的编程语言都有函数“split”和“join”来实现,而SQL中既没有这些函数也没有类似数组和列表这类方便保存成组数据 ...

  3. head first c初探网络编程上

    server连接网络四部曲. 为了与外界沟通,c程序用数据流读写字节,比較经常使用的数据流有标准输入.标准输出.文件等. 假设想写一个与网络通信的程序.就须要一种新的数据流----------套接字. ...

  4. Panel 中加载窗体

    pnlMain.Controls.Clear(); ControlAnalyzer1 CA1 = new ControlAnalyzer1(); CA1.TopLevel = false; CA1.S ...

  5. 【C#】stream图像转byte的问题

    Image xx = Image.FromStream(linkList[ii].stream); byte[] bytes = new Byte[linkList[ii].stream.Length ...

  6. 机器学习中的train valid test以及交叉验证

    转自 https://www.cnblogs.com/rainsoul/p/6373385.html 在以前的网络训练中,有关于验证集一直比较疑惑,在一些机器学习的教程中,都会提到,将数据集分为三部分 ...

  7. enable-ssh-key-logon-disable-password-password-less-logon-centos/

    cat ~/.ssh/id_rsa.pub | ssh root@destination_server_address "cat >> ~/.ssh/authorized_key ...

  8. 记一次gitlab-ce数据恢复过程

    使用的gitlab是用docker启动的,数据目录的owner/group信息被意外全部更改成了root:root导致服务不可用.最终通过复原文件所有者的方式恢复了服务. 步骤如下: 1. 打包备份g ...

  9. C# 6.0:String Interpolation

    在开发中经常需要对字符串进行格式化处理.我们一般使用String.Format()方法,它会将指定字符串中的每个格式项替换为相应对象的值的文本等效项.虽然这很普通,但有时会容易使人迷惑并造成错误.因为 ...

  10. Docker安装使用battery historian

    apt-get insatll docker.io battery historian ubuntu下使用 首先要确保是google浏览器,然后用命令行 google-chrome --proxy-s ...