众所周知,STC8H系列内部32K时钟温飘特别大,频率温飘基本相当于一个NTC电阻的阻值。
把系统时钟调低,比如11.0592MHz,这样内部16位计时器就能充分的测量一个1/32的RTC中断,即可从计时器值估测内部RTC频率;
再根据温飘映射到文档数值,就知道此时单片机的温度了。
- void init_rtc() {
- // 选择内部 32K
- IRC32KCR = 0x80; // 启动内部 32K 振荡器
- while (!(IRC32KCR & 0x01))
- ; // 等待时钟稳定
- RTCCFG |= 0x02; // 选择内部 32K 作为 RTC 时钟源
-
- // 设置 RTC 时间
- INIYEAR = 00;
- INIMONTH = 1;
- INIDAY = 15;
- INIHOUR = 15;
- INIMIN = 30;
- INISEC = 0;
- INISSEC = 0;
- RTCCFG |= 0x01; // 触发 RTC 寄存器初始化
-
- RTCIF = 0; // 清中断标志
- RTCIEN = 0x01; // 使能 RTC 1/32秒中断
- RTCCR = 0x01; // RTC 使能
- }
-
- // @11.0592MHz
- void init_tm0(void) {
- AUXR &= 0x7F; // 定时器时钟12T模式
- TMOD &= 0xF0; // 设置定时器模式
- TMOD |= 0x01; // 设置定时器模式
- }
-
- uint8_t data temp_tl = 0;
- uint8_t data temp_th = 0;
-
- void isr_rtc() interrupt(RTC_VECTOR) using(1) {
- RTCIF = 0; // 清中断标志
- TR0 = 0;
- temp_tl = TL0;
- temp_th = TH0;
- TL0 = 0xff;
- TH0 = 0xff;
- TF0 = 0;
- TR0 = 1;
- }
-
- void main() {
- init_sys();
- init_uart();
- init_tm0();
- init_rtc();
-
- while (1) {
- uint16_t c = 0xffff - (temp_th << 8 | temp_tl);
- int16_t t = (650 * ((int32_t)33563 - c)) / 7900;
- printf("t: %d\r\n", t);
- delay_ms(1000);
- }
- }
复制代码
量程0 ~ 65度,上面的简单线性映射是我用冰块和热水校准的。
其中映射关系因为每个芯片的体制不一样,必须校准。
为了避免计算浮点数,温度t的数值单位是10摄氏度,既24.3C => 243。
假定电压和主时钟是稳定的。
测量精度在室温还说的过去
- // 室温输出
- t: 242
- // 手按上去加热
- t: 271
- // 冰块贴到芯片上
- t: 18
复制代码
各位愚人节快乐
|