矿石收音机论坛

 找回密码
 加入会员

QQ登录

只需一步,快速开始

搜索
12
返回列表 发新帖
楼主: bobby_jack

求助:STC89C52 频率计读数偏低

[复制链接]
     
发表于 2020-2-16 08:33:41 | 显示全部楼层
longshort 发表于 2020-2-16 08:07
说一下STC的51系列单片机的适用情况。
1.在标称12MHz钟频下,计数器的最高计数频率是500KHz,这是性 ...

STC15系列单片机计数的最高频率接近时钟的二分之一,也就是说在12M频率下接近6兆,实际应该可以到4M没什么问题。我用24M时钟计数到8-10兆。试验的STC15单片机在等精度下可以做到万分之几的误差,计数到10Mhz没任何问题。
回复 支持 反对

使用道具 举报

     
发表于 2020-2-16 08:52:27 | 显示全部楼层
本帖最后由 longshort 于 2020-2-16 09:05 编辑
w6955 发表于 2020-2-16 08:33
STC15系列单片机计数的最高频率接近时钟的二分之一,也就是说在12M频率下接近6兆,实际应该可以到4M没什 ...


万分之几那就不叫误差了,对频率计那就是废品。

另外,STC的单片机是基于51的,还是建议您研究下基本结构。虽然定时器可通过设置到1个时钟周期工作,但仍然有许多不可知的因素影响计数准确性。

回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2020-2-16 14:05:20 | 显示全部楼层
回复各位坛友
谢谢各位坛友支招。
现在的情况是:我不会(水平关系)用不调用中断去连续计量频率,所以只能用定时器,每1秒种(用计数定时器2)计量一次100分频后的计数。碰到的问题是:
一,失步。随着中断处理程序的复杂失步会相对增加。我估计是因为计数器暂停工作的关系。
    解决的办法就是在最终结果上加成。因为加成率是固定的,对高低频到是一视同仁。
二,精度。或许是因为100分频(计数器1)的关系,计数器的最大精度只有100Hz。我曾试图把未分频前的信号直接引入计数器0(3-20MHz)并取其尾数,但因远超过89C52计数器的工作范围而失败。对此我完全无计可施。

看来正如#15所言,89C52本身并不合适做精确的频率计(特别是在结构简化的情况下)。相比之下,PIC16可能会更好些。

再次谢谢各位。
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2020-2-16 14:13:00 | 显示全部楼层
对了,我还有一个想法,或许可以折衷解决部分问题。
即,一,用36MHz的外部晶振,二,用10分频。这样精度可达到 10Hz了(在15MHz以内)。
当然,只是想法而已。现在快递尚未完全正常,手里没有36MHz晶振,只能等。
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2020-2-16 18:07:23 | 显示全部楼层
最新成果:
听坛友们的意见,或改用不关中断直接操作,或者在开中断取值后立即打开(效果几乎相同),果然失步大大减少。以5MHz晶振为例,在外购套件频率计(晶振测试仪)上显示5000.1,而在我自制的89C52频率计上为4999.9(在以前是4999.3)。中断处理程序的影响可见一斑。
对于尚存的误差,希望可以通过微调外部晶振电容的方法加以解决。
但对100Hz的精度尚未找到解决方法。

再次谢谢众多坛友的支招。
回复 支持 反对

使用道具 举报

     
发表于 2020-2-16 18:59:22 | 显示全部楼层
建仪用时钟模块做计数闸门,否则51极难做出六万分之一精度的频率计。
回复 支持 反对

使用道具 举报

     
发表于 2020-2-16 20:13:09 | 显示全部楼层
bobby_jack 发表于 2020-2-16 18:07
最新成果:
听坛友们的意见,或改用不关中断直接操作,或者在开中断取值后立即打开(效果几乎相同),果然 ...


建议LZ看看数据手册。我也是正在看。
前段时间,看了个51学习视频,当然不是stc的。但是板子上是stc89c52.

看的实在不想看了。根本与stc不是一码事。自己看看stc的数据手册,更明白一些,当然,添加的功能也不是一点半点的。

这个单片机可以6分频,而不是12分频fosc的机器指令。

对于12分频的机器周期;1us计数一次;这样65536,也就是定时器溢出一次,需要65.536ms;这样:如果计数655360位,就需要0.655s了。

也就是,再慢,计数6.55s的时候,才能计数6553600;同理推算,10s计数大约可以到10000000,10MHZ。分辨率是1HZ。

关于精度,参考STC89C52这些页面:
170341ja44a6u4faqm4zz4.jpg
20090517_eca77d61f047c68a7dddbrwxt4FMyjon.png
微信截图_20200216201206.png
回复 支持 反对

使用道具 举报

     
发表于 2020-2-16 23:12:52 | 显示全部楼层
采用定时器脉冲扑捉方式,可以提高精度。用STM32F205,工作频率高有32位定时器,测频更方便。51系列的单片机还是弱了。
回复 支持 反对

使用道具 举报

     
发表于 2020-2-16 23:25:06 | 显示全部楼层

#include "Freq_Measure.h"


#define FREQ_DIV                        TIM_ExtTRGPSC_OFF //TIM_ExtTRGPSC_DIV4//TIM_ExtTRGPSC_OFF //TIM_ExtTRGPSC_DIV4                //ÉèÖÃÆµÂʵÄÊäÈë·ÖƵϵÊý

static float Freq=0;
static unsigned int FREQ_DIV_K;                        //ÊäÈë·ÖƵϵÊýÖµ£¡
//*******************************************************************************************************
//STM32F205  pa0--ETR--tim2  µÄIO½Å¶¨Òå´¦Àí
void TIM2_ETR_IO_Init(void){
        GPIO_InitTypeDef GPIO_InitStructure;
       
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
        //------------------------------------------------------------------------
        GPIO_InitStructure.GPIO_Pin         =        ETR_IN;
        GPIO_InitStructure.GPIO_Mode         = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_PuPd         = GPIO_PuPd_UP;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
  /* GPIOA Configuration: PA.0(TIM2 CH1) */
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource0, GPIO_AF_TIM2);
}
//************************************************************************************************************
//¶¨ÒåTIM4 1ÃëÖÓ²úÉúÄÚ²¿¶¨Ê±´¥·¢
//*************************************************************************
//¼ÆË㶨ʱ²ÎÊý£¬ÓÃÓÚTim3,´«ÈëÒª¶¨Ê±µÄʱ¼ä£¬µ¥Î»ÊÇmÃë  ¶¨Ê±Æ÷µÄʱÖÓ±¶ÆµÆ÷2
//*************************************************************************
unsigned int Get_Timer_TIM4(float ms){
        unsigned int tick;
        RCC_ClocksTypeDef  RCC_Clocks;
        //---------------------------------------------------------------
        //ÏȼÆËã·ÖƵϵÊý£¡
        FREQ_DIV_K=1;
        if(FREQ_DIV        ==TIM_ExtTRGPSC_DIV2) FREQ_DIV_K=2;
        if(FREQ_DIV        ==TIM_ExtTRGPSC_DIV4) FREQ_DIV_K=4;
        if(FREQ_DIV        ==TIM_ExtTRGPSC_DIV8) FREQ_DIV_K=8;
        //---------------------------------------------------------------
        RCC_GetClocksFreq(&RCC_Clocks);
        tick=2*(RCC_Clocks.PCLK1_Frequency/TIM4_DIV/1000)*ms;//µÃµ½¼ä¸ô³£Êý£¡1000 ÊÇÃëµÄת»»£¬TIM4_DIVÊÇ·ÖÆµÏµÊý£¡
        return tick;
}
//*****************************************************************************
//²¶×½²âƵ
void TIM4_Config(void){
        TIM_TimeBaseInitTypeDef   TIM_TimeBaseStructure;
  NVIC_InitTypeDef                                   NVIC_InitStructure;
  /**************************** TIM4 Config ***********************************/
  /* TIM4 clock enable */
  TIM_DeInit(TIM4);
        TIM2_ETR_IO_Init();
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);  
  /* TIM4 Time base configuration */
  TIM_TimeBaseStructure.TIM_Prescaler =TIM4_DIV-1;                                                //·ÖƵÊý£¬½µµÍƵÂÊ£¬½µµÍ¼ì²âµÄƵÂÊ£¡
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseStructure.TIM_Period = Get_Timer_TIM4(MEASURE_ms);                //xxxºÁÃëɨÃèÒ»´Î£¡
  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
  TIM_ClearFlag(TIM4, TIM_FLAG_Update);
        TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE); //¶¨Ê±1ÃëÖжÏ
        //------------------------------------------------------------------------------------------------------
        //ÉèÖÃÖ÷¶¨ÊÇÊä³öµ½µ½TIM2
        /* Use the TIM4 Update event  as TIM4 Trigger Output(TRGO) */
  TIM_SelectOutputTrigger(TIM4, TIM_TRGOSource_Update);//ËͳöTIM4¸üÐÂʼþUEV×öΪ´¥·¢Êä³ö(TIM4_CR2¼Ä´æÆ÷µÄMMS=¡¯010¡¯)
  /* Enable the TIM4 Master Slave Mode */
  TIM_SelectMasterSlaveMode(TIM4, TIM_MasterSlaveMode_Enable);//ÅäÖö¨Ê±Æ÷4ΪÖ÷ģʽ
  /* Enable and set EXTI Line0 Interrupt to the lowest priority */
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//µÚ2×飺×î¸ß2λÓÃÓÚÖ¸¶¨ÇÀռʽÓÅÏȼ¶£¬ºóÃæ2λÓÃÓÚÖ¸¶¨ÏìÓ¦ÓÅÏȼ¶£»
  NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//rTIM4
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;//
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
  TIM_Cmd(TIM4, ENABLE);
}
//******************************************************************************************
//1000ºÁÃë ¶¨Ê±²éѯ£¡
void TIM4_IRQHandler_Lib(void){

        if(TIM_GetITStatus(TIM4, TIM_IT_Update) == SET){
                Freq=(float)TIM_GetCapture1(TIM2);
                Freq *=FREQ_DIV_K*(1000/MEASURE_ms);               
                TIM_ClearITPendingBit(TIM4, TIM_IT_Update);  
        }                
}
//**********************************************************************************************************
// ³õʼ»¯TIM2  Ëü×÷ΪÍⲿÂö³å¼ÆÊýÆ÷£¬Í¬Ê±Ò²ÊÇÓÉTIM4 ÄÚ²¿´¥·¢¸´Î»¿ØÖƵĴӼÆÊýÆ÷
//**********************************************************************************************************
void  TIM2_Config(void){
TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
TIM_ICInitTypeDef                     TIM_ICInitStructure;
       
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
        TIM_DeInit(TIM2);       
        /*---------------------------- TIM2 Configuration ----------------------------*/
        /* Time base configuration */
        TIM_TimeBaseStructure.TIM_Period = 0xffffffff;//fCK_PSC/(PSC[15:0]+1)¡£
        TIM_TimeBaseStructure.TIM_Prescaler = 0;
        TIM_TimeBaseStructure.TIM_ClockDivision = 0;
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
        TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
        TIM_SelectInputTrigger(TIM2, TIM_TS_ITR3);                                        //¶¨Ê±Æ÷2Ñ¡Ôñ¶¨Ê±Æ÷4»ñµÃÊäÈë´¥·¢(TIM2_SMCR¼Ä´æÆ÷µÄTS=011)
        /* Use the External Clock as TIM2 Slave Mode */
        TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Reset);                        //ÅäÖö¨Ê±Æ÷2ʹÓø´Î»Ä£Ê½(TIM2_SMCR¼Ä´æÆ÷µÄSMS=100)
        //--------------------------------------------------------------------------------
        //ÉèÖÃÍⲿÊäÈë: x·ÖƵ£¬ÉÏÉýÑØ£¬²»¹ýÂË£¡
        TIM_ETRClockMode2Config(TIM2,FREQ_DIV,TIM_ExtTRGPolarity_Inverted,0);
        //TIM_ITRxExternalClockConfig(TIM2,TIM_TS_ITR3);
        //----------------------------------------------------------------------------
        //TIM4-tigo  Í¬Ê±²úÉú TIM2µÄÊäÈëÆË×½
TIM_ICInitStructure.TIM_Channel=TIM_Channel_1;
TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_TRC;        //TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter=0;                                                                                        //Fsampling=Fdts/4 N=8  Â˳ý32msµÄ¶¶¶¯
TIM_ICInit(TIM2,&TIM_ICInitStructure);
TIM_SetCounter(TIM2,0);
TIM_Cmd(TIM2, ENABLE);
}
//-------------------------------------------------------------------------------------------
//³õʼ»¯ TIM2,TIM4.ETR
void FREQ_Measure_Init(void){
        TIM4_Config();
        TIM2_Config();
}
//---------------------------------------------------------------------------------------------
//µÃµ½ÆµÂÊÖµ
float Get_Freq_Value(void){
        return Freq;
}
回复 支持 反对

使用道具 举报

     
发表于 2020-2-16 23:27:18 | 显示全部楼层
注释变成乱码?
fr.jpg
回复 支持 反对

使用道具 举报

     
发表于 2020-3-5 20:46:10 | 显示全部楼层
看贴学到东西了
回复 支持 反对

使用道具 举报

     
发表于 2020-3-25 21:58:36 | 显示全部楼层
这是我用stc单片机+数字计数器芯片做的等精度频率计
等精度频率计1.jpg
等精度频率计2.jpg
等精度频率计3.jpg
等精度频率计4.jpg
回复 支持 反对

使用道具 举报

     
发表于 2020-3-26 07:40:10 | 显示全部楼层
本帖最后由 翌阳 于 2020-3-26 07:56 编辑

用等精度方式来实现频率计,与闸门时间没关系了,闸门时间长,精度会更高,但频率与闸门时间的精度没关系。
是这样做,T1和T2做成外部计数,T1可以计输入信号的数,T2计标准时钟频率的数,T3用来做闸门时间计数。若是用51,闸门时间都可以用循环来实现。
开始,闸门关闭,T1,T2清0,然后闸门打开,T3计一秒,时间到闸门关闭,这个闸门要同时用外部器件控制输入信号和时钟频率的接入,用74HC00就可以了,两个一块控制,精度相当高。而闸门时间长点短点都没关系了,因为频率值是这样计算出来的:
频率=T1/T2*标准时钟频率。时钟频率可以用单片机的,也可以用另外一个。
想要更稳定,也可以用外部器件来实现闸门关闭时输入正好是一个整数周期(比如上升沿开始,上升沿结束)。或者想要得到小数点后的频率,可以10秒闸门(但你的标准时钟频率有小数点后的精度没?)。
只用T1,T2频率上不去,在计数器之前再用两个74HC393来先计数,然后用P1,P2来读入它们的值。
计算上用C语言,长整数计算,或者双精度浮点计算。整数计算要注意别溢出,弄点小技巧在里面。

有了单片机,很多事都好办了。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 加入会员

本版积分规则

小黑屋|手机版|矿石收音机 ( 蒙ICP备05000029号-1 )

蒙公网安备 15040402000005号

GMT+8, 2025-4-29 11:16

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表