求问,如何获取内部不精准的32k时钟准确值
首先我知道这个低功耗的32k时钟十分不准,但还是想不加晶振的情况下,尽可能的利用这个做一些东西。现在想获取他在某一时刻的准确值。我的思路是使用rtc的秒中断,设置一个100us一次的定时器,中断时记录计数值。准确频率值应该是(32768/计数值)x10000。
但是我发现,计算值,和用主时钟输出,示波器/另一个单片机pwm测量值不相同,比如计算值是24983Hz,示波器或pwm测量是25370Hz。
我想问下,这两者之间哪个较为准确,如果计算值不准确,能否看看是哪里的问题。万分感谢
附上主要代码
#include "config.h"
#include "STC8G_H_GPIO.h"
#include "STC8G_H_UART.h"
#include "STC8G_H_Delay.h"
#include "STC8G_H_NVIC.h"
#include "STC8G_H_Switch.h"
bit f_1s;
u16 timeCnt, lastCnt, fwt;
float tmp;
u8 st;
void GPIO_config(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //结构定义
P0M0 = 0x00;
P0M1 = 0x00;
P1M0 = 0x00;
P1M1 = 0x00;
P2M0 = 0x00;
P2M1 = 0x00;
P3M0 = 0x00;
P3M1 = 0x00;
P4M0 = 0x00;
P4M1 = 0x00;
P5M0 = 0x00;
P5M1 = 0x00;
GPIO_InitStructure.Pin= GPIO_Pin_0 | GPIO_Pin_1; //指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7
GPIO_InitStructure.Mode = GPIO_PullUp; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Inilize(GPIO_P3, &GPIO_InitStructure); //初始化
}
/***************串口初始化函数 *****************/
void UART_config(void)
{
COMx_InitDefine COMx_InitStructure; //结构定义
COMx_InitStructure.UART_Mode = UART_8bit_BRTx; //模式, UART_ShiftRight,UART_8bit_BRTx,UART_9bit,UART_9bit_BRTx
COMx_InitStructure.UART_BRT_Use = BRT_Timer1; //选择波特率发生器, BRT_Timer1, BRT_Timer2 (注意: 串口2固定使用BRT_Timer2)
COMx_InitStructure.UART_BaudRate= 115200ul; //波特率, 一般 110 ~ 115200
COMx_InitStructure.UART_RxEnable= ENABLE; //接收允许, ENABLE或DISABLE
COMx_InitStructure.BaudRateDouble = DISABLE; //波特率加倍, ENABLE或DISABLE
UART_Configuration(UART1, &COMx_InitStructure); //初始化串口1 UART1,UART2,UART3,UART4
NVIC_UART1_Init(ENABLE, Priority_1); //中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3
UART1_SW(UART1_SW_P30_P31); //UART1_SW_P30_P31,UART1_SW_P36_P37,UART1_SW_P16_P17,UART1_SW_P43_P44
}
/**********************************************/
void Timer0_Init(void) //100微秒@24.000MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xA0; //设置定时初始值
TH0 = 0xF6; //设置定时初始值
TF0 = 0; //清除TF0标志
ET0 = 1;
TR0 = 1; //定时器0开始计时
}
void Timer0Proc() interrupt 1
{
timeCnt++;
}
//rtc
void RTC_Isr() interrupt 13//RTC_VECTOR
{
if(RTCIF & 0x08) //秒中断
{
RTCIF &= ~0x08;
lastCnt = timeCnt;
timeCnt = 0;
f_1s = 1;
}
}
void RTC_Init()
{
//使用内部时钟
IRC32KCR = 0x80;
while(!(IRC32KCR & 0x01));
RTCCFG |= 0x02;
INIYEAR = 23; //Y:23
INIMONTH = 02; //M:02
INIDAY = 21; //D:19
INIHOUR = 23; //H:23
INIMIN = 00; //M:45
INISEC = 00; //S:55
INISSEC = 0; //S/128:0
RTCCFG |= 0x01;
RTCIF = 0;
RTCIEN = 0x08; //秒中断
timeCnt = 0;
RTCCR = 1; //启动
}
void main(void)
{
u8 i;
EAXSFR(); /* 扩展寄存器访问使能 */
GPIO_config();
UART_config();
EA = 1;
Timer0_Init();
RTC_Init();
fwt = CHIPID9 << 8 | CHIPID10;
st = 0;
MCLKOCR = 0x01; //主时钟输出到P5.4口
while (1)
{
if(st == 10)
{
st++;
//关闭rtc
RTCIEN = 0;
timeCnt = 0;
RTCCR = 0;
//切换主时钟
CLKDIV = 0x00; //时钟不分频
CLKSEL = 0x03; //选择内部32K
}
if(f_1s)
{
f_1s = 0;
tmp = 32768.0 / lastCnt * 10000.0;
printf("b=%huHzCnt=%hu calc=%fHz\r\n", fwt, lastCnt, tmp);
st++;
}
}
}
输出示例 b=30070Hz Cnt=13116 calc=24983Hz
内部高频时钟比内部32K时钟精度高 内部32K时钟精度只适合掉电唤醒和段式LCD刷屏,有温飘和压飘,不要做别的用 DebugLab 发表于 2024-9-5 20:57
内部32K时钟精度只适合掉电唤醒和段式LCD刷屏,有温飘和压飘,不要做别的用 ...
你说的我知道,通过上面代码试验我也看出来了,飘的挺多,费劲去校准不如加外部晶振。正常需要精准定时是不会去用的。我现在想的是否是代码问题导致获取到的频率不同,或者有什么不了解的机制 你这个属于逻辑问题啊,没有参照,怎么会知道自己是多少呢?
你手上只有一把尺子,你能有办法判断这把尺子准不准吗?没有其他已知量的情况下。 最简单的方法还是加外部晶振啊 既然pwm测量值=示波器测量值,那肯定相信这个准确。
至于理论计算值,怎么也要把能想到的误差都考虑进去然后更正,这样应该可以无限接近测量值,且在一定的范围内。
至于何时准确的话,怎么也必须得把测试条件(温度、湿度、供电等)调整到最相近的理论条件吧。 这种钻研的精神值得学习,如果各方面都试过确实不行,至少测试过程的经验是真正的收获 Yim_Hom 发表于 2024-9-5 23:50
既然pwm测量值=示波器测量值,那肯定相信这个准确。
至于理论计算值,怎么也要把能想到的误差都考虑进去然 ...
对,测量值应该是准确的,现在就是想不出来计算的值误差在哪里,用的stc8h8k64u,换了一个单片机也是差200-500,所以就想把代码发出来给大佬们看看有无没考虑到的地方 cnos 发表于 2024-9-5 21:27
你这个属于逻辑问题啊,没有参照,怎么会知道自己是多少呢?
你手上只有一把尺子,你能有办法判断这把尺子 ...
按老师您说的,我认为我并不是只有一把尺子,是3把,两把长尺(示波器和另一个单片机)可以直接测量出准确值,一把短尺(单片机自身高速时钟),通过计算得到数据。现在尺子是准的,测量/计算方法可能有问题
页:
[1]
2