STM32 HAL库常用功能封装

关中断

/**
 * @brief       关闭所有中断(但是不包括fault和NMI中断)
 * @param       无
 * @retval      无
 */
void sys_intx_disable(void)
{
    __ASM volatile("cpsid i");
}

开中断

/**
 * @brief       开启所有中断
 * @param       无
 * @retval      无
 */
void sys_intx_enable(void)
{
    __ASM volatile("cpsie i");
}

进入待机模式

/**
 * @brief       进入待机模式
 * @param       无
 * @retval      无
 */
void sys_standby(void)
{
    __HAL_RCC_PWR_CLK_ENABLE();    /* 使能电源时钟 */
    SET_BIT(PWR->CR, PWR_CR_PDDS); /* 进入待机模式 */
}

设置栈顶指针

/**
 * @brief       设置栈顶地址
 * @note        左侧若出现红X, 属于MDK误报, 实际是没问题的
 * @param       addr: 栈顶地址
 * @retval      无
 */
void sys_msr_msp(uint32_t addr)
{
    __set_MSP(addr);    /* 设置栈顶地址 */
}

进入低功耗模式

/**
 * @brief       执行: WFI指令(执行完该指令进入低功耗状态, 等待中断唤醒)
 * @param       无
 * @retval      无
 */
void sys_wfi_set(void)
{
    __ASM volatile("wfi");
}

系统软复位 (第一种)

/**
 * @brief       系统软复位
 * @param       无
 * @retval      无
 */
void sys_soft_reset(void)
{
    NVIC_SystemReset();
}

系统软复位 (第二种)

/*!
* @brief ARM 软重启 
* @retval: 无
*/
#define SCB_AIRCR             (*(unsigned long *)0xE000ED0C)      //Reset control Address Register
#define SCB_RESET_VALUE       0x05FA0004                          //reset value ,write to SCB_AIRCR  can reset cpu
void Reset_System(void)
{
	SCB_AIRCR=SCB_RESET_VALUE;
}

GPIO初始化封装

/**
  * @brief 初始化GPIO
  * @note   
  * @retval 
  */
void MX_GPIOX_PIN_Init(GPIO_TypeDef *GPIOx,uint32_t GPIO_PIN_x,uint32_t GPIO_MODE_x,uint32_t Speed_x)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0}; /* gpio初始化 */
	
	GPIO_InitStruct.Pin = GPIO_PIN_x; // 设置GPIO_Pin
	GPIO_InitStruct.Mode = GPIO_MODE_x; // 设置模式为输入
	GPIO_InitStruct.Pull = GPIO_NOPULL; // 不使用上拉或下拉
	GPIO_InitStruct.Speed = Speed_x;
	HAL_GPIO_Init(GPIOx, &GPIO_InitStruct); // 初始化GPIOX的GPIO_Pin
}

开启GPIOx相应时钟

/**
  * @brief 开启对应GPIO Port时钟
  * @note   
  * @retval 
  */
void MX_GPIOX_Clock_Enable(GPIO_TypeDef *GPIOx) {
    /* 确保GPIOx是有效的GPIO口 */
    if (GPIOx == GPIOA) {
        __HAL_RCC_GPIOA_CLK_ENABLE();
    } else if (GPIOx == GPIOB) {
        __HAL_RCC_GPIOB_CLK_ENABLE();
    } else if (GPIOx == GPIOC) {
        __HAL_RCC_GPIOC_CLK_ENABLE();
    } else if (GPIOx == GPIOD) {
        __HAL_RCC_GPIOD_CLK_ENABLE();
    } else if (GPIOx == GPIOE) {
        __HAL_RCC_GPIOE_CLK_ENABLE();
    } else if (GPIOx == GPIOF) {
        __HAL_RCC_GPIOF_CLK_ENABLE();
    } else if (GPIOx == GPIOG) {
        __HAL_RCC_GPIOG_CLK_ENABLE();
    } else if (GPIOx == GPIOH) {
        __HAL_RCC_GPIOH_CLK_ENABLE();
    } else if (GPIOx == GPIOI) {
        __HAL_RCC_GPIOI_CLK_ENABLE();
    }
}

SP330协议转换芯片配置接口封装

sp330.h

#define USE_SP330	1 //使用sp330
/* sp330 configure begin */
#if USE_SP330
#define U1_SP330_SLEW_Pin GPIO_PIN_15
#define U1_SP330_SLEW_GPIO_Port GPIOA
#define U1_SP330_SHDN_Pin GPIO_PIN_12
#define U1_SP330_SHDN_GPIO_Port GPIOC
#define U1_SP330_DE_Pin GPIO_PIN_0
#define U1_SP330_DE_GPIO_Port GPIOD
#define U1_SP330_RE_Pin GPIO_PIN_1
#define U1_SP330_RE_GPIO_Port GPIOD
#define U1_SP330_HALE_FULL_Pin GPIO_PIN_2
#define U1_SP330_HALE_FULL_GPIO_Port GPIOD
#define U1_SP330_MODE_Pin GPIO_PIN_5
#define U1_SP330_MODE_GPIO_Port GPIOD

#define U4_SP330_DE_Pin GPIO_PIN_6
#define U4_SP330_DE_GPIO_Port GPIOD
#define U4_SP330_RE_Pin GPIO_PIN_7
#define U4_SP330_RE_GPIO_Port GPIOB
#define U4_SP330_HALE_FULL_Pin GPIO_PIN_8
#define U4_SP330_HALE_FULL_GPIO_Port GPIOB
#define U4_SP330_MODE_Pin GPIO_PIN_9
#define U4_SP330_MODE_GPIO_Port GPIOB
#define U4_SP330_SLEW_Pin GPIO_PIN_0
#define U4_SP330_SLEW_GPIO_Port GPIOE
#define U4_SP330_SHDN_Pin GPIO_PIN_1
#define U4_SP330_SHDN_GPIO_Port GPIOE

/* sp330模式 */
typedef enum
{
	RS232_MODE = 232,
	RS422_MODE = 422,
	RS485_MODE = 485
}SP330_MODE;

/* sp330通信方式 */
typedef enum
{
	HALF_DUPLEX = 11,
	FULL_DUPLEX = 22 //全双工
}SP330_COMM_MODE;

/* 配置结构体 */
typedef struct
{
	uint16_t SP330_Work_Mode;   //取值范围为SP330_MODE枚举
	uint16_t SP330_Comm_Mode;   //SP330_COMM_MODE
	uint16_t SP330_DE_GPIO_Pin; //发送脚
	uint16_t SP330_RE_GPIO_Pin; //接收脚
	uint16_t SP330_MODE_GPIO_Pin; //模式配置
	uint16_t SP330_SLEW_GPIO_Pin; //限摆率设置
	uint16_t SP330_SHDN_GPIO_Pin; //功耗模式设置:
	uint16_t SP330_HALE_FULL_GPIO_Pin; //双工模式
	GPIO_TypeDef *SP330_RE_GPIOx;
	GPIO_TypeDef *SP330_DE_GPIOx;
	GPIO_TypeDef *SP330_SLEW_GPIOx;
	GPIO_TypeDef *SP330_SHDN_GPIOx;
	GPIO_TypeDef *SP330_MODE_GPIOx;
	GPIO_TypeDef *SP330_HALE_FULL_GPIOx;   
}Sp330_Configure;

void Sp330_Init(Sp330_Configure *sp330); //sp330初始化
void Uart_Sp330_Configure(void); //sp330配置
/* sp330 configure end */
#endif

sp330.c

/**
  * @brief sp330配置函数
  * @note   
  * @retval 
  */
void Uart_Sp330_Configure(void)
{
	/* 配置结构体定义 */
	Sp330_Configure u1_sp330; 
	Sp330_Configure u4_sp330; 
	
	u1_sp330.SP330_DE_GPIOx = U1_SP330_DE_GPIO_Port;
	u1_sp330.SP330_DE_GPIO_Pin = U1_SP330_DE_Pin;
	u1_sp330.SP330_RE_GPIOx = U1_SP330_RE_GPIO_Port;
	u1_sp330.SP330_RE_GPIO_Pin = U1_SP330_RE_Pin;
	u1_sp330.SP330_SHDN_GPIOx = U1_SP330_SHDN_GPIO_Port;
	u1_sp330.SP330_SHDN_GPIO_Pin = U1_SP330_SHDN_Pin;
	u1_sp330.SP330_SLEW_GPIOx = U1_SP330_SLEW_GPIO_Port;
	u1_sp330.SP330_SLEW_GPIO_Pin = U1_SP330_SLEW_Pin;
	u1_sp330.SP330_MODE_GPIOx = U1_SP330_MODE_GPIO_Port;
	u1_sp330.SP330_MODE_GPIO_Pin = U1_SP330_MODE_Pin;
	u1_sp330.SP330_Work_Mode = RS422_MODE; //422模式
	u1_sp330.SP330_Comm_Mode = FULL_DUPLEX; //全双工
	
	Sp330_Init(&u1_sp330); //初始化uart1 sp330
	
	u4_sp330.SP330_DE_GPIOx = U4_SP330_DE_GPIO_Port;
	u4_sp330.SP330_DE_GPIO_Pin = U4_SP330_DE_Pin;
	u4_sp330.SP330_RE_GPIOx = U4_SP330_RE_GPIO_Port;
	u4_sp330.SP330_RE_GPIO_Pin = U4_SP330_RE_Pin;
	u4_sp330.SP330_SHDN_GPIOx = U4_SP330_SHDN_GPIO_Port;
	u4_sp330.SP330_SHDN_GPIO_Pin = U4_SP330_SHDN_Pin;
	u4_sp330.SP330_SLEW_GPIOx = U4_SP330_SLEW_GPIO_Port;
	u4_sp330.SP330_SLEW_GPIO_Pin = U4_SP330_SLEW_Pin;
	u4_sp330.SP330_MODE_GPIOx = U4_SP330_MODE_GPIO_Port;
	u4_sp330.SP330_MODE_GPIO_Pin = U4_SP330_MODE_Pin;
	u4_sp330.SP330_Work_Mode = RS422_MODE; //422模式
	u4_sp330.SP330_Comm_Mode = FULL_DUPLEX; //全双工
	
	Sp330_Init(&u4_sp330); //初始化uart4 sp330	
}

void Sp330_Init(Sp330_Configure *sp330)
{
#if 0 //mx生成时已初始化引脚,不在这里再次初始化了
	/* 开启GPIO时钟 */
	MX_GPIOX_Clock_Enable(sp330->SP330_DE_GPIOx);
	MX_GPIOX_Clock_Enable(sp330->SP330_RE_GPIOx);
	MX_GPIOX_Clock_Enable(sp330->SP330_SLEW_GPIOx);
	MX_GPIOX_Clock_Enable(sp330->SP330_SHDN_GPIOx);
	MX_GPIOX_Clock_Enable(sp330->SP330_HALE_FULL_GPIOx);
	MX_GPIOX_Clock_Enable(sp330->SP330_MODE_GPIOx);
	
	/* 初始化GPIO */
	MX_GPIOX_PIN_Init(sp330->SP330_DE_GPIOx,sp330->SP330_DE_GPIO_Pin,GPIO_MODE_OUTPUT_PP,GPIO_SPEED_LOW);
	MX_GPIOX_PIN_Init(sp330->SP330_RE_GPIOx,sp330->SP330_RE_GPIO_Pin,GPIO_MODE_OUTPUT_PP,GPIO_SPEED_LOW);
	MX_GPIOX_PIN_Init(sp330->SP330_SLEW_GPIOx,sp330->SP330_SLEW_GPIO_Pin,GPIO_MODE_OUTPUT_PP,GPIO_SPEED_LOW);
	MX_GPIOX_PIN_Init(sp330->SP330_SHDN_GPIOx,sp330->SP330_SHDN_GPIO_Pin,GPIO_MODE_OUTPUT_PP,GPIO_SPEED_LOW);
	MX_GPIOX_PIN_Init(sp330->SP330_HALE_FULL_GPIOx,sp330->SP330_HALE_FULL_GPIO_Pin,GPIO_MODE_OUTPUT_PP,GPIO_SPEED_LOW);
	MX_GPIOX_PIN_Init(sp330->SP330_MODE_GPIOx,sp330->SP330_MODE_GPIO_Pin,GPIO_MODE_OUTPUT_PP,GPIO_SPEED_LOW);
#endif 
	
	/* 模式配置 RS485 \RS422 \RS232设置*/
	if(sp330->SP330_Work_Mode == RS232_MODE)
		HAL_GPIO_WritePin(sp330->SP330_MODE_GPIOx,sp330->SP330_MODE_GPIO_Pin,GPIO_PIN_RESET);
	else if(sp330->SP330_Work_Mode == RS422_MODE || sp330->SP330_Work_Mode == RS485_MODE)	
	{
		HAL_GPIO_WritePin(sp330->SP330_MODE_GPIOx,sp330->SP330_MODE_GPIO_Pin,GPIO_PIN_SET);
		HAL_GPIO_WritePin(sp330->SP330_DE_GPIOx,sp330->SP330_DE_GPIO_Pin,GPIO_PIN_SET);//使能发送
		HAL_GPIO_WritePin(sp330->SP330_RE_GPIOx,sp330->SP330_RE_GPIO_Pin,GPIO_PIN_RESET); //使能接收
	}
	/* 通信方式设置  全双工、半双工设置*/
	if(sp330->SP330_Comm_Mode == HALF_DUPLEX) 
		HAL_GPIO_WritePin(sp330->SP330_HALE_FULL_GPIOx,sp330->SP330_HALE_FULL_GPIO_Pin,GPIO_PIN_SET);
	else if(sp330->SP330_Comm_Mode == FULL_DUPLEX) 
		HAL_GPIO_WritePin(sp330->SP330_HALE_FULL_GPIOx,sp330->SP330_HALE_FULL_GPIO_Pin,GPIO_PIN_RESET);
	
	/* 限摆率设置 */
	HAL_GPIO_WritePin(sp330->SP330_SLEW_GPIOx,sp330->SP330_SLEW_GPIO_Pin,GPIO_PIN_SET); /*无限制*/
	
	/* 低功耗设置 */
	HAL_GPIO_WritePin(sp330->SP330_SHDN_GPIOx,sp330->SP330_SHDN_GPIO_Pin,GPIO_PIN_SET); /* 关闭低功耗 */
	
}
### 使用STM32 HAL进行模块化编程 #### 什么是模块化编程? 模块化编程是一种将程序分解成独立的功能单元的方法,这些单元被称为模块。每个模块负责特定的任务,并通过定义良好的接口与其他模块交互。这种方法提高了代码的可读性、维护性和重用性。 对于STM32 HAL而言,模块化编程意味着按照不同的外设或功能创建单独的文件和函数,从而实现清晰的结构划分[^2]。 #### 创建项目框架 为了展示如何利用HAL实施模块化编程,下面是一个简单的例子: 假设目标是构建一个应用程序,该应用能够控制LED灯并通过串口发送消息给PC端。此过程涉及初始化GPIO引脚用于驱动LED以及配置USART通信接口。 ##### 文件夹结构建议如下: ``` Project/ ├── Inc/ │ ├── main.h │ └── led_driver.h │ └── usart_communication.h └── Src/ ├── main.c ├── led_driver.c └── usart_communication.c ``` #### 编写头文件 在`Inc/main.h`中声明全局变量和包含必要的头文件。 ```c /* USER CODE BEGIN Includes */ #include "led_driver.h" #include "usart_communication.h" /* USER CODE END Includes */ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_USART2_UART_Init(void); ``` #### 实现具体功能 接下来,在相应的源文件里编写具体的逻辑。 **Led Driver (`Src/led_driver.c`)** ```c #include "led_driver.h" // 定义LED状态切换函数 void LED_Toggle(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin){ HAL_GPIO_TogglePin(GPIOx, GPIO_Pin); } ``` **Usart Communication (`Src/usart_communication.c`)** ```c #include "usart_communication.h" // 发送字符串到指定串口 void USART_SendString(UART_HandleTypeDef *huart, char *str){ while(*str != '\0'){ HAL_UART_Transmit(huart, (uint8_t*)str++, 1, HAL_MAX_DELAY); } } ``` #### 主程序入口 最后回到`main.c`完成整个流程串联起来的工作。 ```c int main(void) { /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* Configure the system clock */ SystemClock_Config(); /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_USART2_UART_Init(); while (1) { // 调用LED翻转方法 LED_Toggle(LED_PORT, LED_PIN); // 延迟一段时间再继续执行下一次循环体内的操作 HAL_Delay(500); // 向电脑终端打印一条信息 const char msg[] = "Hello from STM32!\r\n"; USART_SendString(&huart2,msg); } } ``` 上述实例展示了怎样基于HAL来进行基本层次上的模块分割——即把不同职责分配给了各个子系统(如LED控制与串行通讯),并让它们各自封装好内部细节之后对外暴露简洁易懂的操作方式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值