嵌入式系统:应用层

应用层的系统功能:CM启动、STM32的系统初始化、中断、HAL依赖管理、外设初始化、外设操作、业务逻辑

一、CMSIS的启动程序

CubeMX工程目录 系统功能函数 STM32Cube固件包的Driver目录
MDK-ARM\ startup_stm32f411xe.s CMSIS\Include\Device\ST\STM32F4xx\Source\Templates\arm
Core\Src\ system_stm32f4xx.c CMSIS\Include\Device\ST\STM32F4xx\Source\Templates
  • 【厂商ST实现】STM32的启动程序:system_stm32f4xx.h、system_stm32f4xx.c
  • 【厂商ST实现】CM处理器启动程序:startup_stm32f411xe.s

二、HAL的依赖管理

CubeMX工程目录 系统功能函数 STM32Cube固件包的Driver目录
Core\Inc\ stm32f4xx_hal_conf.h STM32F4xx_HAL_Driver\Inc\
stm32f4xx_hal_conf_template.h(改名)
  • 编译时的条件宏:USE_HAL_DRIVER(使用HAL库)
  • stm32f4xx_hal_conf.h: HAL库依赖管理(利用条件编译引入PPP的依赖文件hal_ppp.h和hal_ppp.c)
#define HAL_PPP_MODULE_ENABLED

三、HAL的外设中断

CubeMX工程目录 系统功能函数 STM32Cube固件包的Driver目录
Core\Inc\ stm32f4xx_it.h STM32F4xx_HAL_Driver\Inc\
Core\Src\ stm32f4xx_it.c STM32F4xx_HAL_Driver\Src\

中断回调(中断向量→CMSIS的中断回调函数→HAL库外设中断回调函数→前台程序)

  • startup_<device>.s:定义<vector>_Handler、并作为中断向量
  • <device>_it.c:对中断回调函数声明并定义_Handler
  • <device>_hal_ppp.c:定义HAL_PPP_IRQHandler
  • main.c:具体的回调函数
HAL_GPIO_EXTI_Callback(GPIO_PIN_y);
HAL_TIM_PeriodElapsedCallback(&htimx);
/**
 ******************************************************************************
 * 由CubeMX生成的中断相关代码
 * 在<device>_hal_it.h和<device>_hal_it.c文件中
 ****************************************************************************** 
 */
// 头文件中定义
void EXTIx_IRQHandler(void);
void PPP_IRQHandler(void);
//引用外部变量:在main.c中定义的外设初始化全局变量
extern PPP_HandleTypeDef hpppx;
//调用HAL库定义的外设通用中断回调函数:HAL_PPP_IRQHandler
void EXTIx_IRQHandler(void)
{
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_x);
}
void PPP_IRQHandler(void)
{
  HAL_PPP_IRQHandler(&hpppx);
}

四、外设初始化、业务流程

CubeMX工程目录 系统功能函数 STM32Cube固件包的Driver目录
Core\Src\ stm32f4xx_hal_msp.c
Core\Src\ main.c
Core\Inc\ main.h

1. main.c

  • 定义全局变量XxxFlag:作为某个中断是否产生的标志
  • MCU初始化、配置系统时钟
  • 外设初始化:使能时钟、初始化变量定义、初始化变量赋值、初始化函数调用、设置中断优先级、中断使能
  • 可选:清中断、启动外设
  • 后台程序(业务逻辑:判断XxxFlag并清除,进行业务处理)
  • 前台程序(中断回调:赋值XxxFlag)、用户自定义函数

嵌入式系统:应用层

#include "main.h"
//USER CODE Includes:头文件
//USER CODE PTD:数据类型typedef
//USER CODE PD:常量定义define
//USER CODE PM:宏函数定义macro

// 定义外设句柄全局变量
PPP_HandleTypeDef hpppx; //初始化全局变量
//USER CODE PV:变量定义variables

// 声明外设初始化函数
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_PPPx_Init(void);
//USER CODE PFP:函数声明function prototypes
//USER CODE0
int main(void)
{
  //USER CODE1
  //设置MCU
  HAL_Init(); //MCU初始化:复位全部外设,初始化flash接口和systick
  //USER CODE Init
  SystemClock_Config(); //配置系统时钟
  //USER CODE SysInit
  //调用外设初始化函数
  MX_GPIO_Init();
  MX_PPPx_Init();
  //...
  //USER CODE2:外设启动
  //无限循环
  while (1)
  {
    //USER CODE3:后台程序(无限循环)
  }
}
//USER CODE4:用户函数定义或前台程序(定义中断回调函数)

/**
 ******************************************************************************
 * 时钟树
 * HCLK为高速总线时钟:CortexM处理器、存储器、DMA
 *  - HCLK→APB分频器→PCLK→APB peripheral clock(APB的外设时钟)
 *  - HCLK→APB分频器→PCLK→倍频器→APB Timer Clock(APB的定时器时钟:TIM_CLK)
 ******************************************************************************
 */

// CubeMX根据Clock Configuration配置生成
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  //配置输出电压
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  //初始化时钟振荡器:根据RCC_OscInitTypeDef结构体的参数
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_BYPASS;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 4;
  RCC_OscInitStruct.PLL.PLLN = 100;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  //初始化CortexM的CPU、STM32的AHB、APB总线时钟
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK)
  {
    Error_Handler();
  }
}

// CubeMX根据PinOut&Configuration配置生成
// 使用HAL库:对GPIO的多个端口进行初始化设置
static void MX_GPIO_Init(void)
{
  //【可选】设置GPIOx的GPIO_PIN_y引脚的初始电平
  HAL_GPIO_WritePin(GPIOx, GPIO_PIN_y, 初始电平);

  //GPIOx端口时钟使能
  __HAL_RCC_GPIOx_CLK_ENABLE();

  //【可选】GPIOx端口参数配置
  GPIO_InitTypeDef GPIO_InitStruct = {0}; //初始化变量
  GPIO_InitStruct.各种参数 = 参数值;      //初始化变量赋值
  HAL_GPIO_Init(GPIOx, &GPIO_InitStruct); //调用外设初始化函数

  //【可选】GPIO_EXIT中断初始化
  HAL_NVIC_SetPriority(EXTIy_IRQn, 抢占优先级, 子优先级); //设置中断优先级
  HAL_NVIC_EnableIRQ(EXTIy_IRQn);                         //使能中断
}
// 使用HAL库:对某个外设PPP进行初始化设置
static void MX_PPPx_Init(void)
{
  //对于多数外设PPP:UART
  hpppx.Instance = PPPx;        //外设对象
  hpppx.Init.各种参数 = 参数值; //初始化变量赋值
  if (HAL_PPP_Init(&hpppx) != HAL_OK)
  { //调用外设初始化函数:调用HAL_PPP_MspInit(&hpppx)
    Error_Handler();
  }
  //可选:PPP内部多个模块Xxx单独初始化
  PPP_XxxConfigTypeDef sXxxConfig = {0}; //初始化变量
  sXxxConfig.各种参数 = 参数值;          //初始化变量赋值
  if (HAL_PPP_ConfigXxx(&hpppx, &sXxxConfig) != HAL_OK)
  { //调用外设初始化函数
    Error_Handler();
  }
}

// 当错误发生时执行的回调函数
void Error_Handler(void)
{
  //USER CODE Error_Handler_Debug
  //用户可自行实现:上报HAL错误返回状态
  __disable_irq();
  while (1)
  {
  }
}

2.hal_msp.c

初始化(与具体芯片型号相关的配置:将外设时钟使能、GPIO时钟使能和GPIO引脚复用、外设中断初始化)

/**
 ******************************************************************************
 * 由CubeMX生成的外设MSP的相关代码
 * 在<device>_hal_msp.c文件中
 * PPP可以为UART、TIM_Base
 ****************************************************************************** 
 */
void HAL_PPP_MspInit(PPP_HandleTypeDef *hppp)
{
  if (hppp->Instance == PPPx)
  {
    //PPP外设时钟使能
    __HAL_RCC_PPPx_CLK_ENABLE();

    //【可选】将GPIO引脚复用为PPP外设的引脚
    __HAL_RCC_GPIOx_CLK_ENABLE(); //GPIO时钟使能

    GPIO_InitTypeDef GPIO_InitStruct = {0}; //初始化变量
    GPIO_InitStruct.各种参数 = 参数值;      //初始化变量赋值
    HAL_GPIO_Init(GPIOx, &GPIO_InitStruct); //调用GPIO初始化函数

    //【可选】PPP外设中断初始化
    HAL_NVIC_SetPriority(PPPx_IRQn, 抢占优先级, 子优先级); //设置中断优先级
    HAL_NVIC_EnableIRQ(PPPx_IRQn);                         //使能中断
  }
}

void HAL_PPP_MspDeInit(PPP_HandleTypeDef *hppp)
{
  if (hppp->Instance == PPPx)
  {
    // 外设时钟失能
    __HAL_RCC_PPPx_CLK_DISABLE();
    // 【可选】将GPIO引脚复位
    HAL_GPIO_DeInit(GPIOx, GPIO_PIN_y);
    //【可选】PPP外设中断禁用
    HAL_PPP_DisableIRQ(PPPx_IRQn);
  }
}
上一篇:数据链路


下一篇:python3实现银行家,作业调度,磁盘调度,页面置换(高级版)