串口發送程序配置流程
HAL庫中串口暫存器定義檔案:
stm32f429xx.h F429芯片
stm32f767xx.h F767芯片
stm32f103xx.h F103芯片
stm32fnnnx.x.h 其他芯片
可以在其中找到USART_TypeDef:最侄訓映射到暫存器的地址,
typedef struct
{
__IO uint32_t CR1; /*!< USART Control register 1, Address offset: 0x00 */
__IO uint32_t CR2; /*!< USART Control register 2, Address offset: 0x04 */
__IO uint32_t CR3; /*!< USART Control register 3, Address offset: 0x08 */
__IO uint32_t BRR; /*!< USART Baud rate register, Address offset: 0x0C */
__IO uint32_t GTPR; /*!< USART Guard time and prescaler register, Address offset: 0x10 */
__IO uint32_t RTOR; /*!< USART Receiver Time Out register, Address offset: 0x14 */
__IO uint32_t RQR; /*!< USART Request register, Address offset: 0x18 */
__IO uint32_t ISR; /*!< USART Interrupt and status register, Address offset: 0x1C */
__IO uint32_t ICR; /*!< USART Interrupt flag Clear register, Address offset: 0x20 */
__IO uint32_t RDR; /*!< USART Receive Data register, Address offset: 0x24 */
__IO uint32_t TDR; /*!< USART Transmit Data register, Address offset: 0x28 */
} USART_TypeDef;
HAL庫中串口函式定義檔案:
stm32f7xx_hal_uart.c ,stm32f7xx_hal_usart.c
串口位元組發送流程:
- 編程USARTx_CR1的M位來定義字長,
- 編程USARTx_CR2的STOP位來定義停止位位數,
- 編程USARTx_BRR暫存器確定波特率,
- 使能USARTx_CR1的UE位使能USARTx,
- 如果進行多緩沖通信,配置USARTx_CR3的DMA使能(DMAT),具體請參考后面DMA實驗,
- 使能USARTx_CR1的TE位使能發送器,
- 向發送資料暫存器TDR寫入要發送的資料(對于M3,發送和接收共用DR暫存器),
- 向TRD暫存器寫入最后一個資料后,等待狀態暫存器USARTx_SR(ISR)的TC位置1,傳輸完成,
對于stm32f4:控制暫存器 1 (USART_CR1):

位12 M:字長 (Word length) 該位決定了字長,該位由軟體置 1 或清零,
0:1 起始位,8 資料位,n 停止位
1:1 起始位,9 資料位,n 停止位
注意:在資料傳輸(發送和接收)期間不得更改 M 位
stm32f4控制暫存器 2 (USART_CR2):

位 13:12 STOP:停止位 (STOP bit)
這些位用于編程停止位,
00:1 個停止位
01:0.5 個停止位
10:2 個停止位
11:1.5 個停止位
注意:0.5 個停止位和 1.5 個停止位不適用于 UART4 和 UART5,
串口位元組發送流程中的1、2、3設定串口的一些引數,接下來要使能使用到的串口:
同樣在stm32f4控制暫存器 1 (USART_CR1)中可以找到:
位 13 UE:USART 使能 (USART enable)
該位清零后,USART 預分頻器和輸出將停止,并會結束當前位元組傳輸以降低功耗,此位由軟體置 1 和清零,
0:禁止 USART 預分頻器和輸出
1:使能 USART
位 3 TE:發送器使能 (Transmitter enable)
該位使能發送器,該位由軟體置 1 和清零,
0:禁止發送器
1:使能發送器
注意:1:除了在智能卡模式下以外,傳送期間 TE 位上的“0”脈沖(“0”后緊跟的是“1”)會在當前字的后面發送一個報頭(空閑線路),
2:當 TE 置 1 時,在發送開始前存在 1 位的時間延遲,
串口位元組發送流程中的4、5、6步驟使能完成之后,接下來進行資料發送也就是7、8步驟,
串口位元組發送流程(HAL庫函式)
配置步驟①~⑥:配置字長,停止位,奇偶校驗位,波特率等:
可以在stm32f7xx_hal_uart.c中找到:HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart)函式:該函式內部會參考識別符號__HAL_USART_ENABLE使能相應串口,
/**
* @brief Initializes the UART mode according to the specified
* parameters in the UART_InitTypeDef and creates the associated handle .
* @param huart: uart handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart)
{
/* Check the UART handle allocation */
if(huart == NULL)
{
return HAL_ERROR;
}
if(huart->Init.HwFlowCtl != UART_HWCONTROL_NONE)
{
/* Check the parameters */
assert_param(IS_UART_HWFLOW_INSTANCE(huart->Instance));
}
else
{
/* Check the parameters */
assert_param(IS_UART_INSTANCE(huart->Instance));
}
if(huart->gState == HAL_UART_STATE_RESET)
{
/* Allocate lock resource and initialize it */
huart->Lock = HAL_UNLOCKED;
/* Init the low level hardware : GPIO, CLOCK */
HAL_UART_MspInit(huart);
}
huart->gState = HAL_UART_STATE_BUSY;
/* Disable the Peripheral */
__HAL_UART_DISABLE(huart);
/* Set the UART Communication parameters */
if (UART_SetConfig(huart) == HAL_ERROR)
{
return HAL_ERROR;
}
if (huart->AdvancedInit.AdvFeatureInit != UART_ADVFEATURE_NO_INIT)
{
UART_AdvFeatureConfig(huart);
}
/* In asynchronous mode, the following bits must be kept cleared:
- LINEN and CLKEN bits in the USART_CR2 register,
- SCEN, HDSEL and IREN bits in the USART_CR3 register.*/
CLEAR_BIT(huart->Instance->CR2, (USART_CR2_LINEN | USART_CR2_CLKEN));
CLEAR_BIT(huart->Instance->CR3, (USART_CR3_SCEN | USART_CR3_HDSEL | USART_CR3_IREN));
/* Enable the Peripheral */
__HAL_UART_ENABLE(huart);
/* TEACK and/or REACK to check before moving huart->gState and huart->RxState to Ready */
return (UART_CheckIdleState(huart));
}
步驟⑦~⑧發送資料和等待發送完成:可以在stm32f7xx_hal_uart.c中找到:HAL_UART_Transmit函式:
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
__weak關鍵字:
函式前面加__weak修飾符,我們稱之為弱函式,對于弱函式,用戶可以在用戶檔案中重新定義一個同名函式,最終編譯器編譯的時候會選擇用戶定義的函式,如果用戶沒有定義,那么函式內容就是弱函式定義的內容,
函式宣告:
可以在stm32f7xx_hal_uart.h中找到:void HAL_UART_MspInit(UART_HandleTypeDef *huart);
函式定義(弱函式):里面不做事
__weak void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
}
弱函式被其他函式呼叫:
HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart)
{
if(huart->gState == HAL_UART_STATE_RESET)
{
/* Allocate lock resource and initialize it */
huart->Lock = HAL_UNLOCKED;
? /* Init the low level hardware : GPIO, CLOCK */
? HAL_UART_MspInit(huart);
? }
}
為什么要定義一個弱函式?
因為在hal庫里面有其他的函式需要呼叫這樣一個函式,但是里面的內容還不確定如何初始化,所以先定義一個weak函式,然后用戶在可以再去撰寫函式的真正內容,這樣的話不會報函式重定義的錯誤,運行流程一樣,但是初始化可能不一樣,使用weak函式的話,好處是我們不會對既有程式流程做任何修改,只需要修改流程中的某部分與用戶相關的代碼即可,
弱函式重新被定義:
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
…//內容
}
__weak關鍵字的好處:
- 對于事先已經定義好的一個流程,我們只希望修改流程中的某部分與用戶相關的代碼,這個時候我們可以采用弱函式定義一個空函式,然后讓用戶自行定義該函式,這樣做的好處是我們不會對既有程式流程做任何修改,
- HAL庫中大量使用__weak關鍵字修飾外設回呼函式,
- 外設回呼函式供用戶撰寫MCU相關程式,大大提高程式的通用性移植性,
串口發送程式配置程序(HAL庫):
- 初始化串口相關引數,使能串口:HAL_UART_Init();
- 串口相關IO口配置,復用配置:在HAL_UART_MspInit中呼叫HAL_GPIO_Init函式,
- 發送資料,并等待資料發送完成:HAL_UART_Transmit()函式;
然后根據上面的流程,開始撰寫代碼:
初始化串口相關引數HAL_UART_Init();
先編一個初始化函式:
void uart1_init(void)
{
}
然后在HALLIB-stm32f7xx_hal_uart.c中找到:HAL_UART_Init函式,粘貼到初始化函式里,呼叫它:
然后發現他有一個入口引數UART_HandleTypeDef *huart是結構體指標部分,然后找到UART_HandleTypeDef的定義,可以找到:這個是串口句柄
typedef struct
{
USART_TypeDef *Instance; /*!< UART registers base address */
UART_InitTypeDef Init; /*!< UART communication parameters */
UART_AdvFeatureInitTypeDef AdvancedInit; /*!< UART Advanced Features initialization parameters */
uint8_t *pTxBuffPtr; /*!< Pointer to UART Tx transfer Buffer */
uint16_t TxXferSize; /*!< UART Tx Transfer size */
uint16_t TxXferCount; /*!< UART Tx Transfer Counter */
uint8_t *pRxBuffPtr; /*!< Pointer to UART Rx transfer Buffer */
uint16_t RxXferSize; /*!< UART Rx Transfer size */
uint16_t RxXferCount; /*!< UART Rx Transfer Counter */
uint16_t Mask; /*!< UART Rx RDR register mask */
DMA_HandleTypeDef *hdmatx; /*!< UART Tx DMA Handle parameters */
DMA_HandleTypeDef *hdmarx; /*!< UART Rx DMA Handle parameters */
HAL_LockTypeDef Lock; /*!< Locking object */
__IO HAL_UART_StateTypeDef gState; /*!< UART state information related to global Handle management
and also related to Tx operations.
This parameter can be a value of @ref HAL_UART_StateTypeDef */
__IO HAL_UART_StateTypeDef RxState; /*!< UART state information related to Rx operations.
This parameter can be a value of @ref HAL_UART_StateTypeDef */
__IO uint32_t ErrorCode; /*!< UART Error code */
}UART_HandleTypeDef;
USART_TypeDef是串口的型別,在檔案中可以找到:
#define USART2 ((USART_TypeDef *) USART2_BASE)
#define USART3 ((USART_TypeDef *) USART3_BASE)
#define UART4 ((USART_TypeDef *) UART4_BASE)
#define UART5 ((USART_TypeDef *) UART5_BASE)
然后找到UART_InitTypeDef的定義,可以看到,是配置串口外設的一些特性引數,
typedef struct
{
uint32_t BaudRate; /*!< This member configures the UART communication baud rate.
The baud rate register is computed using the following formula:
- If oversampling is 16 or in LIN mode,
Baud Rate Register = ((PCLKx) / ((huart->Init.BaudRate)))
- If oversampling is 8,
Baud Rate Register[15:4] = ((2 * PCLKx) / ((huart->Init.BaudRate)))[15:4]
Baud Rate Register[3] = 0
Baud Rate Register[2:0] = (((2 * PCLKx) / ((huart->Init.BaudRate)))[3:0]) >> 1 */
uint32_t WordLength; /*!< Specifies the number of data bits transmitted or received in a frame.
This parameter can be a value of @ref UARTEx_Word_Length */
uint32_t StopBits; /*!< Specifies the number of stop bits transmitted.
This parameter can be a value of @ref UART_Stop_Bits */
uint32_t Parity; /*!< Specifies the parity mode.
This parameter can be a value of @ref UART_Parity
@note When parity is enabled, the computed parity is inserted
at the MSB position of the transmitted data (9th bit when
the word length is set to 9 data bits; 8th bit when the
word length is set to 8 data bits). */
uint32_t Mode; /*!< Specifies whether the Receive or Transmit mode is enabled or disabled.
This parameter can be a value of @ref UART_Mode */
uint32_t HwFlowCtl; /*!< Specifies whether the hardware flow control mode is enabled
or disabled.
This parameter can be a value of @ref UART_Hardware_Flow_Control */
uint32_t OverSampling; /*!< Specifies whether the Over sampling 8 is enabled or disabled, to achieve higher speed (up to fPCLK/8).
This parameter can be a value of @ref UART_Over_Sampling */
uint32_t OneBitSampling; /*!< Specifies whether a single sample or three samples' majority vote is selected.
Selecting the single sample method increases the receiver tolerance to clock
deviations. This parameter can be a value of @ref UART_OneBit_Sampling */
}UART_InitTypeDef;
此時可以在初始化函式中寫:
UART_HandleTypeDef usart1_handler;
void uart1_init(void)
{
usart1_handler.Instance = USART1;
usart1_handler.Init.BaudRate = 115200;
usart1_handler.Init.WordLength = UART_WORDLENGTH_8B;
usart1_handler.Init.StopBits = UART_STOPBITS_1;
usart1_handler.Init.HwFlowCtl = UART_HWCONTROL_NONE;
usart1_handler.Init.Mode = UART_MODE_TX_RX;
usart1_handler.Init.Parity = UART_PARITY_NONE;
HAL_UART_Init(&usart1_handler);
}
《這里面引數都有哪些怎么找?》可以首先在HALLIB-stm32f7xx_hal_uart.c找到assert_param(IS_UART_INSTANCE(huart->Instance));然后雙擊IS_UART_INSTANCE找到它的定義,可以發現如下代碼:然后就知道都可以填啥引數了,可以選擇USART1作為引數,其他的引數設定也是類似的方式,
#define IS_UART_INSTANCE(__INSTANCE__) (((__INSTANCE__) == USART1) || \
((__INSTANCE__) == USART2) || \
((__INSTANCE__) == USART3) || \
((__INSTANCE__) == UART4) || \
((__INSTANCE__) == UART5) || \
((__INSTANCE__) == USART6) || \
((__INSTANCE__) == UART7) || \
((__INSTANCE__) == UART8))
串口相關IO口配置HAL_UART_MspInit
在HALLIB-stm32f7xx_hal_uart.h中可以找到HAL_UART_MspInit的宣告:void HAL_UART_MspInit(UART_HandleTypeDef *huart);
現在撰寫這個函式:最終這個函式會被HAL_UART_Init呼叫,由于STM32有好幾個UART串口,所以先進行判斷
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
if(huart->Instance==UART1)
{
}
}
埠復用配置程序:
1.GPIO埠時鐘使能,
__HAL_RCC_GPIOA_CLK_ENABLE(); //使能GPIO時鐘
2.復用外設時鐘使能,
比如你要將埠PA9,PA10復用為串口,所以要使能串口時鐘,
__HAL_RCC_USART1_CLK_ENABLE(); //使能串口1時鐘
3.埠模式配置為復用功能, HAL_GPIO_Init函式,
GPIO_Initure.Mode=GPIO_MODE_AF_PP; //復用推挽輸出
4.配置GPIOx_AFRL或者GPIOx_AFRH暫存器,將IO連接到所需的AFx,HAL_GPIO_Init函式,
GPIO_Initure.Alternate=GPIO_AF7_USART1;//復用為USART1
對于埠,需要設定GPIO_InitTypeDef *GPIO_Init引數,如下
typedef struct
{
uint32_t Pin; /*!< Specifies the GPIO pins to be configured.
This parameter can be any value of @ref GPIO_pins_define */
uint32_t Mode; /*!< Specifies the operating mode for the selected pins.
This parameter can be a value of @ref GPIO_mode_define */
uint32_t Pull; /*!< Specifies the Pull-up or Pull-Down activation for the selected pins.
This parameter can be a value of @ref GPIO_pull_define */
uint32_t Speed; /*!< Specifies the speed for the selected pins.
This parameter can be a value of @ref GPIO_speed_define */
uint32_t Alternate; /*!< Peripheral to be connected to the selected pins.
This parameter can be a value of @ref GPIO_Alternate_function_selection */
}GPIO_InitTypeDef;
都設定完之后就是下面的串口相關IO口配置代碼:
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
GPIO_InitTypeDef GPIO_Initure;
if(huart->Instance==UART1)
{
__HAL_RCC_GPIOA_CLK_ENABLE(); //使能GPIOA時鐘
__HAL_RCC_USART1_CLK_ENABLE(); //使能USART1時鐘
GPIO_Initure.Pin=GPIO_PIN_9; //PA9
GPIO_Initure.Mode=GPIO_MODE_AF_PP; //復用推挽輸出
GPIO_Initure.Pull=GPIO_PULLUP; //上拉
GPIO_Initure.Speed=GPIO_SPEED_HIGH; //高速
GPIO_Initure.Alternate=GPIO_AF7_USART1; //復用為USART1
HAL_GPIO_Init(GPIOA,&GPIO_Initure); //初始化PA9
GPIO_Initure.Pin=GPIO_PIN_10; //PA10
HAL_GPIO_Init(GPIOA,&GPIO_Initure); //初始化PA10
}
}
發送資料HAL_UART_Transmit()
首先在stm32f7xx_hal_uart.c中找到HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
然后可以發現這里面要呼叫的一些引數,
最終的代碼:
#include "sys.h"
#include "delay.h"
#include "usart.h"
UART_HandleTypeDef usart1_handler;
void uart1_init(void)
{
usart1_handler.Instance = USART1;
usart1_handler.Init.BaudRate = 115200;
usart1_handler.Init.WordLength = UART_WORDLENGTH_8B;
usart1_handler.Init.StopBits = UART_STOPBITS_1;
usart1_handler.Init.HwFlowCtl = UART_HWCONTROL_NONE;
usart1_handler.Init.Mode = UART_MODE_TX_RX;
usart1_handler.Init.Parity = UART_PARITY_NONE;
HAL_UART_Init(&usart1_handler);
}
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
GPIO_InitTypeDef GPIO_Initure;
if(huart->Instance==USART1)
{
__HAL_RCC_GPIOA_CLK_ENABLE(); //使能GPIOA時鐘
__HAL_RCC_USART1_CLK_ENABLE(); //使能USART1時鐘
GPIO_Initure.Pin=GPIO_PIN_9; //PA9
GPIO_Initure.Mode=GPIO_MODE_AF_PP; //復用推挽輸出
GPIO_Initure.Pull=GPIO_PULLUP; //上拉
GPIO_Initure.Speed=GPIO_SPEED_HIGH; //高速
GPIO_Initure.Alternate=GPIO_AF7_USART1; //復用為USART1
HAL_GPIO_Init(GPIOA,&GPIO_Initure); //初始化PA9
GPIO_Initure.Pin=GPIO_PIN_10; //PA10
HAL_GPIO_Init(GPIOA,&GPIO_Initure); //初始化PA10
}
}
int main(void)
{
u8 buff[]="test";
Cache_Enable(); //打開L1-Cache
HAL_Init(); //初始化HAL庫
Stm32_Clock_Init(432,25,2,9); //設定時鐘,216Mhz
delay_init(216);
uart1_init();
while(1)
{
HAL_UART_Transmit(&usart1_handler,buff,sizeof(buff),1000);
delay_ms(300);
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/302023.html
標籤:其他
