STM32-F407ZGT6

STM32-F407ZGT6

144引脚 1024K字节闪存储存器 LQFP封装 -40°C~85°C工作范围

开发板介绍

开发板介绍

开发板介绍

image-20210404103005743

image-20210404103005743

image-20210404103005743

STM32内核

ARM内核的32位MCU系列

–Cortex-M内核

–标准的ARM架构

uCortex-M4采用ARMv7-ME架构

image-20210404103355273

image-20210404103355273

image-20210404103355273

Cortex-M4与M3对比

image-20210404103505452

image-20210404103505452

image-20210404103505452

ARMv7架构定义了三大分工明确的系列:

“A”系列:面向尖端的基于虚拟内存的操作系统和用户应用

“R”系列:针对实时系统;

“M”系列:对微控制器。

学习方法

掌握调试工具:JTAG

image-20210404102642577

image-20210404102642577

image-20210404102642577

多使用JTAG调试代码,深入理解代码执行流程。在基础不够扎实的时候,不要走马换花的看,要做到深入理解代码涵义。

库函数和寄存器对比学习

项目中大多数用库函数。但是学习,如果你只会看几个函数的话,你根本没有学懂,遇到问题很难自己解决,所以必要了解一下寄存器配置原理,加深理解。

尤其前面几个章节实验,最好了解寄存器配置,加深对STM32本质的理解。

STM32最小系统

供电

复位

时钟:外部晶振(2个)

Boot启动模式选择

下载电路(串口/JTAG/SWD)

后备电池

连接串口

image-20210404151322239

image-20210404151322239

image-20210404151322239

RXD和TXD是连接usb_232 PA9和PA10用来烧录程序

串口1(PA1)才能作为串口下载,也可以用于串口通信

PA2和PA3 只能用来串口通信,不能下载

下载程序flyMcu使用

搜索串口,F4波特率最高设置为76800 其他按照下图配置

image-20210404152655145

image-20210404152655145

image-20210404152655145

下载程序是用Jlink

配置:

enterDebug

enterDebug

enterDebug

Setting

Setting

Setting

select

select

select

下载程序

load

load

load

STM32启动模式

image-20210404153858964

image-20210404153858964

image-20210404153858964

由下图控制

image-20210404153911198

image-20210404153911198

image-20210404153911198

STM32GPIO

7组每组16 从GPIOA.0GPIOA.15 ~~GPIOG.0GPIOG.15

每组IO口有10个寄存器

每个IO口都可以作为中断输入

IO口

4种模式:输入浮空,输入上拉,输入下拉,模拟输入

4种输出模式:开漏输出,开漏复用功能,推挽式输出。推挽式复用功能

4种最大输出速度:2Mhz,25Mhz,50Mhz,100Mhz

一个端口模式寄存器(GPIOx_MODER)

一个端口输出类型寄存器(GPIOx_OTYPER)

一个端口输出速度寄存器(GPIOx_OSPEEDR)

一个端口上拉下拉寄存器(GPIOx_PUPDR)

一个端口输入数据寄存器(GPIOx_IDR)

一个端口输出数据寄存器(GPIOx_ODR)

一个端口置位/复位寄存器(GPIOx_BSRR)

一个端口配置锁存寄存器(GPIOx_LCKR)

两个复位功能寄存器(低位GPIOx_AFRL & GPIOx_AFRH)

端口模式寄存器

image-20210405164406767

image-20210405164406767

image-20210405164406767

端口输出类型寄存器

image-20210405164434228

image-20210405164434228

image-20210405164434228

高16位未使用

端口输出速度寄存器

image-20210405164457134

image-20210405164457134

image-20210405164457134

端口上拉/下拉寄存器

image-20210405164518948

image-20210405164518948

image-20210405164518948

端口输入数据寄存器

image-20210405164546230

image-20210405164546230

image-20210405164546230

端口输出数据寄存器

QQ图片20210405165937

QQ图片20210405165937

QQ图片20210405165937

端口上输出0或1是有影响的

端口置位/复位寄存器

image-20210405164613372

image-20210405164613372

image-20210405164613372

端口位写0的话不会对端口有影响

写1就会置为1

端口配置锁存寄存器(待写)

端口位复用功能寄存器(待写)

跑马灯

重要源文件:

misc.c

stm32f4xx_rcc.c 一定要加

stm32f4xx_gpio.c 用于串口

stm32f4xx_usart.c SYSTEM里的usart.c有用到

顶层头文件

stm32f4xx.h

使用的头文件

#include "delay.h"

使用的函数

重要函数:
1个初始化函数:
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);

2个读取输入电平函数:
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);

2个读取输出电平函数:
uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);

4个设置输出电平函数:
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); //设置低电平

void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);	//设置高电平
void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);
void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);



//1个初始化函数:
     void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
//作用:初始化一个或者多个IO口(同一组)的工作模式,输出类型,速度以及上下拉方式。也就是一组IO口的4个配置寄存器。
  (GPIOx->MODER, GPIOx->OSPEEDR,GPIOx->OTYPER,GPIOx->PUPDR)

   GPIOx: GPIOA~GPIOK(最多11组,也就是16X11=176个IO)

//使能IO口时钟。调用函数RCC_AHB1PeriphClockCmd();


led.c

GPIO_InitTypeDef GPIO_InitStructre;  //定义结构体
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE); //开启GPIO的时钟线,之后就可以对IO口进行操作,否则任何操作都是无效操作

GPIO_InitStructre.GPIO_Mode=GPIO_Mode_OUT;
GPIO_InitStructre.GPIO_OType=GPIO_OType_PP;
//GPIO_OType_PP 推挽   GPIO_OType_OD 开漏
GPIO_InitStructre.GPIO_Pin=GPIO_Pin_9|GPIO_Pin_10;
GPIO_InitStructre.GPIO_PuPd=GPIO_PuPd_UP;
GPIO_InitStructre.GPIO_Speed=GPIO_Speed_2MHz;

GPIO_Init(GPIOF,&GPIO_InitStructre);//IO口初始化
GPIO_SetBits(GPIOF,GPIO_Pin_9|GPIO_Pin_10);  //设置电平
//GPIO_Pin_9|GPIO_Pin_10   如果IO口初始化参数一样,就这样设置

main.c

delay_init(168);

寄存器操作版本

//|=与&=
RCC->AHB1ENR |= (1<<5);//启动时钟
    GPIOF->MODER &= ~(3<<9*2); //清零
    GPIOF->MODER |= 1<<(2*9);//模式设置

    GPIOF->OTYPER &= ~(1<<9); //清零
    GPIOF->OTYPER |= 0<<9;//类型设置

    GPIOF->OSPEEDR &= ~(3<<(9*2));//清零
    GPIOF->OSPEEDR |=2<<(9*2);//速度设置

    GPIOF->PUPDR &= ~(3<<(9*2));//清零
    GPIOF->PUPDR |=1<<(2*9);//上下拉设置

    GPIOF->ODR |= 1<<9;  //置为1

位操作版本

PFout(9)=1;  //到sys.h中查看 通过将寄存器的位映射为地址,通过操作地址达到操作位的作用  (读-改-写)
PFout(10)=1;
delay_ms(500);
PFout(9)=0;
PFout(10)=0;
delay_ms(500);
//PFout(n) 输出F组的第N个IO
//PFin(n) 输入F组的第N个IO

蜂鸣器

位置:F8引脚

蜂鸣器电路,接在三极管的C端

蜂鸣器电路图

蜂鸣器电路图

蜂鸣器电路图

三极管

三极管

三极管

按键输入

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE);//对应时钟使能
//然后初始化


//按键核心代码
u8 KEY_Scan(u8 mode)
{
    static int flag=1;
    if(mode==1) flag=1;   //0不支持连按
    if(flag&&(Key0==0||Key1==0||Key2==0||WK_UP==1))
    {
        delay_ms(10);
        flag=0;

        if(Key0==0) return 1;
        if(Key1==0)	return 2;
        if(Key2==0)	return 3;
        if(WK_UP==1) return 4;

    }else if(Key0==1&&Key1==1&&Key2==1&&WK_UP==0) flag=1;
    return 0;
}

时钟系统

时钟频率的计算

PLLclock计算(常用)

image-20210429201803486

image-20210429201803486

image-20210429201803486

STM32F4开发指南-库函数版本_V1

STM32F4开发指南-库函数版本_V1

STM32F4开发指南-库函数版本_V1

image-20210429203507847

image-20210429203507847

image-20210429203507847

SystemInit函数解读

初始化之后的状态:
SYSCLK(系统时钟) =168MHz
AHB总线时钟(HCLK=SYSCLK) =168MHz
APB1总线时钟(PCLK1=SYSCLK/4) =42MHz
APB2总线时钟(PCLK2=SYSCLK/2) =84MHz
PLL主时钟 =168MHz

获取系统时钟函数

初始化之后可以通过变量SystemCoreClock获取系统变量。如果SYSCLK=168MHz,那么变量SystemCoreClock=168000000。

Systick定时器

24位倒时

睡眠时也能工作

4个Systick寄存器

CTRL    SysTick 控制和状态寄存器  LOAD(开关)
SysTick 自动重装载除值寄存器       VAL
SysTick 当前值寄存器             CALIB
SysTick 校准值寄存器

SysTick 控制和状态寄存器- CTRL

image-20210429211531521

image-20210429211531521

image-20210429211531521

对于STM32,外部时钟源是 HCLK(AHB总线时钟)的1/8
          内核时钟是 HCLK时钟
配置函数:SysTick_CLKSourceConfig();

SysTick 重装载数值寄存器- LOAD

image-20210429211659749

image-20210429211659749

image-20210429211659749

SysTick 当前值寄存器- VAL

image-20210429211712874

image-20210429211712874

image-20210429211712874

固件库中的Systick相关函数:

SysTick_CLKSourceConfig()    //Systick时钟源选择  misc.c文件中

SysTick_Config(uint32_t ticks) //初始化systick,时钟为HCLK,并开启中断
                               //core_cm3.h/core_cm4.h文件中
Systick中断服务函数:

void SysTick_Handler(void);

端口复用

概念:本来是GPIO,复用完就作为串口1的发送接收引脚

复用器一次只允许一个外设的复用功能(AF)连接到对应的IO口

每个IO引脚都有一个复用器,该复用器采用16路复用功能输入(AF0到AF15),可通过GPIOx_AFRL(针对引脚0-7)和GPIOx_AFRH(针对引脚8-15)寄存器对这些输入进行配置,每四位控制一路复用。

AFRL寄存器

image-20210503214607884

image-20210503214607884

image-20210503214607884

对于ADC和DAC,在GPIOx_MODER寄存器中将所需I/O配置为模拟通道

端口复用配置过程

1.GPIO端口时钟使能

2.复用外设时钟使能

3.端口模式配置为复用功能。 GPIO_Init()函数

4.配置GPIOx_AFRL或者GPIOx_AFRH寄存器,将IO连接

到所需的AFx。

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //使能GPIOA时钟 ①
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能USART1时钟 ②

//USART1端口配置③
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; //GPIOA9与GPIOA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	//速度50MHz
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA9,PA10

//串口1对应引脚复用映射 ④
GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); //GPIOA9复用为USART1
GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); //GPIOA10复用为USART1

完全重映射

GPIO_PinRemapConfig(GPIO_FullRemap_TIM2, ENABLE);  //完全重映射
    /*
    TIM2_CH1_ETR  ->	PA15
    TIM2_CH2	->	PB3
    TIM2_CH3	->	PB10
    TIM2_CH4	->	PB11
    */

禁用JTAG

GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable , ENABLE); 	// 改变指定管脚的映射,JTAG-DP 禁用 + SW-DP 使能,禁用JTAG

NVIC中断优先级管理

STM32F40xx/STM32F41xx的92个中断里面,包括10个内核中断和82个可屏蔽中断,具有16级可编程的中断优先级。

位置:STM32F4xx中文参考手册》P234 表45和46

中断管理方法

image-20210503233951039

image-20210503233951039

image-20210503233951039

抢占优先级 & 响应优先级区别

1.高优先级的抢占优先级是可以打断正在进行的低抢占优先级中断的。
2.抢占优先级相同的中断,高响应优先级不可以打断低响应优先级的中断。
3.抢占优先级相同的中断,当两个中断同时发生的情况下,哪个响应优先级高,哪个先执行。
4.如果两个中断的抢占优先级和响应优先级都是一样的话,则看哪个中断先发生就先执行;

中断优先级设置

初始化函数:

void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);

分组函数:

void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);

最好只设置一次

代码:

NVIC_InitTypeDef   NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1 ;// 抢占优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;// 子优先级位2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//IRQ通道使能
NVIC_Init(&NVIC_InitStructure);	//根据上面指定的参数初始化NVIC寄存器

串口通信

STM32的串口通信接口

UART:通用异步收发器
​ USART:通用同步异步收发器

STM32串口异步通信需要定义的参数

① 起始位

② 数据位(8位或者9位)

③ 奇偶校验位(第9位)

④ 停止位(1,15,2位)

⑤ 波特率设置

image-20210503235553407

image-20210503235553407

image-20210503235553407

void My_USART1_Init(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure; //GPIO寄存器
    USART_InitTypeDef USART_InitStructure; //串口寄存器
    NVIC_InitTypeDef NVIC_InitStructure;	//优先级寄存器

 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能USART1时钟
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
    //使能IO
    GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);//端口复用A9->
    GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);//端口复用A10->
  //IO配置
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
    //串口配置
  	USART_InitStructure.USART_BaudRate=115200;//波特率设置
    USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
    USART_InitStructure.USART_Parity=USART_Parity_No;
    USART_InitStructure.USART_StopBits=USART_StopBits_1;
    USART_InitStructure.USART_WordLength=USART_WordLength_8b;

    USART_Init(USART1,&USART_InitStructure);
    USART_Cmd(USART1 ,ENABLE);//使能串口


    USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//使能相关中断

    //优先级配置
    NVIC_InitStructure.NVIC_IRQChannel=USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
    NVIC_Init(&NVIC_InitStructure);


}

void USART1_IRQHandler(void)
{
    u8 res;
    if(USART_GetITStatus(USART1,USART_IT_RXNE)){


        res=USART_ReceiveData(USART1);//接受数据,从DR读取接受到的数据

        USART_SendData(USART1,res); //发送数据到串口,DR

}
/*
FlagStatus USART_GetFlagStatus();//获取状态标志位
void USART_ClearFlag();//清除状态标志位
ITStatus USART_GetITStatus();//获取中断状态标志位
void USART_ClearITPendingBit();//清除中断状态标志位
*/

状态寄存器

FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);

image-20210504000831841

image-20210504000831841

image-20210504000831841

数据寄存器

void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);
uint16_t USART_ReceiveData(USART_TypeDef* USARTx);

image-20210504000938955

image-20210504000938955

image-20210504000938955

void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);

image-20210504001007646

image-20210504001007646

image-20210504001007646

波特率计算公式

image-20210504001138065

image-20210504001138065

image-20210504001138065

串口配置一般步骤

① 串口时钟使能:RCC_APBxPeriphClockCmd();
GPIO时钟使能:RCC_AHB1PeriphClockCmd();
② 引脚复用映射:
GPIO_PinAFConfig();
③GPIO端口模式设置:GPIO_Init(); 模式设置为GPIO_Mode_AF
④串口参数初始化:USART_Init();
⑤开启中断并且初始化NVIC(如果需要开启中断才需要这个步骤)
NVIC_Init();
USART_ITConfig();
⑥使能串口:USART_Cmd();
⑦编写中断处理函数:USARTx_IRQHandler();
⑧串口数据收发:
void USART_SendData();//发送数据到串口,DR
uint16_t USART_ReceiveData();//接受数据,从DR读取接受到的数据
⑨串口传输状态获取:
FlagStatus USART_GetFlagStatus();
void USART_ClearITPendingBit();

Printf支持

//加入以下代码,支持printf函数,而不需要选择use MicroLIB
#if 1
#pragma import(__use_no_semihosting)
//标准库需要的支持函数
struct __FILE
{ int handle;
};

FILE __stdout;
//定义_sys_exit()以避免使用半主机模式
_sys_exit(int x)
{ x = x; }

//重定义fputc函数
int fputc(int ch, FILE *f)
{
    while((USART1->SR&0X40)==0);//循环发送,直到发送完毕
    USART1->DR = (u8) ch;
   return ch;
}
#endif

外部中断

头文件 exti.h

GPIOx.0映射到EXTI0

GPIOx.1映射到EXTI1

…

GPIOx.15映射到EXTI15

IO口外部中断在中断向量表中只分配了7个中断向量,也就是只能使用7个中断服务函数

image-20210504001736923

image-20210504001736923

image-20210504001736923

中断服务函数列表

用于写中断后的操作

EXTI0_IRQHandler

EXTI1_IRQHandler

EXTI2_IRQHandler

EXTI3_IRQHandler

EXTI4_IRQHandler

EXTI9_5_IRQHandler

EXTI15_10_IRQHandler
/*
EXTI0_IRQHandler()
{
    ...

}
*/

外部中断的一般配置步骤

①使能SYSCFG时钟:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
②初始化IO口为输入。
GPIO_Init();
③设置IO口与中断线的映射关系。
void SYSCFG_EXTILineConfig();
④初始化线上中断,设置触发条件等。
EXTI_Init();
⑤配置中断分组(NVIC),并使能中断。
NVIC_Init();
⑥编写中断服务函数。
EXTIx_IRQHandler();
⑦清除中断标志位
EXTI_ClearITPendingBit();

独立看门狗

功能:在启动正常运行的时候,系统不能复位。在系统跑飞(程序异常执行)的情况,系统复位,程序重新执行。

独立看门狗(IWDG)由专用的低速时钟(LSI)驱动,即使主时钟发生故障它仍有效。

键寄存器

预分频寄存器IWDG_PR:0~2位有效。具有写保护功能,要操作先取消写保护

重装载寄存器IWDG_RLR:0~11位有效。具有写保护功能,要操作先取消写保护

image-20210504002306393

image-20210504002306393

image-20210504002306393

预分频寄存器

image-20210504002357377

image-20210504002357377

image-20210504002357377

重载寄存器

image-20210504002432525

image-20210504002432525

image-20210504002432525

状态寄存器

image-20210504002451419

image-20210504002451419

image-20210504002451419

独立看门狗超时时间

image-20210504002506848

image-20210504002506848

image-20210504002506848

溢出时间计算:
  Tout=((4×2^prer) ×rlr) /32 (M4)

时钟频率LSI=32K, 一个看门狗时钟周期就是最短超时时间。最长超时时间= (IWDG_RLR寄存器最大值)X看门狗时钟周期

IWDG独立看门狗操作库函数

void IWDG_WriteAccessCmd(uint16_t IWDG_WriteAccess);//取消写保护:0x5555使能

void IWDG_SetPrescaler(uint8_t IWDG_Prescaler);//设置预分频系数:写PR

void IWDG_SetReload(uint16_t Reload);//设置重装载值:写RLR

void IWDG_ReloadCounter(void);//喂狗:写0xAAAA到KR

void IWDG_Enable(void);//使能看门狗:写0xCCCC到KR

FlagStatus IWDG_GetFlagStatus(uint16_t IWDG_FLAG);//状态:重装载/预分频 更新

独立看门狗操作步骤

① 取消寄存器写保护:

IWDG_WriteAccessCmd();

② 设置独立看门狗的预分频系数,确定时钟:

IWDG_SetPrescaler();

③ 设置看门狗重装载值,确定溢出时间:

IWDG_SetReload();

④ 使能看门狗

IWDG_Enable();

⑤ 应用程序喂狗:

IWDG_ReloadCounter();

窗口看门狗

窗口看门狗由从APB1时钟分频后得到时钟驱动。通过可配置的时间窗口来检测应用程序非正常的过迟或过早操作。

独立看门狗限制喂狗时间在0-x内,x由相关寄存器决定。喂狗的时间不能过晚。

image-20210504002906239

image-20210504002906239

image-20210504002906239

2种情况之一时产生看门狗复位

①当喂狗的时候如果计数器的值大于某一设定数值W[6:0]时,此设定数值在WWDG_CFR寄存器定义。

② 当计数器的数值从0x40减到0x3F时【T6位跳变到0】。

如果启动了看门狗并且允许中断,当递减计数器等于0x40时产生早期唤醒中断(EWI),它可以用于喂狗以避免WWDG复位

窗口看门狗超时时间

image-20210504003037163

image-20210504003037163

image-20210504003037163

image-20210504003042213

image-20210504003042213

image-20210504003042213

image-20210504003048243

image-20210504003048243

image-20210504003048243

控制寄存器WWDG_CR

image-20210504003143608

image-20210504003143608

image-20210504003143608

void WWDG_Enable(uint8_t Counter);//启动并设置初始值
void WWDG_SetCounter(uint8_t Counter);//喂狗

配置寄存器WWDG_CFR

image-20210504003222479

image-20210504003222479

image-20210504003222479

void WWDG_EnableIT(void);//使能提前唤醒中断
void WWDG_SetPrescaler(uint32_t WWDG_Prescaler);
void WWDG_SetWindowValue(uint8_t WindowValue);

状态寄存器WWDG_SR

image-20210504003250942

image-20210504003250942

image-20210504003250942

FlagStatus WWDG_GetFlagStatus(void);
void WWDG_ClearFlag(void);

窗口看门狗的一般配置步骤

① 使能看门狗时钟:

RCC_APB1PeriphClockCmd();

② 设置分频系数:

WWDG_SetPrescaler();

③ 设置上窗口值:

WWDG_SetWindowValue();

④ 开启提前唤醒中断并分组(可选):

WWDG_EnableIT();

NVIC_Init();

⑤ 使能看门狗:

WWDG_Enable();

⑥ 喂狗:

WWDG_SetCounter();

⑦编写中断服务函数

WWDG_IRQHandler();

wwdg.c

void WWDG_Init(u8 tr,u8 wr,u32 fprer)
{

    NVIC_InitTypeDef NVIC_InitStructure;


    RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG,ENABLE); //使能窗口看门狗时钟

    WWDG_CNT=tr&WWDG_CNT;   //初始化WWDG_CNT.
    WWDG_SetPrescaler(fprer); //设置分频值
    WWDG_SetWindowValue(wr); //设置窗口值
//	WWDG_SetCounter(WWDG_CNT);//设置计数值
    WWDG_Enable(WWDG_CNT);  //开启看门狗

    NVIC_InitStructure.NVIC_IRQChannel=WWDG_IRQn;  //窗口看门狗中断
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x02;  //抢占优先级为2
    NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x03;					//子优先级为3
    NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;  //使能窗口看门狗
    NVIC_Init(&NVIC_InitStructure);

    WWDG_ClearFlag();//清除提前唤醒中断标志位
  WWDG_EnableIT();//开启提前唤醒中断
}



//窗口看门狗中断服务程序
void WWDG_IRQHandler(void)
{
    WWDG_SetCounter(WWDG_CNT); //重设窗口看门狗值
    WWDG_ClearFlag();//清除提前唤醒中断标志位
    LED1=!LED1;
}

main.c

int main(void)
{
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
    delay_init(168);  //初始化延时函数
    LED_Init();				//初始化LED端口
    KEY_Init();		  	//初始化按键
    LED0=0;				   //点亮LED0
    delay_ms(300);
    WWDG_Init(0x7F,0X5F,WWDG_Prescaler_8); 	//计数器值为7f,窗口寄存器为5f,分频数为8

    while(1)
    {
        LED0=1;  //熄灭LED灯
    }
}

通用定时器

STM32F40x系列总共最多有14个定时器

image-20210504211715441

image-20210504211715441

image-20210504211715441

4 个独立通道(TIMx_CH1~4),这些通道可以用来作为:

① 输入捕获

② 输出比较

③ PWM 生成(边缘或中间对齐模式)

④ 单脉冲模式输出

可使用外部信号(TIMx_ETR)控制定时器和定时器互连(可以用 1 个定时器控制另外一个定时器)的同步电路。

如下事件发生时产生中断/DMA(6个独立的IRQ/DMA请求生成器):

①更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)

②触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)

③输入捕获

④输出比较

⑤支持针对定位的增量(正交)编码器和霍尔传感器电路

触发输入作为外部时钟或者按周期的电流管理

计数器模式

通用定时器可以向上计数、向下计数、向上向下双向计数模式

image-20210504212028234

image-20210504212028234

image-20210504212028234

内部时钟选择

image-20210504212300402

image-20210504212300402

image-20210504212300402

计数器当前值寄存器CNT

image-20210504212422395

image-20210504212422395

image-20210504212422395

TIMx->CNT 获取当前值

预分频寄存器TIMx_PSC

image-20210504212439222

image-20210504212439222

image-20210504212439222

自动重装载寄存器(TIMx_ARR)

image-20210504212454628

image-20210504212454628

image-20210504212454628

控制寄存器1(TIMx_CR1)

image-20210504212506320

image-20210504212506320

image-20210504212506320

DMA中断使能寄存器(TIMx_DIER)

image-20210504212523100

image-20210504212523100

image-20210504212523100

image-20210504212625091

image-20210504212625091

image-20210504212625091

image-20210504212551406

image-20210504212551406

image-20210504212551406

image-20210504212634593

image-20210504212634593

image-20210504212634593

image-20210504212646983

image-20210504212646983

image-20210504212646983

高级定时器做PWM注意事项

要加这句代码

TIM_CtrlPWMOutputs(TIM8,ENABLE);    //MOE 主输出使能

OLED

//OLED的显存
//存放格式如下.
//[0]0 1 2 3 ... 127
//[1]0 1 2 3 ... 127
//[2]0 1 2 3 ... 127
//[3]0 1 2 3 ... 127
//[4]0 1 2 3 ... 127
//[5]0 1 2 3 ... 127
//[6]0 1 2 3 ... 127
//[7]0 1 2 3 ... 127
u8 OLED_GRAM[128][8];

//OLED初始化
void OLED_Init(void)

//功能描述:显示显示BMP图片128×64起始点坐标(x,y),x的范围0~127,y为页的范围0~7
void OLED_DrawBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char BMP[])

//显示汉字
void OLED_ShowCHinese(u8 x,u8 y,u8 no)

//显示一个字符号串
void OLED_ShowString(u8 x,u8 y,u8 chr[],u8 Char_Size)


//显示2个数字
//x,y :起点坐标
//len :数字的位数
//size:字体大小
//mode:模式	0,填充模式;1,叠加模式
//num:数值(0~4294967295);
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size2)


//m^n函数
u32 oled_pow(u8 m,u8 n)


//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//mode:0,反白显示;1,正常显示
//size:选择字体 16/12
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 Char_Size)


//清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!
void OLED_Clear(void)

//开启OLED显示
void OLED_Display_On(void)

//fill_picture
void fill_picture(unsigned char fill_Data)


//OLED写命令
void Write_OLED_Command(unsigned char OLED_Command)

ESP8266

AP模式:可以将ESP8266作为热点,可以让其他的设备连接上它;
STA模式:可以连接上当前环境下的WIFI热点。、

HC-05蓝牙模块

灯的状态

模块自带了一个状态指示灯:STA。该灯有3种状态
此时STA慢闪(1秒亮1次),模块进入AT状态
模块配对成功,此时STA双闪(一次闪2下,2秒闪一次)。

进入AT模式的两种方式

①上电同时/上电之前将KEY设置为VCC,上电后,模块即进入AT指令状态。

② 模块上电后,通过将KEY接VCC,使模块进入AT状态。

方法1进入AT状态后,模块的波特率为:38400(8位数据位,1位停止位)。方法2进入AT状态后,模块波特率和通信波特率一致

指令结构

AT+<CMD><=PARAM>  设置参数格式
AT+<CMD> ? 查询参数格式

其中CMD(指令)和PARAM(参数)都是可选的,不过切记在发送末尾添加回车符(\r\n)(串口调试助手勾选发送新行就不用添加回车符),否则模块不响应,比如我们要查看模块的版本:

串口发送:AT+VERSION?\r\n

模块回应:+VERSION:2.0-20100601

OK

修改模块主从指令

AT+ROLE=0或1,该指令来设置模块为从机或主机

AT+ROLE?   来查看模块的主从状态

设置记忆指令

AT+CMODE=1,该指令设置模块可以对任意地址的蓝牙模块进行配对,模块默认设置为该参数。

AT+CMODE=0,该指令设置模块为指定地址配对,如果先设置模块为任意地址,然后配对,接下去使用该指令,则模块会记忆最后一次配对的地址,下次上电会一直搜索该地址的模块,直到搜索到为止。

修改通信波特率指令

AT+UART= <Param1>,<Param2>,<Param3>

该指令用于设置串口波特率、停止位、校验位等。

Param1为波特率,可选范围为:4800、9600、19200、38400、

57600、115200、230400、460800、921600、1382400;

Param2为停止位选择,0表示1位停止位,1表示2位停止位;

Param3为校验位选择,0表示没有校验位(None),1表示奇校验

(Odd),2表示偶校验(Even)。

比如我们发送:AT+UART=9600,0,0,则是设置通信波特率为9600,1位停止位,没有校验位,这也是我们模块的默认设置。

修改密码指令

AT+PSWD=<password>

该指令用于设置模块的配对密码,password必须为4个字节长度。

修改蓝牙模块名字

AT+NAME=<name>

该指令用于设置模块的名字,name为你要设置的名字,必须为ASCII字符,且最长不能超过32个字符。模块默认的名字为ATK-HC05。比如发送:AT+NAME=GUANG ZHOU,即可设置模块名字为“GUANG ZHOU”。

Usmart调试组件

Usmart文件说明

usmart.c负责与外部互交等。

usmat_str.c主要负责命令和参数解析。

usmart_config.c主要由用户添加需要由usmart管理的函数。

usmart.h和usmart_str.h是两个头文件,其中usmart.h里面含有几个用户配置宏定义,可以用来配置usmart的功能及总参数长度(直接和SRAM占用挂钩)、是否使能定时器扫描、是否使用读写函数等。

添加USMART包到工程,以及设置头文件路径

添加需要调用的函数添加到usmart_config.c文件中

主函数调用usmart_dev.init函数初始化Usmart

通过助手发送命令,调用再usmart中注册过的函数

delay_init(168);
uart_init(115200);
usmart_dev.init(SystemCoreClock/1000000);
LED_Init();
while(1) //这个要加串口通讯才能用,我也不知道为啥
{
    GPIO_SetBits(GPIOF,GPIO_Pin_9);
    delay_ms(500);
    GPIO_ResetBits(GPIOF,GPIO_Pin_9);
    delay_ms(500);
}

这段函数写在main函数上面

void light_led(void)  //外部实现
{
    GPIO_SetBits(GPIOF,GPIO_Pin_9|GPIO_Pin_10);
    delay_ms(500);
    GPIO_ResetBits(GPIOF,GPIO_Pin_9|GPIO_Pin_10);
    delay_ms(500);
}
extern void light_led(void); //启用外部定义,就是上面那个函数,不用再led头文件里声明,因为这个已经算是声明了,就差实现了
struct _m_usmart_nametab usmart_nametab[]=
{
    (void*)light_led,"void light_led(void)",    //这是格式,记住就好
};

USMART系统命令

?: 获取帮助信息

help: 获取帮助信息

list: 可用的函数列表

id: 可用函数的ID列表

hex: 参数16进制显示,后跟空格+数字即执行进制转换

dec: 参数10进制显示,后跟空格+数字即执行进制转换

runtime 1,开启函数运行计时;0,关闭函数运行计时;

请按照程序编写格式输入函数名及参数并以回车键结束.

RTC时钟

if(RTC_ReadBackupRegister(RTC_BKP_DR0)!=0x5050)
    {
        RCC_LSEConfig(RCC_LSE_ON);  //LSE时钟需要加
        while(RCC_GetFlagStatus(RCC_FLAG_LSERDY)==RESET)//检查指定的RCC标志位设置与否,等待低速晶振就绪
        {
            retry++;
            delay_ms(10);
        }
        if(retry==0)return 1;	 //LSE 开启失败
        RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);  //设置RTC时钟(RTCCLK),选择LSE作为RTC时钟
        RCC_RTCCLKCmd(ENABLE);	//使能RTC时钟

      //配置RTC

        RTC_InitStructure.RTC_AsynchPrediv = 0x7F;//RTC异步分频系数(1~0X7F)
        RTC_InitStructure.RTC_SynchPrediv  = 0xFF;//RTC同步分频系数(0~7FFF)
        RTC_InitStructure.RTC_HourFormat   = RTC_HourFormat_24;//RTC设置为,24小时格式
        RTC_Init(&RTC_InitStructure);


        RTC_Set_Time(11,28,00,RTC_H12_AM);	//设置时间
        RTC_Set_Date(21,7,4,7);		//设置日期

        RTC_WriteBackupRegister(RTC_BKP_DR0,0x5050);	//标记已经初始化过了
    }

硬件随机数

u8  RNG_Init(void);			//RNG初始化
u32 RNG_Get_RandomNum(void);//得到随机数
int RNG_Get_RandomRange(int min,int max);//生成[min,max]范围的随机数

ADC模数转换

IIC

24c02

SPI

W25Qxx


#stm32