继续之前的中断学习,编写中断代码。

标书签的是常用函数

教程是要初始化TIM2,所以我也跟着教程走。

开启定时器时钟

首先初始化时钟,TIM2是在APB1总线上的,所以要是使用APB1的开启时钟函数。

使用TIM_InternalClockConfig函数选择TIM2内部时钟。这个如果不严谨的来说可以省略,因为定时器上电后默认就是使用内部时钟如果不调用这个函数是使用的内部时钟。

配置TIM2定时器

使用TIM_TimeBaseInit函数初始化定时器。TIM_TimeBaseInitTypeDef结构体定义一下。

然后引出所有的结构体成员:

TIM_ClockDivision:时钟分频参数。

TIM_CounterMode:计数器模式

TIM_Period:ARR自动重装器的值

TIM_Prescaler:PSC预分频器的值

TIM_RepetitionCounter:重复计数器的值(这个参数是高级定时器才有的,因为是设置TIM2定时器,没有这个东西,所以设置0就好。)

然后再将TIM_TimeBaseInitStructure放入TIM_TimeBaseInit函数里就好了。

TIM_Period和TIM_Prescaler的值需要根据之前的计数器溢出频率来算,如果定时1s的话定时频率为1Hz(1MHz=106 Hz),代入公式就是1=216000000/(21599+1)/(9999+1)

所以这里把PSC设置为21599,ARR设置为9999。要注意PSC和ARR的取值都要在0~65535之间,不可以超出范围)

TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 9999;
TIM_TimeBaseInitStructure.TIM_Prescaler = 21599;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);

使能更新中断

TIM_ITConfig就是使能中断的函数。

开启更新中断到NVIC的通路

TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);

然后配置NVIC

	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel= TIM2_IRQn;              //通道选择TIM2中断
	NVIC_InitStructure.NVIC_IRQChannelCmd= ENABLE;              //使能
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 2;    //响应优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority= 1;           //抢占优先级
	
	NVIC_Init(&NVIC_InitStructure);

启动定时器

配置TIM_Cmd函数即可

TIM_Cmd(TIM2, ENABLE);

然后配置一下中断函数设置一个变量NUM每进一次中断NUM++就好了,这里教程还有个点就是如果库函数想读取主函数的值可以在开头定义的变量前面加个extern这样就是读取的主函数那个文件变量NUM的值了。

然后编译一下没问题的话就可以烧录了,下面展示下烧录完以后程序运行的效果:

小bug

每次上电/复位单片机都是从1开始计数,而不是从0开始。

首先看下TIM_TimeBaseInit的最后有一条TIMx->EGR = TIM_PSCReloadMode_Immediate; 是用来生成一个更新事件来立刻装载预分频器和重复计数器的值,会让更新事件和更新中断同时发生,导致刚上电就进中断了。

解决方法:使用TIM_ClearFlag函数手动清除一下更新中断标志位,这样就能避免刚初始化完就进中断的问题了。TIM_ClearFlag函数添加在TIM_ITConfig之前。

TIM2中断初始化修改后函数

void Timer_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	
	TIM_InternalClockConfig(TIM2);
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = 9999;
	TIM_TimeBaseInitStructure.TIM_Prescaler = 21599;
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
	
	TIM_ClearFlag(TIM2,TIM_FLAG_Update);                        //手动清除一次标志位
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel= TIM2_IRQn;              //通道选择TIM2中断
	NVIC_InitStructure.NVIC_IRQChannelCmd= ENABLE;              //使能
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 2;    //响应优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority= 1;           //抢占优先级
	
	NVIC_Init(&NVIC_InitStructure);
	
	TIM_Cmd(TIM2, ENABLE);
}

定时器时钟选择实验

切换内部时钟到外部时钟先删除之前的时钟配置函数TIM_InternalClockConfig使用TIM_ETRClockMode2Config函数。

这里我失败了,我本来想用端口重映射到PA15来按着教程继续走可是AIR32还是和STM32不同,他不能部分重映射到PA15,我一开始看的是规格书,规格书上写的是有这功能,我以为部分重映射就可以了结果去官网一查发现只有全部重映射才行。。。。哎,如果我选择全部重映射的话就要关闭JTAG功能,但是AIR32不可以自由关闭JTAG功能,要么就JTAG和SW同时开,要么同时关,所以步做不下去了,不过应该问题不大,原理明白了,其实改下软IIC的引脚定义就好,今天有点晚了,改天吧。

附上官网截图:

地址:https://wiki.luatos.com/chips/air32f103/switchFromSxx.html#air32f103

某种意义上“骗”我的规格书。。。。。