STM32L0xx_HAL_Driver库的使用——UART

发布者:小九分析仪最新更新时间:2018-12-29 关键字:STM32L0xx  HAL  Driver库  UART 手机看文章 扫描二维码
随时随地手机看文章

单片机型号:STM32L051C8T6


开发环境MDK5.12


库版本:STM32L0xx_HAL_Driver V1.1.0


主机环境:Windows XP


之前一直使用的STM32F030C8T6单片机来做开发,因需求更改更换了一个新型号STM32L051C8T6,主要是用到了其低功耗特性,本以为直接把代码拷贝一下就可以使用了,结果是太天真了,STM32F030C8T6使用的库是STM32F0_StdPeriph_Lib而STM32L051C8T6使用的库是STM32L0xx_HAL_Driver两者的差别还是很大的,而且官方也推荐使用后者,没办法,重新学习一下吧。。。参考其例程磕磕绊绊的勉强可以写一个工程了,这里写一下有关UART的调试。


参考的程序是STM32L053R8-Nucleo例程中的UART_TwoBoards_ComIT工程,采用中断方式来进行两个单片机之间的通信。STM32L0xx_HAL_Driver库的分层更加明显,板极初始化代码如下



void HAL_UART_MspInit(UART_HandleTypeDef *huart)

{  

  GPIO_InitTypeDef  GPIO_InitStruct;

  

  /*##-1- Enable peripherals and GPIO Clocks #################################*/

  /* Enable GPIO TX/RX clock */

  USARTx_TX_GPIO_CLK_ENABLE();

  USARTx_RX_GPIO_CLK_ENABLE();

  /* Enable USART1 clock */

  USARTx_CLK_ENABLE(); 

  

  /*##-2- Configure peripheral GPIO ##########################################*/  

  /* UART TX GPIO pin configuration  */

  GPIO_InitStruct.Pin       = USARTx_TX_PIN;

  GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;

  GPIO_InitStruct.Pull      = GPIO_NOPULL;

  GPIO_InitStruct.Speed     = GPIO_SPEED_HIGH;

  GPIO_InitStruct.Alternate = USARTx_TX_AF;

  

  HAL_GPIO_Init(USARTx_TX_GPIO_PORT, &GPIO_InitStruct);

    

  /* UART RX GPIO pin configuration  */

  GPIO_InitStruct.Pin = USARTx_RX_PIN;

  GPIO_InitStruct.Alternate = USARTx_RX_AF;

    

  HAL_GPIO_Init(USARTx_RX_GPIO_PORT, &GPIO_InitStruct);

    

  /*##-3- Configure the NVIC for UART ########################################*/

  /* NVIC for USART1 */

  HAL_NVIC_SetPriority(USARTx_IRQn, 0, 1);

  HAL_NVIC_EnableIRQ(USARTx_IRQn);

}

 

/**

  * @brief UART MSP De-Initialization 

  *        This function frees the hardware resources used in this example:

  *          - Disable the Peripheral's clock

  *          - Revert GPIO and NVIC configuration to their default state

  * @param huart: UART handle pointer

  * @retval None

  */

void HAL_UART_MspDeInit(UART_HandleTypeDef *huart)

{

  /*##-1- Reset peripherals ##################################################*/

  USARTx_FORCE_RESET();

  USARTx_RELEASE_RESET();

 

  /*##-2- Disable peripherals and GPIO Clocks #################################*/

  /* Configure UART Tx as alternate function  */

  HAL_GPIO_DeInit(USARTx_TX_GPIO_PORT, USARTx_TX_PIN);

  /* Configure UART Rx as alternate function  */

  HAL_GPIO_DeInit(USARTx_RX_GPIO_PORT, USARTx_RX_PIN);

  

  /*##-3- Disable the NVIC for UART ##########################################*/

  HAL_NVIC_DisableIRQ(USARTx_IRQn);

}


这两个函数没什么可说的跟开发板对应修改即可,这样使得串口初始化更加的简洁只需要进行逻辑上的初始化即可


/**********************************************************************

函数:uart_init()

函数作用:串口初始化

参数:

uint32_t BaudRate=========================串口波特率

返回值:无

上一版本:无

当前版本:1.0

作者:

最后修改时间:2015-04-02

说明: 

**********************************************************************/

void uart_init(uint32_t BaudRate)

{

    

    UartHandle.Instance        = USARTx;

    UartHandle.Init.BaudRate   = BaudRate;

    UartHandle.Init.WordLength = UART_WORDLENGTH_8B;

    UartHandle.Init.StopBits   = UART_STOPBITS_1;

    UartHandle.Init.Parity     = UART_PARITY_NONE;

    UartHandle.Init.HwFlowCtl  = UART_HWCONTROL_NONE;

    UartHandle.Init.Mode       = UART_MODE_TX_RX;

    

    if(HAL_UART_Init(&UartHandle) != HAL_OK)

    {

        Error_Handler();

    }

__HAL_UART_ENABLE(&UartHandle);

 

NVIC_SetPriority(USARTx_IRQn,0);

NVIC_EnableIRQ(USARTx_IRQn);

uart_rev.front = aRxBuffer;

uart_rev.rear = aRxBuffer; //两个指针指向相同的地址空间

if(HAL_UART_Receive_IT(&UartHandle,(uint8_t*)aRxBuffer,1) != HAL_OK)

{

Error_Handler();

}

}


这里为串口的接收开辟了500个字节的缓冲区aRxBuffer使用首尾指针来进行数据的接收和存取,即单缓冲机制。


struct uart

{

uint8_t *rear; //在中断函数中更改

uint8_t *front; //在主循环中更改

};


由于STM32L0xx_Hal_Driver库的使用串口底层分为了3种:查询方式、中断方式、DMA方式,都是使用HAL函数来实现,因此我们使用中断方式接收不能自动开启,必须使用函数HAL_UART_Receive_IT来打开接收中断,这里我们每接收一个字节就进入中断。STM32L0xx_Hal_Driver库的使用使得中断函数也十分简洁一句话搞定,采用回调函数机制来处理中断


void USARTx_IRQHandler(void)

{

  HAL_UART_IRQHandler(& UartHandle);

}

在HAL_UART_IRQHandler()中会自动调用串口接收中断的回调函数


/**

  * @brief  Rx Transfer completed callback

  * @param  UartHandle: UART handle

  * @note   This example shows a simple way to report end of IT Rx transfer, and 

  *         you can add your own implementation.

  * @retval None

  */

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)

{

uint8_t ret = HAL_OK;

/* Set transmission flag: trasfer complete*/

uart_rev.rear++; //更新rear指针

if(uart_rev.rear >= (aRxBuffer + BUFFSIZE))

uart_rev.rear = aRxBuffer;

do

{

ret = HAL_UART_Receive_IT(UartHandle,uart_rev.rear,1);

}while(ret != HAL_OK);

}


每次把接收到的数据存入rear所指向的地址空间,存入数据只更新rear指针,同时开启请求下一个数据的到来。在主函数中调用uart_read函数来取出数据


/**********************************************************************

函数:uart_read()

函数作用:从接收缓冲区中读取数据

参数:

uint8_t *fmt--------------------------------接收到的数据

uint16_t time_out---------------------------超时时间

返回值:0:读取到数据-1:没有读取到数据

上一版本:无

当前版本:1.0

作者:

最后修改时间:2015-04-08

说明: 

**********************************************************************/

int8_t uart_read(uint8_t *fmt, uint16_t time_out)

{

while(time_out)

{

if(uart_rev.front != uart_rev.rear)

{

//如果队首指针和队尾指针不同表明缓冲区中有数据还未收取

*fmt=*uart_rev.front;


uart_rev.front++;

 

if (uart_rev.front >= (aRxBuffer+BUFFSIZE))

uart_rev.front = aRxBuffer;

 

return 0;

}

time_out--;

}

return (int8_t)-1;

}


取数据只更新front指针,这里有个不足的地方是如果一直不取数据或者取数据速度较慢而接收的数据很多会造成数据覆盖即出现数据丢失的情况,不过一般很少会有这种情发生(对于我来说是在主循环中不停地进行读取操作,所以没事啦),整个文件如下


#include "UART.h"

#include "stm32l0xx_hal_def.h"

#include "utils.h"

 

UART_HandleTypeDef UartHandle;

uint8_t aRxBuffer[BUFFSIZE];

struct uart uart_rev;

 

void HAL_UART_MspInit(UART_HandleTypeDef *huart)

{  

  GPIO_InitTypeDef  GPIO_InitStruct;

  

  /*##-1- Enable peripherals and GPIO Clocks #################################*/

  /* Enable GPIO TX/RX clock */

  USARTx_TX_GPIO_CLK_ENABLE();

  USARTx_RX_GPIO_CLK_ENABLE();

  /* Enable USART1 clock */

  USARTx_CLK_ENABLE(); 

  

  /*##-2- Configure peripheral GPIO ##########################################*/  

  /* UART TX GPIO pin configuration  */

  GPIO_InitStruct.Pin       = USARTx_TX_PIN;

  GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;

  GPIO_InitStruct.Pull      = GPIO_NOPULL;

  GPIO_InitStruct.Speed     = GPIO_SPEED_HIGH;

  GPIO_InitStruct.Alternate = USARTx_TX_AF;

  

  HAL_GPIO_Init(USARTx_TX_GPIO_PORT, &GPIO_InitStruct);

    

  /* UART RX GPIO pin configuration  */

  GPIO_InitStruct.Pin = USARTx_RX_PIN;

  GPIO_InitStruct.Alternate = USARTx_RX_AF;

    

  HAL_GPIO_Init(USARTx_RX_GPIO_PORT, &GPIO_InitStruct);

    

  /*##-3- Configure the NVIC for UART ########################################*/

  /* NVIC for USART1 */

  HAL_NVIC_SetPriority(USARTx_IRQn, 0, 1);

  HAL_NVIC_EnableIRQ(USARTx_IRQn);

}

 

/**

  * @brief UART MSP De-Initialization 

  *        This function frees the hardware resources used in this example:

  *          - Disable the Peripheral's clock

  *          - Revert GPIO and NVIC configuration to their default state

  * @param huart: UART handle pointer

  * @retval None

  */

void HAL_UART_MspDeInit(UART_HandleTypeDef *huart)

{

  /*##-1- Reset peripherals ##################################################*/

  USARTx_FORCE_RESET();

  USARTx_RELEASE_RESET();

 

  /*##-2- Disable peripherals and GPIO Clocks #################################*/

  /* Configure UART Tx as alternate function  */

  HAL_GPIO_DeInit(USARTx_TX_GPIO_PORT, USARTx_TX_PIN);

  /* Configure UART Rx as alternate function  */

  HAL_GPIO_DeInit(USARTx_RX_GPIO_PORT, USARTx_RX_PIN);

  

  /*##-3- Disable the NVIC for UART ##########################################*/

  HAL_NVIC_DisableIRQ(USARTx_IRQn);

}

 

/**********************************************************************

函数:uart_init()

函数作用:串口初始化

参数:

uint32_t BaudRate=========================串口波特率

返回值:无

上一版本:无

当前版本:1.0

作者:

最后修改时间:2015-04-02

说明: 

**********************************************************************/

void uart_init(uint32_t BaudRate)

{

    

    UartHandle.Instance        = USARTx;

    UartHandle.Init.BaudRate   = BaudRate;

    UartHandle.Init.WordLength = UART_WORDLENGTH_8B;

    UartHandle.Init.StopBits   = UART_STOPBITS_1;

    UartHandle.Init.Parity     = UART_PARITY_NONE;

    UartHandle.Init.HwFlowCtl  = UART_HWCONTROL_NONE;

    UartHandle.Init.Mode       = UART_MODE_TX_RX;

    

    if(HAL_UART_Init(&UartHandle) != HAL_OK)

    {

        Error_Handler();

    }

__HAL_UART_ENABLE(&UartHandle);

 

NVIC_SetPriority(USARTx_IRQn,0);

NVIC_EnableIRQ(USARTx_IRQn);

uart_rev.front = aRxBuffer;

uart_rev.rear = aRxBuffer; //两个指针指向相同的地址空间

if(HAL_UART_Receive_IT(&UartHandle,(uint8_t*)aRxBuffer,1) != HAL_OK)

{

Error_Handler();

}

}

void Error_Handler(void)

{

    while(1)

    {

        

    }

}

 

/**********************************************************************

函数:uart_read()

函数作用:从接收缓冲区中读取数据

参数:

uint8_t *fmt--------------------------------接收到的数据

uint16_t time_out---------------------------超时时间

返回值:0:读取到数据-1:没有读取到数据

上一版本:无

当前版本:1.0

作者:

最后修改时间:2015-04-08

说明: 

**********************************************************************/

int8_t uart_read(uint8_t *fmt, uint16_t time_out)

{

while(time_out)

{

if(uart_rev.front != uart_rev.rear)

{

//如果队首指针和队尾指针不同表明缓冲区中有数据还未收取

*fmt=*uart_rev.front;


uart_rev.front++;

 

if (uart_rev.front >= (aRxBuffer+BUFFSIZE))

uart_rev.front = aRxBuffer;

 

return 0;

}

time_out--;

}

return (int8_t)-1;

}

 

int8_t uart_send(uint8_t *fmt, uint8_t len)

{

while(len)

{

printf("%c",*fmt);

fmt++;

len--;

}

 

return 0;

}

 

#ifdef UART_DEBUG

int fputc(int ch, FILE *f)

{

    USART1->TDR = ch;

    while(!(USART1->ISR & USART_ISR_TXE));

    return(ch);

}

#endif

 

/**

  * @brief  Tx Transfer completed callback

  * @param  UartHandle: UART handle. 

  * @note   This example shows a simple way to report end of IT Tx transfer, and 

  *         you can add your own implementation. 

  * @retval None

  */

void HAL_UART_TxCpltCallback(UART_HandleTypeDef * huart)

{

uint8_t ret = HAL_OK;

UartReady = SET;

#if 1

uart_snd.front++; //更新rear指针

if(uart_snd.front >= (aTxBuffer + BUFFSIZE))

uart_snd.front = aTxBuffer;

if(uart_snd.front != uart_snd.rear)

{

//如果队首指针和队尾指针不同表明缓冲区中有数据还未发送

do

{

ret = HAL_UART_Transmit_IT(&UartHandle,uart_snd.front,1);//请求发送下一个数据

}while(ret != HAL_OK);

}

#endif

}

/**

  * @brief  Rx Transfer completed callback

  * @param  UartHandle: UART handle

  * @note   This example shows a simple way to report end of IT Rx transfer, and 

  *         you can add your own implementation.

  * @retval None

  */

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)

{

uint8_t ret = HAL_OK;

/* Set transmission flag: trasfer complete*/

uart_rev.rear++; //更新rear指针

if(uart_rev.rear >= (aRxBuffer + BUFFSIZE))

uart_rev.rear = aRxBuffer;

do

{

ret = HAL_UART_Receive_IT(UartHandle,uart_rev.rear,1);

}while(ret != HAL_OK);

}

/******************************************************************************/

/*                 STM32L0xx Peripherals Interrupt Handlers                   */

/*  Add here the Interrupt Handler for the used peripheral(s) (PPP), for the  */

/*  available peripheral interrupt handler's name please refer to the startup */

/*  file (startup_stm32l0xx.s).                                               */

/******************************************************************************/

/**

  * @brief  This function handles UART interrupt request.  

  * @param  None

  * @retval None

  * @Note   This function is redefined in "main.h" and related to DMA stream 

  *         used for USART data transmission     

  */

void USARTx_IRQHandler(void)

{

  HAL_UART_IRQHandler(& UartHandle);

}


在实际测试中也没有问题,当单缓冲机制可用时,就会考虑使用双缓冲机制即为串口发送也开辟一个缓冲区。下次再分解。。。


关键字:STM32L0xx  HAL  Driver库  UART 引用地址:STM32L0xx_HAL_Driver库的使用——UART

上一篇:STM32 HAL库 定时中断和编码输入
下一篇:STM32F429HAL库定时器学习笔记

推荐阅读最新更新时间:2024-03-16 16:21

STM32 HAL 定时器中断
//定时时间t=(Prescaler +1)*(Period +1) /clock(定时器时钟评率) ` MX_TIM3_Init(); HAL_TIM_Base_Start_IT(&htim3); //(必须要,启动定时器中断) static void MX_TIM3_Init(void) { /* USER CODE BEGIN TIM3_Init 0 */ /* USER CODE END TIM3_Init 0 */ TIM_ClockConfigTypeDef sClockSourceConfig = {0}; TIM_MasterConfigTypeDef sMasterConfig =
[单片机]
CubeMX 5.5 修改HAL库函数版本
最初我是按照软件推荐,自动按安装的1.15的。 为了和正点原子的例程统一库函数版本,就下载了1.11。 但是在工程配置界面始终没有办法修改 hal库 版本的选择: 关闭CubeMX,使用记事本打开工程文件: 修改版本号: 重新打开工程,库版本修改成功: 工程生成成功:
[单片机]
CubeMX 5.5 修改<font color='red'>HAL</font><font color='red'>库</font>库函数版本
FPGA与GPS_OEM板的UART设计
引言 UART(标准异步接收器/发射器)得到了相当广泛的应用,它允许串行链路上进行全双工通信。一般使用通用的UART接口芯片,但这种芯片存在电路复杂、成本高,降低了系统的可靠性和稳定度,由于结构和功能的相对固定,因而我们不能根据自己的设计需要去进行剪裁和移植。而日益成熟的SOPC(Silicon on Programmable Chip,系统可编程芯片)技术要求将整个设计功能集成到一块或几块芯片中,本文通过对UART功能的分析,提出了在FPGA上集成UART功能模块,增强了设计的灵活性,简化了电路,并通过有限状态机来描述核心功能控制逻辑,从而提高了整个系统的稳定性和可靠度。基于这种思想,本文提出了一种使用VHDL 语言开
[嵌入式]
FPGA与GPS_OEM板的<font color='red'>UART</font>设计
LPC1114/LPC11U14和LPC1343对比学习(五)UART
LPC1114/LPC1343串口特点: 16字节收发FIFO; 寄存器位置符合16C550工业标准; 接收器FIFO触发点可为1、4、8和14字节; 内置波特率发生器; 用于精确控制波特率的小数分频器,并拥有赖以实现软件流控制的自动波特率检测能力和机制; 支持软件或硬件流控制执行; 包含标准Modem接口信号(CTS、DCD、DTS、DTR、RI、RTS); 支持RS-458/EIA-485的9位模式和输出使能。 LPC11U14串口特点: 16-byte receive and transmit FIFOs. Register locations conform to 550 industry s
[单片机]
LPC1114/LPC11U14和LPC1343对比学习(五)<font color='red'>UART</font>
MSP430F169(二)——UART波特率(论上)
串口通信 1. 什么叫串口 串行接口简称串口,也称串行通信接口或串行通讯接口(通常指COM接口),是采用串行通信方式的扩展接口。串行接口 (Serial Interface)是指数据一位一位地顺序传送。 与并行接口相比,其优点也非常明显: 成本低,最少需要一根线就可以完成传输; 没有数据的相互干扰,误码率相对较低; 缺点:传输速率相对较低。 2. 串口如何建立通信 对单片机有所了解的人都应该知道,串口通信是通过调配单片机内部的寄存器来控制速率。而MSP430F169内部最重要的几个配置无非是波特率的设置和多机通信。 2.1什么是波特率 在讲波特率之前我们要区分两个概念:波特率和比特率。 比特率: 比特率是指每秒传送的比
[单片机]
MSP430F169(二)——<font color='red'>UART</font>波特率(论上)
PIC软件串行异步通信三倍速采样法设计
在利用 单片机 开发各种嵌入式应用系统时,异步 串行通信 是常用的一种通信模式,有的应用中还要求实现多路异步串行通信。人们平时所应用的各种厂商的单片机,绝大部分片上只提供一个UART(通用异步收发器)硬件模块,利用它可以方便地实现一路串行通讯。PIC系列单片机也不例外,在其丰富的一系列产品中,除高端系列(PIC 17/18)一些型号片上带有2路UART硬件模块外,其他大部分型号片上只有1路UART,一些低端廉价的PIC单片机甚至还不带硬件UART。为了提高系统的性价比,要求设计者用软件实现1路或多路异步串行通信。很多人对用软件实现的UART在可靠性和效率方面持怀疑态度,其实关键问题是采用何种方式来实现可靠的UART功能。 1
[单片机]
STM32F0单片机快速入门十: 用 SPI HAL 读写W25Q128
1.W25Q128 介绍 当我们有比较多的数据需要掉电存储时,上一篇文章所介绍的 24C02 (256个字节EEPROM)就不够了。此时我们会用到另外一种类型的存储器,即 Flash。比如具有 SPI 接口的 W25Q128。这颗小芯片虽然也只有简单的 8 个引脚,但存储容量却达到了128M-bit,也就是 16M 字节,同时它的读写速度可以达到 66MB/S。但是由于 STM32F030 不支持 Quad/Dual SPI,只能以标准 SPI 方式读写,所以速度会低一些。以下是 W25Q128 的主要特点: 133MHz SPI Clock。 10万次擦写寿命,20年数据保持时间。 每颗具有64-Bit唯一序列号 Uni
[单片机]
STM32F0单片机快速入门十: 用 SPI <font color='red'>HAL</font> <font color='red'>库</font>读写W25Q128
ARM:UART串口异步通信驱动编程
1. 串口的基本概念 1.1 UART - 串行异步收发器 Universal Asynchronous Receiver/Transmitter 串行/并行(课后补充) 异步/同步:'异步/同步通信两者之间的区别' (补充) '单工/半双工/全双工: 单工:任何时候数据只能朝一个方向传输 半双工:数据可以向两个方向传输,任何同一时刻只能朝同一方向传输 全双工:数据可以同时向两个方向传输 1.2 串口通信标准 RS232 (电子工业协议EIA) - 目前最常用的'串行接口标准' 规定了'电气特性': 逻辑 0 ,+3 v ~ +15 v,SPACE 逻辑 1 ,- 3 v ~
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved