
比如说按键中断
1.要使能时钟和相关GPIO口(按键口)
2.使能中断嵌套程序NVIC,里面的关键是中断类型(在本例子中就是外部中断啦,所有的中断都要使能NVIC,否则不能中断),如果就一个中断,优先级可忽略
3.使能外部中断EXTI,其实就是按键中断了
4.主程序中一般是循环啦
举个例子,最简单的
mian()
{
RCC_config()
GPIO_config()
NVIC_config()
EXTI_Config()
while(1)
}
5.中断函数程序中,注意这个是在另一个文件下stm32f10x_it.c,而上面的所有步骤都是在main.c文件中的
编写中断程序
void EXTI9_5_IRQHandler(void)
{
delay()//延时函数
}
因为我用的是第8道,所以函数名是
EXTI9_5_IRQHandler
6.开始运行程序啦,从上往坦樱下走,配置完了时钟,GPIO,NVIC,EXTI后就进入while(1)死循环中,这时候当你按下按键后,会产生一个电平的变换1变0或0变1,对应的GPIO口接受到这个变换后就会发生中断,进入中断函数
EXTI9_5_IRQHandler,中断函数中是个延时函数,等延时完就会结束中断函数返回主函数啦。
贴一个我写的小例子,就是按键中断的。主函数中为橘孝点亮灯,中断函数为熄灭灯
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "圆信稿stm32f10x_rcc.h"
#include "stm32f10x_exti.h"
void RCC_Configuration(void) //时钟配置函数
{
ErrorStatus HSEStartUpStatus
//使能外部晶振
RCC_HSEConfig(RCC_HSE_ON)
//等待外部晶振稳定
HSEStartUpStatus = RCC_WaitForHSEStartUp()
//如果外部晶振启动成功,则进行下一步 *** 作
if(HSEStartUpStatus==SUCCESS)
{
//设置HCLK(AHB时钟)=SYSCLK 将系统时钟进行分频后,作为AHB总线时钟
RCC_HCLKConfig(RCC_SYSCLK_Div1)
//PCLK1(APB1) = HCLK/2 将HCLK时钟2分频后给低速外部总线
RCC_PCLK1Config(RCC_HCLK_Div2)
//PCLK2(APB2) = HCLK HCLK时钟配置给高速外部总线
RCC_PCLK2Config(RCC_HCLK_Div1)
//外部高速时钟HSE 4倍频
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_4)
//启动PLL
RCC_PLLCmd(ENABLE)
//等待PLL稳定
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
//系统时钟SYSCLK来自PLL输出
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK)
//切换时钟后等待系统时钟稳定
while(RCC_GetSYSCLKSource()!=0x08)
}
// RCC system reset(for debug purpose) 下面这些都是外设总线上所挂的外部设备时钟的配置
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE)
}
extern void Delay(int cnt) //延时函数
{
int i,j
for (i=0i<cnti++)
{ for (j=0j<1000j++)
{
}
}
}
void GPIO_Configuration(void) //GPIO配置函数
{
//GPIO_DeInit(GPIOA)
GPIO_InitTypeDef GPIO_InitStructure
//RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE)
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz
GPIO_InitStructure.GPIO_Mode= GPIO_Mode_Out_PP
GPIO_Init(GPIOA,&GPIO_InitStructure)
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_12
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz
GPIO_InitStructure.GPIO_Mode= GPIO_Mode_Out_PP
GPIO_Init(GPIOB,&GPIO_InitStructure)
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_8|GPIO_Pin_9
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz
GPIO_InitStructure.GPIO_Mode= GPIO_Mode_IPU
GPIO_Init(GPIOB,&GPIO_InitStructure)
}
void EXTI_Config(void)
{
EXTI_InitTypeDef EXTI_InitStructure
// 管脚选择
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource8)
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource9)
// 清除 EXTI线路挂起位
EXTI_ClearITPendingBit(EXTI_Line8|EXTI_Line9)
//
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling
EXTI_InitStructure.EXTI_Line = EXTI_Line8
EXTI_InitStructure.EXTI_LineCmd = ENABLE
EXTI_Init(&EXTI_InitStructure)
}
void NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0)
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn// 注意名称是“_IRQn”,不是“_IRQChannel”
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0//
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0//
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE
NVIC_Init(&NVIC_InitStructure)
}
int main(void)
{
RCC_Configuration()
GPIO_Configuration()
EXTI_Config()
NVIC_Config()
while(1)
{
GPIO_ResetBits(GPIOB,GPIO_Pin_12)
GPIO_ResetBits(GPIOA,GPIO_Pin_4)
}
}
IT中的函数
void Delay()
void EXTI9_5_IRQHandler(void)
{
if ( EXTI_GetITStatus(EXTI_Line8) != RESET )
{
EXTI_ClearITPendingBit(EXTI_Line8)
GPIO_SetBits(GPIOA,GPIO_Pin_4)
//Delay(100)
while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_8)==0)
}
if ( EXTI_GetITStatus(EXTI_Line9) != RESET )
{
EXTI_ClearITPendingBit(EXTI_Line9)
//Delay(1000)
GPIO_SetBits(GPIOB,GPIO_Pin_12)
while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_9)==0)
}
}
STM32F10XXX系列包含TIM6、TIM7两个基本定时器,计数器为16位,其功能比较简单,仅支持向上计数,且只能计时,没有外部I/O口。一、基本定时器的功能框图
1、时钟源TIMxCLK:定时器的时钟源来自系统内部时钟,准确来说由APB1预分频器分频提供,因为TIM6、7都是挂载在APB1上的外设。如果APB1的预分频系数等于1,则频率不变,其他情况,频率乘以2,库函数中APB1的分频系数为2,故定时器的时钟TIMxCLK=36*2=72MHz。
2、计数器时钟CK_CNT:CK_PSC可看成直接由CK_INT经触发控制器引入,PSC预分频器为16位寄存器,可对TIMxCLK进行1~65536分频,计算公式为:CK_CNT=TIMxCLK/(PSC+1)。
3、计数器CNT:计数器CNT为16位寄存器,只能向上计数,最大值为65535,当计数器有0加到65535并溢出时,可以产生一个更新中断/更新键碧事件。
4、自动重装寄存器ARR:16位寄存器,里面的数值为计数器能达到的最大数值。
5、产生一次中断的时间计算:time=(ARR+1)/(TIMxCLK/(PSC+1))
在实际中,预分频器起分频作用的是其影子寄存器谈亮升或称为缓冲器。由下图的时序图可见:
ARR的值为FC-1,最开始预分频控制寄存器的值为0,此时预分频系数为1,即计数器时钟为72MHz。当计数器计数到F8时,我们将预分频控制寄存含老器的值写为1,此时,预分频器缓冲寄存器的值并没有立即更新为1,定时器的时钟依然为72MHz,计数器计数到FC,产生一个更新事件后,才将预分频器缓冲器的值更新为1,此时定时器的时钟变为原来的一半,即36MHz,保证了计数的准确性。
二、时基单元
typedef struct
{
uint16_t TIM_Prescaler/*!<Specifies the prescaler value used to divide the TIM clock.
This parameter can be a number between 0x0000 and 0xFFFF */
uint16_t TIM_CounterMode /*!<Specifies the counter mode.
This parameter can be a value of @ref TIM_Counter_Mode */
uint16_t TIM_Period /*!<Specifies the period value to be loaded into the active
Auto-Reload Register at the next update event.
This parameter must be a number between 0x0000 and 0xFFFF. */
uint16_t TIM_ClockDivision/*!<Specifies the clock division.
This parameter can be a value of @ref TIM_Clock_Division_CKD */
uint8_t TIM_RepetitionCounter /*!<Specifies the repetition counter value. Each time the RCR downcounter
reaches zero, an update event is generated and counting restarts
from the RCR value (N).
This means in PWM mode that (N+1) corresponds to:
- the number of PWM periods in edge-aligned mode
- the number of half PWM period in center-aligned mode
This parameter must be a number between 0x00 and 0xFF.
@note This parameter is valid only for TIM1 and TIM8. */
} TIM_TimeBaseInitTypeDef
1、TIM_Prescaler:定时器预分频器设置
2 、TIM_CounterMode:计数器有向上计数、向下计数、中心对齐计数3中模式,基本定时器仅支持向上计算,这里不用设置
3、TIM_Period:定时器周期,实际就是设置自动重装寄存器ARR的值
4 、TIM_ClockDivision:时钟分频,设置定时器时钟CK_INT频率与数字滤波器采样时钟频率的分频比,基本定时器不用设置
5 、TIM_RepetitionCounter:重复计数器,属于高级定时器的功能,不用设置
三、代码
使用定时器实现1S定时,因为STM32F103C8T6只有TIM1、TIM2、TIM3、TIM4这几个定时器,这里使用TIM2代替TIM6。
Timer.c文件
#include "stm32f10x.h" // Device header
void Timer_Init(void)
{
//第一步:开启APB1上的TIM2外设时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE)
//第二步:时钟源选择内部时钟
TIM_InternalClockConfig(TIM2)
//第三步:初始化TIM2时基单元
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up
TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1
TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure)
//第四步:手动清除计数器中断标志位
TIM_ClearFlag(TIM2, TIM_FLAG_Update)
//第五步:开启计数器中断
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE)
//第六步:配置NVIC
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2)
NVIC_InitTypeDef NVIC_InitStructure
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1
NVIC_Init(&NVIC_InitStructure)
//第七步:计数器使能
TIM_Cmd(TIM2, ENABLE)
}
main.c文件
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"
uint16_t Num
int main(void)
{
OLED_Init()
Timer_Init()
OLED_ShowString(1, 1, "Num:")
while (1)
{
OLED_ShowNum(1, 5, Num, 5)
}
}
/*TIM2中断处理程序*/
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
{
Num ++
TIM_ClearITPendingBit(TIM2, TIM_IT_Update)
}
}
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)