低功耗模式原理

本节用到的固件库函数

  • NVIC_SystemLPConfig(手册13.2.22)//选择系统进入低功耗模式的条件
  • PWR_EnterSTOPMode(手册14.2.6)//进入停机(STOP)模式
  • PWR_WakeUpPinCmd (手册14.2.5)//使能或者失能唤醒管脚功能
  • PWR_EnterSTANDBYMode (手册 14.2.7)//进入待机(STANDBY)模式

文件用到了 sys.h,delay.h,relay.h,oled0561.h,led.h,key.h,NVIC.h;这里只需改一下 NVIC.h,NVIC.c即可

睡眠模式程序

NVIC.h

# ifndef __NVIC_H
# define __NVIC_H	 
# include "sys.h"


extern u8 INT_MARK;//中断标志位


void KEY_INT_INIT (void);

# endif

NVIC.c

# include "NVIC2.h"

u8 INT_MARK;//中断标志位

void KEY_INT_INIT(void)//按键中断初始化
{
	NVIC_InitTypeDef NVIC_InitStruct;
	EXTI_InitTypeDef EXTI_InitStruct;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//启动GPIO时钟 (需要与复用时钟一同启动)
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//配置端口中断需要启用复用时钟
	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0); //定义 GPIO  中断
	
	EXTI_InitStruct.EXTI_Line=EXTI_Line0;//定义中断线0
	EXTI_InitStruct.EXTI_LineCmd=ENABLE;//中断使能
	EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt;//中断模式为 中断
	EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Falling;//下降沿触发
	EXTI_Init(&EXTI_InitStruct);
	
	NVIC_InitStruct.NVIC_IRQChannel=EXTI0_IRQn;//中断线
	NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;//使能中断
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级 2
	NVIC_InitStruct.NVIC_IRQChannelSubPriority=2;//子优先级 2
	NVIC_Init(&NVIC_InitStruct);
}

void EXTI0_IRQHandler(void)//名字是固定的!!!千万不能漏写尤其是0,刚刚搞半天原来是0漏了写
{
	if(EXTI_GetITStatus(EXTI_Line0)!=RESET)//判断某条线上的中断是否发生,Set:发生 Reset:没发生
	{
		INT_MARK=1;//标志位置1,表示有按键中断
		EXTI_ClearITPendingBit(EXTI_Line0);//清除LINE 上的中断标志位
	}
}

main.c

# include "stm32f10x.h" //STM32头文件
# include "sys.h"
# include "delay.h"
# include "relay.h"
# include "oled0561.h"

# include "led.h"
# include "key.h"
# include "NVIC2.h"


int main (void) //主程序
{
    delay_ms(500); //上电时等待其他器件就绪
    RCC_Configuration(); //系统时钟初始化
    RELAY_Init();//继电器初始化
	LED_Init();
	KEY_Init();

    I2C_Configuration();//I2C初始化
    OLED0561_Init(); //OLED初始化
    OLED_DISPLAY_8x16_BUFFER(0, "   SLEEP TEST    "); //显示字符串
    INT_MARK=0;//标志位清0
	NVIC_Configuration();//设置中断优先级
	KEY_INT_INIT();//按键中断初始化(PA0是按键中断输入)
	
    //SEVONPEND: 0:只有使能的中断或事件才能唤醒内核。1:任何中断和事件都可以唤醒内核。(0=DISABLE,1=ENABLE) 
	NVIC_SystemLPConfig(NVIC_LP_SEVONPEND,DISABLE);
	//SLEEPDEEP: 0:低功耗模式为睡眠模式。1:进入低功耗时为深度睡眠模式。
	NVIC_SystemLPConfig(NVIC_LP_SLEEPDEEP,DISABLE);
	//SLEEPONEXIT: 0: 被唤醒进入线程模式后不再进入睡眠模式。1:被唤醒后执行完相应的中断处理函数后进入睡眠模式。
	NVIC_SystemLPConfig(NVIC_LP_SLEEPONEXIT,DISABLE);
	
    while(1)
    {
        GPIO_SetBits(LEDPORT,LED1);//LED控制,亮
		OLED_DISPLAY_8x16_BUFFER(4,"  CPU Sleep!    "); //显示字符串
		delay_ms(500);
		__WFI(); //进入睡眠模式,等待中断唤醒
		//		__WFE(); //进入睡眠模式,等待事件唤醒
		GPIO_ResetBits(LEDPORT,LED1);//LED控制,灭
		OLED_DISPLAY_8x16_BUFFER(4,"  CPU WAKE UP!  "); //显示字符串
		delay_ms(500); //
    }
}

实验现象

停机模式程序

文件跟 31一样,只是 main.c 不一样;

main.c

# include "stm32f10x.h" //STM32头文件
# include "sys.h"
# include "delay.h"
# include "relay.h"
# include "oled0561.h"

# include "led.h"
# include "key.h"
# include "NVIC2.h"


int main (void) //主程序
{
    delay_ms(500); //上电时等待其他器件就绪
    RCC_Configuration(); //系统时钟初始化
    RELAY_Init();//继电器初始化
	LED_Init();
	KEY_Init();

    I2C_Configuration();//I2C初始化
    OLED0561_Init(); //OLED初始化
    OLED_DISPLAY_8x16_BUFFER(0, "   STOP TEST    "); //显示字符串
    INT_MARK=0;//标志位清0
	NVIC_Configuration();//设置中断优先级
	KEY_INT_INIT();//按键中断初始化(PA0是按键中断输入)
	
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);//使能电源PWR时钟
	
    while(1)
    {
        GPIO_WriteBit(LEDPORT,LED1,(BitAction)(1)); 
		OLED_DISPLAY_8x16_BUFFER(4,"  CPU Stop!    "); //显示字符串
		delay_ms(500);
		
		PWR_EnterSTOPMode(PWR_Regulator_LowPower,PWR_STOPEntry_WFI);//进入停机模式
		RCC_Configuration(); //系统时钟初始化(停机唤醒后会改用HSI时钟,需要重新对时钟初始化) 
		
		GPIO_WriteBit(LEDPORT,LED1,(BitAction)(0));//LED控制,灭
		OLED_DISPLAY_8x16_BUFFER(4,"  CPU WAKE UP!  "); //显示字符串
		delay_ms(500); //
    }
}

实验现象跟睡眠模式差不多。

待机模式程序

文件跟 31一样,只是 main.c 不一样;

main.c

# include "stm32f10x.h" //STM32头文件
# include "sys.h"
# include "delay.h"
# include "relay.h"
# include "oled0561.h"

# include "led.h"
# include "key.h"
# include "NVIC2.h"


int main (void) //主程序
{
    delay_ms(500); //上电时等待其他器件就绪
    RCC_Configuration(); //系统时钟初始化
    RELAY_Init();//继电器初始化
	LED_Init();

    I2C_Configuration();//I2C初始化
	
    OLED0561_Init(); //OLED初始化
    OLED_DISPLAY_8x16_BUFFER(0, "   STANDBY TEST    "); //显示字符串
	
	
	
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);//使能电源PWR时钟
	PWR_WakeUpPinCmd(ENABLE);//WKUP唤醒功能开启(待机时WKUP脚PA0为模拟输入)
	GPIO_ResetBits(LEDPORT,LED1);
	OLED_DISPLAY_8x16_BUFFER(4,"  CPU RESET!    "); //显示字符串
	delay_ms(500); //

	GPIO_SetBits(LEDPORT,LED1);
	OLED_DISPLAY_8x16_BUFFER(4,"   STANDBY!     "); //显示字符串
	delay_ms(500); //

	PWR_EnterSTANDBYMode();//进入待机模式
	
	//因为待机唤醒后程序从头运行,所以不需要加while(1)的主循环体。

实验现象

看门狗

本节用到的固件库函数

  • IWDG_WriteAccessCmd(手册 12.2.1)//使能或者失能对寄存器IWDG_PR和IWDG_RLR的写操作
  • IWDG_SetPrescaler(手册 12.2.2)//设置IWDG预分频值
  • IWDG_SetReload(手册 12.2.3)//设置IWDG重装载值
  • IWDG_ReloadCounter(手册 12.2.4)//按照IWDG重装载寄存器的值重装载IWDG计数器
  • IWDG_Enable(手册 12.2.5)//使能IWDG
  • WWDG_SetPrescaler(手册 22.1.2)//设置WWDG预分频值
  • WWDG_SetWindowValue(手册 22.1.3)//设置WWDG窗口值
  • WWDG_Enable(手册 22.1.6)//使能WWDG并装入计数器值
  • WWDG_ClearFlag(手册 22.1.8)//清除早期唤醒中断标志位
  • WWDG_EnableIT(手册 22.1.4)//使能WWDG早期唤醒中断(EWI)
  • WWDG_SetCounter(手册 22.1.5)//设置WWDG计数器值

文件与 31 相同,只需添加 iwdg.h,iwdg.c 文件即可(Lib 文件添加 stm32f10x_iwdg.c

  • 窗口看门狗必须在规定的时间范围内喂狗入;作用是监控单片机运行时效是否精确

独立看门狗程序

iwdg.h

# ifndef __IWDG_H
# define __IWDG_H
# include "sys.h"

//看门狗定时时间计算公式:Tout=(预分频值*重装载值)/40 (单位:ms)
//当前pre为64,rlr为625,计算得到Tout时间为1秒(大概值)。
//(64x625)/40=1000ms=1s
# define pre IWDG_Prescaler_64
# define rlr 625

void IWDG_Init(void);
void IWDG_Feed(void);

# endif

iwdg.c

  • 独立看门狗的溢出时间计算:Tout=(预分频值*重装载值)/40 (单位:ms) prer是分频系数,rlr是重装值 其中:/40是独立看门狗专有的时钟,时钟频率为40k
# include "iwdg.h"


void IWDG_Init(void){ //初始化独立看门狗
    IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); //使能对寄存器IWDG_PR和IWDG_RLR的写操作(取消寄存器写保护)
    IWDG_SetPrescaler(pre); //设置IWDG预分频值
    IWDG_SetReload(rlr); //设置IWDG重装载值
    IWDG_ReloadCounter(); //按照IWDG重装载寄存器的值重装载IWDG计数器
    IWDG_Enable(); //使能IWDG
}

void IWDG_Feed(void){ //喂狗程序
    IWDG_ReloadCounter();//固件库的喂狗函数
}

main.c

# include "stm32f10x.h" //STM32头文件
# include "sys.h"
# include "delay.h"
# include "relay.h"
# include "oled0561.h"
# include "led.h"
# include "key.h"

# include "iwdg.h"

int main (void){//主程序
	delay_ms(500); //上电时等待其他器件就绪
	RCC_Configuration(); //系统时钟初始化 
	RELAY_Init();//继电器初始化
	LED_Init();//LED 
	KEY_Init();//KEY

	I2C_Configuration();//I2C初始化

	OLED0561_Init(); //OLED初始化---------------"
	OLED_DISPLAY_8x16_BUFFER(0,"   IWDG TEST    "); //显示字符串
	OLED_DISPLAY_8x16_BUFFER(4,"    RESET!      "); //显示字符串
	delay_ms(800); //
	OLED_DISPLAY_8x16_BUFFER(4,"                "); //显示字符串

	IWDG_Init(); //初始化并启动独立看门狗

	while(1){

		IWDG_Feed(); //喂狗

		if(!GPIO_ReadInputDataBit(KEYPORT,KEY1)){
			delay_s(2);	//延时2秒,使程序不能喂狗而导致复制
		}
	}
}

实验现象

窗口看门狗程序

文件和 31 相同,只需增加 wwdg.h,wwdg.c 即可

wwdg.h

# ifndef __WWDG_H
# define __WWDG_H
# include "sys.h"

//窗口看门狗定时时间计算公式:
//上窗口超时时间(单位us) = 4096*预分频值*(计数器初始值-窗口值)/APB1时钟频率(单位MHz)
//下窗口超时时间(单位us) = 4096*预分频值*(计数器初始值-0x40)/APB1时钟频率(单位MHz)

# define WWDG_CNT 0x7F //计数器初始值,范围:0x40~0x7F
# define wr 0x50 //窗口值,范围:0x40~0x7F
# define fprer WWDG_Prescaler_8 //预分频值,取值:1,2,4,8

//如上三个值是:0x7f,0x50,8时,上窗口48MS,下窗口64MS。
void WWDG_Init(void);
void WWDG_NVIC_Init(void);
void WWDG_Feed(void);

# endif

wwdg.c

# include "wwdg.h"

void WWDG_Init(void)//初始化窗口看门狗
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG,ENABLE);//WWDG 时钟使能
	WWDG_SetPrescaler(fprer);//设置IWDG预分频值
	WWDG_SetWindowValue(wr);//设置窗口值
	WWDG_Enable(WWDG_CNT);//使能看门狗,设置 counter
	WWDG_ClearFlag();//清除提前唤醒中断标志位
	WWDG_NVIC_Init();//初始化窗口看门狗 NVIC
	WWDG_EnableIT();//开启窗口看门狗中断
}

void WWDG_NVIC_Init(void)//窗口看门狗中断服务程序(被WWDG_Init调用)
{
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel=WWDG_IRQn;//WWDG 中断
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占2 子优先级 3 组2
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=3;//抢占 2,子优先级 3,组 2
	NVIC_Init(&NVIC_InitStructure);//NVIC初始化
}

void WWDG_Feed(void)//窗口喂狗程序
{
	WWDG_SetCounter(WWDG_CNT);//清除提前唤醒中断标志位
}

void WWDG_IRQHandler(void)//窗口看门狗中断处理程序
{
	WWDG_ClearFlag();//清除提前唤醒中断标志位
	//此处加入在复位前需要处理的工作或保存数据
}

main.c

# include "stm32f10x.h" //STM32头文件
# include "sys.h"
# include "delay.h"
# include "relay.h"
# include "oled0561.h"
# include "led.h"
# include "key.h"

# include "wwdg.h"

int main (void){//主程序
	delay_ms(500); //上电时等待其他器件就绪
	RCC_Configuration(); //系统时钟初始化 
	RELAY_Init();//继电器初始化
	LED_Init();//LED 
	KEY_Init();//KEY

	I2C_Configuration();//I2C初始化

	OLED0561_Init(); //OLED初始化---------------"
	OLED_DISPLAY_8x16_BUFFER(0,"   WWDG TEST    "); //显示字符串
	OLED_DISPLAY_8x16_BUFFER(4,"    RESET!      "); //显示字符串
	delay_ms(800); //
	OLED_DISPLAY_8x16_BUFFER(4,"                "); //显示字符串

	WWDG_Init(); //初始化并启动独立看门狗

	while(1){
		delay_ms(54); //用延时找到喂狗的窗口时间
		WWDG_Feed(); //喂狗

		if(!GPIO_ReadInputDataBit(KEYPORT,KEY1)){
			delay_s(2);	//延时2秒,使程序不能喂狗而导致复制
		}
	}
}

实验现象跟独立看门狗差不多。

定时器原理与应用

本节用到的固件库函数(有的在 28步)

  • TIM_ITConfig (手册 19.2.9)//使能或者失能指定的TIM中断
  • TIM_GetITStatus (手册 19.2.71)//检查指定的TIM中断发生与否
  • TIM_ClearITPendingBit (手册 19.2.72)//清除TIMx的中断待处理位

文件和31相同,只需添加 tim.h,tim.c 即可(Lib 文件需要添加 stm32f10x_tim.c

tim.h

# ifndef  __PWM_H
# define  __PWM_H
# include "sys.h"

void TIM3_Init(u16 arr,u16 psc);
void TIM3_NVIC_Init (void);

# endif

tim.c

  • Tout = ((重装载值+1)*(预分频系数+1))/时钟频率(9999+1)x(7199+1)/72 = 100,0000us=1s

# include "tim.h"
# include "led.h"

//定时器时间计算公式Tout = ((重装载值+1)*(预分频系数+1))/时钟频率;
//例如:1秒定时,重装载值=9999,预分频系数=7199

void TIM3_Init(u16 arr, u16 psc) ////TIM3 初始化 arr重装载值 psc预分频系数
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //使能TIM3
    TIM3_NVIC_Init();//开启TIM3中断向量

    TIM_TimeBaseInitStructure.TIM_Period = arr; //设置自动重装载值
    TIM_TimeBaseInitStructure.TIM_Prescaler = psc; //预分频值
    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器向上溢出
    TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟的分频因子,起到了一点点的延时作用,一般设为TIM_CKD_DIV1
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure); //TIM3初始化设置
    TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); //使能TIM3中断
    TIM_Cmd(TIM3, ENABLE); //使能TIM3
}

void TIM3_NVIC_Init(void)//开启TIM3中断向量
{
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x3; //设置抢占和子优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x3;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

void TIM3_IRQHandler(void)//TIM3中断处理函数
{
    if(TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //判断是否是TIM3中断
    {
        TIM_ClearITPendingBit(TIM3, TIM_IT_Update);//清除TIM3中断标志

        //此处写入用户自己的处理程序
        GPIO_WriteBit(LEDPORT, LED1, (BitAction)(1 - GPIO_ReadOutputDataBit(LEDPORT, LED1))); //取反LED
    }
}

main.c

# include "stm32f10x.h" //STM32头文件
# include "sys.h"
# include "delay.h"
# include "relay.h"
# include "oled0561.h"
# include "led.h"
# include "key.h"

# include "tim.h"


int main (void) //主程序
{
    delay_ms(500); //上电时等待其他器件就绪
    RCC_Configuration(); //系统时钟初始化
    RELAY_Init();//继电器初始化
    LED_Init();//LED
    KEY_Init();//KEY

    I2C_Configuration();//I2C初始化

    OLED0561_Init(); //OLED初始化---------------"
    OLED_DISPLAY_8x16_BUFFER(0, "   TIM TEST     "); //显示字符串

    TIM3_Init(9999, 7199); //定时器初始化,定时1秒(9999,7199)

    while(1)
    {

        //写入用户的程序
        //LED1闪烁程序在TIM3的中断处理函数中执行


    }
}

实验现象

CRC与芯片ID原理

本节用到的固件库函数

文件跟 33 一样,没用到另外的文件只需在 main.c 上写即可

main.c

# include "stm32f10x.h" //STM32头文件
# include "sys.h"
# include "delay.h"
# include "relay.h"
# include "oled0561.h"
# include "led.h"
# include "key.h"


int main (void) //主程序
{
    u32 a, b;
    u8 c;
    u32 y[3] = {0x87654321, 0x98765432, 0x09876543};
    delay_ms(500); //上电时等待其他器件就绪
    RCC_Configuration(); //系统时钟初始化
    RELAY_Init();//继电器初始化
    LED_Init();//LED
    KEY_Init();//KEY

    I2C_Configuration();//I2C初始化

    OLED0561_Init(); //OLED初始化---------------"
    OLED_DISPLAY_8x16_BUFFER(0, "   CRC TEST     "); //显示字符串

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE);//开启CRC时钟

    while(1)
    {
        CRC_ResetDR();//复位CRC,需要清0重新计算时先复位
        CRC_CalcCRC(0x12345678);//CRC计算一个32位数据。参数:32位数据。返回值:32位计算结果
        CRC_CalcCRC(0x23456789);//CRC计算一个32位数据。参数:32位数据。返回值:32位计算结果
        a = CRC_CalcCRC(0x34567890);//CRC计算一个32位数据。参数:32位数据。返回值:32位计算结果

        CRC_ResetDR();//复位CRC,需要清0重新计算时先复位
        b = CRC_CalcBlockCRC(y, 3); //CRC计算一个32位数组。参数:32位数组名,数组长度。返回值:32位计算结果

        CRC_SetIDRegister(0x5a);//向独立寄存器CRC_IDR写数据。参数:8位数据。
        c = CRC_GetIDRegister();//从独立寄存器CRC_IDR读数据。返回值:8位数据。

        //此时,a存放的是3个独立数的CRC结果。(32位)
        //b存放的是数组y中3个数据CRC计算结果。(32位)
        //c存放的是我们写入的独立寄存器数据0x5a。(8位)
    }
}

//	以下是CRC固件库函数,可在主程序中直接调用  //

//	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE);//开启CRC时钟,主程序开始时调用
//	CRC_ResetDR();//复位CRC,需要清0重新计算时先复位
//	uint32_t CRC_CalcCRC(uint32_t Data);//CRC计算一个32位数据。参数:32位数据。返回值:32位计算结果
//	uint32_t CRC_CalcBlockCRC(uint32_t pBuffer[], uint32_t BufferLength);//CRC计算一个32位数组。参数:32位数组名,数组长度。返回值:32位计算结果
//	uint32_t CRC_GetCRC(void);//从CRC中读出计算结果。返回值:32位计算结果。

//	void CRC_SetIDRegister(uint8_t IDValue);//向独立寄存器CRC_IDR写数据。参数:8位数据。
//	uint8_t CRC_GetIDRegister(void);//从独立寄存器CRC_IDR读数据。返回值:8位数据。

芯片ID程序

文件复制 34 即可 ,用到了 usart.h ,usart.c

usart.c 需要把中断关闭,因为只用到了 printf 函数

main.c

# include "stm32f10x.h" //STM32头文件
# include "sys.h"
# include "delay.h"
# include "relay.h"
# include "oled0561.h"
# include "led.h"
# include "key.h"

# include "usart.h"

int main (void) //主程序
{
    u32 ID[3];
    delay_ms(500); //上电时等待其他器件就绪
    RCC_Configuration(); //系统时钟初始化
    RELAY_Init();//继电器初始化
    LED_Init();//LED
    KEY_Init();//KEY

    USART1_Init(115200); //串口初始化(参数是波特率)
    I2C_Configuration();//I2C初始化

    OLED0561_Init(); //OLED初始化---------------"
    OLED_DISPLAY_8x16_BUFFER(0, "  CHIP ID TEST  "); //显示字符串

    ID[0] = *(__IO u32 *)(0X1FFFF7E8); //读出3个32位ID 高字节
    ID[1] = *(__IO u32 *)(0X1FFFF7EC); //
    ID[2] = *(__IO u32 *)(0X1FFFF7F0); // 低字节

    printf("ChipID: %08X %08X %8X \r\n", ID[0], ID[1], ID[2]); //从串口输出16进制ID

    if(ID[0] == 0x066EFF48 && ID[1] == 0x48577152 && ID[2] == 0x87241422) //检查ID是否匹配
    {
        printf("chipID OK! \r\n"); //匹配
    }
    else
    {
        printf("chipID error! \r\n"); //不同
    }

    while(1)
    {

    }
}

实验现象

把程序烧到开发板后打开超级终端,再按一下单片机的复位按键即可显示,如果芯片ID和程序里写的匹配则返回 OK,反之返回 Error

回顾与总结

关于HAL库

HAL库并不是HAL库就要全面优秀于标准库,它们各有优势用标准库作为入门教学更好,网上相关的资料多、用的人多、有助于对程序框架的理解。HAL库学习起来更简单,也更封闭。可以在入门之后、理解STM32编程框架之后使用。ST公司未来会全面更新、支持HAL库

​ 在B站上看了 stm32入门100步 已经距离现在是一个月左右了,到这说明已经结束了,但是也是一个新的开始,因为现在只是入门了而已,还有很多很多知识还没学到,继续努力吧!后面还有关于物联网的入门30步我会继续看下去并且也做好笔记,加油,学习真的会上瘾(要是我中专就觉悟了该多好,现在想想非常后悔),但是世上没有后悔药所以大专觉悟还来得及!