STM32F103 IWDG时钟准确度的疑问
看文档上面介绍IWDG使用的内部低速时钟LSI,大约40K,可是当我配置IWDG预分频为32,装载值位2500(40K/16),也就是2秒钟不喂狗重启,但我测试下来结果却是10秒钟不喂狗才重启。这是为何,40K的LSI不可能误差这么多吧?IWDG配置如下:IWDG_SetPrescaler(IWDG_Prescaler_32);IWDG_SetReload(40000 / 16);
另外我测试了下RTC也使用内部的40K LSI,来实现秒中断,测试下来1分钟触发58次,也就是说LSI的误差在1/30左右。
看到有关文档上结束如下:
看门狗超时时间(40kHz的输入时钟(LSI))(1)
最短时间(ms)
RL = 0x000 最长时间(ms)
RL = 0xFFF预分频系数 PR位
/4 0 0.1 409.6
/8 1 0.2 819.2
/16 2 0.4 1638.4
/32 3 0.8 3276.8
/64 4 1.6 6553.6
/128 5 3.2 13107.2
/256 (6或7) 6.4 26214.4
“这些时间是按照40kHz时钟给出。实际上, MCU内部的RC频率会在30kHz到60kHz之间变化。
此外,即使RC振荡器的频率是精确的,确切的时序仍然依赖于APB接口时钟与RC振荡器时钟
之间的相位差,因此总会有一个完整的RC周期是不确定的。”
APB接口时钟与RC振荡器时钟之间的相位差,请问会对IWDG的时钟产生这么大的影响吗?有没有大神知道的?
不可能这么大误差 再确认下配置参数
或者说配置写进去没有? 多谢,楼上的提醒,的确是预分频寄存器PR的值没有设进去,但重载寄存器RLR的值却设进去了。很是奇怪。
初始化步骤如下:
void IWDG_Init(void)
{
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
IWDG_SetPrescaler(IWDG_Prescaler_32);
IWDG_SetReload(CLK_LSI / 16);
IWDG_ReloadCounter();
IWDG_Enable();
}
然后通过串口打印会读的寄存器值PR RLR SR_PVU SR_RVU如下:
PR, RLR, PVU, RVU
预分频寄存器PR的值却是默认的256分频!!!
于是做了如下处理:
void IWDG_Init(void)
{
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
while(IWDG_GetFlagStatus(IWDG_FLAG_PVU));
IWDG_SetPrescaler(IWDG_Prescaler_32);
while(IWDG_GetFlagStatus(IWDG_FLAG_RVU));
IWDG_SetReload(CLK_LSI / 16);
IWDG_ReloadCounter();
IWDG_Enable();
}
实验测试,却是陷入上面的死循环,MCU起不来了。于是继续测试:
uint16 ptimeout;
uint16 rtimeout;
void IWDG_Init(void)
{
ptimeout = 0;
rtimeout = 0;
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
while(IWDG_GetFlagStatus(IWDG_FLAG_PVU))
{
ptimeout ++;
if (ptimeout >= 500)
{
break;
}
}
IWDG_SetPrescaler(IWDG_Prescaler_32);
while(IWDG_GetFlagStatus(IWDG_FLAG_RVU))
{
rtimeout ++;
if (rtimeout >= 500)
{
break;
}
}
IWDG_SetReload(CLK_LSI / 16);
IWDG_ReloadCounter();
IWDG_Enable();
}
初始化后打印的结果如下:
PR, RLR, PVU, RVU, ptimeout, rtimeout
原来是硬件上一直没有将SR_PVU清0.。。。
无奈在上点开机几秒钟之后,再次手动初始化IWDG,此时再查下寄存器终于好了:
PR, RLR, PVU, RVU, ptimeout, rtimeout
那么问题又来了,为什么刚开机初始化时,SR_PVU一直不清0呢,有没有大神遇到过这种情况呀? /** <summary>
* 打开IWDG。
* </summary>
* <param name="pr">40KHz看门狗时钟的预分频值。</param>
* <param name="rlr">看门狗倒计数的最大值,Max=0xFFF。</param>
* <exception cref=""></exception>
*/
void OpenIWDG(uint8_t pr, uint16_t rlr)
{
IWDG->KR = 0x5555; //使能对IWDG->PR和IWDG->RLR的写
IWDG->PR = pr; //LSI/32=40Khz/(4*2^pre) //4、8、16、32、64、128、256
IWDG->RLR = rlr; //从加载寄存器 IWDG->RLR,Max=0xFFF。因为看门狗计数器正是从这个值开始向下计数。
IWDG->KR = 0xAAAA; //reload
IWDG->KR = 0xCCCC; //使能看门狗
}
/** <summary>
* 给IWDG喂狗。
* </summary>
* <param name=""></param>
* <exception cref=""></exception>
*/
void FeedIWDG(void)
{
IWDG->KR = 0xAAAA; //reload
}
好像只要这样就可以的:)
页:
[1]