stm32l051c8t6-stop模式-按键、串口可唤醒
时间: 2023-08-07 17:00:30 浏览: 282
STM32L051C8T6是一款低功耗的32位微控制器,具有丰富的外设接口和强大的计算能力。其中的Stop模式是一种低功耗模式,可以通过按键和串口来唤醒。
在Stop模式下,微控制器的主频停止工作,但由于内部的RTC(实时时钟)仍然工作,因此可以通过定时器或外部中断来保持唤醒功能。本文主要介绍通过按键和串口来唤醒的实现方法。
首先,通过按键来唤醒。在Stop模式下,可以配置一个外部中断引脚作为唤醒源,使按键按下时产生中断信号。通过配置外部中断的触发方式为上升或下降沿触发,设置中断优先级,并使能中断,当按键按下时,中断引脚会产生中断信号,使芯片从Stop模式唤醒并执行相应的中断服务程序。
其次,通过串口来唤醒。在Stop模式下,可以配置串口的特殊唤醒功能,使能串口的唤醒功能,并设置相应的触发条件。例如,可以设置当串口接收到特定的数据或位变化时触发唤醒。当满足特定的条件时,串口会产生唤醒信号,使芯片从Stop模式唤醒并执行相应的处理程序。
以上就是使用STM32L051C8T6的Stop模式实现按键和串口唤醒的简要介绍。具体的实现方法需要根据具体的应用场景和需求进行详细的配置和编程。通过合理配置外部中断和串口的唤醒功能,可以实现低功耗的同时保持按键和串口的唤醒功能,提高系统的灵活性和响应速度。
相关问题
stm32L051C8T6串口中断进不去
根据引用\[1\]和引用\[2\],可以看出在STM32的HAL库中,使用HAL_UART_Transmit函数可以发送数据到串口。而在引用\[3\]中提到,由于没有STM32L051C8T6这个型号的例程,可以尝试使用STM32L053R8这个型号的例程。所以,如果在STM32L051C8T6中串口中断进不去的情况下,可以先检查低功耗相关说明和寄存器操作,确保配置正确。另外,可以参考STM32L0中文参考手册来获取更详细的信息和指导。
#### 引用[.reference_title]
- *1* *2* [[STM32F103C8T6] 串口](https://blog.csdn.net/weixin_63303786/article/details/129529089)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item]
- *3* [STM32L051C8T6 HAL库 stop模式下的低功耗 RTC+外部中断唤醒 总结+源码](https://blog.csdn.net/qq_36075612/article/details/100605983)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item]
[ .reference_list ]
写一个STM32L051C8T6的HAL库代码,要求上电就进入地址设置轮询状态,用内部EEPROM存储9个地址,并在9个地址分别写入对应的瓶子放置位置数据,轮询三次检测对应位置是否放置了瓶子,若正确放置瓶子则闪三下绿灯,不正确则显示三下红灯,9个地址全部检测完成,则结束地址设置状态,进入工作状态
好的,我会根据你的要求编写STM32L051C8T6的HAL库代码,如下所示:
```c
#include "stm32l0xx_hal.h"
#include "stm32l0xx_hal_flash.h"
#include "stm32l0xx_hal_flash_ex.h"
#include "stm32l0xx_hal_gpio.h"
#include "stm32l0xx_hal_rcc.h"
#include "stm32l0xx_hal_rtc.h"
#include "stm32l0xx_hal_tim.h"
#include "stm32l0xx_hal_uart.h"
#include "stdlib.h"
#include "string.h"
/* 定义EEPROM存储的地址个数 */
#define ADDR_NUM 9
/* 定义瓶子放置位置数据的长度 */
#define POS_DATA_LEN 1
/* 定义绿灯的GPIO口和引脚 */
#define GREEN_LED_GPIO_PORT GPIOA
#define GREEN_LED_GPIO_PIN GPIO_PIN_1
/* 定义红灯的GPIO口和引脚 */
#define RED_LED_GPIO_PORT GPIOA
#define RED_LED_GPIO_PIN GPIO_PIN_2
/* 定义地址设置状态 */
#define ADDR_SET_STATUS 0
/* 定义工作状态 */
#define WORKING_STATUS 1
/* 定义全局变量,用于存储当前状态 */
uint8_t g_status = ADDR_SET_STATUS;
/* 定义全局变量,用于存储地址数据 */
uint8_t g_addr_data[ADDR_NUM][POS_DATA_LEN] = {{0}};
/* 定义全局变量,用于记录当前检测的地址 */
uint8_t g_current_addr = 0;
/* 定义全局变量,用于记录当前轮询的次数 */
uint8_t g_poll_count = 0;
/* 定义函数指针类型,用于存储闪灯函数的地址 */
typedef void (*led_func_ptr_t)(void);
/* 定义函数指针变量,用于存储闪灯函数的地址 */
led_func_ptr_t g_led_func_ptr = NULL;
/* 定义函数,用于初始化系统时钟 */
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
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_0) != HAL_OK)
{
Error_Handler();
}
}
/* 定义函数,用于初始化GPIO口 */
void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
/* 配置绿灯GPIO口 */
GPIO_InitStruct.Pin = GREEN_LED_GPIO_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GREEN_LED_GPIO_PORT, &GPIO_InitStruct);
/* 配置红灯GPIO口 */
GPIO_InitStruct.Pin = RED_LED_GPIO_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(RED_LED_GPIO_PORT, &GPIO_InitStruct);
}
/* 定义函数,用于初始化EEPROM */
void MX_EEPROM_Init(void)
{
FLASH_EraseInitTypeDef EraseInitStruct = {0};
uint32_t PageError = 0;
HAL_FLASH_Unlock();
/* 初始化擦除结构体 */
EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
EraseInitStruct.PageAddress = 0x08080000;
EraseInitStruct.NbPages = 1;
/* 擦除EEPROM所在的扇区 */
if (HAL_FLASHEx_Erase(&EraseInitStruct, &PageError) != HAL_OK)
{
Error_Handler();
}
HAL_FLASH_Lock();
}
/* 定义函数,用于向EEPROM写入数据 */
void EEPROM_WriteData(uint32_t addr, uint8_t *data, uint32_t len)
{
HAL_FLASH_Unlock();
/* 写入数据 */
for (uint32_t i = 0; i < len; i++)
{
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, addr + i, data[i]) != HAL_OK)
{
Error_Handler();
}
}
HAL_FLASH_Lock();
}
/* 定义函数,用于从EEPROM读取数据 */
void EEPROM_ReadData(uint32_t addr, uint8_t *data, uint32_t len)
{
for (uint32_t i = 0; i < len; i++)
{
data[i] = *(uint8_t *)(addr + i);
}
}
/* 定义函数,用于检测瓶子放置位置是否正确 */
void CheckBottlePos(uint8_t *pos_data)
{
/* 如果瓶子放置位置正确,闪三下绿灯 */
if (pos_data[0] == 0x01)
{
g_led_func_ptr = HAL_GPIO_TogglePin(GREEN_LED_GPIO_PORT, GREEN_LED_GPIO_PIN);
HAL_Delay(500);
g_led_func_ptr();
HAL_Delay(500);
g_led_func_ptr();
HAL_Delay(500);
g_led_func_ptr();
}
/* 如果瓶子放置位置不正确,闪三下红灯 */
else
{
g_led_func_ptr = HAL_GPIO_TogglePin(RED_LED_GPIO_PORT, RED_LED_GPIO_PIN);
HAL_Delay(500);
g_led_func_ptr();
HAL_Delay(500);
g_led_func_ptr();
HAL_Delay(500);
g_led_func_ptr();
}
}
/* 定义函数,用于检测瓶子放置位置 */
void PollBottlePos(void)
{
/* 读取当前地址的瓶子放置位置数据 */
uint8_t pos_data[POS_DATA_LEN] = {0};
EEPROM_ReadData(0x08080000 + g_current_addr * POS_DATA_LEN, pos_data, POS_DATA_LEN);
/* 检测瓶子放置位置是否正确 */
CheckBottlePos(pos_data);
}
/* 定义函数,用于进入地址设置状态 */
void EnterAddrSetStatus(void)
{
/* 初始化EEPROM */
MX_EEPROM_Init();
/* 进入地址设置状态 */
g_status = ADDR_SET_STATUS;
}
/* 定义函数,用于进入工作状态 */
void EnterWorkingStatus(void)
{
/* 进入工作状态 */
g_status = WORKING_STATUS;
}
/* 定义函数,用于设置地址 */
void SetAddr(uint8_t addr)
{
/* 存储当前地址 */
g_current_addr = addr;
/* 检测当前地址的瓶子放置位置 */
PollBottlePos();
/* 如果当前地址是最后一个地址,则重新开始轮询 */
if (g_current_addr == ADDR_NUM - 1)
{
g_current_addr = 0;
g_poll_count++;
/* 如果轮询次数为3,则进入工作状态 */
if (g_poll_count == 3)
{
EnterWorkingStatus();
}
}
/* 如果当前地址不是最后一个地址,则检测下一个地址 */
else
{
g_current_addr++;
}
}
/* 定义函数,用于初始化定时器 */
void MX_TIM_Init(void)
{
TIM_HandleTypeDef htim2 = {0};
__HAL_RCC_TIM2_CLK_ENABLE();
htim2.Instance = TIM2;
htim2.Init.Prescaler = 32000 - 1;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 500 - 1;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
}
/* 定义函数,用于初始化串口 */
void MX_USART1_UART_Init(void)
{
UART_HandleTypeDef huart1 = {0};
__HAL_RCC_USART1_CLK_ENABLE();
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 | UART_MODE_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)
{
}
}
int main(void)
{
/* 初始化系统时钟 */
HAL_Init();
SystemClock_Config();
/* 初始化GPIO口 */
MX_GPIO_Init();
/* 初始化定时器 */
MX_TIM_Init();
/* 初始化串口 */
MX_USART1_UART_Init();
/* 进入地址设置状态 */
EnterAddrSetStatus();
/* 循环执行 */
while (1)
{
/* 如果处于地址设置状态,则等待串口输入地址 */
if (g_status == ADDR_SET_STATUS)
{
/* 接收串口数据 */
uint8_t addr = 0;
HAL_UART_Receive(&huart1, &addr, 1, 100);
/* 如果接收到的地址不在范围内,则重新等待串口输入地址 */
if (addr < 1 || addr > ADDR_NUM)
{
continue;
}
/* 调用设置地址函数 */
SetAddr(addr - 1);
}
/* 如果处于工作状态,则定时轮询检测瓶子放置位置 */
else if (g_status == WORKING_STATUS)
{
HAL_TIM_Base_Start(&htim2);
HAL_TIM_Base_PollForTimeout(&htim2, 1000);
HAL_TIM_Base_Stop(&htim2);
/* 检测瓶子放置位置 */
PollBottlePos();
}
}
}
```
需要注意的是,以上代码仅供参考,具体实现根据实际情况进行调整。同时,上述代码中还使用了一个函数指针变量`g_led_func_ptr`,用于存储闪灯函数的地址,在调用闪灯函数时通过函数指针来调用,这样可以减少代码冗余。
阅读全文