STM32F103的RTC模块用作32位计数器

需求背景

在使用FreeRTOS时,如果需要统计每个任务的运行时长及百分比,则需要提供一个计时基准。

分别实现以下2个函数:

void vConfigureTimerForRunTimeStats( void );    /* Prototype of function that initialises the run time counter. */
unsigned long ulGetRunTimeCounterValue( void ); /* Prototype of function that returns run time counter. */
 

前一个函数需用初始化配置计时器;后一个函数用于在任务切换时获取当前计时值。

要求计时的频率比tick的频率要高一个数量级。目前tick为1KHz,则计时频率为10K比较合适。

 

方案分析

方案一:使用硬件定时器TIMx。

void vConfigureTimerForRunTimeStats(void)
{
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

	// 时钟使能
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

	//定时器TIMx初始化
	TIM_TimeBaseStructure.TIM_Prescaler = SystemCoreClock / 1000000 - 1; //预分频后为1MHz
	TIM_TimeBaseStructure.TIM_Period = configTICK_RATE_HZ * 10 - 1;
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInit(TIMER_FOR_RUN_TIME_STAT, &TIM_TimeBaseStructure);

	TIM_Cmd(TIM3, ENABLE);
}

unsigned long ulGetRunTimeCounterValue(void)
{
	return TIM_GetCounter(TIM3);
}

问题:STM32F103的硬件定时器是16位的。最大计数值为64K,当计数频率为40K时,只需要1秒多一点就溢出了。

 

方案二:使用2个硬件定时器级联,组成一个32位计数器

方案三:使用os的tick

代码如下。

unsigned long ulGetRunTimeCounterValue(void)
{
	return xTaskGetTickCount();
}

问题:精度较低。

方案四:使用RTC作为计数器

具体如下。

 

使用RTC作为计数器

在STM32F103中,RTC的本质并不是一个实时时钟模块,只是一个计数器而已。可以配置为每秒加一,然后软件将秒数转换为日历时间(类似于unix中,以1970-1-1为起点的秒计数)。

现在不需要时钟了,就把它用于一个10KHz的计数器。最大可计时长为4G/10K = 400K秒,约为100多个小时。

 

RTC的时钟源:使用内部低速时钟LSI。然后再4分频,即可得到10KHz。

RTC工作时需要配置以下几个寄存器:

使能PWR和BKP模块时钟

Disable Backup Domain write:

开启LSI:

复位备份域:

先将BDRST设置为1,再设置为0。否则,不能更改RTCSEL等参数。

参见手册:6.3.9 备份域控制寄存器 (RCC_BDCR)

注意: 备份域控制寄存器中(RCC_BDCR)的LSEON、LSEBYP、RTCSEL和RTCEN位处于备份域。因此,这些位在复位后处于写保护状态,只有在电源控制寄存器(PWR_CR)中的DBP位置’1’后才能对这些位进行改动。进一步信息请参考5.1节。这些位只能由备份域复位清除(见6.1.3节)。任何内部或外部复位都不会影响这些位。

RTC时钟选择LSI:

RTC时钟使能:

设置分频系数:

 

代码如下:

void vConfigureTimerForRunTimeStats(void)
{
	// 使能模块时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP | RCC_APB1Periph_PWR, ENABLE);

	// 使能备份区域访问。将PWR.CR.DBP置1.
	PWR_BackupAccessCmd(ENABLE);

	// 复位备份域(Backup Domain)
	BKP_DeInit();

	//启动内部低速晶振
	RCC_LSICmd(ENABLE);

	//等待外部低速晶振重启
	while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET);

	RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);

	RCC_RTCCLKCmd(ENABLE); //使能RTC时钟

	RTC_WaitForSynchro(); //等待RTC寄存器同步完成

	RTC_WaitForLastTask(); //等待最后一次对RTC的寄存器写操作完成

	RTC_SetPrescaler(4);	// 4分频后为10KHz

	RTC_WaitForLastTask();

}

/*-----------------------------------------------------------*/

unsigned long ulGetRunTimeCounterValue(void)
{
	return RTC_GetCounter();
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值