0x0E PWR

本文的大部分内容来自B站up主 江协科技, 此文只供本人学习记录用途, 侵删

一、PWR

  • PWR(Power Control)电源控制PWR负责管理STM32内部的电源供电部分,可以实现可编程电压监测器和低功耗模式的功能
  • 可编程电压监测器(PVD)可以监控VDD电源电压,当VDD下降到PVD阀值以下或上升到PVD阀值之上时,PVD会触发中断,用于执行紧急关闭任务 (本节用不到 了解即可)
  • 低功耗模式包括睡眠模式(Sleep)、停机模式(Stop)和待机模式(Standby),可在系统空闲时,降低STM32的功耗,延长设备使用时间

二、电源框图

stm32的电源有四个区域

  • VDDA供电区域 一般这里直接接VDD了
  • VDD供电区域
  • 1.8V供电区域 通过VDD区域里的的电压调节器去到CPU, 存储器, 外设等核心电路
  • 后备供电区域

image-20231105181700607

三、低功耗模式

  • 随眠模式关闭CPU时钟 可被任意中断唤醒

  • 停机模式关闭整个1.8V供电区域 只能被外部中断唤醒

    这四个借道外部中断的通道, 就可以用于唤醒停机模式

    image-20231105191030974

  • 待机模式关闭几乎所有电路 只能被WKUP(PA0)的上升延, RTC闹钟, 复位, 看门狗唤醒

image-20231105182053384

image-20231105182134415

四、示例代码

1 修改主频

虽然能达到低功耗的效果, 但是以降低性能为代价, 而且类似Delay这样依赖系统主频计时的代码也会混乱,不建议使用

这是System_stm32f10x.c/h中外部可调用的三个函数/变量, 系统默认是用HSI(8Mhz)为主频, 不过复位时, 启动函数会调用SystemInit 把系统主频改成HSE经过锁相环倍频之后的频率 一般9倍频就是72Mhz

extern uint32_t SystemCoreClock;           //该变量存放系统主频
extern void SystemInit(void);              //初始化时钟
extern void SystemCoreClockUpdate(void);   //更新SystemCoreClock的值

本博客使用的不是超值系列产品, 所以只需改System_stm32f10x.c中 这段代码#else下的define 就能改变系统主频了

(记得把这个文件取消只读)

image-20231105183652227

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
int main(void)
{
	OLED_Init(); 
	SystemCoreClockUpdate();  //更新SystemCoreClock的值
	OLED_ShowNum(1,1,SystemCoreClock,8); //显示系统主频
	//如果把系统主频改低, 而不修改Delay函数, 就能发现hello闪的慢了
	while (1)
	{
		OLED_ShowString(2,1,"hello");
		Delay_ms(500);
		OLED_ShowString(2,1,"     ");
		Delay_ms(500);
	}
}

2 睡眠模式

这是一段串口接收数据的程序, 在无信号时进入睡眠模式, 等待中断的唤醒

#include "stm32f10x.h"                  // Device header
#include "delay.h"
#include "OLED.H"
#include "usart.h"

int main(void){
	OLED_Init();
	UART_Init(); 
	
	uint8_t result;
	while(1){
		if(UART_Flag==1){
			result=UART_Data;
			OLED_ShowHexNum(1,1,result,2);
			UART_Flag=0;
		} 
        
		OLED_ShowString(2,1,"Runing");
		Delay_ms(1000);
		OLED_ShowString(2,1,"      ");
		Delay_ms(1000); //用Runing的闪动标志程序的运行
        
		__WFI(); //进入睡眠模式(中断唤醒)
	}
}

3 停机模式

这是一段传感器触发外部中断计次的代码, 在传感器无信号时进入停机模式, 等待外部中断的唤醒

#include "stm32f10x.h"                  // Device header
#include "delay.h"
#include "OLED.H"
#include "sensorCounter.h"

int main(void){

	OLED_Init();
	SensorCount_Init(); 
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE); //开启PWR时钟
    
    uint8_t Num=0;
	OLED_ShowNum(1,1,Num,3);
	while(1){
		if(IPflag){
			Num++;
			OLED_ShowNum(1,1,Num,3);
			IPflag=0;
		}
        
		OLED_ShowString(2,1,"Runing");
		Delay_ms(1000);
		OLED_ShowString(2,1,"      ");
		Delay_ms(1000); //用Runing的闪动标志程序的运行
		
		PWR_EnterSTOPMode(PWR_Regulator_ON, PWR_STOPEntry_WFI);
        /*
        	进入停止模式 
        	PWR_Regulator_ON 电压调节器不开启低功耗模式(开了唤醒有一定延迟)
        	PWR_STOPEntry_WFI 中断唤醒(而不是事件唤醒)
        */
		SystemInit(); //每次停止模式被唤醒 系统主频默认是HSI 8Mhz,这里手动设置时钟主频为HSE的倍频
	}
}

4 待机模式

待机模式能由WakeUp的上升沿, RTC的闹钟唤醒, 以下代码的现象表现为:

  1. 复位
  2. 重新初始化一切
  3. 设置闹钟值
  4. Runing闪动
  5. 进入待机模式(等待闹钟响, 或者WakeUp的上升沿, 重新复位)
#include "stm32f10x.h"                  // Device header
#include "delay.h"
#include "OLED.H"
#include "MYRTC.h"

int main(void){
	OLED_Init();
	MYRTC_Init();
	RCC_APB1PeriphClockCmd(RCC_APB1ENR_PWREN,ENABLE); //开启PWR时钟
	PWR_WakeUpPinCmd(ENABLE);  //使能WakeUp引脚
    
	uint32_t alarm = RTC_GetCounter() + 5; 
	RTC_SetAlarm(alarm);   //设置闹钟为5秒后
	while(1){
		OLED_ShowNum(1,1,RTC_GetCounter(),10); //RTC_CNT
		OLED_ShowNum(2,1,alarm,10); //闹钟值
		OLED_ShowNum(3,1,RTC_GetFlagStatus(RTC_FLAG_ALR),1);  //闹钟唤醒状态位
		
		OLED_ShowString(4,1,"Runing");
		Delay_ms(500);
		OLED_ShowString(4,1,"      ");
		Delay_ms(500); //用Runing的闪动标志程序的运行
		
		OLED_Clear();//关闭所有外设
		PWR_EnterSTANDBYMode(); //进入待机模式
	}
}

五、总结

  • 修改主频最好别用
  • 睡眠模式和停机模式, 适合大部分时间不工作, 只在少部分时间工作的监测项目使用, 两者的区别在于你的中断是不是来自EXTI
  • 停机模式 适合满足间隔一段时间做固定的事情, 且要求低功耗的项目
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于灵位微电子MM32F5277E微控制器,您可以使用HAL库来与RFID-RC522模块进行通信。由于没有针对MM32F5277E的特定RFID-RC522库,您需要自己编写相应的驱动代码。 以下是一个简单的示例代码,演示如何使用MM32F5277E的HAL库与RFID-RC522模块进行通信: ```c #include "main.h" #include "stm32f1xx_hal.h" #include "spi.h" #include "gpio.h" #define RFID_CS_Pin GPIO_PIN_4 #define RFID_CS_GPIO_Port GPIOA SPI_HandleTypeDef hspi1; void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_SPI1_Init(void); void RFID_RC522_Init(void); void RFID_RC522_WriteReg(uint8_t addr, uint8_t val); uint8_t RFID_RC522_ReadReg(uint8_t addr); void RFID_RC522_Init(void) { HAL_GPIO_WritePin(RFID_CS_GPIO_Port, RFID_CS_Pin, GPIO_PIN_SET); HAL_Delay(10); RFID_RC522_WriteReg(0x01, 0x0F); // 重置RFID模块 // 进行其他初始化设置... HAL_Delay(10); } void RFID_RC522_WriteReg(uint8_t addr, uint8_t val) { HAL_GPIO_WritePin(RFID_CS_GPIO_Port, RFID_CS_Pin, GPIO_PIN_RESET); uint8_t txData[2]; txData[0] = (addr << 1) & 0x7E; txData[1] = val; HAL_SPI_Transmit(&hspi1, txData, 2, 100); HAL_GPIO_WritePin(RFID_CS_GPIO_Port, RFID_CS_Pin, GPIO_PIN_SET); } uint8_t RFID_RC522_ReadReg(uint8_t addr) { HAL_GPIO_WritePin(RFID_CS_GPIO_Port, RFID_CS_Pin, GPIO_PIN_RESET); uint8_t txData = ((addr << 1) & 0x7E) | 0x80; uint8_t rxData; HAL_SPI_TransmitReceive(&hspi1, &txData, &rxData, 1, 100); HAL_GPIO_WritePin(RFID_CS_GPIO_Port, RFID_CS_Pin, GPIO_PIN_SET); return rxData; } int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_SPI1_Init(); RFID_RC522_Init(); while (1) { // 进行其他操作... HAL_Delay(100); } } void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct; RCC_ClkInitTypeDef RCC_ClkInitStruct; __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_HCLK | 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(); } HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / 1000); HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0); } static void MX_SPI1_Init(void) { 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_128; hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB; hspi1.Init.TIMode = SPI_TIMODE_DISABLE; hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; hspi1.Init.CRCPolynomial = 10; if (HAL_SPI_Init(&hspi1) != HAL_OK) { Error_Handler(); } } void Error_Handler(void) { while (1) { } } ``` 在这个例子中,我们使用SPI1来与RFID-RC522模块进行通信,并使用GPIOA的Pin 4作为RFID模块的CS引脚。您需要根据实际连接情况修改这些引脚。 RFID_RC522_Init()函数用于初始化RFID模块,并且您可以在主循环中进行其他操作。 请注意,这只是一个基本的示例代码,您可能需要根据实际需求进行更多的功能扩展和错误处理。 希望对您有所帮助!如果您有其他问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值