STMicroelectronics 系列:STM32L4 系列_(1).STM32L4系列概述

STM32L4系列概述

1. 引言

STM32L4系列是STMicroelectronics公司推出的一款低功耗、高性能的32位ARM Cortex-M4内核微控制器。该系列微控制器广泛应用于各种嵌入式系统中,特别适合于需要高处理性能和低功耗的应用场景,如物联网设备、便携式医疗设备、智能家居等。本文将详细介绍STM32L4系列的特性、架构、引脚配置、电源管理、外设功能以及开发环境的设置。

2. 特性概述

2.1 性能特点

STM32L4系列微控制器采用ARM Cortex-M4内核,具备以下主要性能特点:

  • 高性能: 最高主频可达80MHz,提供强大的处理能力。

  • 低功耗: 支持多种低功耗模式,如睡眠模式、停止模式和待机模式,适合电池供电的应用。

  • 高集成度: 集成了多种外设,如ADC、DAC、UART、SPI、I2C、USB等,减少外部组件需求。

  • 大容量存储: 提供不同容量的闪存和RAM,满足不同应用需求。

  • 安全特性: 集成硬件加密引擎,支持AES、TRNG等安全功能。

  • 2.2 功耗管理

    STM32L4系列的低功耗特性是其一大亮点。以下是一些功耗管理的关键技术:

  • 动态电压调整 (DVS): 根据当前的负载情况动态调整供电电压,降低功耗。

  • 多种低功耗模式: 支持睡眠模式、停止模式和待机模式,每种模式下的功耗都有详细的数据说明。

  • 低功耗定时器: 如RTC和LPTIM,可在低功耗模式下继续运行,实现定时唤醒功能。

  • 2.3 集成外设

    STM32L4系列集成了丰富的外设,以下是一些主要的外设:

  • 模拟外设: 包括12位和16位ADC、12位DAC,支持多种采样率和转换模式。

  • 通信接口: 支持UART、SPI、I2C、USART、CAN、USB等多种通信接口,方便与其他设备进行数据交换。

  • 定时器: 包括通用定时器、高级定时器、低功耗定时器等,适用于各种定时和计数需求。

  • 实时钟 (RTC): 提供精确的时间基准,支持闰秒和闰年处理。

  • 外设接口: 如GPIO、DMA、SDIO、Ethernet MAC等,提供灵活的I/O操作和数据传输。

  • 2.4 存储器

    STM32L4系列提供了不同容量的闪存和RAM,满足不同应用的需求:

  • 闪存: 最高可达1MB,支持快速读写和擦除操作。

  • RAM: 最高可达320KB,提供高速数据处理能力。

  • 嵌入式EEPROM: 用于存储关键数据,支持多次擦写操作。

  • 2.5 安全特性

    STM32L4系列集成了多种安全特性,确保数据的安全性和系统的可靠性:

  • 硬件加密引擎: 支持AES、TRNG等加密算法,保护数据传输的安全性。

  • 安全启动: 支持安全启动和安全更新,防止固件被篡改。

  • 故障检测和保护: 内置多种故障检测机制,如电源电压监测、温度监测等,确保系统稳定运行。

  • 3. 架构详解

    3.1 内核架构

    STM32L4系列采用ARM Cortex-M4内核,具备以下特点:

  • 浮点运算单元 (FPU): 提供高效的浮点运算能力,适用于复杂算法的处理。

  • 嵌套向量中断控制器 (NVIC): 支持优先级中断处理,确保中断的及时响应。

  • 总线矩阵: 采用多层AMBA总线结构,确保高效的数据传输和处理。

  • 3.2 存储器架构

    STM32L4系列的存储器架构如下:

  • 闪存: 用于存储程序代码和常量数据。

  • RAM: 用于存储运行时数据和堆栈。

  • 嵌入式EEPROM: 用于存储关键数据,支持多次擦写操作。

  • 系统存储器: 包含启动代码和配置数据。

  • 3.3 电源管理

    STM32L4系列的电源管理架构如下:

  • 多电源域: 支持多个电源域,可根据需要关闭或开启某些域以降低功耗。

  • 低功耗模式: 包括睡眠模式、停止模式和待机模式,每种模式下的功耗和唤醒时间都有详细的数据说明。

  • 电源管理单元 (PWR): 负责电源的管理和控制,提供多种功耗优化策略。

  • 4. 引脚配置

    4.1 引脚功能

    STM32L4系列的引脚功能多样,以下是一些常见的引脚功能:

  • 电源引脚: VDD、VSS、VDDA、VSSA等,用于供电和接地。

  • 复位引脚: NRST,用于复位微控制器。

  • 时钟引脚: 晶振引脚、外部时钟引脚等,用于提供系统时钟。

  • I/O引脚: GPIO引脚,用于输入输出操作。

  • 模拟引脚: ADC和DAC引脚,用于模拟信号的采集和输出。

  • 通信引脚: UART、SPI、I2C、USART等通信接口的引脚。

  • 4.2 引脚映射

    STM32L4系列的引脚映射如下:

  • GPIO: 每个引脚可以配置为不同的功能,如输入、输出、外设功能等。

  • 外设引脚: 每个外设都有对应的引脚映射,可以在引脚配置表中查找。

  • 4.3 引脚配置示例

    以下是一个简单的GPIO配置示例,展示如何配置一个引脚为输出模式并控制其状态:

    
    #include "stm32l4xx_hal.h"
    
    
    
    // 定义GPIO端口和引脚
    
    #define LED_PORT GPIOA
    
    #define LED_PIN GPIO_PIN_5
    
    
    
    void GPIO_Init(void) {
    
        // 初始化GPIO端口
    
        __HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOA时钟
    
    
    
        // 配置GPIO引脚
    
        GPIO_InitTypeDef GPIO_InitStruct = {0};
    
        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 Toggle_LED(void) {
    
        // 切换LED状态
    
        HAL_GPIO_TogglePin(LED_PORT, LED_PIN);
    
    }
    
    
    
    int main(void) {
    
        HAL_Init(); // 初始化HAL库
    
    
    
        GPIO_Init(); // 初始化GPIO
    
    
    
        while (1) {
    
            Toggle_LED(); // 切换LED状态
    
            HAL_Delay(500); // 延时500ms
    
        }
    
    }
    
    

    4.4 电源引脚配置

    以下是一个简单的电源引脚配置示例,展示如何正确连接电源引脚:

    
    #include "stm32l4xx_hal.h"
    
    
    
    int main(void) {
    
        HAL_Init(); // 初始化HAL库
    
    
    
        // 使能PWR时钟
    
        __HAL_RCC_PWR_CLK_ENABLE();
    
        HAL_PWR_EnableBkUpAccess(); // 使能备份寄存器访问
    
    
    
        // 配置电源引脚
    
        __HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOA时钟
    
        __HAL_RCC_GPIOB_CLK_ENABLE(); // 使能GPIOB时钟
    
    
    
        // 连接VDD和VSS
    
        GPIO_InitTypeDef GPIO_InitStruct = {0};
    
        GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1;
    
        GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; // 模拟模式
    
        GPIO_InitStruct.Pull = GPIO_NOPULL; // 无上拉下拉
    
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    
    
        // 连接VDDA和VSSA
    
        GPIO_InitStruct.Pin = GPIO_PIN_2 | GPIO_PIN_3;
    
        HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    
    
    
        while (1) {
    
            // 主循环
    
        }
    
    }
    
    

    5. 开发环境设置

    5.1 开发工具

    STM32L4系列的开发工具如下:

  • STM32CubeMX: 用于初始化配置和代码生成。

  • STM32CubeIDE: 用于编写、编译和调试代码。

  • STM32CubeProgrammer: 用于烧录和调试固件。

  • 5.2 STM32CubeMX配置

    使用STM32CubeMX进行初始化配置的步骤如下:

    1. 选择微控制器: 在STM32CubeMX中选择STM32L4系列的微控制器型号。

    2. 配置时钟: 根据应用需求配置系统时钟和外设时钟。

    3. 配置GPIO: 选择需要的GPIO引脚并配置其功能和模式。

    4. 配置外设: 选择需要的外设并配置其参数。

    5. 生成代码: 生成初始化代码并导入到STM32CubeIDE中。

    5.3 STM32CubeIDE配置

    使用STM32CubeIDE进行代码开发的步骤如下:

    1. 导入项目: 将STM32CubeMX生成的项目导入到STM32CubeIDE中。

    2. 编写代码: 在主函数中编写应用代码。

    3. 编译代码: 编译项目以生成二进制文件。

    4. 烧录固件: 使用STM32CubeProgrammer将固件烧录到微控制器中。

    5. 调试代码: 使用调试工具进行代码调试和测试。

    5.4 代码生成示例

    以下是一个使用STM32CubeMX生成代码的示例:

    1. 选择微控制器: 选择STM32L476RG。

    2. 配置时钟: 设置系统时钟为80MHz,外设时钟为48MHz。

    3. 配置GPIO: 选择PA5引脚,配置为推挽输出模式。

    4. 配置外设: 选择USART1,配置为异步通信模式。

    5. 生成代码: 生成初始化代码并导入到STM32CubeIDE中。

    生成的初始化代码如下:

    
    #include "stm32l4xx_hal.h"
    
    
    
    // 定义GPIO端口和引脚
    
    #define LED_PORT GPIOA
    
    #define LED_PIN GPIO_PIN_5
    
    
    
    // 定义USART1
    
    UART_HandleTypeDef huart1;
    
    
    
    void SystemClock_Config(void);
    
    static void MX_GPIO_Init(void);
    
    static void MX_USART1_UART_Init(void);
    
    
    
    int main(void) {
    
        HAL_Init(); // 初始化HAL库
    
        SystemClock_Config(); // 配置系统时钟
    
        MX_GPIO_Init(); // 初始化GPIO
    
        MX_USART1_UART_Init(); // 初始化USART1
    
    
    
        while (1) {
    
            HAL_GPIO_TogglePin(LED_PORT, LED_PIN); // 切换LED状态
    
            HAL_Delay(500); // 延时500ms
    
        }
    
    }
    
    
    
    void SystemClock_Config(void) {
    
        // 配置系统时钟为80MHz
    
        RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    
        RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
    
    
    
        // 使能HSE振荡器
    
        RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    
        RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    
        if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    
    
        // 配置系统时钟
    
        RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    
        RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSE;
    
        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_4) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    }
    
    
    
    static void MX_GPIO_Init(void) {
    
        // 初始化GPIO
    
        __HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOA时钟
    
    
    
        GPIO_InitTypeDef GPIO_InitStruct = {0};
    
        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_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();
    
        }
    
    }
    
    
    
    void Error_Handler(void) {
    
        // 错误处理函数
    
        while (1) {
    
            // 无限循环
    
        }
    
    }
    
    

    5.5 代码调试示例

    以下是一个使用STM32CubeIDE进行代码调试的示例:

    1. 设置断点: 在main函数中设置断点,以便在调试时暂停执行。

    2. 启动调试: 使用STM32CubeIDE启动调试会话。

    3. 查看变量: 在调试模式下查看变量的值,确保程序按预期运行。

    4. 单步执行: 使用单步执行功能逐步执行代码,观察每一步的执行效果。

    6. 外设功能详解

    6.1 ADC功能

    STM32L4系列的ADC功能强大,支持12位和16位转换,具备以下特点:

  • 多通道: 支持多个通道的模拟信号采集。

  • 采样率: 支持多种采样率,满足不同应用需求。

  • 触发模式: 支持软件触发和硬件触发,如定时器触发、外部事件触发等。

  • 6.2 ADC配置示例

    以下是一个简单的ADC配置示例,展示如何配置ADC并进行模拟信号采集:

    
    #include "stm32l4xx_hal.h"
    
    
    
    // 定义ADC通道
    
    #define ADC_CHANNEL ADC_CHANNEL_1
    
    
    
    // 定义ADC句柄
    
    ADC_HandleTypeDef hadc;
    
    
    
    void SystemClock_Config(void);
    
    static void MX_GPIO_Init(void);
    
    static void MX_ADC_Init(void);
    
    
    
    int main(void) {
    
        HAL_Init(); // 初始化HAL库
    
        SystemClock_Config(); // 配置系统时钟
    
        MX_GPIO_Init(); // 初始化GPIO
    
        MX_ADC_Init(); // 初始化ADC
    
    
    
        while (1) {
    
            uint32_t adc_value;
    
            HAL_ADC_Start(&hadc); // 开始ADC转换
    
            HAL_ADC_PollForConversion(&hadc, 10); // 等待转换完成
    
            adc_value = HAL_ADC_GetValue(&hadc); // 获取转换结果
    
            HAL_ADC_Stop(&hadc); // 停止ADC转换
    
    
    
            // 处理ADC值
    
            if (adc_value > 2048) {
    
                HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET); // 点亮LED
    
            } else {
    
                HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET); // 熄灭LED
    
            }
    
    
    
            HAL_Delay(1000); // 延时1000ms
    
        }
    
    }
    
    
    
    void SystemClock_Config(void) {
    
        // 配置系统时钟为80MHz
    
        RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    
        RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
    
    
    
        // 使能HSE振荡器
    
        RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    
        RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    
        if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    
    
        // 配置系统时钟
    
        RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    
        RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSE;
    
        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_4) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    }
    
    
    
    static void MX_GPIO_Init(void) {
    
        // 初始化GPIO
    
        __HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOA时钟
    
    
    
        GPIO_InitTypeDef GPIO_InitStruct = {0};
    
        GPIO_InitStruct.Pin = GPIO_PIN_5;
    
        GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出模式
    
        GPIO_InitStruct.Pull = GPIO_NOPULL; // 无上拉下拉
    
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; // 低速
    
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    }
    
    
    
    static void MX_ADC_Init(void) {
    
        // 初始化ADC
    
        __HAL_RCC_ADC12_CLK_ENABLE(); // 使能ADC1时钟
    
    
    
        hadc.Instance = ADC1;
    
        hadc.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2; // 时钟预分频
    
        hadc.Init.Resolution = ADC_RESOLUTION_12B; // 12位分辨率
    
        hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT; // 右对齐
    
        hadc.Init.ScanConvMode = DISABLE; // 禁用扫描模式
    
        hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV; // 单次转换结束
    
        hadc.Init.ChannelConfig = ADC_CHANNEL_1; // 选择通道1
    
        hadc.Init.ContinuousConvMode = DISABLE; // 禁用连续转换模式
    
        hadc.Init.DiscontinuousConvMode = DISABLE; // 禁用不连续转换模式
    
        hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START; // 软件触发
    
        hadc.Init.DMAContinuousRequests = DISABLE; // 禁用DMA连续请求
    
        hadc.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN; // 覆盖数据
    
    
    
        if (HAL_ADC_Init(&hadc) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    
    
        // 配置ADC通道
    
        ADC_ChannelConfTypeDef sConfig = {0};
    
        sConfig.Channel = ADC_CHANNEL_1;
    
        sConfig.Rank = ADC_REGULAR_RANK_1;
    
        sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
    
        if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    }
    
    
    
    void Error_Handler(void) {
    
        // 错误处理函数
    
        while (1) {
    
            // 无限循环
    
        }
    
    }
    
    

    6.3 DAC功能

    STM32L4系列的DAC功能同样强大,支持12位输出,具备以下特点:

  • 多通道: 支持多个通道的模拟信号输出。

  • 采样率: 支持高速和低速模式,满足不同应用需求。

  • 触发模式: 支持软件触发和硬件触发,如定时器触发、外部事件触发等。

  • 6.4 DAC配置示例

    以下是一个简单的DAC配置示例,展示如何配置DAC并输出模拟信号:

    
    #include "stm32l4xx_hal.h"
    
    
    
    // 定义DAC通道
    
    #define DAC_CHANNEL DAC_CHANNEL_1
    
    
    
    // 定义DAC句柄
    
    DAC_HandleTypeDef hdac;
    
    
    
    void SystemClock_Config(void);
    
    static void MX_GPIO_Init(void);
    
    static void MX_DAC_Init(void);
    
    
    
    int main(void) {
    
        HAL_Init(); // 初始化HAL库
    
        SystemClock_Config(); // 配置系统时钟
    
        MX_GPIO_Init(); // 初始化GPIO
    
        MX_DAC_Init(); // 初始化DAC
    
    
    
        while (1) {
    
            // 输出模拟信号
    
            HAL_DAC_SetValue(&hdac, DAC_CHANNEL, DAC_ALIGN_12B_R, 2048); // 设置输出值为2048
    
            HAL_Delay(1000); // 延时1000ms
    
    
    
            HAL_DAC_SetValue(&hdac, DAC_CHANNEL, DAC_ALIGN_12B_R, 1024); // 设置输出值为1024
    
            HAL_Delay(1000); // 延时1000ms
    
        }
    
    }
    
    
    
    void SystemClock_Config(void) {
    
        // 配置系统时钟为80MHz
    
        RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    
        RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
    
    
    
        // 使能HSE振荡器
    
        RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    
        RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    
        if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    
    
        // 配置系统时钟
    
        RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    
        RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSE;
    
        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_4) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    }
    
    
    
    static void MX_GPIO_Init(void) {
    
        // 初始化GPIO
    
        __HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOA时钟
    
    
    
        GPIO_InitTypeDef GPIO_InitStruct = {0};
    
        GPIO_InitStruct.Pin = GPIO_PIN_5;
    
        GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出模式
    
        GPIO_InitStruct.Pull = GPIO_NOPULL; // 无上拉下拉
    
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; // 低速
    
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    }
    
    
    
    static void MX_DAC_Init(void) {
    
        // 初始化DAC
    
        __HAL_RCC_DAC12_CLK_ENABLE(); // 使能DAC时钟
    
    
    
        hdac.Instance = DAC1;
    
        hdac.Init.Trigger = DAC_TRIGGER_NONE; // 无触发
    
        hdac.Init.OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; // 使能输出缓冲
    
    
    
        if (HAL_DAC_Init(&hdac) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    
    
        // 配置DAC通道
    
        if (HAL_DAC_ConfigChannel(&hdac, &DAC_ChannelConfTypeDef, DAC_CHANNEL_1) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    }
    
    
    
    void Error_Handler(void) {
    
        // 错误处理函数
    
        while (1) {
    
            // 无限循环
    
        }
    
    }
    
    

    6.5 UART功能

    STM32L4系列的UART功能支持多种通信模式,具备以下特点:

  • 多通道: 支持多个UART通道。

  • 数据格式: 支持多种数据格式,如8位、9位、奇偶校验等。

  • 波特率: 支持多种波特率,满足不同通信需求。

  • 中断和DMA: 支持中断和DMA传输,提高通信效率。

  • 6.6 UART配置示例

    以下是一个简单的UART配置示例,展示如何配置UART并进行串口通信:

    
    #include "stm32l4xx_hal.h"
    
    
    
    // 定义UART句柄
    
    UART_HandleTypeDef huart1;
    
    
    
    void SystemClock_Config(void);
    
    static void MX_GPIO_Init(void);
    
    static void MX_USART1_UART_Init(void);
    
    
    
    int main(void) {
    
        HAL_Init(); // 初始化HAL库
    
        SystemClock_Config(); // 配置系统时钟
    
        MX_GPIO_Init(); // 初始化GPIO
    
        MX_USART1_UART_Init(); // 初始化UART
    
    
    
        while (1) {
    
            // 发送字符串
    
            char *message = "Hello, STM32L4!\r\n";
    
            HAL_UART_Transmit(&huart1, (uint8_t *)message, strlen(message), HAL_MAX_DELAY);
    
    
    
            HAL_Delay(1000); // 延时1000ms
    
        }
    
    }
    
    
    
    void SystemClock_Config(void) {
    
        // 配置系统时钟为80MHz
    
        RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    
        RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
    
    
    
        // 使能HSE振荡器
    
        RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    
        RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    
        if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    
    
        // 配置系统时钟
    
        RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    
        RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSE;
    
        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_4) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    }
    
    
    
    static void MX_GPIO_Init(void) {
    
        // 初始化GPIO
    
        __HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOA时钟
    
    
    
        GPIO_InitTypeDef GPIO_InitStruct = {0};
    
        GPIO_InitStruct.Pin = GPIO_PIN_9 | GPIO_PIN_10; // UART1_TX 和 UART1_RX
    
        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; // 选择USART1复用功能
    
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    }
    
    
    
    static void MX_USART1_UART_Init(void) {
    
        // 初始化UART
    
        __HAL_RCC_USART1_CLK_ENABLE(); // 使能UART1时钟
    
    
    
        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();
    
        }
    
    }
    
    
    
    void Error_Handler(void) {
    
        // 错误处理函数
    
        while (1) {
    
            // 无限循环
    
        }
    
    }
    
    

    7. 实际应用案例

    7.1 物联网设备

    STM32L4系列微控制器在物联网设备中具有广泛的应用。以下是一个简单的物联网设备示例,展示如何使用STM32L4系列进行数据采集和传输:

    
    #include "stm32l4xx_hal.h"
    
    #include "stdio.h"
    
    
    
    // 定义ADC通道
    
    #define ADC_CHANNEL ADC_CHANNEL_1
    
    
    
    // 定义UART句柄
    
    UART_HandleTypeDef huart1;
    
    
    
    // 定义ADC句柄
    
    ADC_HandleTypeDef hadc;
    
    
    
    void SystemClock_Config(void);
    
    static void MX_GPIO_Init(void);
    
    static void MX_USART1_UART_Init(void);
    
    static void MX_ADC_Init(void);
    
    
    
    int main(void) {
    
        HAL_Init(); // 初始化HAL库
    
        SystemClock_Config(); // 配置系统时钟
    
        MX_GPIO_Init(); // 初始化GPIO
    
        MX_USART1_UART_Init(); // 初始化UART
    
        MX_ADC_Init(); // 初始化ADC
    
    
    
        while (1) {
    
            uint32_t adc_value;
    
            HAL_ADC_Start(&hadc); // 开始ADC转换
    
            HAL_ADC_PollForConversion(&hadc, 10); // 等待转换完成
    
            adc_value = HAL_ADC_GetValue(&hadc); // 获取转换结果
    
            HAL_ADC_Stop(&hadc); // 停止ADC转换
    
    
    
            // 发送ADC值
    
            char buffer[50];
    
            sprintf(buffer, "ADC Value: %lu\r\n", adc_value);
    
            HAL_UART_Transmit(&huart1, (uint8_t *)buffer, strlen(buffer), HAL_MAX_DELAY);
    
    
    
            HAL_Delay(1000); // 延时1000ms
    
        }
    
    }
    
    
    
    void SystemClock_Config(void) {
    
        // 配置系统时钟为80MHz
    
        RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    
        RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
    
    
    
        // 使能HSE振荡器
    
        RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    
        RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    
        if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    
    
        // 配置系统时钟
    
        RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    
        RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSE;
    
        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_4) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    }
    
    
    
    static void MX_GPIO_Init(void) {
    
        // 初始化GPIO
    
        __HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOA时钟
    
    
    
        GPIO_InitTypeDef GPIO_InitStruct = {0};
    
        GPIO_InitStruct.Pin = GPIO_PIN_5;
    
        GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出模式
    
        GPIO_InitStruct.Pull = GPIO_NOPULL; // 无上拉下拉
    
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; // 低速
    
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    }
    
    
    
    static void MX_USART1_UART_Init(void) {
    
        // 初始化UART
    
        __HAL_RCC_USART1_CLK_ENABLE(); // 使能UART1时钟
    
    
    
        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();
    
        }
    
    }
    
    
    
    static void MX_ADC_Init(void) {
    
        // 初始化ADC
    
        __HAL_RCC_ADC12_CLK_ENABLE(); // 使能ADC1时钟
    
    
    
        hadc.Instance = ADC1;
    
        hadc.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2; // 时钟预分频
    
        hadc.Init.Resolution = ADC_RESOLUTION_12B; // 12位分辨率
    
        hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT; // 右对齐
    
        hadc.Init.ScanConvMode = DISABLE; // 禁用扫描模式
    
        hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV; // 单次转换结束
    
        hadc.Init.ChannelConfig = ADC_CHANNEL_1; // 选择通道1
    
        hadc.Init.ContinuousConvMode = DISABLE; // 禁用连续转换模式
    
        hadc.Init.DiscontinuousConvMode = DISABLE; // 禁用不连续转换模式
    
        hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START; // 软件触发
    
        hadc.Init.DMAContinuousRequests = DISABLE; // 禁用DMA连续请求
    
        hadc.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN; // 覆盖数据
    
    
    
        if (HAL_ADC_Init(&hadc) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    
    
        // 配置ADC通道
    
        ADC_ChannelConfTypeDef sConfig = {0};
    
        sConfig.Channel = ADC_CHANNEL_1;
    
        sConfig.Rank = ADC_REGULAR_RANK_1;
    
        sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
    
        if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    }
    
    
    
    void Error_Handler(void) {
    
        // 错误处理函数
    
        while (1) {
    
            // 无限循环
    
        }
    
    }
    
    

    7.2 便携式医疗设备

    STM32L4系列微控制器在便携式医疗设备中也有广泛应用。以下是一个简单的便携式医疗设备示例,展示如何使用STM32L4系列进行心率监测并显示结果:

    7.2.1 硬件配置
  • 心率传感器: 连接到ADC通道。

  • 显示屏: 通过SPI或I2C接口连接。

  • 电池: 通过低功耗模式延长电池寿命。

  • 7.2.2 代码示例
    
    #include "stm32l4xx_hal.h"
    
    #include "stdio.h"
    
    
    
    // 定义ADC通道
    
    #define ADC_CHANNEL ADC_CHANNEL_1
    
    
    
    // 定义UART句柄
    
    UART_HandleTypeDef huart1;
    
    
    
    // 定义ADC句柄
    
    ADC_HandleTypeDef hadc;
    
    
    
    // 定义I2C句柄
    
    I2C_HandleTypeDef hi2c1;
    
    
    
    // 定义显示屏地址
    
    #define DISPLAY_I2C_ADDRESS 0x3C
    
    
    
    void SystemClock_Config(void);
    
    static void MX_GPIO_Init(void);
    
    static void MX_USART1_UART_Init(void);
    
    static void MX_ADC_Init(void);
    
    static void MX_I2C1_Init(void);
    
    static void I2C_Write(uint8_t reg, uint8_t value);
    
    static void I2C_Read(uint8_t reg, uint8_t *value);
    
    
    
    int main(void) {
    
        HAL_Init(); // 初始化HAL库
    
        SystemClock_Config(); // 配置系统时钟
    
        MX_GPIO_Init(); // 初始化GPIO
    
        MX_USART1_UART_Init(); // 初始化UART
    
        MX_ADC_Init(); // 初始化ADC
    
        MX_I2C1_Init(); // 初始化I2C
    
    
    
        // 初始化显示屏
    
        I2C_Write(0x00, 0x01); // 命令:显示开启
    
    
    
        while (1) {
    
            uint32_t adc_value;
    
            HAL_ADC_Start(&hadc); // 开始ADC转换
    
            HAL_ADC_PollForConversion(&hadc, 10); // 等待转换完成
    
            adc_value = HAL_ADC_GetValue(&hadc); // 获取转换结果
    
            HAL_ADC_Stop(&hadc); // 停止ADC转换
    
    
    
            // 发送心率值
    
            char buffer[50];
    
            sprintf(buffer, "Heart Rate: %lu BPM\r\n", adc_value / 10); // 假设ADC值与心率成正比
    
            HAL_UART_Transmit(&huart1, (uint8_t *)buffer, strlen(buffer), HAL_MAX_DELAY);
    
    
    
            // 显示心率值
    
            char display_buffer[10];
    
            sprintf(display_buffer, "%lu BPM", adc_value / 10);
    
            I2C_Write(0x40, display_buffer[0]); // 显示第一位
    
            I2C_Write(0x41, display_buffer[1]); // 显示第二位
    
            I2C_Write(0x42, display_buffer[2]); // 显示第三位
    
    
    
            HAL_Delay(1000); // 延时1000ms
    
        }
    
    }
    
    
    
    void SystemClock_Config(void) {
    
        // 配置系统时钟为80MHz
    
        RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    
        RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
    
    
    
        // 使能HSE振荡器
    
        RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    
        RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    
        if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    
    
        // 配置系统时钟
    
        RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    
        RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSE;
    
        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_4) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    }
    
    
    
    static void MX_GPIO_Init(void) {
    
        // 初始化GPIO
    
        __HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOA时钟
    
    
    
        GPIO_InitTypeDef GPIO_InitStruct = {0};
    
        GPIO_InitStruct.Pin = GPIO_PIN_5;
    
        GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出模式
    
        GPIO_InitStruct.Pull = GPIO_NOPULL; // 无上拉下拉
    
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; // 低速
    
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    }
    
    
    
    static void MX_USART1_UART_Init(void) {
    
        // 初始化UART
    
        __HAL_RCC_USART1_CLK_ENABLE(); // 使能UART1时钟
    
    
    
        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();
    
        }
    
    }
    
    
    
    static void MX_ADC_Init(void) {
    
        // 初始化ADC
    
        __HAL_RCC_ADC12_CLK_ENABLE(); // 使能ADC1时钟
    
    
    
        hadc.Instance = ADC1;
    
        hadc.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2; // 时钟预分频
    
        hadc.Init.Resolution = ADC_RESOLUTION_12B; // 12位分辨率
    
        hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT; // 右对齐
    
        hadc.Init.ScanConvMode = DISABLE; // 禁用扫描模式
    
        hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV; // 单次转换结束
    
        hadc.Init.ChannelConfig = ADC_CHANNEL_1; // 选择通道1
    
        hadc.Init.ContinuousConvMode = DISABLE; // 禁用连续转换模式
    
        hadc.Init.DiscontinuousConvMode = DISABLE; // 禁用不连续转换模式
    
        hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START; // 软件触发
    
        hadc.Init.DMAContinuousRequests = DISABLE; // 禁用DMA连续请求
    
        hadc.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN; // 覆盖数据
    
    
    
        if (HAL_ADC_Init(&hadc) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    
    
        // 配置ADC通道
    
        ADC_ChannelConfTypeDef sConfig = {0};
    
        sConfig.Channel = ADC_CHANNEL_1;
    
        sConfig.Rank = ADC_REGULAR_RANK_1;
    
        sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
    
        if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    }
    
    
    
    static void MX_I2C1_Init(void) {
    
        // 初始化I2C
    
        __HAL_RCC_I2C1_CLK_ENABLE(); // 使能I2C1时钟
    
    
    
        hi2c1.Instance = I2C1;
    
        hi2c1.Init.ClockSpeed = 100000; // 100kHz
    
        hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
    
        hi2c1.Init.OwnAddress1 = 0;
    
        hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
    
        hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
    
        hi2c1.Init.OwnAddress2 = 0;
    
        hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
    
        hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
    
    
    
        if (HAL_I2C_Init(&hi2c1) != HAL_OK) {
    
            Error_Handler();
    
        }
    
    }
    
    
    
    static void I2C_Write(uint8_t reg, uint8_t value) {
    
        HAL_I2C_Master_Transmit(&hi2c1, DISPLAY_I2C_ADDRESS, &reg, 1, HAL_MAX_DELAY);
    
        HAL_I2C_Master_Transmit(&hi2c1, DISPLAY_I2C_ADDRESS, &value, 1, HAL_MAX_DELAY);
    
    }
    
    
    
    static void I2C_Read(uint8_t reg, uint8_t *value) {
    
        HAL_I2C_Master_Transmit(&hi2c1, DISPLAY_I2C_ADDRESS, &reg, 1, HAL_MAX_DELAY);
    
        HAL_I2C_Master_Receive(&hi2c1, DISPLAY_I2C_ADDRESS, value, 1, HAL_MAX_DELAY);
    
    }
    
    
    
    void Error_Handler(void) {
    
        // 错误处理函数
    
        while (1) {
    
            // 无限循环
    
        }
    
    }
    
    

    作者:kkchenkx

    物联沃分享整理
    物联沃-IOTWORD物联网 » STMicroelectronics 系列:STM32L4 系列_(1).STM32L4系列概述

    发表回复