Hello,小伙伴们大家好,最近从STM32平台转战到PIC平台,一开始不是特别的顺手。首先资料不如32那么详尽,其次相关的论坛比较少,遇到问题只能去看官方手册和百度。今天按照官方的寄存器手册,调用<plb.h>函数库,在编写完定时器的配置后,发现无法进入中断,经过一番苦苦寻找,终于找到了问题所在。我会把源码以及解决方案放在下面。
平台:PIC32MX795F512L单片机,主频80MHz,定时器时钟频率为40MHz。采用外部4M晶振,通过PLL倍频器20倍频得到80MHz主时钟,外设时钟2分频,得到40MHz。
下面是我的初始化代码:
/************************************************
* @函数功能:定时器2初始化
* @参 数:无
* @返 回:无
* @说 明:定时时间为1ms 外设时钟为40M
*************************************************/
void Tim2_Init()
{
//定时器2初始化
OpenTimer2(T2_ON /* 打开定时器 */
|T2_IDLE_CON /* 空闲模式继续 */
|T2_PS_1_64, /* 64分频 */
625); /* 定时周期设置 1ms */
TMR2 = 0; /* 清除计数 */
ConfigIntTimer2(T2_INT_ON|T2_INT_PRIOR_4);/* 定时器中断配置 */
}
定时器2采用外设时钟,时钟周期为40MHz,设置64分频,所以1s的计数值为 40000000/64 = 625000,所以定时1ms的重装值为625.
公式:预设值 = 主频 / 分频系数 / 1000 * n,n为定时周期,单位为ms。
下面是中断服务函数
/************************************************
* @函数功能:定时器2中断服务函数
* @参 数:无
* @返 回:无
*************************************************/
void __ISR(_TIMER_2_VECTOR, ipl4auto) IsrTIM2Handler(void)
{
delay_count++;
INTClearFlag(INT_T2);/* 清除中断标志位 */
}
其中 “_TIMER_2_VECTOR”为定时器2的向量地址,ipl4auto表示定时器2的中断优先级为4。
问题来了,确定配置没问题后,调试发现竟然无法进入中断,在网上一顿乱找,最后终于找到了。
PIC32MX没有所谓的总中断控制位,但是CPU有两种中断方式,中断单向量模式和多向量模式。意思就是如果工作在单向量模式,CPU只会进入同一个中断向量地址(没用过,故不多介绍)。我们主要关心多向量模式,就是根据不同的中断地址进入不同的中断函数。但是PIC32MX每次复位默认处于单向量模式,因此需要手动配置。下面介绍如何配置。
配置代码:
/* CPU工作多中断向量模式配置 */
#define hwGLOBAL_INTERRUPT_BIT ( 0x01UL )
#define hwBEV_BIT ( 0x00400000 )
#define hwEXL_BIT ( 0x00000002 )
#define hwIV_BIT ( 0x00800000 )
/************************************************
* @函数功能:设置CPU工作于多向量模式
* @参 数:无
* @返 回:无
* @说 明:定时时间为1ms 外设时钟为40M
*************************************************/
void vHardwareUseMultiVectoredInterrupts( void )
{
unsigned long ulStatus, ulCause;
extern unsigned long _ebase_address[];
/* 获取当前状态 */
ulStatus = _CP0_GET_STATUS();
/* 禁止中断 */
ulStatus &= ~hwGLOBAL_INTERRUPT_BIT;
/* 设置 BEV */
ulStatus |= hwBEV_BIT;
/* 写状态返回 */
_CP0_SET_STATUS( ulStatus );
/* 设置 Ebase */
_CP0_SET_EBASE( ( unsigned long ) _ebase_address );
/* 0x20字节空间向量 */
_CP0_XCH_INTCTL( 0x20 );
/* 设置 CAUSE寄存器的 IV位 */
ulCause = _CP0_GET_CAUSE();
ulCause |= hwIV_BIT;
_CP0_SET_CAUSE( ulCause );
/* 清除 BEV和 EXL */
ulStatus &= ~( hwBEV_BIT | hwEXL_BIT );
_CP0_SET_STATUS( ulStatus );
/* 设置MVEC */
INTCONbits.MVEC = 1;
/* 使能中断 */
ulStatus |= hwGLOBAL_INTERRUPT_BIT;
_CP0_SET_STATUS( ulStatus );
}
为啥要这样配置呢,我也不知道,但是有参考,可以在microchip的官网找到相应的手册。如下图1.1
图1.1
可能有的朋友看英文比较费劲(比如像我),因此特地找到了中文版的,如下图1.2所示。
图1.2
把多向量配置函数放在man()函数的开头就行了,到此解决!
最后附上参考手册的链接
中文文档链接:http://www.microchip.com.cn/newcommunity/Uploads/Download/Library/60001108h_cn.pdf
英文文档链接:http://ww1.microchip.com/downloads/en/DeviceDoc/60001108H.pdf
第一次写博客,如有大神看到有错误的地方,还请指正!