打印
[PIC®/AVR®/dsPIC®产品]

PIC32系列 定时器TMR-16位定时器使用

[复制链接]
9376|15
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
qcliu|  楼主 | 2021-8-7 17:57 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
1、PIC32参考资源

PIC32系列参考手册 中文版.


使用特权

评论回复
沙发
qcliu|  楼主 | 2021-8-7 17:57 | 只看该作者
2、使用Harmony3配置定时器生成代码

1、启动MPLAB Harmony3 Configurator组件;



使用特权

评论回复
板凳
qcliu|  楼主 | 2021-8-7 17:58 | 只看该作者

2、选择Harmony路径,不用管,按照给定的就可以,点击Launch;



使用特权

评论回复
地板
qcliu|  楼主 | 2021-8-7 17:59 | 只看该作者

3、选择器件库和CMSIS组件,按照给定的就可以,点击Launch;



使用特权

评论回复
5
qcliu|  楼主 | 2021-8-7 17:59 | 只看该作者

4、启动后界面组件内容如下,左侧为可用的功能组件,右侧为项目功能图形显示;


使用特权

评论回复
6
qcliu|  楼主 | 2021-8-7 18:00 | 只看该作者

5、在左侧的列表中打开Peripherals,选择TMR下的TMR2,也就是定时器2,将其拖入右侧的界面中;


使用特权

评论回复
7
qcliu|  楼主 | 2021-8-7 18:01 | 只看该作者

6、拖入后右侧界面显示如下,可以看到右侧多了一个TMR2组件;



使用特权

评论回复
8
qcliu|  楼主 | 2021-8-7 18:02 | 只看该作者

7、点击组件,右侧Configuration Options显示组件信息,此时可按照需求进行组件配置,图中的配置为,分频系数为2,16位定时器模式,时钟源使用内部时钟,定时时间为1ms,在空闲模式下继续工作;


使用特权

评论回复
9
qcliu|  楼主 | 2021-8-7 18:03 | 只看该作者

8、组件配置完成后点击左侧的Generate Code按钮生成代码;


使用特权

评论回复
10
qcliu|  楼主 | 2021-8-7 18:03 | 只看该作者

9、点击后会有生成的信息需要确认,是否需要修改;


使用特权

评论回复
11
qcliu|  楼主 | 2021-8-7 18:05 | 只看该作者
10、代码生成后需要的操作;

        1、启动定时器;

                在初始化完成后启动定时器;

TMR2_Start();
        2、添加中断任务内容;

        在plib_tmr2.c的TIMER_2_InterruptHandler函数中添加内容

uint16_t u16Counter=0;
void TIMER_2_InterruptHandler (void)
{
    uint32_t status  = 0U;
    status = IFS0bits.T2IF;
    IFS0CLR = _IFS0_T2IF_MASK;

    if(u16Counter<500)
    {
        u16Counter++;
    }
    else
    {
        u16Counter=0;
        GPIO_RB0_Toggle();
    }

    if((tmr2Obj.callback_fn != NULL))
    {
        tmr2Obj.callback_fn(status, tmr2Obj.context);
    }
}


使用特权

评论回复
12
qcliu|  楼主 | 2021-8-7 18:05 | 只看该作者

11、编译运行将代码烧录到开发板中;

点击编译按钮,编译提示BUILD SUCCESSFUL,点击烧录,提示Programming/Verify complete,开发板上的LED灯闪烁。


使用特权

评论回复
13
qcliu|  楼主 | 2021-8-7 18:07 | 只看该作者
3、工程代码分析
1、TMR2 Configuration Options配置分析



Enable Interrupts?

使能中断服务,勾选该项后,会生成中断相关的代码及函数;

在plib_tmr2.c文件中

初始化完成后使能中断:IEC0SET = _IEC0_T2IE_MASK;

void TIMER_2_InterruptHandler (void)

void TMR2_InterruptEnable(void)

void TMR2_InterruptDisable(void)

void TMR2_CallbackRegister(TMR_CALLBACK callback_fn, uintptr_t context)

在interrupt.c文件中生成中断服务函数

void __ISR(_TIMER_2_VECTOR, ipl1SOFT) TIMER_2_Handler (void)

在plib_evic.c文件中的void EVIC_Initialize( void )函数增加中断优先级设置

IPC2SET = 0x4 | 0x0; /* TIMER_2: Priority 1 / Subpriority 0 */

Select Prescaler

选择分频系数,分频系数修改后会影响计时时间

在初始化时,TCKPS会变化,即T2CONSET;PR2也会变化;

uint32_t TMR2_FrequencyGet(void)函数会返回计时频率;

32-Bit Timer Mode Select Bit

可选Odd numbered and even numbered timers form separate 16-bit timers奇数和偶数定时器形成单独的16位定时器

以及Odd numbered and even numbered timers form a 32-bit timer奇数和偶数定时器组成一个32位定时器

T32位为32位定时器判断,32位定时器中断控制在Slave定时器中



Select Timer Clock Frequency选择时钟源;

可选择Internal peripheral clock或External clock from TxCK pin

选择外部时钟源时需要指定时钟频率

TCS 位为时钟选择位

Timer Clock Frequency 时钟频率,计算得到,是分频后得到的值,定时器时钟;

Timer Period Unit 为定时器时间单位,可选millisecond、microsecond、nanosecond;也就是毫秒、微秒以及纳秒;



Time为计时时间,与上面的单位结合使用,Period Register为周期寄存器数值,通过时间计算得到;

Stop in Idle Mode bit停止在空闲模式位,可选Continue operation even in Idle mode(空闲模式下继续)或Discontinue operation when device enters Idle mode(当设备进入空闲模式时停止)



该位影响SIDL位

SIDL :空闲模式停止位

1 = 在器件进入 Idle (空闲)模式时停止工作;0 = 即使在 Idle (空闲)模式下仍继续工作


使用特权

评论回复
14
qcliu|  楼主 | 2021-8-7 18:09 | 只看该作者
2、具体代码分析

//定时器初始化函数
void TMR2_Initialize(void)
{
    /* Disable Timer */
    T2CONCLR = _T2CON_ON_MASK; //禁止定时器,清零ON控制位

    /*
    SIDL = 0 //空闲模式停止位
    TCKPS =1 //预分频设置
    T32   = 0 //32定时器
    TCS = 0 //时钟源选择,内部时钟源或外部时钟源
    */
    T2CONSET = 0x10;  //TxCON与定时器相关的 16 位控制寄存器

    /* Clear counter */
    TMR2 = 0x0; //TMRx 16位定时器计数器寄存器

    /*Set period */
    PR2 = 39999U; //PRx与定时器相关的 16 位周期寄存器

    /* Enable TMR Interrupt */
    IEC0SET = _IEC0_T2IE_MASK; //TxIE中断允许控制位在IEC0中断寄存器中
}

//开启定时器
void TMR2_Start(void)
{
    T2CONSET = _T2CON_ON_MASK; //TxIF中断标志状态位在IFS0 中断寄存器中;
}

//关闭定时器
void TMR2_Stop (void)
{
    T2CONCLR = _T2CON_ON_MASK; //TxIF中断标志状态位在IFS0 中断寄存器中;
}

//设置周期寄存器
void TMR2_PeriodSet(uint16_t period)
{
    PR2  = period; //PRx与定时器相关的16位周期寄存器
}

//获取周期寄存器
uint16_t TMR2_PeriodGet(void)
{
    return (uint16_t)PR2; //PRx与定时器相关的16位周期寄存器
}

//获取计数值
uint16_t TMR2_CounterGet(void)
{
    return (uint16_t)(TMR2); //TMRx 16位定时器计数器寄存器
}

//获取定时器频率
uint32_t TMR2_FrequencyGet(void)
{
    return (40000000); //返回定时器的时钟频率
}

//定时器中断服务函数
void TIMER_2_InterruptHandler (void)
{
    uint32_t status  = 0U;
    status = IFS0bits.T2IF;
    IFS0CLR = _IFS0_T2IF_MASK; //清零IFSx寄存器中的TxIF中断标志位

/*可在这添加中断处理内容*/

    if((tmr2Obj.callback_fn != NULL))
    {
        tmr2Obj.callback_fn(status, tmr2Obj.context);
    }
}

//中断使能
void TMR2_InterruptEnable(void)
{
    IEC0SET = _IEC0_T2IE_MASK; //TxIE中断允许控制位在IEC0中断寄存器
}

//禁止中断
void TMR2_InterruptDisable(void)
{
    IEC0CLR = _IEC0_T2IE_MASK;  //TxIE中断允许控制位在IEC0中断寄存器
}

//
void TMR2_CallbackRegister(TMR_CALLBACK callback_fn, uintptr_t context)
{
    /* Save callback_fn and context in local memory */
    tmr2Obj.callback_fn = callback_fn;
    tmr2Obj.context = context;
}

//中断服务函数,在interrupts.c中,调用TIMER_2_InterruptHandler
void __ISR(_TIMER_2_VECTOR, ipl1SOFT) TIMER_2_Handler (void)
{
    TIMER_2_InterruptHandler();
}


使用特权

评论回复
15
qcliu|  楼主 | 2021-8-7 18:09 | 只看该作者
4、16 位同步计数器的初始化步骤
1. 清零 ON 控制位 (TxCON<15> = 0)以禁止定时器。

2. 清零 TCS 控制位 (TxCON<1> = 0)以选择内部 PBCLK 源。

3. 选择所需的定时器输入时钟预分频比。

4. 装载 / 清零定时器寄存器 TMRx。

5. 将所需的 16 位匹配值装入周期寄存器 PRx。

6. 如果使用了中断:

        a) 清零 IFSx 寄存器中的 TxIF 中断标志位。

        b) 在 IPCx 寄存器中配置中断优先级和子优先级。

        c) 将 IECx 寄存器中的 TxIE 中断允许位置 1。

7. 将 ON 控制位置 1 (TxCON<15> = 1)以使能定时器。

4、定时器定时时间计算

T=(P+1)*N/F

其中T为定时时间,单位为s;P为周期数,16位定时器最大值为65535;N为分频数;F为时钟频率;内部时钟频率为80MHz;


使用特权

评论回复
16
qcliu|  楼主 | 2021-8-7 18:10 | 只看该作者
5、实验验证

点击编译按钮,编译提示BUILD SUCCESSFUL,点击烧录,提示Programming/Verify complete,开发板上的LED灯闪烁。


使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

62

主题

3315

帖子

4

粉丝