本帖最后由 RISCVLAR 于 2021-1-21 16:20 编辑
CH32V103应用教程——TIM-定时器同步
本章教程主要演示4种定时器同步模式。
1、TIM简介及相关函数介绍 定时器能够输出时钟脉冲(TRGO),也能接收其他定时器的输入(ITRx)。不同的定时器的ITRx的来源(别的定时器的TRGO)是不一样的。 所有TIMx定时器在内部相连,用于定时器同步或链接。当一个定时器处于主模式时,它可以对另一个处于从模式的定时器的计数器进行复位、启动、停止或提供时钟等操作。 1、使用一个定时器作为另一个定时器的预分频器 如上图:可以配置定时器1作为定时器2的预分频器。进行下述操作: ● 配置定时器1(TIM1)为主模式,它可以在每一个更新事件UEV时输出一个周期性的触发信号。当控制寄存器2(TIM1_CTLR2)的MMS域的值为010时,即更新事件被选为触发输入(TRGO),每当产生一个更新事件时在TRGO1上输出一个上升沿信号。 ● 连接定时器1的TRGO1输出至定时器2,设置定时器2的从模式控制寄存器(TIM2_SMCFGR)的TS域值为000,即选择内部触发(ITR1)用于同步计数器的触发输入源。 ● 设置定时器2的从模式控制寄存器(TIM2_SMCFGR)的SMS域值为111,即外部时钟模式 1,选中的触发输入(TRGI)的上升沿驱动计数器。这样定时器2即可由定时器1周期性的上升沿(即定时器1的计数器溢出)信号驱动。 ● 最后,设置控制寄存器1(TIMx_CTLR1)的CEN位为1使能启动两个定时器。 注:如果OCx已被选中为定时器1的触发输出(MMS=1xx),它的上升沿用于驱动定时器2的计数器。
2、使用一个定时器使能另一个定时器 当使用一个定时器使能另一个定时器时,定时器2的使能由定时器1的输出比较控制。参考第一种配置定时器1和定时器2的连接方式。只当定时器1的OC1REF(输出参考信号)为高时,定时器2才对分频后的内部时钟计数。两个定时器的时钟频率都是由预分频器对定时器时钟(CK_INT)除以3(fCK_CNT=fCK_INT/3)得到。 ● 设置定时器1(TIM1)的控制寄存器2(TIM1_CTLR2)的MMS的值为100,即配置定时器1为主模式,其输出比较参考信号(OC1REF)被用于作为触发输出(TRGO) ● 通过设置比较/捕获控制寄存器1(TIM1_CHCTLR1)的相应位配置定时器1的OC1REF波形 ●设置从模式控制寄存器(TIM1_SMCFGR)的TS域的值为000,选择内部触发用于同步计数器的触发输入源,即配置定时器2从定时器1获得输入触发。 ● 设置从模式控制寄存器(TIM1_SMCFGR)的SMS域的值为101,即选择选择核心计数器的时钟和触发模式为门控模式,当触发输入(TRGI)为高时,计数器的时钟开启;在触发输入变为低,计数器停止,计数器的启停都是受控的。 ● 最后,设置控制寄存器1(TIMx_CTLR1)的CEN位为1使能启动两个定时器(TIM2和TIM1)。 注:定时器2的时钟不与定时器1的时钟同步,这个模式只影响定时器2计数器的使能信号。 在上述配置中,在定时器2启动之前,它们的计数器和预分频器未被初始化,因此它们从当前的数值开始计数。可以在启动定时器1之前复位2个定时器,使它们从给定的数值开始,即在定时器计数器中写入需要的任意数值。通过设置事件产生寄存器(TIM1_SWEVGR) 的UG位为1即可复位定时器。 在下述配置中,需要同步定时器1和定时器2。定时器1是主模式并从0开始,定时器2是从模式并从0xE7开始;2个定时器的预分频器系数相同。设置控制寄存器 1(TIM1_CTLR1) 的CEN位为0,即可禁止定时器1,定时器2随即停止。 ●设置定时器1(TIM1)的控制寄存器2(TIM1_CTLR2)的MMS域的值为100,即配置定时器1为主模式,其输出比较参考信号(OC1REF)被用于作为触发输出(TRGO) ● 通过设置比较/捕获控制寄存器1(TIM1_CHCTLR1)的相应位配置定时器1的OC1REF波形 ●设置从模式控制寄存器(TIM1_SMCFGR)的TS域的值为000,选择内部触发用于同步计数器的触发输入源,即配置定时器2从定时器1获得输入触发。 ● 设置从模式控制寄存器(TIM1_SMCFGR)的SMS域的值为101,即选择选择核心计数器的时钟和触发模式为门控模式,当触发输入(TRGI)为高时,计数器的时钟开启;在触发输入变为低,计数器停止,计数器的启停都是受控的。 ●设置事件产生寄存器(TIM1_SWEVGR和TIM2_SWEVGR)的UG位的值为1,复位定时器1和定时器2。 ● 写’0xE7’至定时器2计数器(TIM2_CNT),初始化它为0xE7。 ● 设置控制寄存器1(TIMx_CTLR1)的CEN位为1使能启动两个定时器(TIM1和TIM2)。 ●设置定时器1控制寄存器1(TIM1_CTLR1)的CEN位为0停止定时器1
3、使用一个定时器去启动另一个定时器 当使用一个定时器去启动另一个定时器时,可以使用定时器1的更新事件使能定时器2。参考第一种配置定时器1和定时器2的连接方式。一旦定时器1产生更新事件,定时器2即从它当前的数值(可以是非0)按照分频的内部时钟开始计数。在收到触发信号时,定时器2的控制寄存器1(TIM2_CTLR1)的CEN位被置1,同时计数器开始计数一直到控制寄存器1(TIM2_CTLR1)的CEN位被置0. 两个定时器的时钟频率都是由预分频器对CK_INT除以3(fCK_CNT=fCK_INT/3)。 ● 设置定时器1(TIM1)的控制寄存器2(TIM1_CTLR2)的MMS的值为010,即更新事件被选为触发输入(TRGO)。 ● 通过设置自动重装值寄存器(TIM1_ATRLR)配置定时器1的周期。 ● 通过设置定时器2从模式控制寄存器(TIM2_SMCFGR)的TS域的值为000,配置定时器2从定时器1获得输入触发。 ● 通过设置定时器2从模式控制寄存器(TIM2_SMCFGR)的SMS域的值为110,配置定时器2为触发模式。 ● 通过设置TIM1_CTLR1寄存器的CEN位为1启动定时器1。
4、使用一个定时器作为另一个的预分频器
本次配置讲述使用定时器1作为定时器2的预分频器。参考第一种配置定时器1和定时器2的连接方式。配置流程如下:
● 设置定时器1控制寄存器 2(TIM1_CTLR2)的MMS域的值为010,更新事件被选为触发输入(TRGO)。配置定时器1为主模式,送出它的更新事件UEV做为触发输出。然后每次计数器溢出时输出一个周期信号。 ● 通过设置定时器1自动重装值寄存器(TIM1_ATRLR)配置定时器1的周期。
● 通过设置定时器2从模式控制寄存器(TIM2_SMCFGR)的TS域的值为000,配置定时器2从定时器1获得输入触发。
● 通过设置定时器2从模式控制寄存器(TIM2_SMCFGR)的SMS域的值为111,配置定时器2使用外部时钟模式。
● 设置定时器2和定时器1控制寄存器1(TIMx_CTLR1)寄存器的CEN位为1启动定时器2和定时器1。
5、使用一个外部触发同步启动2个定时器 在使用一个外部触发同步启动2个定时器时,当定时器1的TI1输入上升时使能定时器1,使能定时器1的同时使能定时器2,参考第一种配置定时器1和定时器2的连接方式。为保证计数器的对齐,定时器1必须配置为主/从模式(对应TI1为从,对应定时器2为主): ● 通过设置定时器1控制寄存器 2(TIM1_CTLR2)的MMS域的值为001,配置定时器1为主模式,送出它的使能做为触发输出。 ● 通过设置定时器1从模式控制寄存器(TIM1_SMCFGR)的TS域的值为100,
配置定时器1为从模式,从TI1获得输入触发。 ● 通过设置定时器1从模式控制寄存器(TIM2_SMCFGR)的SMS域的值为110,配置定时器1为触发模式。 ● 通过设置定时器1从模式控制寄存器(TIM1_SMCFGR)的MSM位的值为1,配置定时器1为主/从模式。 ● 通过设置定时器2从模式控制寄存器(TIM2_SMCFGR)的TS域的值为000,配置定时器2从定时器1获得输入触发。 ● 通过设置定时器2从模式控制寄存器(TIM2_SMCFGR)的SMS域的值为110,配置定时器2为触发模式。 当定时器1的TI1上出现一个上升沿时,两个定时器同步地按照内部时钟开始计数,两个TIF标志也同时被设置。 注: 在上述配置中,在启动之前两个定时器都通过设置事件产生寄存器(TIM1_SWEVGR) 的UG位进行初始化,两个计数器都从0开始,但可以通过写入任意一个计数器寄存器(TIMx_CNT)在定时器间插入一个偏移。 关于CH32V103 TIM具体信息,可参考CH32V103应用手册。TIM标准库函数在第七章节已介绍,在此不再赘述。
2、硬件设计 本章教程主要演示4种定时器同步模式,其中使用一个外部触发同步启动定时器1和定时器2时,需使用PA8引脚进行外部触发。
3、软件设计 本章教程主要演示4种定时器同步模式,具体程序如下: tim.h文件 #ifndef __TIM_H
#define __TIM_H
#include "ch32v10x_conf.h"
void TIM_TimSynchroMode1_Init(void);
void TIM_TimSynchroMode2_Init(void);
void TIM_TimSynchroMode3_Init(void);
void TIM_TimSynchroMode4_Init(void);
#endif
tim.h文件主要进行相关函数声明; tim.c文件 #include "tim.h"
/*******************************************************************************
* Function Name : TIM_TimSynchroMode1_Init
* Description : Using TIM2 as prescaler for TIM1.
* Input : None
* Return : None
*******************************************************************************/
//使用定时器2作为定时器1的预分频器
void TIM_TimSynchroMode1_Init(void)
{
RCC_APB2PeriphClockCmd( RCC_APB2Periph_TIM1, ENABLE );
RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM2, ENABLE );
//将TIM1和TIM2计数模式设置为向上计数模式
TIM_CounterModeConfig( TIM1, TIM_CounterMode_Up );
TIM_CounterModeConfig( TIM2, TIM_CounterMode_Up );
//设置TIM1自动重装值寄存器值
TIM_SetAutoreload( TIM1, 0x3E8 );
//设置定时器TIM1预分频器值
TIM_PrescalerConfig( TIM1, 48000-1, TIM_PSCReloadMode_Immediate );
//当控制寄存器2(TIM1_CTLR2)的MMS域的值为010时,即更新事件被选为触发输入(TRGO),每当产生一个更新事件时在TRGO1上输出一个上升沿信号。
TIM_SelectOutputTrigger( TIM1, TIM_TRGOSource_Update );
//连接定时器1的TRGO1输出至定时器2,设置定时器2的从模式控制寄存器(TIM2_SMCFGR)的TS域值为000,即选择内部触发(ITR1)用于同步计数器的触发输入源。
TIM_ITRxExternalClockConfig( TIM2, TIM_TS_ITR0 );
//TIM2作为从机模式且 选中的触发输入(TRGI)的上升沿驱动计数器
//设置定时器2的从模式控制寄存器(TIM2_SMCFGR)的SMS域值为111,即外部时钟模式 1,选中的触发输入(TRGI)的上升沿驱动计数器。这样定时器2即可由定时器1周期性的上升沿(即定时器1的计数器溢出)信号驱动。
TIM_SelectSlaveMode( TIM2, TIM_SlaveMode_External1 );
//使能开启TIM1和TIM2,即设置控制寄存器1(TIMx_CTLR1)的CEN位为1使能启动两个定时器。
TIM_Cmd( TIM1, ENABLE );
TIM_Cmd( TIM2, ENABLE );
}
/*******************************************************************************
* Function Name : TIM_TimSynchroMode2_Init
* Description : Using TIM2 to use TIM1.
* Input : None
* Return : None
*******************************************************************************/
//使用定时器2使能定时器1
void TIM_TimSynchroMode2_Init(void)
{
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_TIM1, ENABLE );
RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM2, ENABLE );
TIM_CounterModeConfig( TIM1, TIM_CounterMode_Up );
TIM_CounterModeConfig( TIM2, TIM_CounterMode_Up );
TIM_SetAutoreload( TIM1, 0x3E8 );
TIM_PrescalerConfig( TIM1, 48000-1, TIM_PSCReloadMode_Immediate );
//输出比较结构体初始化
//通过设置比较/捕获控制寄存器1(TIM1_CHCTLR1)的相应位配置定时器1的OC1REF波形
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //配置为PWM模式1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //输出使能
TIM_OCInitStructure.TIM_Pulse = 0x64; //设置占空比大小
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出通道电平极性配置
TIM_OC1Init( TIM1, &TIM_OCInitStructure ); //初始化
//设置定时器1(TIM1)的控制寄存器2(TIM1_CTLR2)的MMS的值为100,即配置定时器1为主模式,其输出比较参考信号(OC1REF)被用于作为触发输出(TRGO)
TIM_SelectOutputTrigger( TIM1, TIM_TRGOSource_OC1Ref );
//设置从模式控制寄存器(TIM1_SMCFGR)的TS域的值为000,选择内部触发用于同步计数器的触发输入源,即配置定时器2从定时器1获得输入触发。
TIM_SelectInputTrigger( TIM2, TIM_TS_ITR0 );
//设置从模式控制寄存器(TIM1_SMCFGR)的SMS域的值为101,即选择选择核心计数器的时钟和触发模式为门控模式,当触发输入(TRGI)为高时,计数器的时钟开启;在触发输入变为低,计数器停止,计数器的启停都是受控的。
TIM_SelectSlaveMode( TIM2, TIM_SlaveMode_Gated );
//最后,设置控制寄存器1(TIMx_CTLR1)的CEN位为1使能启动两个定时器(TIM2和TIM1)。
TIM_Cmd( TIM2, ENABLE );
TIM_Cmd( TIM1, ENABLE );
}
/*******************************************************************************
* Function Name : TIM_TimSynchroMode3_Init
* Description : Using TIM2 to start TIM1.
* Input : None
* Return : None
*******************************************************************************/
//使用定时器2启动定时器1
void TIM_TimSynchroMode3_Init(void)
{
RCC_APB2PeriphClockCmd( RCC_APB2Periph_TIM1, ENABLE );
RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM2, ENABLE );
TIM_CounterModeConfig( TIM1, TIM_CounterMode_Up );
TIM_CounterModeConfig( TIM2, TIM_CounterMode_Up );
//通过设置自动重装值寄存器(TIM1_ATRLR)配置定时器1的周期。
TIM_SetAutoreload( TIM1, 0xFFFF );
TIM_PrescalerConfig( TIM1, 48000-1, TIM_PSCReloadMode_Immediate );
//设置定时器1(TIM1)的控制寄存器2(TIM1_CTLR2)的MMS的值为010,即更新事件被选为触发输入(TRGO)。
TIM_SelectOutputTrigger( TIM1, TIM_TRGOSource_Update );
//通过设置定时器2从模式控制寄存器(TIM2_SMCFGR)的TS域的值为000,配置定时器2从定时器1获得输入触发。
TIM_SelectInputTrigger( TIM2, TIM_TS_ITR0 );
//通过设置定时器2从模式控制寄存器(TIM2_SMCFGR)的SMS域的值为110,配置定时器2为触发模式。
TIM_SelectSlaveMode( TIM2, TIM_SlaveMode_Trigger );
//通过设置TIM1_CTLR1寄存器的CEN位为1启动定时器1。
TIM_Cmd( TIM1, ENABLE );
}
/*******************************************************************************
* Function Name : TIM_TimSynchroMode4_Init
* Description : Starting TIM1 and TIM2 synchronously in response to an external trigger.
* Input : None
* Return : None
*******************************************************************************/
//使用外部触发同步启动定时器1和定时器2
void TIM_TimSynchroMode4_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_TIM1, ENABLE );
RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM2, ENABLE );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //输入下拉
GPIO_Init( GPIOA, &GPIO_InitStructure);
GPIO_ResetBits( GPIOA, GPIO_Pin_8 );
TIM_CounterModeConfig( TIM1, TIM_CounterMode_Up );
TIM_CounterModeConfig( TIM2, TIM_CounterMode_Up );
TIM_SetAutoreload( TIM1, 0xFFFF );
TIM_PrescalerConfig( TIM1, 48000-1, TIM_PSCReloadMode_Immediate );
//输入捕获结构体初始化
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; //配置输入捕获的通道,需要根据具体的GPIO来配置
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //输入的需要被捕获的信号的分频系数
TIM_ICInitStructure.TIM_ICFilter = 0x00; //输入的需要被捕获的信号的滤波系数
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling; //输入捕获信号的极性配置
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //输入通道和捕获通道的映射关系,有直连和非直连两种
TIM_ICInit( TIM1, &TIM_ICInitStructure ); //初始化
//通过设置定时器1从模式控制寄存器(TIM1_SMCFGR)的TS域的值为100,配置定时器1为从模式,从TI1获得输入触发。
TIM_SelectInputTrigger( TIM1, TIM_TS_TI1FP1 );
//通过设置定时器1从模式控制寄存器(TIM2_SMCFGR)的SMS域的值为110,配置定时器1为触发模式。
TIM_SelectSlaveMode( TIM1, TIM_SlaveMode_Trigger );
//通过设置定时器1控制寄存器 2(TIM1_CTLR2)的MMS域的值为001,配置定时器1为主模式,送出它的使能做为触发输出。
TIM_SelectMasterSlaveMode( TIM1, TIM_MasterSlaveMode_Enable );
TIM_SelectOutputTrigger( TIM1, TIM_TRGOSource_Enable );
//通过设置定时器2从模式控制寄存器(TIM2_SMCFGR)的TS域的值为000,配置定时器2从定时器1获得输入触发。
TIM_SelectInputTrigger( TIM2, TIM_TS_ITR0 );
//通过设置定时器2从模式控制寄存器(TIM2_SMCFGR)的SMS域的值为110,配置定时器2为触发模式。
TIM_SelectSlaveMode( TIM2, TIM_SlaveMode_Trigger );
}
tim.c文件主要进行4种定时器同步模式的配置; main.c文件 int main(void)
{
USART_Printf_Init(115200);
printf("SystemClk:%d\r\n",SystemCoreClock);
/* Timer synchronization Mode Selection */
// TIM_TimSynchroMode1_Init();
// TIM_TimSynchroMode2_Init();
// TIM_TimSynchroMode3_Init();
TIM_TimSynchroMode4_Init();
while(1)
{
printf("TIM1 cnt:%d\r\n", TIM1->CNT);
printf("TIM2 cnt:%d\r\n", TIM2->CNT);
}
}
main.c文件主要进行初始化以及定时器1、2的计数值的打印输出。
4、下载验证 将编译好的程序分别在4种不同模式下下载到开发版并复位,串口打印如下: 1、使用定时器2作为定时器1的预分频器; 2、使用定时器2使能定时器1; 3、使用定时器2启动定时器1; 4、使用一个外部触发同步启动定时器1和定时器2;(需使用PA8引脚进行外部触发)
|