HAL库外设初始化MSP回调机制
HAL_PPP_Init() PPP是任意外设,会自动调用MSP回调函数~>HAL_PPP_MspInit()
HAL_PPP_MspInit()配置外设,如USART1 PA9,PA10,可以重新定义,因为weak是弱定义
如果HAL_PPP_Init() 被调用3次,则HAL_PPP_MspInit()也被调用3次,要根据外设寄存器基地址来区分
HAL库外设初始化MSP回调机制-USART为例
UART_HandleTypeDef *huart 是句柄
huart->Instance 基地址
HAL库中断回调机制
//中断服务函数
void EXTI0_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0); //调用中断处理公用函数
}void EXTI2_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_2); //调用中断处理公用函数
}void EXTI3_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_3); //调用中断处理公用函数
}void EXTI4_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_4); //调用中断处理公用函数
}//中断服务程序中需要做的事情
//在HAL库中所有的外部中断服务函数都会调用此函数
//GPIO_Pin:中断引脚号
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
delay_ms(100); //消抖
switch(GPIO_Pin)
{
case GPIO_PIN_0:
if(WK_UP==1)
{
LED1=!LED1;//控制LED0,LED1互斥点亮
LED0=!LED1;
}
break;
case GPIO_PIN_2:
if(KEY2==0) //LED1翻转
{
LED1=!LED1;
}
break;
case GPIO_PIN_3:
if(KEY1==0) //同时控制LED0,LED1翻转
{
LED0=!LED0;
LED1=!LED1;
}
break;
case GPIO_PIN_4:
if(KEY0==0)
{
LED0=!LED0;//控制LED0翻转
}
break;
}
}
中断函数在启动文件上找
以USART的例子
USARTxIRQHandler() 或者UARx_IRQHandler()用户调用中断共同处理函数
HAL_USART_IRQHandler()
则HAL库自己调用中断回调函数
回调函数与反回调函数
UART回调函数
外部中断函数
公共函数:清除中断函数标志位
UART_Receive_IT(huast)是接收完成标志位,再清除标志位,调用HAL_UART_RxCpltcallback()函数
UART_Receive_IT(huast)是发送,当为空的时候发送
UART_EndTransmit_IT(huast)是发送完成标志位,再清除标志,调HAL_UART_TxCpltcallback()函数
UART异步通信配置步骤
1,配置窗口工作函数 HAL_UART_Init() 会调用MSP回调函数
2,窗口底层初始化 HAL_UART_MspInit() 配置GPIO,NVIC,CLOCK等
3,开启串口异步接收中断 HAL_UART_Receive_IT() 看见_IT则开启相应中断
4.设置优先级,使能中断 HAL_NVIC_IRQHandler(),HAL_NVIC_EnalbeIRQ()
5,编写中断服务函数 UARTx_IRQHander() 在启动文件找
6,串口数据发送 USART_DR,HAL_UART_Transmit()
_HandleTypeDef *huart 这样的结构体命名为句柄
注意:只看前俩个 *Instance , Init
HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart)
1.Instance:指向UART寄存器基地址,实际上是USART1~USART3,USART4,USART5
注:基地址在stm32407xx.h里面
关键结构体(F1):
typedef struct
{ uint32_t BaudRate; /* 波特率 */
uint32_t WordLength; /* 字长 */
uint32_t StopBits; /* 停止位 */
uint32_t Parity; /* 奇偶校验位 */
uint32_t Mode; /* UART 模式 */
uint32_t HwFlowCtl; /* 硬件流设置 */ 可以不用管
uint32_t OverSampling; /* 过采样设置 */ 可以选8或者16
}UART_InitTypeDef
/* 字长 */
#define UART_WORDLENGTH_8B 0x00000000U
#define UART_WORDLENGTH_9B ((uint32_t)USART_CR1_M)/* 停止位 */
#define UART_STOPBITS_1 0x00000000U
#define UART_STOPBITS_2 ((uint32_t)USART_CR2_STOP_1)/* 奇偶校验位 */
#define UART_PARITY_NONE 0x00000000U
#define UART_PARITY_EVEN ((uint32_t)USART_CR1_PCE)
#define UART_PARITY_ODD ((uint32_t)(USART_CR1_PCE | USART_CR1_PS))/* UART 模式 */
#define UART_MODE_RX ((uint32_t)USART_CR1_RE)
#define UART_MODE_TX ((uint32_t)USART_CR1_TE)
#define UART_MODE_TX_RX ((uint32_t)(USART_CR1_TE | USART_CR1_RE))
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
作用:以中断的方式接收指定字节的数据
形参1:是 UART_HandleTypeDef结构体类型的指针变量 句柄
形参2:是指向接收数据缓冲区
形参3:是要接收数据的大小, 以字节为单位
句柄就是个指针,判断中断来源,比如usart1,usart2等
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
没有IT,没有开启中断
作用:以阻塞的方式发送指定字节的数据 阻塞:(干不完,不能出来)
形参 1 :UART_HandleTypeDef 结构体类型指针变量
形参 2:指向要发送的数据地址
形参 3:要发送的数据大小,以字节为单位
形参 4:设置的超时时间,以ms单位
IO口引脚复用功能:
7.1,何为复用?
1,通用:IO端口的输入或输出是由GPIO外设控制,我们称为为通用 (控制ODR,BSRR,IDR寄存器)
2.复用:IO端口的输入或输出是由其它非GPIO外设控制(由USART,TIM,ADC,DAC控制)
7.2,STM32F1的IO引脚复用
1.各IO支持什么复用功能 可查芯片数据手册
2.IO复用功能冲突问题:同一时间只能用作一种复用功能,否则冲突
3.遇到IO复用功能冲突,考虑重映射
7.3,STM32F4/F7/H7的IO引脚复用
只能一个连接,俩个不行,否则都无效
为了解决F1系列存在的IO复用功能冲突问题,F4往后的系列都加入了复用器
复用器特点:
1、每个 IO 引脚都有一个复用器
2、复用器采用 16 路复用功能输入(AF0 到 AF15) 16选1
3、复用器一次仅允许一个外设的复用功能 (AF) 连接到 IO 引脚
4、通过GPIOx_AFRL和GPIOx_AFRH寄存器进行配置
32位,8引脚,所以由4个位控制
PA10直接复用,可以不用设置
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
//GPIO端口设置
GPIO_InitTypeDef GPIO_Initure;
if(huart->Instance==USART1)//如果是串口1,进行串口1 MSP初始化
{
__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_FAST; //高速
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}
}
错了,不知道原因
#include "bsp_uart.h"
uint8_t g_rx_buffer[1]; //一个字节 HAl库使用的串口接收数据缓冲区
uint8_t g_uart1_rx_flag=0; /*串口接收到数据标志*/UART_HandleTypeDef uart1_handeler; /*句柄*/
void bsp_uart(uint32_t baudrate)
{
uart1_handeler.Instance=USART1;
uart1_handeler.Init.BaudRate=baudrate;
uart1_handeler.Init.HwFlowCtl=UART_HWCONTROL_NONE;
uart1_handeler.Init.Mode=UART_MODE_TX_RX;
uart1_handeler.Init.OverSampling=UART_OVERSAMPLING_16;
uart1_handeler.Init.Parity=UART_PARITY_NONE;
uart1_handeler.Init.StopBits=UART_STOPBITS_1;
uart1_handeler.Init.WordLength=UART_WORDLENGTH_8B;
HAL_UART_Init(&uart1_handeler);
HAL_UART_Receive_IT(&uart1_handeler, g_rx_buffer,1);/*开启接收中断*/
/*使能数据寄存器非空中断
__HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);*/
}/*串口MSP回调函数 */
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(huart->Instance==USART1)
{
__HAL_RCC_USART1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE() ;
GPIO_InitStruct.Mode=GPIO_MODE_AF_PP; /*推挽式复用*/
GPIO_InitStruct.Pin=GPIO_PIN_9;
//GPIO_InitStruct.Pull=GPIO_PULLUP; /*上下拉不用管*/
GPIO_InitStruct.Speed=GPIO_SPEED_FREQ_VERY_HIGH; /*高速*/
HAL_GPIO_Init(GPIOA,&GPIO_InitStruct);
;
GPIO_InitStruct.Mode=GPIO_MODE_INPUT; /*推挽式复用*/
GPIO_InitStruct.Pin=GPIO_PIN_10;
GPIO_InitStruct.Pull=GPIO_PULLUP; /*空闲是上拉高电平*/
//GPIO_InitStruct.Speed=GPIO_SPEED_FREQ_VERY_HIGH; /*速度不用管*/
HAL_GPIO_Init(GPIOA,&GPIO_InitStruct);
HAL_NVIC_SetPriority(USART1_IRQn, 2 , 2 );
HAL_NVIC_EnableIRQ(USART1_IRQn);
}}
/*串口中断服务函数*/
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&uart1_handeler); /*这个会清除中断标志,失能,并且进入 */
HAL_UART_Receive_IT(&uart1_handeler, g_rx_buffer,1);/*再调用一次*/
}
/*串口数据接收完成回调函数*/
void HAL_USART_RxCpltCallback(USART_HandleTypeDef *husart)
{
g_uart1_rx_flag=1;}
HAL库轮询方式
#include "bsp_uart.h"
/*全局变量,句柄在哪都用,也就是总结构体*/
UART_HandleTypeDef uart1;void Ul_Init(uint32_t bandrate)
{
uart1.Instance=USART1;
uart1.Init.BaudRate=bandrate;
uart1.Init.WordLength=UART_WORDLENGTH_8B;
uart1.Init.StopBits=UART_STOPBITS_1; //一个停止位
uart1.Init.Parity=UART_PARITY_NONE; //无奇偶校验位
uart1.Init.HwFlowCtl=UART_HWCONTROL_NONE; //无硬件流控
uart1.Init.Mode=UART_MODE_TX_RX; //收发模式
HAL_UART_Init(&uart1);
/* Init the low level hardware : GPIO, CLOCK
HAL_UART_MspInit(huart); HAL_UART_Init(&uart1);会自动调用回调函数
*/
}
/*回调函数*/
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_FAST; //高速
//必须是这样操作
GPIO_Initure.Alternate=GPIO_AF7_USART1; //复用为USART1
HAL_GPIO_Init(GPIOA,&GPIO_Initure); //初始化PA9GPIO_Initure.Pin=GPIO_PIN_10; //PA10
HAL_GPIO_Init(GPIOA,&GPIO_Initure); //初始化PA10
}}
#define RX_SIZE 200
uint8_t buff[256];
int main(void){
HAL_Init();
RccClock_Init();
U1_Init(921600);
while(1){
switch(HAL_UART_Receive(&uart1,buff,RX_SIZE,200)){
case HAL_OK:
HAL_UART_Transmit(&uart1,buff,RX_SIZE,200);
break;
case HAL_TIMEOUT:if(uart1.RxXferCount != (RX_SIZE - 1)){
HAL_UART_Transmit(&uart1,buff,(RX_SIZE - 1 - uart1.RxXferCount),200);
}else{
HAL_Delay(1);
}
break;
}
}
}
接收函数
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
typedef enum
{
HAL_OK = 0x00U,
HAL_ERROR = 0x01U,
HAL_BUSY = 0x02U,
HAL_TIMEOUT = 0x03U
} HAL_StatusTypeDef;
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
uint16_t *tmp;
uint32_t tickstart = 0U;
/* Check that a Rx process is not already ongoing */
if (huart->RxState == HAL_UART_STATE_READY)
{
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR; //表示没有收到,返回错误
}
/* Process Locked */
__HAL_LOCK(huart);
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->RxState = HAL_UART_STATE_BUSY_RX;
/* Init tickstart for timeout managment */
tickstart = HAL_GetTick();
huart->RxXferSize = Size; //接收的容量大小
huart->RxXferCount = Size; //计数
/* Check the remain data to be received */
while (huart->RxXferCount > 0U)
{
huart->RxXferCount--;
if (huart->Init.WordLength == UART_WORDLENGTH_9B)
{
if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK)
{
return HAL_TIMEOUT;//超时
}
tmp = (uint16_t *) pData;
if (huart->Init.Parity == UART_PARITY_NONE)
{
*tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x01FF);
pData += 2U;
}
else
{
*tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x00FF);
pData += 1U;
}
}
else
{
if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK)
{
return HAL_TIMEOUT;
}
if (huart->Init.Parity == UART_PARITY_NONE)
{
*pData++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);
}
else
{
*pData++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x007F);
}
}
}
/* At end of Rx process, restore huart->RxState to Ready */
huart->RxState = HAL_UART_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(huart);
return HAL_OK;//OK
}
else
{
return HAL_BUSY;//繁忙
}
}