STMicroelectronics 系列:STM32L5 系列_(6).STM32L5系列编程基础

STM32L5系列编程基础

1. 硬件概览

1.1 CPU架构

STM32L5系列基于Arm® Cortex®-M33内核,这是一种高性能的32位处理器,支持浮点运算和数字信号处理(DSP)指令。Cortex-M33内核还集成了TrustZone®技术,用于实现安全功能。以下是Cortex-M33内核的一些关键特性:

  • 32位架构:提供高效的32位数据处理能力。

  • 浮点运算单元(FPU):支持单精度和双精度浮点运算。

  • DSP指令:提高数字信号处理的性能。

  • TrustZone®技术:实现硬件级别的安全隔离,保护敏感数据和代码。

  • 低功耗模式:支持多种低功耗模式,适用于电池供电的嵌入式系统。

  • 1.2 存储器

    STM32L5系列单片机具有丰富的存储器选项,包括Flash存储器、SRAM和备份SRAM。以下是存储器的主要特性:

  • Flash存储器:高达512 KB的非易失性存储器,用于存储程序代码和静态数据。

  • SRAM:高达288 KB的易失性存储器,用于运行时数据存储。

  • 备份SRAM:4 KB的备份SRAM,可以在低功耗模式下保持数据。

  • 1.3 外设

    STM32L5系列集成了多种外设,以满足不同应用的需求。以下是一些常见的外设:

  • 定时器:包括通用定时器和高级定时器,用于生成精确的定时信号。

  • 通信接口:支持SPI、I2C、USART、USB等多种通信接口。

  • 模拟外设:包括ADC、DAC和模拟比较器,用于处理模拟信号。

  • 电源管理:支持多种电源管理功能,如低功耗模式和电压监控。

  • 1.4 电源和功耗管理

    STM32L5系列单片机具有多种电源和功耗管理功能,以优化能效。以下是一些关键的电源管理特性:

  • 多种低功耗模式:包括睡眠模式、停机模式和待机模式,每种模式都有不同的功耗和唤醒时间。

  • 电压监控:内置电压检测器,可以在电源电压过低时触发中断或复位。

  • 电源管理单元(PMU):用于控制各种电源管理功能,如电压调节和电流监控。

  • 2. 开发环境设置

    2.1 安装STM32CubeIDE

    STM32CubeIDE是STMicroelectronics官方提供的集成开发环境(IDE),支持STM32系列单片机的开发。以下是安装步骤:

    1. 访问STMicroelectronics官网,下载STM32CubeIDE安装包。

    2. 运行安装包,选择安装路径并按照提示完成安装。

    3. 启动STM32CubeIDE,选择“Create a New Project”创建新项目。

    4. 选择项目类型为“STM32 Project”,选择相应的STM32L5系列单片机型号。

    5. 配置项目设置,如编译器选项和调试接口。

    2.2 配置调试接口

    STM32L5系列单片机支持多种调试接口,如SWD(Serial Wire Debug)和JTAG(Joint Test Action Group)。以下是配置调试接口的步骤:

    1. 连接调试器:使用ST-Link调试器连接到STM32L5单片机的调试接口。

    2. 配置项目:在STM32CubeIDE中选择“Project” -> “Properties” -> “C/C++ Build” -> “Settings” -> “Debug”,配置调试器选项。

    3. 启动调试:点击“Debug”按钮,启动调试会话。

    2.3 创建和管理项目

    在STM32CubeIDE中创建和管理项目的基本步骤如下:

    1. 创建新项目:选择“File” -> “New” -> “STM32 Project”,输入项目名称和存储路径。

    2. 选择单片机型号:在“Project Manager”中选择相应的STM32L5系列单片机型号。

    3. 配置外设:使用STM32CubeMX工具配置所需的外设,如GPIO、定时器和通信接口。

    4. 生成代码:点击“Generate Code”按钮,生成初始化代码和外设配置代码。

    5. 编写应用程序:在生成的代码基础上编写用户应用程序。

    6. 编译和烧录:点击“Build”按钮编译代码,点击“Program”按钮将编译后的程序烧录到单片机中。

    3. GPIO编程

    3.1 GPIO概述

    GPIO(General Purpose Input/Output)是STM32L5系列单片机中最基本的外设之一,用于控制数字输入和输出。STM32L5系列单片机具有多个GPIO端口,每个端口包含多个引脚,可以配置为输入、输出、中断等多种模式。

    3.2 GPIO配置

    在STM32CubeIDE中配置GPIO的基本步骤如下:

    1. 打开STM32CubeMX:在项目中打开STM32CubeMX工具。

    2. 选择引脚:在“Pinout”视图中选择需要配置的GPIO引脚。

    3. 配置模式:在“Configuration”视图中选择引脚的模式,如“GPIO_Output”、“GPIO_Input”等。

    4. 生成代码:点击“Generate Code”按钮,生成初始化代码。

    3.3 GPIO操作示例

    以下是一个简单的GPIO操作示例,通过STM32L5系列单片机的GPIO引脚控制一个LED灯。

    
    #include "stm32l5xx_hal.h"
    
    
    
    // 定义LED引脚
    
    #define LED_PIN GPIO_PIN_5
    
    #define LED_PORT GPIOA
    
    
    
    void SystemClock_Config(void);
    
    static void MX_GPIO_Init(void);
    
    
    
    int main(void) {
    
        // 初始化HAL库
    
        HAL_Init();
    
    
    
        // 配置系统时钟
    
        SystemClock_Config();
    
    
    
        // 初始化GPIO
    
        MX_GPIO_Init();
    
    
    
        while (1) {
    
            // 点亮LED
    
            HAL_GPIO_WritePin(LED_PORT, LED_PIN, GPIO_PIN_SET);
    
            // 延时500毫秒
    
            HAL_Delay(500);
    
            // 熄灭LED
    
            HAL_GPIO_WritePin(LED_PORT, LED_PIN, GPIO_PIN_RESET);
    
            // 延时500毫秒
    
            HAL_Delay(500);
    
        }
    
    }
    
    
    
    void SystemClock_Config(void) {
    
        // 配置系统时钟
    
        RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    
        RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
    
    
    
        // 初始化RCC_OscInitTypeDef结构体
    
        RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
    
        RCC_OscInitStruct.MSIState = RCC_MSI_ON;
    
        RCC_OscInitStruct.MSICalibrationValue = 0;
    
        RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
    
        RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    
        RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
    
        RCC_OscInitStruct.PLL.PLLM = 1;
    
        RCC_OscInitStruct.PLL.PLLN = 40;
    
        RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
    
        RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
    
        RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
    
        if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
    
            // 时钟配置失败
    
            Error_Handler();
    
        }
    
    
    
        // 初始化RCC_ClkInitTypeDef结构体
    
        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_DIV1;
    
        RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
    
        if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) {
    
            // 时钟配置失败
    
            Error_Handler();
    
        }
    
    }
    
    
    
    static void MX_GPIO_Init(void) {
    
        // 定义GPIO结构体
    
        GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    
    
        // 使能GPIOA时钟
    
        __HAL_RCC_GPIOA_CLK_ENABLE();
    
    
    
        // 配置GPIOA的PIN5为输出模式
    
        GPIO_InitStruct.Pin = LED_PIN;
    
        GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    
        GPIO_InitStruct.Pull = GPIO_NOPULL;
    
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    
        HAL_GPIO_Init(LED_PORT, &GPIO_InitStruct);
    
    }
    
    
    
    void Error_Handler(void) {
    
        // 错误处理函数
    
        while (1) {
    
        }
    
    }
    
    

    3.4 GPIO中断

    GPIO中断用于检测引脚的状态变化,并触发相应的中断处理函数。以下是一个简单的GPIO中断示例,检测按钮按下事件。

    
    #include "stm32l5xx_hal.h"
    
    
    
    // 定义按钮引脚
    
    #define BUTTON_PIN GPIO_PIN_0
    
    #define BUTTON_PORT GPIOA
    
    
    
    // 定义LED引脚
    
    #define LED_PIN GPIO_PIN_5
    
    #define LED_PORT GPIOA
    
    
    
    void SystemClock_Config(void);
    
    static void MX_GPIO_Init(void);
    
    void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);
    
    
    
    int main(void) {
    
        HAL_Init();
    
        SystemClock_Config();
    
        MX_GPIO_Init();
    
    
    
        while (1) {
    
            // 主循环
    
        }
    
    }
    
    
    
    void SystemClock_Config(void) {
    
        // 配置系统时钟
    
        RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    
        RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
    
    
    
        // 初始化RCC_OscInitTypeDef结构体
    
        RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
    
        RCC_OscInitStruct.MSIState = RCC_MSI_ON;
    
        RCC_OscInitStruct.MSICalibrationValue = 0;
    
        RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
    
        RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    
        RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
    
        RCC_OscInitStruct.PLL.PLLM = 1;
    
        RCC_OscInitStruct.PLL.PLLN = 40;
    
        RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
    
        RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
    
        RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
    
        if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    
    
        // 初始化RCC_ClkInitTypeDef结构体
    
        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_DIV1;
    
        RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
    
        if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    }
    
    
    
    static void MX_GPIO_Init(void) {
    
        // 定义GPIO结构体
    
        GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    
    
        // 使能GPIOA时钟
    
        __HAL_RCC_GPIOA_CLK_ENABLE();
    
    
    
        // 配置GPIOA的PIN0为输入模式
    
        GPIO_InitStruct.Pin = BUTTON_PIN;
    
        GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
    
        GPIO_InitStruct.Pull = GPIO_NOPULL;
    
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    
        HAL_GPIO_Init(BUTTON_PORT, &GPIO_InitStruct);
    
    
    
        // 配置GPIOA的PIN5为输出模式
    
        GPIO_InitStruct.Pin = LED_PIN;
    
        GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    
        GPIO_InitStruct.Pull = GPIO_NOPULL;
    
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    
        HAL_GPIO_Init(LED_PORT, &GPIO_InitStruct);
    
    
    
        // 使能GPIO中断
    
        HAL_NVIC_SetPriority(GPIOA_IRQn, 0, 0);
    
        HAL_NVIC_EnableIRQ(GPIOA_IRQn);
    
    }
    
    
    
    void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
    
        // 中断处理函数
    
        if (GPIO_Pin == BUTTON_PIN) {
    
            // 按钮按下,切换LED状态
    
            HAL_GPIO_TogglePin(LED_PORT, LED_PIN);
    
        }
    
    }
    
    
    
    void Error_Handler(void) {
    
        // 错误处理函数
    
        while (1) {
    
        }
    
    }
    
    
    
    // 中断服务函数
    
    void GPIOA_IRQHandler(void) {
    
        HAL_GPIO_EXTI_IRQHandler(BUTTON_PIN);
    
    }
    
    

    4. 定时器编程

    4.1 定时器概述

    定时器是STM32L5系列单片机中非常重要的外设之一,用于生成精确的定时信号和处理定时任务。定时器可以配置为多种模式,如定时器模式、计数器模式和PWM模式。

    4.2 定时器配置

    在STM32CubeIDE中配置定时器的基本步骤如下:

    1. 打开STM32CubeMX:在项目中打开STM32CubeMX工具。

    2. 选择定时器:在“Pinout”视图中选择需要配置的定时器。

    3. 配置模式:在“Configuration”视图中选择定时器的模式,如“Timer Output Compare”、“PWM”等。

    4. 生成代码:点击“Generate Code”按钮,生成初始化代码和定时器配置代码。

    4.3 定时器操作示例

    以下是一个简单的定时器操作示例,使用定时器生成周期性的中断,每秒切换一次LED的状态。

    
    #include "stm32l5xx_hal.h"
    
    
    
    // 定义LED引脚
    
    #define LED_PIN GPIO_PIN_5
    
    #define LED_PORT GPIOA
    
    
    
    void SystemClock_Config(void);
    
    static void MX_GPIO_Init(void);
    
    static void MX_TIM2_Init(void);
    
    void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);
    
    
    
    TIM_HandleTypeDef htim2;
    
    
    
    int main(void) {
    
        HAL_Init();
    
        SystemClock_Config();
    
        MX_GPIO_Init();
    
        MX_TIM2_Init();
    
    
    
        // 启动定时器
    
        HAL_TIM_Base_Start_IT(&htim2);
    
    
    
        while (1) {
    
            // 主循环
    
        }
    
    }
    
    
    
    void SystemClock_Config(void) {
    
        // 配置系统时钟
    
        RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    
        RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
    
    
    
        // 初始化RCC_OscInitTypeDef结构体
    
        RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
    
        RCC_OscInitStruct.MSIState = RCC_MSI_ON;
    
        RCC_OscInitStruct.MSICalibrationValue = 0;
    
        RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
    
        RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    
        RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
    
        RCC_OscInitStruct.PLL.PLLM = 1;
    
        RCC_OscInitStruct.PLL.PLLN = 40;
    
        RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
    
        RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
    
        RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
    
        if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    
    
        // 初始化RCC_ClkInitTypeDef结构体
    
        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_DIV1;
    
        RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
    
        if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    }
    
    
    
    static void MX_GPIO_Init(void) {
    
        // 定义GPIO结构体
    
        GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    
    
        // 使能GPIOA时钟
    
        __HAL_RCC_GPIOA_CLK_ENABLE();
    
    
    
        // 配置GPIOA的PIN5为输出模式
    
        GPIO_InitStruct.Pin = LED_PIN;
    
        GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    
        GPIO_InitStruct.Pull = GPIO_NOPULL;
    
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    
        HAL_GPIO_Init(LED_PORT, &GPIO_InitStruct);
    
    }
    
    
    
    static void MX_TIM2_Init(void) {
    
        // 定义定时器结构体
    
        TIM_MasterConfigTypeDef sMasterConfig = {0};
    
        TIM_OC_InitTypeDef sConfigOC = {0};
    
    
    
        // 使能TIM2时钟
    
        __HAL_RCC_TIM2_CLK_ENABLE();
    
    
    
        // 初始化定时器结构体
    
        htim2.Instance = TIM2;
    
        htim2.Init.Prescaler = 8000 - 1;
    
        htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
    
        htim2.Init.Period = 10000 - 1;
    
        htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    
        htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
    
        if (HAL_TIM_Base_Init(&htim2) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    
    
        // 配置定时器主模式
    
        sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
    
        sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
    
        if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    
    
        // 配置定时器中断
    
        HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);
    
        HAL_NVIC_EnableIRQ(TIM2_IRQn);
    
    }
    
    
    
    void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
    
        // 定时器周期中断处理函数
    
        if (htim == &htim2) {
    
            // 每秒切换一次LED状态
    
            HAL_GPIO_TogglePin(LED_PORT, LED_PIN);
    
        }
    
    }
    
    
    
    void Error_Handler(void) {
    
        // 错误处理函数
    
        while (1) {
    
        }
    
    }
    
    
    
    // 中断服务函数
    
    void TIM2_IRQHandler(void) {
    
        HAL_TIM_IRQHandler(&htim2);
    
    }
    
    

    5. 通信接口编程

    5.1 USART编程

    USART(Universal Synchronous/Asynchronous Receiver-Transmitter)是STM32L5系列单片机中的串行通信接口,支持异步和同步通信。通过USART,可以实现单片机与外部设备(如计算机、其他单片机、传感器等)的串行数据传输。以下是配置和使用USART的基本步骤和示例代码。

    5.1.1 USART配置

    在STM32CubeIDE中配置USART的基本步骤如下:

    1. 打开STM32CubeMX:在项目中打开STM32CubeMX工具。

    2. 选择USART:在“Pinout”视图中选择需要配置的USART接口,如USART1。

    3. 配置参数:在“Configuration”视图中配置USART的参数,如波特率、数据位、停止位和校验位。

    4. 生成代码:点击“Generate Code”按钮,生成初始化代码和USART配置代码。

    5.1.2 USART操作示例

    以下是一个简单的USART操作示例,通过USART1接口发送和接收数据。

    
    #include "stm32l5xx_hal.h"
    
    
    
    // 定义USART1的GPIO引脚
    
    #define USART1_TX_PIN GPIO_PIN_9
    
    #define USART1_RX_PIN GPIO_PIN_10
    
    #define USART1_GPIO_PORT GPIOA
    
    
    
    // 定义USART1的句柄
    
    UART_HandleTypeDef huart1;
    
    
    
    void SystemClock_Config(void);
    
    static void MX_GPIO_Init(void);
    
    static void MX_USART1_UART_Init(void);
    
    void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);
    
    
    
    int main(void) {
    
        HAL_Init();
    
        SystemClock_Config();
    
        MX_GPIO_Init();
    
        MX_USART1_UART_Init();
    
    
    
        // 发送初始化消息
    
        char *msg = "USART1 Initialization Complete\r\n";
    
        HAL_UART_Transmit(&huart1, (uint8_t *)msg, strlen(msg), HAL_MAX_DELAY);
    
    
    
        while (1) {
    
            // 主循环
    
        }
    
    }
    
    
    
    void SystemClock_Config(void) {
    
        // 配置系统时钟
    
        RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    
        RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
    
    
    
        // 初始化RCC_OscInitTypeDef结构体
    
        RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
    
        RCC_OscInitStruct.MSIState = RCC_MSI_ON;
    
        RCC_OscInitStruct.MSICalibrationValue = 0;
    
        RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
    
        RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    
        RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
    
        RCC_OscInitStruct.PLL.PLLM = 1;
    
        RCC_OscInitStruct.PLL.PLLN = 40;
    
        RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
    
        RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
    
        RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
    
        if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    
    
        // 初始化RCC_ClkInitTypeDef结构体
    
        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_DIV1;
    
        RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
    
        if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    }
    
    
    
    static void MX_GPIO_Init(void) {
    
        // 定义GPIO结构体
    
        GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    
    
        // 使能GPIOA时钟
    
        __HAL_RCC_GPIOA_CLK_ENABLE();
    
    
    
        // 配置USART1的TX和RX引脚
    
        GPIO_InitStruct.Pin = USART1_TX_PIN | USART1_RX_PIN;
    
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    
        GPIO_InitStruct.Pull = GPIO_NOPULL;
    
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    
        GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
    
        HAL_GPIO_Init(USART1_GPIO_PORT, &GPIO_InitStruct);
    
    }
    
    
    
    static void MX_USART1_UART_Init(void) {
    
        // 定义USART1的初始化结构体
    
        huart1.Instance = USART1;
    
        huart1.Init.BaudRate = 115200;
    
        huart1.Init.WordLength = UART_WORDLENGTH_8B;
    
        huart1.Init.StopBits = UART_STOPBITS_1;
    
        huart1.Init.Parity = UART_PARITY_NONE;
    
        huart1.Init.Mode = UART_MODE_TX_RX;
    
        huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    
        huart1.Init.OverSampling = UART_OVERSAMPLING_16;
    
        if (HAL_UART_Init(&huart1) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    
    
        // 配置USART1接收中断
    
        HAL_UART_Receive_IT(&huart1, (uint8_t *)&rx_data, 1);
    
    }
    
    
    
    void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
    
        // USART接收完成中断处理函数
    
        if (huart == &huart1) {
    
            // 处理接收到的数据
    
            uint8_t rx_data;
    
            HAL_UART_Receive_IT(&huart1, &rx_data, 1);
    
    
    
            // 回显接收到的数据
    
            HAL_UART_Transmit(&huart1, &rx_data, 1, HAL_MAX_DELAY);
    
        }
    
    }
    
    
    
    void Error_Handler(void) {
    
        // 错误处理函数
    
        while (1) {
    
        }
    
    }
    
    
    
    // USART1中断服务函数
    
    void USART1_IRQHandler(void) {
    
        HAL_UART_IRQHandler(&huart1);
    
    }
    
    

    5.2 SPI编程

    SPI(Serial Peripheral Interface)是STM32L5系列单片机中的另一种串行通信接口,通常用于与外部设备(如传感器、存储器等)进行高速同步通信。以下是配置和使用SPI的基本步骤和示例代码。

    5.2.1 SPI配置

    在STM32CubeIDE中配置SPI的基本步骤如下:

    1. 打开STM32CubeMX:在项目中打开STM32CubeMX工具。

    2. 选择SPI:在“Pinout”视图中选择需要配置的SPI接口,如SPI1。

    3. 配置参数:在“Configuration”视图中配置SPI的参数,如时钟频率、数据模式和传输方向。

    4. 生成代码:点击“Generate Code”按钮,生成初始化代码和SPI配置代码。

    5.2.2 SPI操作示例

    以下是一个简单的SPI操作示例,通过SPI1接口与外部设备进行数据传输。

    
    #include "stm32l5xx_hal.h"
    
    
    
    // 定义SPI1的GPIO引脚
    
    #define SPI1_SCK_PIN GPIO_PIN_5
    
    #define SPI1_MISO_PIN GPIO_PIN_6
    
    #define SPI1_MOSI_PIN GPIO_PIN_7
    
    #define SPI1_GPIO_PORT GPIOA
    
    
    
    // 定义SPI1的句柄
    
    SPI_HandleTypeDef hspi1;
    
    
    
    void SystemClock_Config(void);
    
    static void MX_GPIO_Init(void);
    
    static void MX_SPI1_Init(void);
    
    
    
    int main(void) {
    
        HAL_Init();
    
        SystemClock_Config();
    
        MX_GPIO_Init();
    
        MX_SPI1_Init();
    
    
    
        // 发送测试数据
    
        uint8_t tx_data[] = {0xAA, 0xBB, 0xCC};
    
        HAL_SPI_Transmit(&hspi1, tx_data, 3, HAL_MAX_DELAY);
    
    
    
        while (1) {
    
            // 主循环
    
        }
    
    }
    
    
    
    void SystemClock_Config(void) {
    
        // 配置系统时钟
    
        RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    
        RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
    
    
    
        // 初始化RCC_OscInitTypeDef结构体
    
        RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
    
        RCC_OscInitStruct.MSIState = RCC_MSI_ON;
    
        RCC_OscInitStruct.MSICalibrationValue = 0;
    
        RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
    
        RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    
        RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
    
        RCC_OscInitStruct.PLL.PLLM = 1;
    
        RCC_OscInitStruct.PLL.PLLN = 40;
    
        RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
    
        RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
    
        RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
    
        if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    
    
        // 初始化RCC_ClkInitTypeDef结构体
    
        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_DIV1;
    
        RCC_ClkInitStruct.APB2CLKDivider = RCC_H_CLK_DIV1;
    
        if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    }
    
    
    
    static void MX_GPIO_Init(void) {
    
        // 定义GPIO结构体
    
        GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    
    
        // 使能GPIOA时钟
    
        __HAL_RCC_GPIOA_CLK_ENABLE();
    
    
    
        // 配置SPI1的SCK、MISO和MOSI引脚
    
        GPIO_InitStruct.Pin = SPI1_SCK_PIN | SPI1_MISO_PIN | SPI1_MOSI_PIN;
    
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    
        GPIO_InitStruct.Pull = GPIO_NOPULL;
    
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    
        GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
    
        HAL_GPIO_Init(SPI1_GPIO_PORT, &GPIO_InitStruct);
    
    }
    
    
    
    static void MX_SPI1_Init(void) {
    
        // 定义SPI1的初始化结构体
    
        hspi1.Instance = SPI1;
    
        hspi1.Init.Mode = SPI_MODE_MASTER;
    
        hspi1.Init.Direction = SPI_DIRECTION_2LINES;
    
        hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
    
        hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
    
        hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
    
        hspi1.Init.NSS = SPI_NSS_SOFT;
    
        hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
    
        hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
    
        hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
    
        hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
    
        hspi1.Init.CRCPolynomial = 7;
    
        hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
    
        hspi1.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
    
        if (HAL_SPI_Init(&hspi1) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    
    
        // 使能SPI1时钟
    
        __HAL_RCC_SPI1_CLK_ENABLE();
    
    }
    
    
    
    void Error_Handler(void) {
    
        // 错误处理函数
    
        while (1) {
    
        }
    
    }
    
    

    5.3 I2C编程

    I2C(Inter-Integrated Circuit)是STM32L5系列单片机中的另一种串行通信接口,通常用于与外部设备(如传感器、存储器等)进行低速同步通信。以下是配置和使用I2C的基本步骤和示例代码。

    5.3.1 I2C配置

    在STM32CubeIDE中配置I2C的基本步骤如下:

    1. 打开STM32CubeMX:在项目中打开STM32CubeMX工具。

    2. 选择I2C:在“Pinout”视图中选择需要配置的I2C接口,如I2C1。

    3. 配置参数:在“Configuration”视图中配置I2C的参数,如时钟频率和模式(主模式或从模式)。

    4. 生成代码:点击“Generate Code”按钮,生成初始化代码和I2C配置代码。

    5.3.2 I2C操作示例

    以下是一个简单的I2C操作示例,通过I2C1接口与外部设备进行数据传输。

    
    #include "stm32l5xx_hal.h"
    
    
    
    // 定义I2C1的GPIO引脚
    
    #define I2C1_SCL_PIN GPIO_PIN_6
    
    #define I2C1_SDA_PIN GPIO_PIN_7
    
    #define I2C1_GPIO_PORT GPIOB
    
    
    
    // 定义I2C1的句柄
    
    I2C_HandleTypeDef hi2c1;
    
    
    
    void SystemClock_Config(void);
    
    static void MX_GPIO_Init(void);
    
    static void MX_I2C1_Init(void);
    
    
    
    int main(void) {
    
        HAL_Init();
    
        SystemClock_Config();
    
        MX_GPIO_Init();
    
        MX_I2C1_Init();
    
    
    
        // 发送测试数据
    
        uint8_t tx_data[] = {0x01, 0x02, 0x03};
    
        HAL_I2C_Master_Transmit(&hi2c1, 0x50 << 1, tx_data, 3, HAL_MAX_DELAY);
    
    
    
        while (1) {
    
            // 主循环
    
        }
    
    }
    
    
    
    void SystemClock_Config(void) {
    
        // 配置系统时钟
    
        RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    
        RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
    
    
    
        // 初始化RCC_OscInitTypeDef结构体
    
        RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
    
        RCC_OscInitStruct.MSIState = RCC_MSI_ON;
    
        RCC_OscInitStruct.MSICalibrationValue = 0;
    
        RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
    
        RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    
        RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
    
        RCC_OscInitStruct.PLL.PLLM = 1;
    
        RCC_OscInitStruct.PLL.PLLN = 40;
    
        RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
    
        RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
    
        RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
    
        if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    
    
        // 初始化RCC_ClkInitTypeDef结构体
    
        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_DIV1;
    
        RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
    
        if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    }
    
    
    
    static void MX_GPIO_Init(void) {
    
        // 定义GPIO结构体
    
        GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    
    
        // 使能GPIOB时钟
    
        __HAL_RCC_GPIOB_CLK_ENABLE();
    
    
    
        // 配置I2C1的SCL和SDA引脚
    
        GPIO_InitStruct.Pin = I2C1_SCL_PIN | I2C1_SDA_PIN;
    
        GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    
        GPIO_InitStruct.Pull = GPIO_NOPULL;
    
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    
        GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;
    
        HAL_GPIO_Init(I2C1_GPIO_PORT, &GPIO_InitStruct);
    
    }
    
    
    
    static void MX_I2C1_Init(void) {
    
        // 定义I2C1的初始化结构体
    
        hi2c1.Instance = I2C1;
    
        hi2c1.Init.ClockSpeed = 100000;
    
        hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
    
        hi2c1.Init.OwnAddress1 = 0x00;
    
        hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
    
        hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
    
        hi2c1.Init.OwnAddress2 = 0x00;
    
        hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
    
        hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
    
        if (HAL_I2C_Init(&hi2c1) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    
    
        // 使能I2C1时钟
    
        __HAL_RCC_I2C1_CLK_ENABLE();
    
    }
    
    
    
    void Error_Handler(void) {
    
        // 错误处理函数
    
        while (1) {
    
        }
    
    }
    
    

    6. 模拟外设编程

    6.1 ADC编程

    ADC(Analog-to-Digital Converter)是STM32L5系列单片机中的模拟到数字转换器,用于将外部模拟信号转换为数字信号。以下是配置和使用ADC的基本步骤和示例代码。

    6.1.1 ADC配置

    在STM32CubeIDE中配置ADC的基本步骤如下:

    1. 打开STM32CubeMX:在项目中打开STM32CubeMX工具。

    2. 选择ADC:在“Pinout”视图中选择需要配置的ADC通道,如ADC1_IN1。

    3. 配置参数:在“Configuration”视图中配置ADC的参数,如采样时间、分辨率和触发源。

    4. 生成代码:点击“Generate Code”按钮,生成初始化代码和ADC配置代码。

    6.1.2 ADC操作示例

    以下是一个简单的ADC操作示例,通过ADC1通道读取外部模拟信号并显示结果。

    
    #include "stm32l5xx_hal.h"
    
    
    
    // 定义ADC1的GPIO引脚
    
    #define ADC1_PIN GPIO_PIN_0
    
    #define ADC1_GPIO_PORT GPIOA
    
    
    
    // 定义ADC1的句柄
    
    ADC_HandleTypeDef hadc1;
    
    
    
    void SystemClock_Config(void);
    
    static void MX_GPIO_Init(void);
    
    static void MX_ADC1_Init(void);
    
    
    
    int main(void) {
    
        HAL_Init();
    
        SystemClock_Config();
    
        MX_GPIO_Init();
    
        MX_ADC1_Init();
    
    
    
        // 启动ADC
    
        HAL_ADC_Start(&hadc1);
    
    
    
        while (1) {
    
            // 读取ADC值
    
            uint32_t adc_value;
    
            if (HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY) == HAL_OK) {
    
                adc_value = HAL_ADC_GetValue(&hadc1);
    
                // 处理ADC值
    
                // 例如,可以通过USART或LCD显示ADC值
    
            }
    
    
    
            // 延时
    
            HAL_Delay(1000);
    
        }
    
    }
    
    
    
    void SystemClock_Config(void) {
    
        // 配置系统时钟
    
        RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    
        RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
    
    
    
        // 初始化RCC_OscInitTypeDef结构体
    
        RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
    
        RCC_OscInitStruct.MSIState = RCC_MSI_ON;
    
        RCC_OscInitStruct.MSICalibrationValue = 0;
    
        RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
    
        RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    
        RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
    
        RCC_OscInitStruct.PLL.PLLM = 1;
    
        RCC_OscInitStruct.PLL.PLLN = 40;
    
        RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
    
        RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
    
        RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
    
        if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    
    
        // 初始化RCC_ClkInitTypeDef结构体
    
        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_DIV1;
    
        RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
    
        if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    }
    
    
    
    static void MX_GPIO_Init(void) {
    
        // 定义GPIO结构体
    
        GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    
    
        // 使能GPIOA时钟
    
        __HAL_RCC_GPIOA_CLK_ENABLE();
    
    
    
        // 配置ADC1的引脚
    
        GPIO_InitStruct.Pin = ADC1_PIN;
    
        GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    
        GPIO_InitStruct.Pull = GPIO_NOPULL;
    
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    
        HAL_GPIO_Init(ADC1_GPIO_PORT, &GPIO_InitStruct);
    
    }
    
    
    
    static void MX_ADC1_Init(void) {
    
        // 定义ADC1的初始化结构体
    
        ADC_ChannelConfTypeDef sConfig = {0};
    
    
    
        // 使能ADC1时钟
    
        __HAL_RCC_ADC1_CLK_ENABLE();
    
    
    
        // 初始化ADC1
    
        hadc1.Instance = ADC1;
    
        hadc1.Init.ScanConvMode = DISABLE;
    
        hadc1.Init.ContinuousConvMode = DISABLE;
    
        hadc1.Init.DiscontinuousConvMode = DISABLE;
    
        hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
    
        hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
    
        hadc1.Init.NbrOfConversion = 1;
    
        if (HAL_ADC_Init(&hadc1) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    
    
        // 配置ADC通道
    
        sConfig.Channel = ADC_CHANNEL_0;
    
        sConfig.Rank = ADC_REGULAR_RANK_1;
    
        sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;
    
        if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    }
    
    
    
    void Error_Handler(void) {
    
        // 错误处理函数
    
        while (1) {
    
        }
    
    }
    
    

    6.2 DAC编程

    DAC(Digital-to-Analog Converter)是STM32L5系列单片机中的数字到模拟转换器,用于将数字信号转换为模拟信号。以下是配置和使用DAC的基本步骤和示例代码。

    6.2.1 DAC配置

    在STM32CubeIDE中配置DAC的基本步骤如下:

    1. 打开STM32CubeMX:在项目中打开STM32CubeMX工具。

    2. 选择DAC:在“Pinout”视图中选择需要配置的DAC通道,如DAC1_CH1。

    3. 配置参数:在“Configuration”视图中配置DAC的参数,如输出波形和触发源。

    4. 生成代码:点击“Generate Code”按钮,生成初始化代码和DAC配置代码。

    6.2.2 DAC操作示例

    以下是一个简单的DAC操作示例,通过DAC1_CH1通道输出一个简单的模拟信号。

    
    #include "stm32l5xx_hal.h"
    
    
    
    // 定义DAC1的GPIO引脚
    
    #define DAC1_PIN GPIO_PIN_4
    
    #define DAC1_GPIO_PORT GPIOA
    
    
    
    // 定义DAC1的句柄
    
    DAC_HandleTypeDef hdac1;
    
    
    
    void SystemClock_Config(void);
    
    static void MX_GPIO_Init(void);
    
    static void MX_DAC1_Init(void);
    
    
    
    int main(void) {
    
        HAL_Init();
    
        SystemClock_Config();
    
        MX_GPIO_Init();
    
        MX_DAC1_Init();
    
    
    
        while (1) {
    
            // 输出模拟信号
    
            uint32_t dac_value = 2048; // 12位分辨率,中间值
    
            HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_1, DAC_ALIGN_12B_R, dac_value);
    
    
    
            // 延时
    
            HAL_Delay(1000);
    
        }
    
    }
    
    
    
    void SystemClock_Config(void) {
    
        // 配置系统时钟
    
        RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    
        RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
    
    
    
        // 初始化RCC_OscInitTypeDef结构体
    
        RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
    
        RCC_OscInitStruct.MSIState = RCC_MSI_ON;
    
        RCC_OscInitStruct.MSICalibrationValue = 0;
    
        RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
    
        RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    
        RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
    
        RCC_OscInitStruct.PLL.PLLM = 1;
    
        RCC_OscInitStruct.PLL.PLLN = 40;
    
        RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
    
        RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
    
        RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
    
        if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    
    
        // 初始化RCC_ClkInitTypeDef结构体
    
        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_DIV1;
    
        RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
    
        if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    }
    
    
    
    static void MX_GPIO_Init(void) {
    
        // 定义GPIO结构体
    
        GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    
    
        // 使能GPIOA时钟
    
        __HAL_RCC_GPIOA_CLK_ENABLE();
    
    
    
        // 配置DAC1的引脚
    
        GPIO_InitStruct.Pin = DAC1_PIN;
    
        GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    
        GPIO_InitStruct.Pull = GPIO_NOPULL;
    
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    
        HAL_GPIO_Init(DAC1_GPIO_PORT, &GPIO_InitStruct);
    
    }
    
    
    
    static void MX_DAC1_Init(void) {
    
        // 定义DAC1的初始化结构体
    
        DAC_ChannelConfTypeDef sConfig = {0};
    
    
    
        // 使能DAC1时钟
    
        __HAL_RCC_DAC1_CLK_ENABLE();
    
    
    
        // 初始化DAC1
    
        hdac1.Instance = DAC1;
    
        if (HAL_DAC_Init(&hdac1) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    
    
        // 配置DAC通道
    
        sConfig.DAC_Trigger = DAC_TRIGGER_NONE;
    
        sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
    
        if (HAL_DAC_ConfigChannel(&hdac1, &sConfig, DAC_CHANNEL_1) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    }
    
    
    
    void Error_Handler(void) {
    
        // 错误处理函数
    
        while (1) {
    
        }
    
    }
    
    

    6.3 模拟比较器编程

    STM32L5系列单片机中的模拟比较器(Comparator)用于比较两个模拟信号的大小,并输出比较结果。以下是配置和使用模拟比较器的基本步骤和示例代码。

    6.3.1 模拟比较器配置

    在STM32CubeIDE中配置模拟比较器的基本步骤如下:

    1. 打开STM32CubeMX:在项目中打开STM32CubeMX工具。

    2. 选择模拟比较器:在“Pinout”视图中选择需要配置的模拟比较器,如COMP1。

    3. 配置参数:在“Configuration”视图中配置模拟比较器的参数,如输入信号、输出模式和触发源。

    4. 生成代码:点击“Generate Code”按钮,生成初始化代码和模拟比较器配置代码。

    6.3.2 模拟比较器操作示例

    以下是一个简单的模拟比较器操作示例,通过COMP1比较两个模拟信号,并在结果变化时触发中断。

    
    #include "stm32l5xx_hal.h"
    
    
    
    // 定义模拟比较器引脚
    
    #define COMP1_INM_PIN GPIO_PIN_0
    
    #define COMP1_INP_PIN GPIO_PIN_1
    
    #define COMP1_OUT_PIN GPIO_PIN_2
    
    #define COMP1_GPIO_PORT GPIOA
    
    
    
    // 定义模拟比较器句柄
    
    COMP_HandleTypeDef hcomp1;
    
    
    
    void SystemClock_Config(void);
    
    static void MX_GPIO_Init(void);
    
    static void MX_COMP1_Init(void);
    
    void HAL_COMP_EXTI_Callback(uint16_t GPIO_Pin);
    
    
    
    int main(void) {
    
        HAL_Init();
    
        SystemClock_Config();
    
        MX_GPIO_Init();
    
        MX_COMP1_Init();
    
    
    
        while (1) {
    
            // 主循环
    
        }
    
    }
    
    
    
    void SystemClock_Config(void) {
    
        // 配置系统时钟
    
        RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    
        RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
    
    
    
        // 初始化RCC_OscInitTypeDef结构体
    
        RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
    
        RCC_OscInitStruct.MSIState = RCC_MSI_ON;
    
        RCC_OscInitStruct.MSICalibrationValue = 0;
    
        RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
    
        RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    
        RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
    
        RCC_OscInitStruct.PLL.PLLM = 1;
    
        RCC_OscInitStruct.PLL.PLLN = 40;
    
        RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
    
        RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
    
        RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
    
        if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    
    
        // 初始化RCC_ClkInitTypeDef结构体
    
        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_DIV1;
    
        RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
    
        if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    }
    
    
    
    static void MX_GPIO_Init(void) {
    
        // 定义GPIO结构体
    
        GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    
    
        // 使能GPIOA时钟
    
        __HAL_RCC_GPIOA_CLK_ENABLE();
    
    
    
        // 配置模拟比较器的引脚
    
        GPIO_InitStruct.Pin = COMP1_INM_PIN | COMP1_INP_PIN | COMP1_OUT_PIN;
    
        GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    
        GPIO_InitStruct.Pull = GPIO_NOPULL;
    
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    
        HAL_GPIO_Init(COMP1_GPIO_PORT, &GPIO_InitStruct);
    
    }
    
    
    
    static void MX_COMP1_Init(void) {
    
        // 定义模拟比较器初始化结构体
    
        COMP_InitTypeDef sCompInit = {0};
    
    
    
        // 使能模拟比较器时钟
    
        __HAL_RCC_COMP1_CLK_ENABLE();
    
    
    
        // 初始化模拟比较器
    
        hcomp1.Instance = COMP1;
    
        sCompInit.InvertedInput = COMP_INVERTEDINPUT_1_4VREFINT;
    
        sCompInit.NonInvertedInput = COMP_NONINVERTEDINPUT_IO1;
    
        sCompInit.Output = COMP_OUTPUT_1;
    
        sCompInit.OutputPol = COMP_OUTPUTPOL_NONINVERTED;
    
        sCompInit.Mode = COMP_MODE_HIGH_SPEED;
    
        sCompInit.PowerMode = COMP_POWERMODE_NORMAL;
    
        sCompInit.Hysteresis = COMP_HYSTERESIS_LOW;
    
        sCompInit.BlankingSrce = COMP_BLANKINGSRC_NONE;
    
        sCompInit.TriggerMode = COMP_TRIGGERMODE_NONE;
    
        if (HAL_COMP_Init(&hcomp1) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    
    
        // 配置模拟比较器中断
    
        HAL_COMP_EnableExti(&hcomp1);
    
        HAL_NVIC_SetPriority(COMP1_IRQn, 0, 0);
    
        HAL_NVIC_EnableIRQ(COMP1_IRQn);
    
    }
    
    
    
    void HAL_COMP_EXTI_Callback(uint16_t GPIO_Pin) {
    
        // 模拟比较器中断处理函数
    
        if (GPIO_Pin == COMP1_OUT_PIN) {
    
            // 比较结果变化时的处理
    
            // 例如,可以通过USART或LED指示结果
    
        }
    
    }
    
    
    
    void Error_Handler(void) {
    
        // 错误处理函数
    
        while (1) {
    
        }
    
    }
    
    
    
    // 模拟比较器中断服务函数
    
    void COMP1_IRQHandler(void) {
    
        HAL_COMP_IRQHandler(&hcomp1);
    
    }
    
    

    作者:kkchenkx

    物联沃分享整理
    物联沃-IOTWORD物联网 » STMicroelectronics 系列:STM32L5 系列_(6).STM32L5系列编程基础

    发表回复