历史上的今天
返回首页

历史上的今天

今天是:2024年12月29日(星期日)

2018年12月29日 | STM32L0xx_HAL_Driver库的使用——UART

2018-12-29

单片机型号: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);

}


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


推荐阅读

史海拾趣

Electronic公司的发展小趣事

华为,作为中国的科技巨头,其在电子行业的发展历程中展现出了强大的技术实力和全球视野。华为在通信领域取得了多项技术突破,如5G技术的领先和智能手机拍照技术的创新。同时,华为还积极拓展全球市场,与全球运营商建立了广泛的合作关系。然而,面对国际市场的复杂环境和竞争压力,华为也面临着诸多挑战和不确定性。

Autonics公司的发展小趣事

随着产品质量的提升和市场认可度的提高,Autonics开始积极拓展国内外市场。公司在韩国国内设立了多个办事处和代理公司,覆盖了主要城市和工业区。同时,Autonics还积极开拓海外市场,先后在多个国家和地区设立了销售网点和生产基地。通过国际化战略的实施,Autonics的产品逐渐走向世界,成为国际知名的传感器和控制器品牌。

Cadeka公司的发展小趣事

近年来,随着电子行业的快速变革和新兴技术的不断涌现,Cadeka公司面临着前所未有的挑战。为了应对这些变革,公司及时调整发展战略,加大在新兴技术领域的投入。同时,公司还积极与合作伙伴开展合作,共同探索新的商业模式和市场机会。通过这些努力,Cadeka公司成功应对了行业变革带来的挑战,继续保持了在电子行业中的领先地位。

这些故事虽然是虚构的,但它们反映了电子行业发展的一些普遍规律和趋势。希望这些故事能够为您提供一些启发和参考。

国产公司的发展小趣事
对于功率较大的放大器,需要采用高效的散热措施来确保电路的稳定运行和长寿命。
CITIZEN公司的发展小趣事

进入21世纪,西铁城公司在技术创新方面继续取得显著进展。其中,光动能技术的开发是公司历史上的一大里程碑。1995年,西铁城推出了第一只光动能手表,这一技术能够吸收任何可见光源并转化为动能,为腕表提供持续的动力。随后,公司不断对光动能技术进行改进和优化,使其更加精确、高效。这一技术的成功应用,不仅提升了西铁城产品的竞争力,也为整个电子行业带来了新的发展方向。

CAROLCABLE公司的发展小趣事

在激烈的市场竞争中,CAROLCABLE公司深知技术创新是企业发展的核心动力。因此,公司不断加大研发投入,引进先进的生产设备和技术人才,推动技术创新和产业升级。经过多年的努力,CAROLCABLE成功研发出了一系列具有自主知识产权的高性能线缆产品,这些产品在传输速度、稳定性和耐用性等方面均达到了行业领先水平。

随着产品技术的不断升级,CAROLCABLE开始积极拓展国内外市场。公司参加了多个国际电子线缆展会,与全球同行交流学习,寻找合作机会。同时,CAROLCABLE还加强与国内大型电子企业的合作,为其提供定制化的线缆解决方案。这些举措不仅为公司带来了更多的商机,也进一步巩固了CAROLCABLE在电子线缆行业的领先地位。

这两个故事仅是对CAROLCABLE公司发展起来的简要描述,实际上,公司的成长历程中还有许多值得探讨的细节和里程碑事件。如需了解更多关于CAROLCABLE公司的故事,建议查阅相关新闻报道或公司官方资料。

问答坊 | AI 解惑

一种提高无线局域网传输效率的技术

摘要:随着信息技术的快速发展,无线网络技术的应用越来越广泛,但是无线网络传输的效率一直比较低。针对这 种情况提出了一种提高无线局域网传输效率的技术。先在原理上讨论了使用包融合技术在无线局域网中使用的可 行性,然后通过在NS2 下的模拟 ...…

查看全部问答>

PIC16F73的AD结果存储器只有一个?

只有ADRES? 877好像有ADRESL,ADRESH?…

查看全部问答>

使用sqlce.

现在设备的操作系统升级到了windows   ce   5.0.程序在新的操作系统上运行,提示错误“找不到程序集   system.data.sqlce   version=1.0.50000” ?…

查看全部问答>

新手求助

大家好,本人大二,学习了模电和单片机.这个学期想参加电子设计比赛,初赛题要做一个基于fpga的频率计。我已经基本上了解了fpga的含义,但还是有一些问题想请教: 1.fpga的开发板价位从几十到几万…我看很多都是为嵌入式系统做的.如果只是要做频率 ...…

查看全部问答>

汇编高手乱入 关于十进制指令

看指令表有关与十进制指令 DADD.B 将十进制的进位位和源操作数加至目的操作数 语法 DADD.B src, dst 操作 src + dst + C -> dst (十进制) 有点不理解,大侠,斑竹指点 例如: CLRC ;复位进位位 CLR R5 DADD.B #99, R5 那 ...…

查看全部问答>

TL494的内部两个末级输出三极管集电极的最高耐压是多少啊

      我用494做降压电路,要输入整流以后80V到TL494的内部两个末级输出三极管集电极,不知道TL494的内部两个末级输出三极管集电极的最高耐压是多少啊 ?能不能承受的了 ,找资料也没有看到,帮忙啊!     &nb ...…

查看全部问答>

求助

I/O模拟I2C,假设P2.1接SDA,那么发送过来的8位数据放在什么地方?是P2IN吗?若是的话,8位数据是同时放在P2IN里吗(最高位在P2.7,最低位在P2.0)?但是,用户手册上说“Each bit in each PxIN register reflects the value of the input signal at t ...…

查看全部问答>

CCS5.2中C程序单步过程调用汇编子程序时,反汇编一片空白

点SUSPEND后,可以看到反汇编,也可以继续单步。这是怎么回事?…

查看全部问答>

舵机程序

replyreload += \',\' + 1372493;Timson,如果您要查看本帖隐藏内容请回复…

查看全部问答>