ST提供的固件库给我们很大的方面,但我十分不喜欢使用固件库因为它不简洁等一些原因,所以自己不断琢磨怎么用汇编和C语言编写自己想要的程序。以定时器TMI1上溢中断的产生为例总结一下这种方法。硬件条件是:外部晶振使用HIE=6MHz;目标是:定时器每10S进中断一次使LED闪烁。
首先要知道这个中断(TIM1上溢事件)的中断向量地址在哪?汇编部分就是编写一个跳转程序,用来保证在产生中断时会跳入自己写的C程序中,这个可以参考启动代码STM32F10X.S中的复位函数的编写,但要注意地址的对准,这里不在赘述。
然后根据需要编写一个中断处理程序,这个里面必须将TIM1的上溢中断标志清零(TIM1_SR中第0位),否则时间没到程序一直在这个中断函数里面出不去,接下来就是编写应用代码了,我编写了LED跳动的程序,来验证中断的就是LED闪烁一次间隔(1S)。
当然这个程序没经过NVIC,RCC,TIM1的初始化是跑不起来的。
接下来就是编写上面提到的初始化函数了。
RCC模块有很多寄存器,对这些寄存器的初始化可以灵活地自己写个函数。主要目的就是时钟的选择和设置,外围模块时钟的开关(相当于外围模块的开关)。
TIM1模块的初始化,包括设置周期,计数模式,使能更新中断和打开计数器。
要使用中断必须在NVIC的ISER中打开相应的中断位,当有多个中断时有必要设置中断的优先级别。
这样TIM1上溢中断程序就能跑起来了,其他中断的使用大同小异。
补充:
NVIC是矢量嵌入中断控制,包括:1) ISER;2)
ICER; 3) ISPR; 4) ICPR; 5) IABR; 6)IPR 这几个寄存器。
typedef
struct
{
vu32 ISER[2];
u32 RESERVED0[30];
vu32 ICER[2];
u32 RSERVED1[30];
vu32 ISPR[2];
u32 RESERVED2[30];
vu32 ICPR[2];
u32 RESERVED3[30];
vu32 IABR[2];
u32 RESERVED4[62];
vu32 IPR[15];
} NVIC_TypeDef;
首先分析为什么定义。这是因为ISER的地址是从E000E100开始的,ICER是从E000E180开始的,依次类推;可见从0xE000E100到0xE000E180间隔128个8位,也就是32个32位的数据;这就是vu32
XXX[2]+u32 RESERVED0[30]总的位数。
1)
ISER包括ISER[0]和ISER[1],它们的每位值依次对应一个中断的开启和关闭。例如ISER[0]中的第0位对应
WWDG 窗口定时器中断;第25位对应TIM1_UP TIM1更新中断。---用来开中断
ICER写响应的位为1则对应的中断禁止,默认全0,读如果该位为1则相应的中断允许--用来关中断。
2)
ISPR中某位为1则挂起相应中断;
ICPR中某位为1则清除挂起的中断;
3)
IABR只读用来指示是否有中断发生或要处理;
4)
IPR用来设置优先级别