8、EXTI中断线的映射规则
23根(23个通道,16个针对输入输出端口,每个I/O都可以映射为外部中断线,同一编号的I/O口同时只能由一个映射为外部中断线)
配置:SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource2)
//PE几连到中断线几
9、外部中断、内部中断的中断服务函数名
(固定的,编程用到,外部中断线9-5、10-15共用一个)
在stm32f4xx_it.c定义
void EXTI0_IRQHandler(void)
void EXTI1_IRQHandler(void)
void EXTI9_5_IRQHandler(void)
void EXTI15_10_IRQHandler(void)
外部中断:0~4各一个,5~9共用,10~15共用
10、EXTI相关寄存器含义
中断屏蔽寄存器 (EXTI_IMR)
事件屏蔽寄存器 (EXTI_EMR)
上升沿触发选择寄存器 (EXTI_RTSR)
下降沿触发选择寄存器 (EXTI_FTSR)
软件中断事件寄存器 (EXTI_SWIER)
挂起寄存器 (EXTI_PR)
11、EXTI固件库:
stm32f4xx_exti.h,stm32f4xx_exti.c
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
//初始化中断线类型、触发方式
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);
//判断中断线中断状态是否发生
EXTI_ClearITPendingBit()
//清除中断线上标志位
EXTI_InitStructure.EXTI_Line = EXTI_Line2; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure);
中断服务函数。
EXTIx_IRQHandler();
中断服务函数最后一步:清除中断标志位
void EXTI_ClearITPendingBit(uint32_t EXTI_Line);
示例:
void EXTI3_IRQHandler(void){ if (EXTI_GetITStatus(EXTI_Line3)!=RESET){//判断某个中断是否发生 //中断逻辑 EXTI_ClearITPendingBit(EXTI_Line3); //清除LINE上的中断标志位 } }
12、根据电路连接图判别外部中断的触发方式
按键连接高电平,按下接通电路。则需要默认输出低电平,下拉,高有效,上升沿触发。
按键连接低电平,按下接通电路,则需要默认输出高电平,上拉,低有效,下降沿触发。
第4讲WDG
窗口看门狗挂在APB1。独立看门狗内部自带时钟,不挂载总线。
1、WDG的作用
递减器计数(定时器),溢出时,使系统复位
2、IWDG、WWDG的特点、工作原理
IWDG(独立看门狗):由专用的低速时钟(LSI,32kHz)驱动,即使主时钟发生故障它仍有效,但精度不高(15~47kHz )应用于需要看门狗作为一个在主程序之外能够完全独立工作,并且对时间精度要求较低的场合。
在键值寄存器(IWDG_KR)中写入0xCCCC(启动),开始启用独立看门狗。此时计数器开始从其复位值0xFFF递减,当计数器值计数到尾值0x000时会产生一个复位信号(IWDG_RESET)。无论何时,只要往键值寄存器IWDG_KR中写入0xAAAA(俗称喂狗), 自动重装载寄存器IWDG_RLR的值就会重新加载到计数器,从而避免看门狗复位。如果程序异常,就无法正常喂狗,则导致系统复位。
WWDG(窗口看门狗):由APB1分频(4096)后的时钟驱动,精度高。通过可配置的时间窗口来检测应用程序非正常的过迟或过早操作。最适合那些要求看门狗在精确计时窗口起作用的程序。可触发中断(提前唤醒中断)
3、IWDG、WWDG寄存器的含义
IWDG_KR
:钢铁雄心4mod KaiserReich键值寄存器,只写
IWDG_RLR
:每次喂狗时重载入计数器的初值,具有写保护。
IWDG_SR
:状态寄存器,为1时表示正在更新,为0时表示复位
IWDG_PR
:预分频寄存器。
WWDG_CR
:控制寄存器,第7位为激活位,低位为计数器
WWDG_CFR
:第9位为是否使能提前唤醒中断EWI(在计数值0x40时唤醒并用中断服务程序提醒主程序去喂狗),第8位第7位为定时器时基,低7位为上窗口值。
WWDG_SR
:提前唤醒中断标志,计数器值达到0x40时硬件置1
4、IWDG几个键值的作用:
aaaah:喂狗
5555h:去除写保护,使能对IWDG_PR和IWDG_RLR访问
cccch:启动(使能)看门狗
0000h:加写保护对IWDG_PR和IWDG_RLR
5、了解IWDG、WWDG库函数、配置流程
IWDG库函数:
void IWDG_WriteAccessCmd(uint16_t IWDG_WriteAccess);//写保护:0x5555使能写;0x0000失能写 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(prer);//设置独立看门狗的预分频系数,确定时钟: IWDG_SetReload(rlr);//设置看门狗重装载值,确定溢出时间: IWDG_Enable();//使能(启动)看门狗 IWDG_ReloadCounter(); //应用程序喂狗
void WWDG_SetPrescaler(uint32_t WWDG_Prescaler);//预分频 void WWDG_SetWindowValue(uint8_t WindowValue); //窗口设置 void WWDG_EnableIT(void);//使能EWI中断 void WWDG_SetCounter(uint8_t Counter);//设置计数值,喂狗 void WWDG_Enable(uint8_t Counter);//使能WWDG,并写入计数值 FlagStatus WWDG_GetFlagStatus(void);//获取EWIF void WWDG_ClearFlag(void);//清除EWIF
配置步骤:
RCC_APB1PeriphClockCmd();//使能看门狗时钟 WWDG_SetPrescaler(fprer);//设置分频系数 WWDG_SetWindowValue(wr);//设置上窗口值 WWDG_EnableIT();NVIC_Init();//开启提前唤醒中断并对NVIC初始化(可选): WWDG_Enable(WWDG_CNT);//使能看门狗: WWDG_SetCounter();//喂狗,一般放在ISR(中断服务程序) WWDG_IRQHandler();//编写中断服务函数
第5-7讲TIM
TIM1和TIM8在APB2,TIM2~TIM5在APB1,TIM9~TIM11在APB2,TIM12~TIM14、TIM6和TIM7在APB1
1、STM32F4有哪几类定时器、特点、计数模式
STM32F40x系列总共有最多14个定时器:
通用定时器TIM2~TIM5
通用定时器TIM9~TIM14
基本定时器TIM6、TIM7
高级定时器TIM1、TIM8
看门狗(IWDG、WWDG)本质上也是定时器
TIM2、TIM5为32位,其他16位
Cortex内核的SysTick计时器(24位递减)
2、定时器原理(基本定时模块、输入捕捉模块、输出比较模块)、输入捕捉通道数量、产生PWM的通道数量
16/32位向上、向下、向上/向下(中心对齐)计数模式,自动重装载计数器。16位可编程预分频器,分频系数为1~65536,可实时修改。4个独立通道(TIMx_CH1 ~4),可用作:输入捕获/输出比较/PWM生成/单脉冲输出,可对外部信号(TIMx_ETR)计数,可以定时器级连.
输入捕捉通道数量:TIM6、7无此功能,10、11、13、14一个通道,9、12二个通道,其他4个通道
PWM输出通道数量:TIM1/TIM8产生7路PWM输出,TIM2~5同时4路PWM输出。TIM9、TIM12同时2路PWM输出,TIM10/11/13/14产生1路PWM输出
3、定时时间的计算
若APB1的分频系数是1,则TIMx的时钟等于APB1时钟(×1),否则TIMx的时钟等于APB1时钟的2倍(×2)。
(T1/T8/T9~11时钟信号来自APB2)
CK_PSC为时钟周期。
4、相关寄存器的含义、作用
TIMx_CNT
:实现计数功能
TIMx_PSC
:对CK_PSC预分频,
TIMx_ARR
:自动重载寄存器。
TIMx_CR1
:控制寄存器
TIMx_DIER
:中断控制
TIMx_SR
:状态寄存器,低位表示中断,其他位用于捕获/比较
TIMx_CCER
:捕获比较使能寄存器
TIMx_CCMR1
:PWM输出模式
5、库函数的使用、各方式的配置流程
stm32f4xx_tim.c、stm32f4xx_tim.h
void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);//定时器参数(基本定时功能)初始化 void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);//定时器使能函数 void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);//定时器中断使能函数 //状态标志位获取和清除 FlagStatus TIM_GetFlagStatus(TIM_TypeDef* TIMx, uint16_t TIM_FLAG); void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG); ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT);//获取中断标志位 void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);//中断标志位挂起清除
TIM_TimeBaseStructure.TIM_Prescaler=7199;//预分频 TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;//计数模式 TIM_TimeBaseStructure.TIM_Period = 4999;//周期(重装载值) TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
定时器中断
RCC_APBxPeriphClockCmd();//使能定时器时钟 TIM_TimeBaseInit();//配置ARR、PSC、CR1,初始化定时器 TIM_ITConfig()、NVIC_Init();//开启定时器中断,配置NVIC TIM_Cmd(); //配置CR1的CEN位,使能定时器 TIMx_IRQHandler();//编写中断服务函数
输入捕获通道初始化
void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
TIM5_ICInitStructure.TIM_Channel=TIM_Channel_1;//通道 TIM5_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;//边沿选择 TIM5_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI; //通道映射 TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;//预分频(DIV1不分频) TIM5_ICInitStructure.TIM_ICFilter = 0x00;//不滤波 TIM_ICInit(TIM5, &TIM5_ICInitStructure);
通道极性设置独立函数
void TIM_OCxPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
获取通道捕获值函数uint32_t TIM_GetCapture1(TIM_TypeDef* TIMx);
输入捕获的一般配置步骤
//1.使能定时器和通道对应IO的时钟。 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //2.初始化IO口,模式为复用:GPIO_Init(); GPIO_PinAFConfig();//3.设置引脚复用映射 TIM_TimeBaseInit();//4.初始化定时器ARR,PSC TIM_ICInit();//5.初始化输入捕获通道(time的时基和输入捕获都要初始化) TIM_ITConfig(); NVIC_Init(); NVIC_PriorityGroupConfig();//6.如果要开启捕获中断 TIM_Cmd();//7.使能定时器 TIMx_IRQHandler();//8.编写中断服务函数
PWM输出通道初始化函数:
void TIM_OCxInit(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
示例: TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //PWM模式2 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能 TIM_OCInitStructure. TIM_Pulse=100; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高(CC1P) TIM_OC2Init(TIM3, &TIM_OCInitStructure); //初始化TIM3_OC2
设置比较值函数
void TIM_SetCompareX(TIM_TypeDef* TIMx, uint16_t Comparex);
使能输出比较预装载
void TIM_OCxPreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
使能自动重装载的预装载寄存器允许位
void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);
PWM输出配置步骤
RCC_APB1PeriphClockCmd(); RCC_AHB1PeriphClockCmd ();//使能定时器14和相关IO口时钟。 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//初始化IO口为复用功能输出。//复用功能 GPIO_PinAFConfig(GPIOF,GPIO_PinSource9,GPIO_AF_TIM14);//GPIOF9复用映射到定时器14 TIM_TimeBaseInit();//初始化定时器时基:ARR,PSC等: TIM_OC1Init();//初始化输出比较参数 TIM_OC1PreloadConfig(TIM14, TIM_OCPreload_Enable);//使能预装载寄存器: TIM_ARRPreloadConfig(TIM14,ENABLE);//使能自动重装载的预装载寄存器允许位 void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState)//使能定时器 TIM_SetCompare1();//不断改变比较值CCRx,达到不同的占空比效果:
6、输入捕捉的原理,如何测量脉冲的宽度和周期
输入阶段:消除抖动、边沿选择、通道选择、分频,得到的信号直接控制主电路。得到捕获控制信号后,读取捕获值。
上升沿捕获得到计数值1,下降沿捕获得到计数值2,计算得到脉宽。(中间可能有多次溢出)
7、输入捕捉中的硬件滤波原理
在CK_INT的DTS时钟下控制滤波。假如DTS采样频率=计数器的时钟(CK_INT)频率,采样次数N=4,则在上升沿时采样信号进行倒计数,没记到N次时电平又低了,则不认为是有效信号。若上升沿持续了N个DTS周期,认为有效。在输入信号变低后,经过N个DTS周期,滤波后的信号也变低。时间延迟了N个DTS周期,宽度不变。
8、PWM的原理、作用,占空比、周期如何改变
PWM(Pulse Width Modulation)即脉冲宽度调制,也就是占空比和周期均可变的脉冲波形。
原理:冲量相等而形状不同的窄脉冲加在具有惯性的环节上时,其效果基本相同。
作用:PWM脉冲宽度调制是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,广泛应用在从测量、通信到功率控制与变换的许多领域中。
改变周期可达到调频效果,改变脉宽或占空比可达到调压效果。故采用适当的控制方法即可使电压电流与频率协调变化。
改变重载值ARR可以改变周期,改变比较值CCRx可以改变脉宽(占空比)
PWM频率=计数频率/重装载值
9、影子寄存器与原寄存器的关系,作用
物理上对应两个寄存器(缓冲作用),一个程序可直接操作的,另一个叫影子寄存器(真正起作用的).由TIMx_CR1.APRE控制,APRE=0两者直通,APRE=1,每次更新事件(UEV)时接通。
void TIM_ARRPreloadConfig(TIM_TypeDef *TIMx,FunctionalState NewState);
第9讲USART
USART1、USART6挂在APB2,其他APB1。
1、几种常见串行通信标准(UART、USART、SPI、I2C、1-wire)的特点
USART:引脚同UART,异步通信,全双工。
2、USART主要寄存器
USART_SR:状态寄存器
TXE:发送数据寄存器的数据是否传到移位寄存器,1表示完成
TC:0表示发送未完成,1表示发送完成
RXNE:0表示未接受,1表示已准备好读取接收到的数据
USART_DR:数据寄存器
USART_CR:控制寄存器
USART_BRR:波特率寄存器
15~4位存储USARTDIV的整数部分(PPT有误),3~0存放USART小数。小数部分的数值*16后以二进制存储。
3、波特率计算,
4、常用库函数,中断方式工作、查询方式工作,接收、发送方法(含库函数与寄存器两种方式)
void USART_Init();//串口初始化:波特率、数据字长、奇偶校验、硬件流、收发使能 void USART_Cmd();//串口使能 void USART_ITConfig();//相关中断使能
查询
FlagStatus USART_GetFlagStatus(); //获取状态标志位 void USART_ClearFlag(); //清除状态标志位 while(USART_GetFlagStatus(USART1, UART_FLAG_TC) == RESET); //等待发送完成 while((USART1->SR&0x40)==0);//等待发送完成(寄存器方式) while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET); while(USART1->SR & Ox20 == 0);//等待接收完成
中断
if(USART_GetITStatus(USART1,USART_IT_RXNE)){ res=USART_ReceiveData(USART1);//读取接收到的数据 //USART_SendData(USART1,res);//把接收到的数据发回去 USART_ClearITPendingBit(USART1,USART_IT_RXNE); }
ITStatus USART_GetITStatus(); //获取中断状态标志位 void USART_ClearFlag();//清楚状态标志位 void USART_ClearITPendingBit(); //清除中断状态标志位
接收
uint16_t USART_ReceiveData(); //接受数据,读DR(RDR) ch=USART_ReceiveData(USART1);//读取一个数据存到ch ch=USART1->DR;//寄存器方式
发送
void USART_SendData(); //发送数据,库函数 USART_SendData(USART1,ch);//发送ch USART1->DR=ch;//寄存器方式发送库函数
5、USART的应用,与主机串口调试助手通信,结合其他模块,如GPIO、NVIC等
主机(串口调试助手)发送数据到STM32的USART1, USART1将收到的数据直接再发送到主机。
void My_USART1_Init(void){ GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | 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); USART_SendData(USART1,res); USART_ClearITPendingBit(USART1,USART_IT_RXNE); } } int main(void){ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); My_USART1_Init(); while(1); } struct __FILE { int handle; }; FILE __stdout; int fputc(int ch, FILE *f){ while((USART1->SR&0x40)==0); //等待发送完成 USART1->DR = (u8) ch; return ch; }
6、STM32F407支持多少UART、多少USART
2个UART。挂在APB1:UART4、UART5.
4个USART。挂在APB1:USART2、3,挂在APB2:USART1、USART6