STM32-F407ZGT6
STM32-F407ZGT6
沐飞STM32-F407ZGT6
144引脚 1024K字节闪存储存器 LQFP封装 -40°C~85°C工作范围
开发板介绍
开发板介绍
image-20210404103005743
image-20210404103005743
STM32内核
ARM内核的32位MCU系列
–Cortex-M内核
–标准的ARM架构
uCortex-M4采用ARMv7-ME架构
image-20210404103355273
image-20210404103355273
Cortex-M4与M3对比
image-20210404103505452
image-20210404103505452
ARMv7架构定义了三大分工明确的系列:
“A”系列:面向尖端的基于虚拟内存的操作系统和用户应用
“R”系列:针对实时系统;
“M”系列:对微控制器。
学习方法
掌握调试工具:JTAG
image-20210404102642577
image-20210404102642577
多使用JTAG调试代码,深入理解代码执行流程。在基础不够扎实的时候,不要走马换花的看,要做到深入理解代码涵义。
库函数和寄存器对比学习
项目中大多数用库函数。但是学习,如果你只会看几个函数的话,你根本没有学懂,遇到问题很难自己解决,所以必要了解一下寄存器配置原理,加深理解。
尤其前面几个章节实验,最好了解寄存器配置,加深对STM32本质的理解。
STM32最小系统
供电
复位
时钟:外部晶振(2个)
Boot启动模式选择
下载电路(串口/JTAG/SWD)
后备电池
连接串口
image-20210404151322239
image-20210404151322239
RXD和TXD是连接usb_232 PA9和PA10用来烧录程序
串口1(PA1)才能作为串口下载,也可以用于串口通信
PA2和PA3 只能用来串口通信,不能下载
下载程序flyMcu使用
搜索串口,F4波特率最高设置为76800 其他按照下图配置
image-20210404152655145
image-20210404152655145
下载程序是用Jlink
配置:
enterDebug
enterDebug
Setting
Setting
select
select
下载程序
load
load
STM32启动模式
image-20210404153858964
image-20210404153858964
由下图控制
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-20210405164434228
image-20210405164434228
高16位未使用
端口输出速度寄存器
image-20210405164457134
image-20210405164457134
端口上拉/下拉寄存器
image-20210405164518948
image-20210405164518948
端口输入数据寄存器
image-20210405164546230
image-20210405164546230
端口输出数据寄存器
QQ图片20210405165937
QQ图片20210405165937
端口上输出0或1是有影响的
端口置位/复位寄存器
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
STM32F4开发指南-库函数版本_V1
STM32F4开发指南-库函数版本_V1
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
对于STM32,外部时钟源是 HCLK(AHB总线时钟)的1/8
内核时钟是 HCLK时钟
配置函数:SysTick_CLKSourceConfig();
SysTick 重装载数值寄存器- LOAD
image-20210429211659749
image-20210429211659749
SysTick 当前值寄存器- VAL
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
对于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
抢占优先级 & 响应优先级区别
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
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
数据寄存器
void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);
uint16_t USART_ReceiveData(USART_TypeDef* USARTx);
image-20210504000938955
image-20210504000938955
void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);
image-20210504001007646
image-20210504001007646
波特率计算公式
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
中断服务函数列表
用于写中断后的操作
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-20210504002357377
image-20210504002357377
重载寄存器
image-20210504002432525
image-20210504002432525
状态寄存器
image-20210504002451419
image-20210504002451419
独立看门狗超时时间
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
2种情况之一时产生看门狗复位
①当喂狗的时候如果计数器的值大于某一设定数值W[6:0]时,此设定数值在WWDG_CFR寄存器定义。
② 当计数器的数值从0x40减到0x3F时【T6位跳变到0】。
如果启动了看门狗并且允许中断,当递减计数器等于0x40时产生早期唤醒中断(EWI),它可以用于喂狗以避免WWDG复位
窗口看门狗超时时间
image-20210504003037163
image-20210504003037163
image-20210504003042213
image-20210504003042213
image-20210504003048243
image-20210504003048243
控制寄存器WWDG_CR
image-20210504003143608
image-20210504003143608
void WWDG_Enable(uint8_t Counter);//启动并设置初始值
void WWDG_SetCounter(uint8_t Counter);//喂狗
配置寄存器WWDG_CFR
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
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
4 个独立通道(TIMx_CH1~4),这些通道可以用来作为:
① 输入捕获
② 输出比较
③ PWM 生成(边缘或中间对齐模式)
④ 单脉冲模式输出
可使用外部信号(TIMx_ETR)控制定时器和定时器互连(可以用 1 个定时器控制另外一个定时器)的同步电路。
如下事件发生时产生中断/DMA(6个独立的IRQ/DMA请求生成器):
①更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)
②触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)
③输入捕获
④输出比较
⑤支持针对定位的增量(正交)编码器和霍尔传感器电路
触发输入作为外部时钟或者按周期的电流管理
计数器模式
通用定时器可以向上计数、向下计数、向上向下双向计数模式
image-20210504212028234
image-20210504212028234
内部时钟选择
image-20210504212300402
image-20210504212300402
计数器当前值寄存器CNT
image-20210504212422395
image-20210504212422395
TIMx->CNT 获取当前值
预分频寄存器TIMx_PSC
image-20210504212439222
image-20210504212439222
自动重装载寄存器(TIMx_ARR)
image-20210504212454628
image-20210504212454628
控制寄存器1(TIMx_CR1)
image-20210504212506320
image-20210504212506320
DMA中断使能寄存器(TIMx_DIER)
image-20210504212523100
image-20210504212523100
image-20210504212625091
image-20210504212625091
image-20210504212551406
image-20210504212551406
image-20210504212634593
image-20210504212634593
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