第十三章PWR电源控制

1修改主频

int main(void)
{
	OLED_Init();
	OLED_ShowString(1, 1, "SYSCLK:");
	OLED_ShowNum(1, 8, SystemCoreClock, 8);
	while (1)
	{
		OLED_ShowString(2, 1, "Running");
		Delay_ms(500);
		OLED_ShowString(2, 1, "       ");
		Delay_ms(500);
	}
}

 只要在时钟文件里面修改主频就可以了

2睡眠模式+串口

uint8_t Data;
int main(void)
{
	OLED_Init();
	Serial_Init();
	OLED_ShowString(1, 1, "RxData:");
	while (1)
	{
		if(Serial_GetFlag()==1)
		{
			Data = Serial_GetRxData();
			Serial_SendByte(Data);
			//标志位硬件置0, 不需要我们动
			OLED_ShowHexNum(1, 8, Data, 2);
		}
		OLED_ShowString(2, 1, "Running");
		Delay_ms(500);
		OLED_ShowString(2, 1, "       ");
		Delay_ms(500);
		
		__WFI();//中断唤醒
	}
}

每一次来一个中断, 先执行中断, 然后whle循环重新开始执行一次, 再次进入睡眠

3停止模式+红外计次

应为这里用的是外部中断, 外部中断不需要内部的时钟, 可以满足停止模式的要求

int main(void)
{
	OLED_Init();
	CountSensor_Init();
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
	
	OLED_ShowString(1,1,"count:");
	while (1)
	{
		OLED_ShowNum(1, 7, CountSensor_Get(), 5);
		
		OLED_ShowString(2, 1, "Running");
		Delay_ms(500);
		OLED_ShowString(2, 1, "       ");
		Delay_ms(500);
		PWR_EnterSTOPMode(PWR_Regulator_ON, PWR_STOPEntry_WFI);
		SystemInit();//停止模式之后主频变为8KM, 这时候我重新设置主频为72
	}
}

使用停止模式和待机模式都要开启PWR的时钟, 因为需要用到PWR外设的操作

4实时时钟+待机模式

待机模式退出的时候程序从头开始执行, 而且使用待机模式的时候都是为了极度省电, 所以在待机模式之前可以把能关的都关了

int main(void)
{
	OLED_Init();
	MyRTC_Init();
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
	OLED_ShowString(1, 1, "CNT:");
	OLED_ShowString(2, 1, "ALR");
	OLED_ShowString(3, 1, "ALRF");
	PWR_WakeUpPinCmd(ENABLE);//而且不需要GPIO初始化
	
	uint32_t Alarm = RTC_GetCounter()+10;
	RTC_SetAlarm(Alarm);
	OLED_ShowNum(2, 6, Alarm, 10);
	while (1)
	{
		
		OLED_ShowNum(1, 6, RTC_GetCounter(), 10);
		OLED_ShowNum(3, 6, RTC_GetFlagStatus(RTC_FLAG_ALR), 1);//显示闹钟标志位
		
		
		OLED_ShowString(4, 1, "Running");
		Delay_ms(100);
		OLED_ShowString(4, 1, "       ");
		Delay_ms(100);
		
		OLED_ShowString(4, 9, "STANDBY");
		Delay_ms(1000);
		OLED_ShowString(4, 9, "       ");
		Delay_ms(100);
		
		
		OLED_Clear();
		
		PWR_EnterSTANDBYMode();
	}
}

第十四章看门狗

独立看门狗

计数器减到0的时候就会触发复位

所以就要在减到0之前就要去喂狗 

代码展示

main.c

uint8_t KeyNum;

int main(void)
{
	OLED_Init();
	Key_Init();
	OLED_ShowString(1, 1, "IWDG TEST");
	//判断复位是谁产生的
	if(RCC_GetFlagStatus(RCC_FLAG_IWDGRST)==SET)
	{
		RCC_ClearFlag();
		OLED_ShowString(2, 1, "IWDGRST");
		Delay_ms(500);
		OLED_ShowString(2, 1, "       ");
		Delay_ms(500);
	}
	else
	{
		OLED_ShowString(3, 1, "RST");
		Delay_ms(500);
		OLED_ShowString(3, 1, "       ");
		Delay_ms(500);
	}
	
	//1开启LSI时钟, 自动开启
	//2解除写保护
	IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
	//配置预分频, 从装值
	IWDG_SetPrescaler(IWDG_Prescaler_16);
	IWDG_SetReload(2499);//1000ms
	IWDG_ReloadCounter();//先喂一次狗, 这样第一次的时间就是1000ms
	IWDG_Enable();
	while (1)
	{
		Key_GetNum();//一直按着就会阻塞
		IWDG_ReloadCounter();
		
		OLED_ShowString(4, 1, "FEED");
		Delay_ms(200);
		OLED_ShowString(4, 1, "       ");
		Delay_ms(600);
	}
}

窗口看门狗

上面的CFR寄存器就是最早时间喂狗的实现 

代码展示:

 main.c

uint8_t KeyNum;

int main(void)
{
	OLED_Init();
	Key_Init();
	OLED_ShowString(1, 1, "WWDG TEST");
	//判断复位是谁产生的
	if(RCC_GetFlagStatus(RCC_FLAG_WWDGRST)==SET)
	{
		RCC_ClearFlag();
		OLED_ShowString(2, 1, "WWDGRST");
		Delay_ms(500);
		OLED_ShowString(2, 1, "       ");
		Delay_ms(500);
	}
	else
	{
		OLED_ShowString(3, 1, "RST");
		Delay_ms(500);
		OLED_ShowString(3, 1, "       ");
		Delay_ms(500);
	}
	//开启时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);
	//配置寄存器, 计算超时时间和窗口时间
	WWDG_SetPrescaler(WWDG_Prescaler_8);
	WWDG_SetWindowValue(21 | 0x40);//30ms
	WWDG_Enable(54 | 0x40);//同时要设置T6位 50ms 这里相当于一次喂狗
	while (1)
	{
		Key_GetNum();//一直按着就会阻塞
		
		OLED_ShowString(4, 1, "FEED");
		Delay_ms(20);
		OLED_ShowString(4, 1, "       ");
		Delay_ms(20);
		
		WWDG_SetCounter(54 | 0x40);
	}
}

第十五章FLASH闪存

这是一个用芯片闪存的弊端

因为SRAM是掉电丢失的, 而FLASH掉电不丢失, 这样我们就可以将SRAM的数据在掉电之前转移到FLASH里面, 然后上电的时候就可以先去恢复数据 

这个地方可以修改程序的分配空间, 可以改小一点, 最后几页可以留给自己用 , 而且其实位置也可以去修改  

代码展示:

My_FLASH.c : 底层代码 -> 就是读, 擦除, 写的三个基本功能

其实库里面都是封装好了, 我们只是去调用相应的函数

#include "stm32f10x.h"                  // Device header

//读
uint32_t MyFLASH_ReadWord(uint32_t Address)
{
	return *((__IO uint32_t *)(Address));
}
uint16_t MyFLASH_ReadHalfWord(uint32_t Address)
{
	return *((__IO uint16_t *)(Address));
}

uint8_t MyFLASH_ReadByte(uint32_t Address)
{
	return *((__IO uint8_t *)(Address));
}
//擦除
void MyFLASH_ErasePages(void)
{
	FLASH_Unlock();
	FLASH_EraseAllPages();
	FLASH_Lock();
}
void MyFLASH_ErasePage(uint32_t PageAddress)
{
	FLASH_Unlock();
	FLASH_ErasePage(PageAddress);
	FLASH_Lock();
}
//写入
void MyFLASH_ProgramWord(uint32_t Address, uint32_t Data)
{
	FLASH_Unlock();
	FLASH_ProgramWord(Address, Data);
	FLASH_Lock();
}
void MyFLASH_ProgramHalfWord(uint32_t Address, uint16_t Data)
{
	FLASH_Unlock();
	FLASH_ProgramHalfWord(Address, Data);
	FLASH_Lock();
}

Store.c

这里面就是实现数据从SRAM保存到FLASH里面, 从而掉电不丢失,(因为操作SRAM很方便)

#include "stm32f10x.h"                  // Device header
#include "MyFLASH.h"
#define STORE_START_ADDRESS 0x0800FC00
#define COUNT 512
uint16_t Store_Data[COUNT];

void Store_Init(void)
{
	if(MyFLASH_ReadHalfWord(STORE_START_ADDRESS)!=0xA5A5)
	{
		MyFLASH_ErasePage(STORE_START_ADDRESS);
		MyFLASH_ProgramHalfWord(STORE_START_ADDRESS, 0xA5A5);
		for(uint16_t i = 1;i<COUNT;i++)
		{
			MyFLASH_ProgramHalfWord(STORE_START_ADDRESS + i*2 , 0x0000);//这是写了两个字节所以i*2
		}
	}
	//上电就把数据恢复到SRAM
	for(uint16_t i = 0;i<COUNT;i++)
	{
		Store_Data[i] = MyFLASH_ReadHalfWord(STORE_START_ADDRESS + i*2);
	}
}

void Store_Save(void)
{
	MyFLASH_ErasePage(STORE_START_ADDRESS);
	for(uint16_t i = 0;i<COUNT;i++)
	{
		MyFLASH_ProgramHalfWord(STORE_START_ADDRESS + i*2 , Store_Data[i]);
	}
}

void Store_Clear(void)
{
	for(uint16_t i = 1;i<COUNT;i++)
	{
		Store_Data[i] = 0x0000;
	}
	Store_Save();
}

 

 读取电子签名

 代码展示

uint8_t KeyNum;

int main(void)
{
	OLED_Init();
	OLED_ShowString(1, 1, "F_SIZE:");
	OLED_ShowHexNum(1, 8, *((__IO uint16_t *)(0x1FFFF7E0)), 4);
	OLED_ShowString(2, 1, "U_ID:");
	OLED_ShowHexNum(2, 6, *((__IO uint16_t *)(0x1FFFF7E8)), 4);
	OLED_ShowHexNum(2, 11, *((__IO uint16_t *)(0x1FFFF7E8 + 0x02)), 4);
	OLED_ShowHexNum(3, 1, *((__IO uint32_t *)(0x1FFFF7E8 + 0x04)), 8);
	OLED_ShowHexNum(4, 1, *((__IO uint32_t *)(0x1FFFF7E8 + 0x08)), 8);
	while (1)
	{
		
	}

其实就是练习一下用地址去读取寄存器

在此STM32入门完结

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐