串口驱动
Day3-三、串口驱动
(一)、官方参照
对于串口的功能,32的官方串口hal库文件中的注释里有十分详细的介绍和说明,在配置串口时可多多参照:
“stm32f1xx_hal_uart.c”:
@verbatim
==============================================================================
##### How to use this driver #####
==============================================================================
[..]
The UART HAL driver can be used as follows:
(#) Declare a UART_HandleTypeDef handle structure (eg. UART_HandleTypeDef huart).
(#) Initialize the UART low level resources by implementing the HAL_UART_MspInit() API:
(##) Enable the USARTx interface clock.
(##) UART pins configuration:
(+++) Enable the clock for the UART GPIOs.
(+++) Configure these UART pins (TX as alternate function pull-up, RX as alternate function Input).
(##) NVIC configuration if you need to use interrupt process (HAL_UART_Transmit_IT()
and HAL_UART_Receive_IT() APIs):
(+++) Configure the USARTx interrupt priority.
(+++) Enable the NVIC USART IRQ handle.
(##) DMA Configuration if you need to use DMA process (HAL_UART_Transmit_DMA()
and HAL_UART_Receive_DMA() APIs):
(+++) Declare a DMA handle structure for the Tx/Rx channel.
(+++) Enable the DMAx interface clock.
(+++) Configure the declared DMA handle structure with the required
Tx/Rx parameters.
(+++) Configure the DMA Tx/Rx channel.
(+++) Associate the initialized DMA handle to the UART DMA Tx/Rx handle.
(+++) Configure the priority and enable the NVIC for the transfer complete
interrupt on the DMA Tx/Rx channel.
(+++) Configure the USARTx interrupt priority and enable the NVIC USART IRQ handle
(used for last byte sending completion detection in DMA non circular mode)
(#) Program the Baud Rate, Word Length, Stop Bit, Parity, Hardware
flow control and Mode(Receiver/Transmitter) in the huart Init structure.
(#) For the UART asynchronous mode, initialize the UART registers by calling
the HAL_UART_Init() API.
(#) For the UART Half duplex mode, initialize the UART registers by calling
the HAL_HalfDuplex_Init() API.
(#) For the LIN mode, initialize the UART registers by calling the HAL_LIN_Init() API.
(#) For the Multi-Processor mode, initialize the UART registers by calling
the HAL_MultiProcessor_Init() API.
[..]
(@) The specific UART interrupts (Transmission complete interrupt,
RXNE interrupt and Error Interrupts) will be managed using the macros
__HAL_UART_ENABLE_IT() and __HAL_UART_DISABLE_IT() inside the transmit
and receive process.
[..]
(@) These APIs (HAL_UART_Init() and HAL_HalfDuplex_Init()) configure also the
low level Hardware GPIO, CLOCK, CORTEX...etc) by calling the customized
HAL_UART_MspInit() API.
##### Callback registration #####
==================================
[..]
The compilation define USE_HAL_UART_REGISTER_CALLBACKS when set to 1
allows the user to configure dynamically the driver callbacks.
[..]
Use Function @ref HAL_UART_RegisterCallback() to register a user callback.
Function @ref HAL_UART_RegisterCallback() allows to register following callbacks:
(+) TxHalfCpltCallback : Tx Half Complete Callback.
(+) TxCpltCallback : Tx Complete Callback.
(+) RxHalfCpltCallback : Rx Half Complete Callback.
(+) RxCpltCallback : Rx Complete Callback.
(+) ErrorCallback : Error Callback.
(+) AbortCpltCallback : Abort Complete Callback.
(+) AbortTransmitCpltCallback : Abort Transmit Complete Callback.
(+) AbortReceiveCpltCallback : Abort Receive Complete Callback.
(+) MspInitCallback : UART MspInit.
(+) MspDeInitCallback : UART MspDeInit.
This function takes as parameters the HAL peripheral handle, the Callback ID
and a pointer to the user callback function.
[..]
Use function @ref HAL_UART_UnRegisterCallback() to reset a callback to the default
weak (surcharged) function.
@ref HAL_UART_UnRegisterCallback() takes as parameters the HAL peripheral handle,
and the Callback ID.
This function allows to reset following callbacks:
(+) TxHalfCpltCallback : Tx Half Complete Callback.
(+) TxCpltCallback : Tx Complete Callback.
(+) RxHalfCpltCallback : Rx Half Complete Callback.
(+) RxCpltCallback : Rx Complete Callback.
(+) ErrorCallback : Error Callback.
(+) AbortCpltCallback : Abort Complete Callback.
(+) AbortTransmitCpltCallback : Abort Transmit Complete Callback.
(+) AbortReceiveCpltCallback : Abort Receive Complete Callback.
(+) MspInitCallback : UART MspInit.
(+) MspDeInitCallback : UART MspDeInit.
[..]
By default, after the @ref HAL_UART_Init() and when the state is HAL_UART_STATE_RESET
all callbacks are set to the corresponding weak (surcharged) functions:
examples @ref HAL_UART_TxCpltCallback(), @ref HAL_UART_RxHalfCpltCallback().
Exception done for MspInit and MspDeInit functions that are respectively
reset to the legacy weak (surcharged) functions in the @ref HAL_UART_Init()
and @ref HAL_UART_DeInit() only when these callbacks are null (not registered beforehand).
If not, MspInit or MspDeInit are not null, the @ref HAL_UART_Init() and @ref HAL_UART_DeInit()
keep and use the user MspInit/MspDeInit callbacks (registered beforehand).
[..]
Callbacks can be registered/unregistered in HAL_UART_STATE_READY state only.
Exception done MspInit/MspDeInit that can be registered/unregistered
in HAL_UART_STATE_READY or HAL_UART_STATE_RESET state, thus registered (user)
MspInit/DeInit callbacks can be used during the Init/DeInit.
In that case first register the MspInit/MspDeInit user callbacks
using @ref HAL_UART_RegisterCallback() before calling @ref HAL_UART_DeInit()
or @ref HAL_UART_Init() function.
[..]
When The compilation define USE_HAL_UART_REGISTER_CALLBACKS is set to 0 or
not defined, the callback registration feature is not available
and weak (surcharged) callbacks are used.
[..]
Three operation modes are available within this driver :
*** Polling mode IO operation ***
=================================
[..]
(+) Send an amount of data in blocking mode using HAL_UART_Transmit()
(+) Receive an amount of data in blocking mode using HAL_UART_Receive()
*** Interrupt mode IO operation ***
===================================
[..]
(+) Send an amount of data in non blocking mode using HAL_UART_Transmit_IT()
(+) At transmission end of transfer HAL_UART_TxCpltCallback is executed and user can
add his own code by customization of function pointer HAL_UART_TxCpltCallback
(+) Receive an amount of data in non blocking mode using HAL_UART_Receive_IT()
(+) At reception end of transfer HAL_UART_RxCpltCallback is executed and user can
add his own code by customization of function pointer HAL_UART_RxCpltCallback
(+) In case of transfer Error, HAL_UART_ErrorCallback() function is executed and user can
add his own code by customization of function pointer HAL_UART_ErrorCallback
*** DMA mode IO operation ***
==============================
[..]
(+) Send an amount of data in non blocking mode (DMA) using HAL_UART_Transmit_DMA()
(+) At transmission end of half transfer HAL_UART_TxHalfCpltCallback is executed and user can
add his own code by customization of function pointer HAL_UART_TxHalfCpltCallback
(+) At transmission end of transfer HAL_UART_TxCpltCallback is executed and user can
add his own code by customization of function pointer HAL_UART_TxCpltCallback
(+) Receive an amount of data in non blocking mode (DMA) using HAL_UART_Receive_DMA()
(+) At reception end of half transfer HAL_UART_RxHalfCpltCallback is executed and user can
add his own code by customization of function pointer HAL_UART_RxHalfCpltCallback
(+) At reception end of transfer HAL_UART_RxCpltCallback is executed and user can
add his own code by customization of function pointer HAL_UART_RxCpltCallback
(+) In case of transfer Error, HAL_UART_ErrorCallback() function is executed and user can
add his own code by customization of function pointer HAL_UART_ErrorCallback
(+) Pause the DMA Transfer using HAL_UART_DMAPause()
(+) Resume the DMA Transfer using HAL_UART_DMAResume()
(+) Stop the DMA Transfer using HAL_UART_DMAStop()
*** UART HAL driver macros list ***
=============================================
[..]
Below the list of most used macros in UART HAL driver.
(+) __HAL_UART_ENABLE: Enable the UART peripheral
(+) __HAL_UART_DISABLE: Disable the UART peripheral
(+) __HAL_UART_GET_FLAG : Check whether the specified UART flag is set or not
(+) __HAL_UART_CLEAR_FLAG : Clear the specified UART pending flag
(+) __HAL_UART_ENABLE_IT: Enable the specified UART interrupt
(+) __HAL_UART_DISABLE_IT: Disable the specified UART interrupt
(+) __HAL_UART_GET_IT_SOURCE: Check whether the specified UART interrupt has occurred or not
[..]
(@) You can refer to the UART HAL driver header file for more useful macros
@endverbatim
(二)、半主机模式、C库、Microlib
参考手册:
《Semihosting for AArch32 and AArch64》
《Arm C and C++ Libraries and Floating Point Support User Guide》
1、半主机模式:
半主机模式是ARM标准提出的概念,它是ARM处理器或模拟器(如MDK仿真器)与PC主机进行输入输出通信的一种机制,这里的输入输出指的是,键盘输入信息给PC,PC将信息传递给Target,Target这里可以是MDK仿真模拟器或硬件处理器实物;输出则是将Target的printf()内容输出给PC主机,主机再将printf()里的内容显示出来。
当ARM处理器(Target)使用C库的printf()或scanf()函数时,会调用C库的SVC触发一个异常,然后由主机里的一个debugger调试器处理,与Host主机建立一个通信连接,将目标机要输出的信息打印出来。
所谓半主机的意思是,Target目标机是与Host主机直接相连的,而不是连一个键盘或屏幕。
这样一个模式机制是一系列指令的集合,半主机模式下调用一个printf或scanf或其他的接口时,最终调用的是C库的一些代码。
2、C库
半主机模式在MDK下默认是使能的。也不需要加入什么别的头文件。
让单片机的串口1实现一个printf函数,用来输出一些调试信息。但串口1是没法直接使用printf输出信息的,则需要重定向printf。
C库中对printf的重定向:
将上面红框内的代码复制到driver_dbg.c驱动中。
并且重新修改fpuc()函数:
int fputc(int ch, FILE *f)
{
/* Your implementation of fputc(). */
HAL_UART_Transmit(&huart1,(uint8_t*)&ch,1,10);
return ch;
}
3、Microlib
microlib是一个很小很轻量的C库,但是注意,代码如果使用操作系统,就不能用microlib,不用操作系统才可以使用。
如果使用microlib就不需要重新定义_stdin,_stdout等,在microlib中已有定义,只需要重新实现fpuc函数即可。
(三)、代码实现
根据上述内容对串口对应的IO引脚以及串口功能进行初始化:
1、driver_dbg.c:
#include "driver_dbg.h"
#include <stdio.h>
void HAL_UART1_MspInit(UART_HandleTypeDef *huart);
static UART_HandleTypeDef huart1;//定义成全局变量
int Driver_DBG_Init(void)
{//初始化串口1的相应功能
HAL_UART1_MspInit(&huart1);
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
return -1; // 初始化USART1失败
}
return 0;
}
void HAL_UART1_MspInit(UART_HandleTypeDef *huart)
{//初始化串口1对应的GPIO引脚
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_USART1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/* USART1 TX/RX */
/* PA9 - TX
* PA10 - RX
*/
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;//复用推挽输出
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_AF_INPUT;//复用输入
GPIO_InitStruct.Pull = GPIO_PULLUP; //配置上拉
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
//重定向printf:
struct __FILE
{
int handle;
};
/* FILE is typedef’d in stdio.h. */
FILE __stdout;
int fputc(int ch, FILE *f)
{
/* Your implementation of fputc(). */
HAL_UART_Transmit(&huart1,(uint8_t*)&ch,1,10);
return ch;
}
2、driver_dbg.h:
#ifndef __DRIVER_DBG_H
#define __DRIVER_DBG_H
#include "stm32f1xx_hal.h"
int Driver_DBG_Init(void);
#endif
训练营导航: www.100ask.net