1. 引言
STM32L4 系列是 STMicroelectronics 推出的低功耗高性能微控制器系列,基于 ARM Cortex-M4 内核,具有浮点运算单元(FPU)和数字信号处理(DSP)功能。该系列微控制器广泛应用于各种低功耗应用场景,如物联网设备、可穿戴设备、传感器节点等。本节将详细介绍 STM32L4 系列的主要特点和应用场景。
2. 主要特点
2.1 低功耗性能
STM32L4 系列微控制器通过多种低功耗技术实现了卓越的功耗管理。这些技术包括:
多种低功耗模式:包括睡眠模式、停止模式和待机模式,每种模式都有不同的功耗和唤醒时间。
低功耗外设:许多外设在低功耗模式下仍然可以工作,如 RTC、LPUART 等。
动态电压调整:根据系统负载动态调整供电电压,进一步降低功耗。
2.2 高性能处理
STM32L4 系列基于 ARM Cortex-M4 内核,最高主频可达 80 MHz,具备浮点运算单元(FPU)和数字信号处理(DSP)功能。这些特性使得 STM32L4 系列在处理复杂算法和高精度计算时表现出色。
2.3 丰富的外设
STM32L4 系列微控制器配备了丰富的外设,包括:
ADC:高精度模数转换器,支持多个通道。
DAC:数模转换器,用于生成模拟信号。
SPI:串行外设接口,用于与外部设备通信。
I2C:两线串行接口,用于与外部设备通信。
USART:通用异步收发传输器,支持多种通信协议。
USB:通用串行总线,支持 USB 2.0 全速和高速通信。
CAN:控制器局域网络,用于汽车和工业应用。
RTC:实时时钟,用于时间管理。
SQI:串行 Quad 接口,用于高速数据传输。
2.4 安全特性
STM32L4 系列微控制器具备多种安全特性,包括:
硬件加密:支持 AES 加密和解密,确保数据安全。
安全启动:支持安全启动,防止恶意代码启动。
读出保护:防止非法读取 Flash 内存中的代码。
写入保护:防止非法写入 Flash 内存中的代码。
3. 应用场景
3.1 物联网设备
STM32L4 系列微控制器的低功耗性能使其非常适合用于物联网设备。例如,可以用于智能家居中的传感器节点,通过低功耗模式和丰富的外设,实现长时间的电池供电和高效的数据采集与传输。
3.2 可穿戴设备
可穿戴设备对功耗有非常严格的要求。STM32L4 系列微控制器的低功耗特性和高性能处理能力,使得其在可穿戴设备中表现优异。例如,可以用于智能手表中的运动监测和心率检测,通过低功耗模式和 ADC、DAC 等外设,实现低功耗运行和高精度数据处理。
3.3 传感器节点
传感器节点需要长时间运行并保持低功耗。STM32L4 系列微控制器的RTC、低功耗 UART 等外设,使得其在传感器节点中应用广泛。例如,可以用于环境监测系统中的温度传感器节点,通过低功耗模式和 ADC,实现长时间的电池供电和高效的数据采集。
4. 开发环境
4.1 工具链
开发 STM32L4 系列微控制器需要使用合适的工具链,包括:
STM32CubeIDE:STMicroelectronics 官方的集成开发环境,支持代码生成、编译、调试等功能。
STM32CubeMX:用于配置微控制器的外设和时钟,生成初始化代码。
GNU Arm Embedded Toolchain:开源的编译工具链,支持 ARM 架构的编译和链接。
4.2 开发板
STM32L4 系列微控制器的开发板包括:
STM32L476G-Discovery:包含 STM32L476VG 微控制器,适合初学者和进阶开发。
STM32L496G-Discovery:包含 STM32L496VG 微控制器,支持更多外设和功能。
Nucleo-64:通用开发板,支持多种 STM32L4 系列微控制器,适合灵活开发。
5. 典型应用开发
5.1 低功耗模式编程
低功耗模式是 STM32L4 系列微控制器的一个重要特性。通过合理的模式选择和配置,可以显著降低系统的功耗。
5.1.1 睡眠模式
睡眠模式下,CPU 停止工作,但外设和系统时钟仍然运行。可以通过以下代码进入睡眠模式:
#include "stm32l4xx_hal.h"
void enter_sleep_mode(void) {
// 保存当前状态
__HAL_RCC_PWR_CLK_ENABLE();
HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
// 恢复状态
__HAL_RCC_PWR_CLK_DISABLE();
}
int main(void) {
HAL_Init();
// 初始化系统时钟
SystemClock_Config();
// 初始化GPIO
MX_GPIO_Init();
while (1) {
// 进入睡眠模式
enter_sleep_mode();
// 唤醒后继续运行
HAL_Delay(1000);
}
}
5.1.2 停止模式
停止模式下,CPU 和大部分外设停止工作,但一些低功耗外设(如 RTC)仍然运行。可以通过以下代码进入停止模式:
#include "stm32l4xx_hal.h"
void enter_stop_mode(void) {
// 保存当前状态
__HAL_RCC_PWR_CLK_ENABLE();
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
// 恢复状态
__HAL_RCC_PWR_CLK_DISABLE();
}
int main(void) {
HAL_Init();
// 初始化系统时钟
SystemClock_Config();
// 初始化GPIO
MX_GPIO_Init();
while (1) {
// 进入停止模式
enter_stop_mode();
// 唤醒后继续运行
HAL_Delay(1000);
}
}
5.1.3 待机模式
待机模式下,CPU 和所有外设停止工作,仅保留 RTC 和备份寄存器。可以通过以下代码进入待机模式:
#include "stm32l4xx_hal.h"
void enter_standby_mode(void) {
// 保存当前状态
__HAL_RCC_PWR_CLK_ENABLE();
HAL_PWR_EnterSTANDBYMode();
}
int main(void) {
HAL_Init();
// 初始化系统时钟
SystemClock_Config();
// 初始化GPIO
MX_GPIO_Init();
while (1) {
// 进入待机模式
enter_standby_mode();
// 唤醒后继续运行
// 注意:待机模式下,唤醒后需要重新初始化系统
}
}
5.2 ADC 编程
ADC(模数转换器)是 STM32L4 系列微控制器的重要外设,用于将模拟信号转换为数字信号。以下是一个简单的ADC编程示例:
5.2.1 初始化ADC
#include "stm32l4xx_hal.h"
ADC_HandleTypeDef hadc;
void ADC_Init(void) {
ADC_ChannelConfTypeDef sConfig = {0};
// 使能 ADC 时钟
__HAL_RCC_ADC_CLK_ENABLE();
// 初始化 ADC
hadc.Instance = ADC1;
hadc.Init.ScanConvMode = DISABLE; // 单通道模式
hadc.Init.ContinuousConvMode = DISABLE; // 单次转换模式
hadc.InitExternTrigConv = ADC_SOFTWARE_START; // 软件触发
hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT; // 右对齐
hadc.Init.NbrOfConversion = 1; // 1 次转换
HAL_ADC_Init(&hadc);
// 配置 ADC 通道
sConfig.Channel = ADC_CHANNEL_0; // 选择通道 0
sConfig.Rank = 1; // 通道 0 为第 1 优先级
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES; // 采样时间为 3 个周期
HAL_ADC_ConfigChannel(&hadc, &sConfig);
}
uint32_t ADC_Read(void) {
uint32_t adc_value;
// 启动 ADC 转换
HAL_ADC_Start(&hadc);
// 等待转换完成
HAL_ADC_PollForConversion(&hadc, HAL_MAX_DELAY);
// 读取转换结果
adc_value = HAL_ADC_GetValue(&hadc);
// 停止 ADC 转换
HAL_ADC_Stop(&hadc);
return adc_value;
}
int main(void) {
HAL_Init();
// 初始化系统时钟
SystemClock_Config();
// 初始化ADC
ADC_Init();
while (1) {
uint32_t adc_value = ADC_Read();
// 处理 ADC 读取的值
HAL_Delay(1000);
}
}
5.3 DAC 编程
DAC(数模转换器)用于将数字信号转换为模拟信号。以下是一个简单的 DAC 编程示例:
5.3.1 初始化 DAC
#include "stm32l4xx_hal.h"
DAC_HandleTypeDef hdac;
void DAC_Init(void) {
DAC_ChannelConfTypeDef sConfig = {0};
// 使能 DAC 时钟
__HAL_RCC_DAC1_CLK_ENABLE();
// 初始化 DAC
hdac.Instance = DAC1;
if (HAL_DAC_Init(&hdac) != HAL_OK) {
// 初始化错误处理
Error_Handler();
}
// 配置 DAC 通道
sConfig.DAC_SampleAndHold = DAC_SAMPLEANDHOLD_DISABLE;
sConfig.DAC_Trigger = DAC_TRIGGER_NONE;
sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
if (HAL_DAC_ConfigChannel(&hdac, &sConfig, DAC_CHANNEL_1) != HAL_OK) {
// 配置错误处理
Error_Handler();
}
}
void DAC_SetValue(uint32_t value) {
// 设置 DAC 通道 1 的值
if (HAL_DAC_SetValue(&hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, value) != HAL_OK) {
// 设置值错误处理
Error_Handler();
}
}
int main(void) {
HAL_Init();
// 初始化系统时钟
SystemClock_Config();
// 初始化 DAC
DAC_Init();
while (1) {
// 设置 DAC 通道 1 的值为 2048
DAC_SetValue(2048);
HAL_Delay(1000);
}
}
5.4 SPI 编程
SPI(串行外设接口)是一种高速的主从式通信接口,常用于与外部设备进行数据交换。以下是一个简单的 SPI 编程示例:
5.4.1 初始化 SPI
#include "stm32l4xx_hal.h"
SPI_HandleTypeDef hspi;
void SPI_Init(void) {
// 使能 SPI 时钟
__HAL_RCC_SPI1_CLK_ENABLE();
// 配置 SPI
hspi.Instance = SPI1;
hspi.Init.Mode = SPI_MODE_MASTER;
hspi.Init.Direction = SPI_DIRECTION_2LINES;
hspi.Init.DataSize = SPI_DATASIZE_8BIT;
hspi.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi.Init.NSS = SPI_NSS_SOFT;
hspi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
hspi.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi.Init.TIMode = SPI_TIMODE_DISABLE;
hspi.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi.Init.CRCPolynomial = 10;
hspi.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
hspi.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
if (HAL_SPI_Init(&hspi) != HAL_OK) {
// 初始化错误处理
Error_Handler();
}
}
void SPI_Transmit(uint8_t *data, uint16_t size) {
// 发送数据
if (HAL_SPI_Transmit(&hspi, data, size, HAL_MAX_DELAY) != HAL_OK) {
// 发送错误处理
Error_Handler();
}
}
int main(void) {
HAL_Init();
// 初始化系统时钟
SystemClock_Config();
// 初始化 SPI
SPI_Init();
while (1) {
uint8_t data[] = {0x55, 0xAA, 0xFF, 0x00};
// 发送数据
SPI_Transmit(data, sizeof(data));
HAL_Delay(1000);
}
}
5.5 I2C 编程
I2C(两线串行接口)是一种常用的低速通信接口,常用于与传感器和外部设备通信。以下是一个简单的 I2C 编程示例:
5.5.1 初始化 I2C
#include "stm32l4xx_hal.h"
I2C_HandleTypeDef hi2c;
void I2C_Init(void) {
// 使能 I2C 时钟
__HAL_RCC_I2C1_CLK_ENABLE();
// 配置 I2C
hi2c.Instance = I2C1;
hi2c.Init.ClockSpeed = 100000; // 100 kHz
hi2c.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c.Init.OwnAddress1 = 0;
hi2c.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c.Init.OwnAddress2 = 0;
hi2c.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c) != HAL_OK) {
// 初始化错误处理
Error_Handler();
}
}
void I2C_Write(uint16_t dev_addr, uint16_t reg_addr, uint8_t *data, uint16_t size) {
// 写入数据
if (HAL_I2C_Master_Transmit(&hi2c, dev_addr, data, size, HAL_MAX_DELAY) != HAL_OK) {
// 写入错误处理
Error_Handler();
}
}
void I2C_Read(uint16_t dev_addr, uint16_t reg_addr, uint8_t *data, uint16_t size) {
// 读取数据
if (HAL_I2C_Master_Receive(&hi2c, dev_addr, data, size, HAL_MAX_DELAY) != HAL_OK) {
// 读取错误处理
Error_Handler();
}
}
int main(void) {
HAL_Init();
// 初始化系统时钟
SystemClock_Config();
// 初始化 I2C
I2C_Init();
while (1) {
uint8_t data[] = {0x55, 0xAA, 0xFF, 0x00};
uint16_t dev_addr = 0x68; // 设备地址
uint16_t reg_addr = 0x00; // 寄存器地址
// 写入数据
I2C_Write(dev_addr, reg_addr, data, sizeof(data));
// 读取数据
I2C_Read(dev_addr, reg_addr, data, sizeof(data));
HAL_Delay(1000);
}
}
5.6 USART 编程
USART(通用异步收发传输器)是一种常用的串行通信接口,支持多种通信协议。以下是一个简单的 USART 编程示例:
5.6.1 初始化 USART
#include "stm32l4xx_hal.h"
UART_HandleTypeDef huart;
void USART_Init(void) {
// 使能 USART 时钟
__HAL_RCC_USART1_CLK_ENABLE();
// 配置 USART
huart.Instance = USART1;
huart.Init.BaudRate = 9600;
huart.Init.WordLength = UART_WORDLENGTH_8B;
huart.Init.StopBits = UART_STOPBITS_1;
huart.Init.Parity = UART_PARITY_NONE;
huart.Init.Mode = UART_MODE_TX_RX;
huart.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart) != HAL_OK) {
// 初始化错误处理
Error_Handler();
}
}
void USART_Transmit(uint8_t *data, uint16_t size) {
// 发送数据
if (HAL_UART_Transmit(&huart, data, size, HAL_MAX_DELAY) != HAL_OK) {
// 发送错误处理
Error_Handler();
}
}
void USART_Receive(uint8_t *data, uint16_t size) {
// 接收数据
if (HAL_UART_Receive(&huart, data, size, HAL_MAX_DELAY) != HAL_OK) {
// 接收错误处理
Error_Handler();
}
}
int main(void) {
HAL_Init();
// 初始化系统时钟
SystemClock_Config();
// 初始化 USART
USART_Init();
while (1) {
uint8_t data[] = "Hello, STM32### 5.6 USART 编程
USART(通用异步收发传输器)是一种常用的串行通信接口,支持多种通信协议。以下是一个简单的 USART 编程示例:
#### 5.6.1 初始化 USART
```c
#include "stm32l4xx_hal.h"
UART_HandleTypeDef huart;
void USART_Init(void) {
// 使能 USART 时钟
__HAL_RCC_USART1_CLK_ENABLE();
// 配置 USART
huart.Instance = USART1;
huart.Init.BaudRate = 9600; // 波特率设置为 9600
huart.Init.WordLength = UART_WORDLENGTH_8B; // 8 位数据长度
huart.Init.StopBits = UART_STOPBITS_1; // 1 位停止位
huart.Init.Parity = UART_PARITY_NONE; // 无奇偶校验
huart.Init.Mode = UART_MODE_TX_RX; // 发送和接收模式
huart.Init.HwFlowCtl = UART_HWCONTROL_NONE; // 无硬件流控制
huart.Init.OverSampling = UART_OVERSAMPLING_16; // 16 倍过采样
if (HAL_UART_Init(&huart) != HAL_OK) {
// 初始化错误处理
Error_Handler();
}
}
void USART_Transmit(uint8_t *data, uint16_t size) {
// 发送数据
if (HAL_UART_Transmit(&huart, data, size, HAL_MAX_DELAY) != HAL_OK) {
// 发送错误处理
Error_Handler();
}
}
void USART_Receive(uint8_t *data, uint16_t size) {
// 接收数据
if (HAL_UART_Receive(&huart, data, size, HAL_MAX_DELAY) != HAL_OK) {
// 接收错误处理
Error_Handler();
}
}
int main(void) {
HAL_Init();
// 初始化系统时钟
SystemClock_Config();
// 初始化 USART
USART_Init();
while (1) {
uint8_t data[] = "Hello, STM32L4!"; // 要发送的数据
// 发送数据
USART_Transmit(data, sizeof(data));
HAL_Delay(1000); // 延时 1 秒
}
}
5.7 USB 编程
USB(通用串行总线)是一种广泛使用的通信接口,支持 USB 2.0 全速和高速通信。以下是一个简单的 USB 编程示例:
5.7.1 初始化 USB
#include "stm32l4xx_hal.h"
#include "usbd_core.h"
#include "usbd_cdc.h"
USBD_HandleTypeDef hUsbDeviceFS;
void SystemClock_Config(void) {
// 系统时钟配置
// 例如:配置 HSI 为系统时钟源
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
// 使能 HSI 振荡器
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = 1;
RCC_OscInitStruct.PLL.PLLN = 8;
RCC_OscInitStruct.PLL.PLLR = 2;
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_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_1) != HAL_OK) {
Error_Handler();
}
}
void USB_Init(void) {
// 初始化 USB
USBD_Init(&hUsbDeviceFS, &USBD_Descriptor_FS, 0);
USBD_RegisterClass(&hUsbDeviceFS, &USBD_CDC);
USBD_CDC_RegisterInterface(&hUsbDeviceFS, &USBD_CDC_fops_FS);
USBD_Start(&hUsbDeviceFS);
}
void USB_SendData(uint8_t *data, uint16_t size) {
// 发送数据
USBD_CDC_SendData(&hUsbDeviceFS, data, size);
}
int main(void) {
HAL_Init();
// 初始化系统时钟
SystemClock_Config();
// 初始化 USB
USB_Init();
while (1) {
uint8_t data[] = "Hello, USB!"; // 要发送的数据
// 发送数据
USB_SendData(data, sizeof(data));
HAL_Delay(1000); // 延时 1 秒
}
}
5.8 CAN 编程
CAN(控制器局域网络)是一种广泛用于汽车和工业应用的通信接口。以下是一个简单的 CAN 编程示例:
5.8.1 初始化 CAN
#include "stm32l4xx_hal.h"
CAN_HandleTypeDef hcan;
void CAN_Init(void) {
// 使能 CAN 时钟
__HAL_RCC_CAN1_CLK_ENABLE();
// 配置 CAN
hcan.Instance = CAN1;
hcan.Init.Prescaler = 1;
hcan.Init.Mode = CAN_MODE_NORMAL;
hcan.Init.SyncJumpWidth = CAN_SJW_1TQ;
hcan.Init.TimeSeg1 = CAN_BS1_13TQ;
hcan.Init.TimeSeg2 = CAN_BS2_2TQ;
hcan.Init.TimeTriggeredMode = DISABLE;
hcan.Init.AutoBusOff = DISABLE;
hcan.Init.AutoWakeUp = DISABLE;
hcan.Init.AutoRetransmission = DISABLE;
hcan.Init.ReceiveFifoLocked = DISABLE;
hcan.Init.TransmitFifoPriority = DISABLE;
if (HAL_CAN_Init(&hcan) != HAL_OK) {
// 初始化错误处理
Error_Handler();
}
// 配置 CAN 过滤器
CAN_FilterTypeDef sFilterConfig;
sFilterConfig.FilterBank = 0;
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
sFilterConfig.FilterIdHigh = 0x0000;
sFilterConfig.FilterIdLow = 0x0000;
sFilterConfig.FilterMaskIdHigh = 0x0000;
sFilterConfig.FilterMaskIdLow = 0x0000;
sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;
sFilterConfig.FilterActivation = ENABLE;
sFilterConfig.BankNumber = 14;
if (HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK) {
// 过滤器配置错误处理
Error_Handler();
}
// 启动 CAN
if (HAL_CAN_Start(&hcan) != HAL_OK) {
// 启动错误处理
Error_Handler();
}
// 请求 CAN 中断
if (HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK) {
// 中断激活错误处理
Error_Handler();
}
}
void CAN_SendData(CAN_TxHeaderTypeDef *pTxHeader, uint8_t *pTxData, uint16_t size) {
// 发送 CAN 数据
if (HAL_CAN_AddTxMessage(&hcan, pTxHeader, pTxData, size) != HAL_OK) {
// 发送错误处理
Error_Handler();
}
}
void CAN_ReceiveData(CAN_RxHeaderTypeDef *pRxHeader, uint8_t *pRxData, uint16_t size) {
// 接收 CAN 数据
if (HAL_CAN_GetRxMessage(&hcan, CAN_RX_FIFO0, pRxHeader, pRxData, size) != HAL_OK) {
// 接收错误处理
Error_Handler();
}
}
int main(void) {
HAL_Init();
// 初始化系统时钟
SystemClock_Config();
// 初始化 CAN
CAN_Init();
while (1) {
CAN_TxHeaderTypeDef txHeader;
uint8_t txData[] = {0x01, 0x02, 0x03, 0x04};
uint32_t txMailbox;
// 配置 CAN 发送头部
txHeader.StdId = 0x321;
txHeader.ExtId = 0;
txHeader.RTR = CAN_RTR_DATA;
txHeader.IDE = CAN_ID_STD;
txHeader.DLC = 4;
// 发送数据
if (HAL_CAN_AddTxMessage(&hcan, &txHeader, txData, &txMailbox) != HAL_OK) {
// 发送错误处理
Error_Handler();
}
HAL_Delay(1000); // 延时 1 秒
}
}
5.9 RTC 编程
RTC(实时时钟)是 STM32L4 系列微控制器的重要外设,用于时间管理。以下是一个简单的 RTC 编程示例:
5.9.1 初始化 RTC
#include "stm32l4xx_hal.h"
RTC_HandleTypeDef hrtc;
void RTC_Init(void) {
// 使能 RTC 时钟
__HAL_RCC_RTC_ENABLE();
// 配置 RTC
hrtc.Instance = RTC;
hrtc.Init.AsynchPrediv = 127; // 异步预分频
hrtc.Init.OutPut = RTC_OUTPUT_DISABLE; // 输出禁用
hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH; // 输出极性
hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPEN_DRAIN; // 输出类型
if (HAL_RTC_Init(&hrtc) != HAL_OK) {
// 初始化错误处理
Error_Handler();
}
// 配置 RTC 时间
RTC_TimeTypeDef sTime = {0};
RTC_DateTypeDef sDate = {0};
// 设置时间
sTime.Hours = 12;
sTime.Minutes = 34;
sTime.Seconds = 56;
sTime.TimeFormat = RTC_HOURFORMAT_24;
sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
sTime.StoreOperation = RTC_STOREOPERATION_RESET;
if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK) {
// 设置时间错误处理
Error_Handler();
}
// 设置日期
sDate.WeekDay = RTC_WEEKDAY_TUESDAY;
sDate.Month = RTC_MONTH_SEPTEMBER;
sDate.Date = 15;
sDate.Year = 23; // 2023 年
if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN) != HAL_OK) {
// 设置日期错误处理
Error_Handler();
}
}
void RTC_GetTimeAndDate(RTC_TimeTypeDef *sTime, RTC_DateTypeDef *sDate) {
// 获取时间
if (HAL_RTC_GetTime(&hrtc, sTime, RTC_FORMAT_BIN) != HAL_OK) {
// 获取时间错误处理
Error_Handler();
}
// 获取日期
if (HAL_RTC_GetDate(&hrtc, sDate, RTC_FORMAT_BIN) != HAL_OK) {
// 获取日期错误处理
Error_Handler();
}
}
int main(void) {
HAL_Init();
// 初始化系统时钟
SystemClock_Config();
// 初始化 RTC
RTC_Init();
while (1) {
RTC_TimeTypeDef sTime;
RTC_DateTypeDef sDate;
// 获取当前时间和日期
RTC_GetTimeAndDate(&sTime, &sDate);
// 处理时间和日期
HAL_Delay(1000); // 延时 1 秒
}
}
5.10 SQI 编程
SQI(串行 Quad 接口)是一种高速数据传输接口,常用于与外部存储器进行数据交换。以下是一个简单的 SQI 编程示例:
5.10.1 初始化 SQI
#include "stm32l4xx_hal.h"
QUADSPI_HandleTypeDef hqspi;
void QUADSPI_Init(void) {
// 使能 QUADSPI 时钟
__HAL_RCC_QUADSPI_CLK_ENABLE();
// 配置 QUADSPI
hqspi.Instance = QUADSPI;
hqspi.Init.ClockPrescaler = 1;
hqspi.Init.FifoThreshold = 4;
hqspi.Init.SampleShifting = QSPI_SAMPLESHIFTING_HALFCYCLE;
hqspi.Init.FlashSize = 64;
hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_1_CYCLE;
hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0;
hqspi.Init.FlashId = QSPI_FLASH_ID_1;
hqspi.Init.DualQuad = QSPI_DUALQUAD_DISABLE;
if (HAL_QUADSPI_Init(&hqspi) != HAL_OK) {
// 初始化错误处理
Error_Handler();
}
}
void QUADSPI_Read(uint8_t *data, uint32_t address, uint32_t size) {
// 配置读取命令
QUADSPI_CommandTypeDef sCommand;
uint32_t p_address = address;
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
sCommand.Instruction = 0x03; // 读取指令
sCommand.AddressMode = QSPI_ADDRESS_1_LINE;
sCommand.AddressSize = QSPI_ADDRESS_24_BITS;
sCommand.Address = p_address;
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
sCommand.DataMode = QSPI_DATA_1_LINE;
sCommand.DummyCycles = 0;
sCommand.DQSMode = QSPI_DQS_DISABLE;
sCommand.SDRDMAMode = QSPI_SDRDMAMODE_DISABLE;
sCommand.NbData = size;
sCommand.DdrHoldHalfCycle = QSPI_DDR Hold_HALF_CYCLE_DISABLE;
// 发送命令
if (HAL_QUADSPI_Command(&hqspi, &sCommand, HAL_MAX_DELAY) != HAL_OK) {
// 命令发送错误处理
Error_Handler();
}
// 读取数据
if (HAL_QUADSPI_Receive(&hqspi, data, HAL_MAX_DELAY) != HAL_OK) {
// 读取数据错误处理
Error_Handler();
}
}
int main(void) {
HAL_Init();
// 初始化系统时钟
SystemClock_Config();
// 初始化 QUADSPI
QUADSPI_Init();
while (1) {
uint8_t data[256];
uint32_t address = 0x00000000; // 读取地址
uint32_t size = 256; // 读取大小
// 读取数据
QUADSPI_Read(data, address, size);
// 处理读取的数据
HAL_Delay(1000); // 延时 1 秒
}
}
6. 总结
STM32L4 系列微控制器凭借其低功耗性能、高性能处理能力、丰富的外设和强大的安全特性,成为众多低功耗应用场景的理想选择。通过本节的介绍,读者可以对 STM32L4 系列的主要特点和应用场景有更深入的了解。此外,通过典型应用开发示例,读者可以快速上手并开发出符合需求的应用程序。希望本指南对您的开发工作有所帮助。
7. 参考资料
STM32L4 系列数据手册:详细介绍了 STM32L4 系列微控制器的硬件特性和参数。
STM32CubeMX 用户手册:介绍了如何使用 STM32CubeMX 配置微控制器的外设和时钟。
STM32CubeIDE 用户手册:介绍了如何使用 STM32CubeIDE 进行代码开发和调试。
STM32L4 系列参考手册:提供了详细的编程指南和外设使用方法。
希望这些资料能够帮助您更好地理解和应用 STM32L4 系列微控制器。如果您有任何问题或需要进一步的帮助,请随时联系 STMicroelectronics 的技术支持团队。## 5.6 USART 编程
USART(通用异步收发传输器)是一种常用的串行通信接口,支持多种通信协议。以下是一个简单的 USART 编程示例:
5.6.1 初始化 USART
#include "stm32l4xx_hal.h"
UART_HandleTypeDef huart;
void USART_Init(void) {
// 使能 USART 时钟
__HAL_RCC_USART1_CLK_ENABLE();
// 配置 USART
huart.Instance = USART1;
huart.Init.BaudRate = 9600; // 波特率设置为 9600
huart.Init.WordLength = UART_WORDLENGTH_8B; // 8 位数据长度
huart.Init.StopBits = UART_STOPBITS_1; // 1 位停止位
huart.Init.Parity = UART_PARITY_NONE; // 无奇偶校验
huart.Init.Mode = UART_MODE_TX_RX; // 发送和接收模式
huart.Init.HwFlowCtl = UART_HWCONTROL_NONE; // 无硬件流控制
huart.Init.OverSampling = UART_OVERSAMPLING_16; // 16 倍过采样
if (HAL_UART_Init(&huart) != HAL_OK) {
// 初始化错误处理
Error_Handler();
}
}
void USART_Transmit(uint8_t *data, uint16_t size) {
// 发送数据
if (HAL_UART_Transmit(&huart, data, size, HAL_MAX_DELAY) != HAL_OK) {
// 发送错误处理
Error_Handler();
}
}
void USART_Receive(uint8_t *data, uint16_t size) {
// 接收数据
if (HAL_UART_Receive(&huart, data, size, HAL_MAX_DELAY) != HAL_OK) {
// 接收错误处理
Error_Handler();
}
}
int main(void) {
HAL_Init();
// 初始化系统时钟
SystemClock_Config();
// 初始化 USART
USART_Init();
while (1) {
uint8_t data[] = "Hello, STM32L4!"; // 要发送的数据
// 发送数据
USART_Transmit(data, sizeof(data));
HAL_Delay(1000); // 延时 1 秒
}
}
5.7 USB 编程
USB(通用串行总线)是一种广泛使用的通信接口,支持 USB 2.0 全速和高速通信。以下是一个简单的 USB 编程示例:
5.7.1 初始化 USB
#include "stm32l4xx_hal.h"
#include "usbd_core.h"
#include "usbd_cdc.h"
USBD_HandleTypeDef hUsbDeviceFS;
void SystemClock_Config(void) {
// 系统时钟配置
// 例如:配置 HSI 为系统时钟源
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
// 使能 HSI 振荡器
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = 1;
RCC_OscInitStruct.PLL.PLLN = 8;
RCC_OscInitStruct.PLL.PLLR = 2;
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_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_1) != HAL_OK) {
Error_Handler();
}
}
void USB_Init(void) {
// 初始化 USB
USBD_Init(&hUsbDeviceFS, &USBD_Descriptor_FS, 0);
USBD_RegisterClass(&hUsbDeviceFS, &USBD_CDC);
USBD_CDC_RegisterInterface(&hUsbDeviceFS, &USBD_CDC_fops_FS);
USBD_Start(&hUsbDeviceFS);
}
void USB_SendData(uint8_t *data, uint16_t size) {
// 发送数据
USBD_CDC_SendData(&hUsbDeviceFS, data, size);
}
int main(void) {
HAL_Init();
// 初始化系统时钟
SystemClock_Config();
// 初始化 USB
USB_Init();
while (1) {
uint8_t data[] = "Hello, USB!"; // 要发送的数据
// 发送数据
USB_SendData(data, sizeof(data));
HAL_Delay(1000); // 延时 1 秒
}
}
5.8 CAN 编程
CAN(控制器局域网络)是一种广泛用于汽车和工业应用的通信接口。以下是一个简单的 CAN 编程示例:
5.8.1 初始化 CAN
#include "stm32l4xx_hal.h"
CAN_HandleTypeDef hcan;
void CAN_Init(void) {
// 使能 CAN 时钟
__HAL_RCC_CAN1_CLK_ENABLE();
// 配置 CAN
hcan.Instance = CAN1;
hcan.Init.Prescaler = 1;
hcan.Init.Mode = CAN_MODE_NORMAL;
hcan.Init.SyncJumpWidth = CAN_SJW_1TQ;
hcan.Init.TimeSeg1 = CAN_BS1_13TQ;
hcan.Init.TimeSeg2 = CAN_BS2_2TQ;
hcan.Init.TimeTriggeredMode = DISABLE;
hcan.Init.AutoBusOff = DISABLE;
hcan.Init.AutoWakeUp = DISABLE;
hcan.Init.AutoRetransmission = DISABLE;
hcan.Init.ReceiveFifoLocked = DISABLE;
hcan.Init.TransmitFifoPriority = DISABLE;
if (HAL_CAN_Init(&hcan) != HAL_OK) {
// 初始化错误处理
Error_Handler();
}
// 配置 CAN 过滤器
CAN_FilterTypeDef sFilterConfig;
sFilterConfig.FilterBank = 0;
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
sFilterConfig.FilterIdHigh = 0x0000;
sFilterConfig.FilterIdLow = 0x0000;
sFilterConfig.FilterMaskIdHigh = 0x0000;
sFilterConfig.FilterMaskIdLow = 0x0000;
sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;
sFilterConfig.FilterActivation = ENABLE;
sFilterConfig.BankNumber = 14;
if (HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK) {
// 过滤器配置错误处理
Error_Handler();
}
// 启动 CAN
if (HAL_CAN_Start(&hcan) != HAL_OK) {
// 启动错误处理
Error_Handler();
}
// 请求 CAN 中断
if (HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK) {
// 中断激活错误处理
Error_Handler();
}
}
void CAN_SendData(CAN_TxHeaderTypeDef *pTxHeader, uint8_t *pTxData, uint16_t size) {
// 发送 CAN 数据
if (HAL_CAN_AddTxMessage(&hcan, pTxHeader, pTxData, size) != HAL_OK) {
// 发送错误处理
Error_Handler();
}
}
void CAN_ReceiveData(CAN_RxHeaderTypeDef *pRxHeader, uint8_t *pRxData, uint16_t size) {
// 接收 CAN 数据
if (HAL_CAN_GetRxMessage(&hcan, CAN_RX_FIFO0, pRxHeader, pRxData, size) != HAL_OK) {
// 接收错误处理
Error_Handler();
}
}
int main(void) {
HAL_Init();
// 初始化系统时钟
SystemClock_Config();
// 初始化 CAN
CAN_Init();
while (1) {
CAN_TxHeaderTypeDef txHeader;
uint8_t txData[] = {0x01, 0x02, 0x03, 0x04};
uint32_t txMailbox;
// 配置 CAN 发送头部
txHeader.StdId = 0x321;
txHeader.ExtId = 0;
txHeader.RTR = CAN_RTR_DATA;
txHeader.IDE = CAN_ID_STD;
txHeader.DLC = 4;
// 发送数据
if (HAL_CAN_AddTxMessage(&hcan, &txHeader, txData, &txMailbox) != HAL_OK) {
// 发送错误处理
Error_Handler();
}
HAL_Delay(1000); // 延时 1 秒
}
}
5.9 RTC 编程
RTC(实时时钟)是 STM32L4 系列微控制器的重要外设,用于时间管理。以下是一个简单的 RTC 编程示例:
5.9.1 初始化 RTC
#include "stm32l4xx_hal.h"
RTC_HandleTypeDef hrtc;
void RTC_Init(void) {
// 使能 RTC 时钟
__HAL_RCC_RTC_ENABLE();
// 配置 RTC
hrtc.Instance = RTC;
hrtc.Init.AsynchPrediv = 127; // 异步预分频
hrtc.Init.OutPut = RTC_OUTPUT_DISABLE; // 输出禁用
hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH; // 输出极性
hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPEN_DRAIN; // 输出类型
if (HAL_RTC_Init(&hrtc) != HAL_OK) {
// 初始化错误处理
Error_Handler();
}
// 配置 RTC 时间
RTC_TimeTypeDef sTime = {0};
RTC_DateTypeDef sDate = {0};
// 设置时间
sTime.Hours = 12;
sTime.Minutes = 34;
sTime.Seconds = 56;
sTime.TimeFormat = RTC_HOURFORMAT_24;
sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
sTime.StoreOperation = RTC_STOREOPERATION_RESET;
if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK) {
// 设置时间错误处理
Error_Handler();
}
// 设置日期
sDate.WeekDay = RTC_WEEKDAY_TUESDAY;
sDate.Month = RTC_MONTH_SEPTEMBER;
sDate.Date = 15;
sDate.Year = 23; // 2023 年
if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN) != HAL_OK) {
// 设置日期错误处理
Error_Handler();
}
}
void RTC_GetTimeAndDate(RTC_TimeTypeDef *sTime, RTC_DateTypeDef *sDate) {
// 获取时间
if (HAL_RTC_GetTime(&hrtc, sTime, RTC_FORMAT_BIN) != HAL_OK) {
// 获取时间错误处理
Error_Handler();
}
// 获取日期
if (HAL_RTC_GetDate(&hrtc, sDate, RTC_FORMAT_BIN) != HAL_OK) {
// 获取日期错误处理
Error_Handler();
}
}
int main(void) {
HAL_Init();
// 初始化系统时钟
SystemClock_Config();
// 初始化 RTC
RTC_Init();
while (1) {
RTC_TimeTypeDef sTime;
RTC_DateTypeDef sDate;
// 获取当前时间和日期
RTC_GetTimeAndDate(&sTime, &sDate);
// 处理时间和日期
HAL_Delay(1000); // 延时 1 秒
}
}
5.10 SQI 编程
SQI(串行 Quad 接口)是一种高速数据传输接口,常用于与外部存储器进行数据交换。以下是一个简单的 SQI 编程示例:
5.10.1 初始化 SQI
#include "stm32l4xx_hal.h"
QUADSPI_HandleTypeDef hqspi;
void QUADSPI_Init(void) {
// 使能 QUADSPI 时钟
__HAL_RCC_QUADSPI_CLK_ENABLE();
// 配置 QUADSPI
hqspi.Instance = QUADSPI;
hqspi.Init.ClockPrescaler = 1;
hqspi.Init.FifoThreshold = 4;
hqspi.Init.SampleShifting = QSPI_SAMPLESHIFTING_HALFCYCLE;
hqspi.Init.FlashSize = 64;
hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_1_CYCLE;
hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0;
hqspi.Init.FlashId = QSPI_FLASH_ID_1;
hqspi.Init.DualQuad = QSPI_DUALQUAD_DISABLE;
if (HAL_QUADSPI_Init(&hqspi) != HAL_OK) {
// 初始化错误处理
Error_Handler();
}
}
void QUADSPI_Read(uint8_t *data, uint32_t address, uint32_t size) {
// 配置读取命令
QUADSPI_CommandTypeDef sCommand;
uint32_t p_address = address;
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
sCommand.Instruction = 0x03; // 读取指令
sCommand.AddressMode = QSPI_ADDRESS_1_LINE;
sCommand.AddressSize = QSPI_ADDRESS_24_BITS;
sCommand.Address = p_address;
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
sCommand.DataMode = QSPI_DATA_1_LINE;
sCommand.DummyCycles = 0;
sCommand.DQSMode = QSPI_DQS_DISABLE;
sCommand.SDRDMAMode = QSPI_SDRDMAMODE_DISABLE;
sCommand.NbData = size;
sCommand.DdrHoldHalfCycle = QSPI_DDR_HOLD_HALF_CYCLE_DISABLE;
// 发送命令
if (HAL_QUADSPI_Command(&hqspi, &sCommand, HAL_MAX_DELAY) != HAL_OK) {
// 命令发送错误处理
Error_Handler();
}
// 读取数据
if (HAL_QUADSPI_Receive(&hqspi, data, HAL_MAX_DELAY) != HAL_OK) {
// 读取数据错误处理
Error_Handler();
}
}
int main(void) {
HAL_Init();
// 初始化系统时钟
SystemClock_Config();
// 初始化 QUADSPI
QUADSPI_Init();
while (1) {
uint8_t data[256];
uint32_t address = 0x00000000; // 读取地址
uint32_t size = 256; // 读取大小
// 读取数据
QUADSPI_Read(data, address, size);
// 处理读取的数据
HAL_Delay(1000); // 延时 1 秒
}
}
6. 总结
STM32L4 系列微控制器凭借其低功耗性能、高性能处理能力、丰富的外设和强大的安全特性,成为众多低功耗应用场景的理想选择。通过本节的介绍,读者可以对 STM32L4 系列的主要特点和应用场景有更深入的了解。此外,通过典型应用开发示例,读者可以快速上手并开发出符合需求的应用程序。希望本指南对您的开发工作有所帮助。
7. 参考资料
STM32L4 系列数据手册:详细介绍了 STM32L4 系列微控制器的硬件特性和参数。
STM32CubeMX 用户手册:介绍了如何使用 STM32CubeMX 配置微控制器的外设和时钟。
STM32CubeIDE 用户手册:介绍了如何使用 STM32CubeIDE 进行代码开发和调试。
STM32L4 系列参考手册:提供了详细的编程指南和外设使用方法。
希望这些资料能够帮助您更好地理解和应用 STM32L4 系列微控制器。如果您有任何问题或需要进一步的帮助,请随时联系 STMicroelectronics 的技术支持团队。
8. 进一步学习
8.1 深入了解低功耗技术
STM32L4 系列的低功耗技术是其一大亮点。要进一步了解低功耗技术,可以参考以下资料:
《低功耗嵌入式系统设计》:这本书详细介绍了低功耗嵌入式系统的原理和设计方法,适合深入学习。
STMicroelectronics 低功耗应用指南:官方提供的低功耗应用指南,涵盖了多种低功耗技术的实现和优化方法。
8.2 学习高级外设和功能
除了基础的外设之外,STM32L4 系列还支持许多高级功能,如 DMA、RTOS 等。可以参考以下资料:
《STM32 DMA 应用编程》:这本书详细介绍了 DMA 的原理和应用,适合需要高性能数据传输的开发者。
《FreeRTOS 用户手册》:FreeRTOS 是一个流行的实时操作系统,适用于多任务处理和资源管理。
8.3 参与社区和论坛
参与 STM32 社区和论坛可以帮助您解决开发中的问题,分享经验,获取最新信息。推荐以下社区和论坛:
STM32 社区:STMicroelectronics 官方社区,提供技术支持和交流平台。
Electronics Stack Exchange:一个电子工程师和技术爱好者的问答社区,涉及广泛的技术问题。
希望这些资源能够帮助您在 STM32L4 系列微控制器开发中取得更好的成果。祝您开发顺利!
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/weixin_42749425/article/details/143379837
|
共1人点赞
|