搜索
bottom↓
回复: 26

频率计程序为什么会计不准.为了饭碗.请教高手(附源码)

[复制链接]

出0入0汤圆

发表于 2008-7-10 01:15:23 | 显示全部楼层 |阅读模式
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity count is
port(
        clk:in std_logic;
        freq_in:in std_logic;
        en_in:in std_logic;
        count_out:out std_logic_vector(3 downto 0));
end count;
architecture ari of count is
signal en_num:std_logic_vector(2 downto 0):="000";
signal count_temp:std_logic_vector(18 downto 0);
signal count_num:integer range 0 to 1000;
signal q1,reply_ok:std_logic:='0';
--signal q2:std_logic:=0;
begin
count:process(clk)
        begin
                        if (clk='1' and clk'event )then
               
                                if(count_num =count_num'high)then
                                        q1<='1';--count is up ,stop test
                                else
                                        count_temp<=count_temp+1;
                                end if;
                                                                                               
                                if(reply_ok ='1' and en_num ="000")then -- the data is carry out start testing again
                                        q1  <='0';                               
                                        count_temp<=(others=>'0');
                                end if;


                        end if;
         end process;
       
process(freq_in)
begin
                if(freq_in='1' and freq_in'event) then
                                if(count_num < count_num'high ) then
                                        count_num<=count_num+1;
                                end if;

                                if(en_num = "000" and reply_ok ='1')then
                                        count_num  <=0;
                                end if;
                                if(en_num > "000" )then
                                        reply_ok <= '1';
                                else
                                        reply_ok <= '0';
                                       
                                end if;
                   end if;

        end process;
                               
process(en_in)
begin
                if( en_in'event and en_in='1'   )then
                         en_num<=en_num+1;
                end if;               
end process;

process(en_in)
begin
        if (en_in='1' and en_in'event )then
                        case en_num is
                                        when "001"=>count_out(3 downto 0)<=('0' &count_temp(18 downto 16));
                                        when "010"=>count_out(3 downto 0)<=count_temp(15 downto 12);
                                        when "011"=>count_out(3 downto 0)<=count_temp(11 downto 8);
                                        when "100"=>count_out(3 downto 0)<=count_temp(7  downto 4);
                                        when "101"=>count_out(3 downto 0)<=count_temp(3 downto 0);
                                        when others=>
                        end case;
                end if;
end process;
end ari;

count_out是送给单片机
count_num是要计频率的脉冲个数
count_temp是总的计1000次时的糸统脉冲

CPLD是用有限的10M晶振

设计思路:固定计1000(count_num)个freq_in求得系统脉冲(count_temp)的个数.1/10M

程序出来后结果乱跳
大家救急啊.再做不出来,就要走人了.!!!老板的脸色一天比一天难看了
程序怪得很.一开始是可以的.后来就不行了.

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

发表于 2008-7-10 09:28:19 | 显示全部楼层
别做了 闪人吧
http://hi.baidu.com/xcodes上有个89c2051做的 要不你看看

出0入0汤圆

 楼主| 发表于 2008-7-10 09:45:25 | 显示全部楼层
高人啊.可惜我是CPLD做的

出0入4汤圆

发表于 2008-7-10 10:00:09 | 显示全部楼层
看着都累了. 也不说说你设计的思路, 看了半天也没有猜透reply_ok的含义, 不知道到底要实现什么!
1. 各个时钟域的信号不能直接使用.  
如en_num是在en_in的时钟下跳变的, 但是在别的时钟下"直接"使用(en_num ="000")的判断是极其危险的----如果这个判断发生在en_num跳变的瞬间, 逻辑将出现致命错误.
2. 没有复位信号. 这种时序逻辑最好有复位, 否则难以确定起始值.

出0入0汤圆

 楼主| 发表于 2008-7-10 10:11:02 | 显示全部楼层
谢谢.reply_ok是程序读count_temp完的标志位
en_in是读出count_temp的脉冲
思路:计1000(count_num)个freq_in的系统脉冲(count_temp).1/10M

出0入0汤圆

发表于 2008-7-10 10:21:13 | 显示全部楼层
一频率计有那么复杂嘛?
最简单的做法就是固定时间(固定CLK的计数个数,譬如1秒钟,10M个)记输入信号的个数(输入信号频率较高时采用)。
其次是固定输入信号的个数,记时钟的个数(输入信号频率较低时采用)。
最精确的做法是,固定大概的时间,计算输入信号的个数和CLK的个数,然后送到单片机相除(好像叫等精度频率计哇,忘了)。
其实哪种做法都简单,CPLD实现的话一般超不过20句代码。楼主的代码搞来搞去,搞得我都没耐性看下去了。如果需要在你的程序基础上帮你作出正确的修改的话,你最好把设计思路说出来。

出0入0汤圆

 楼主| 发表于 2008-7-10 10:28:48 | 显示全部楼层
我的设计思路:固定计1000(count_num)个freq_in求得系统脉冲(count_temp)的个数.1/10M
to AD827AQ.不好意思.CPLD还是刚入门,老板...咳..

出0入0汤圆

发表于 2008-7-10 10:31:35 | 显示全部楼层
你这肯定要出错,整个设计没有一个同步信号,en输入信号实际是作为一个串行时钟用的。
reply_ok应该设计成一个外部信号,由单片机送过来,作为同步信号用。

出0入0汤圆

 楼主| 发表于 2008-7-10 10:39:57 | 显示全部楼层
if(en_num = "000" and reply_ok ='1')then
                                        count_num  <=0;
                                end if;
          if(reply_ok ='1' and en_num ="000")then -- the data is carry out start testing again
                                        q1  <='0';                                 
                                        count_temp<=(others=>'0');
                                end if;

我的reply_ok的作用就只有上面一句.就是为了清count_num count_temp 就等于复位信号.如果MCU送过来.那要怎么清count_temp.count_num呢

process(reply_ok)
begin
     if (reply_ok=1 and reply_ok'event) then
        count_temp<=(others=>'0');
        count_num  <=0;
        q1  <='0';
end if
end process
这样好像不行

出0入0汤圆

发表于 2008-7-10 10:42:41 | 显示全部楼层
你这是接口设计错误,传输出错。程序本身对错已经没有任何意义了。等下我给你画个图。

出0入0汤圆

发表于 2008-7-10 10:58:41 | 显示全部楼层

接口 (原文件名:plj.JPG)

程序应该改成这样。
reply_ok,en_in为输入信号,f_out为数据输出。
reply_ok上升沿表示数据已经读完,各计数模块清零。主要是en_num,count_tmp,count_num清零,其他的完成初始化(譬如f_out数据线该拉高就拉高,拉低就拉低,该高阻就高阻,取决于你的电路设计)。
reply_ok为低时en_num计数,同时根据计数值将数据输出。
reply_ok为高时count_tmp和count_num计数开始,为低时计数停止(reply_ok实际是全局使能信号)。
count_num计数超过1000时,count_num和count_tmp计数停止,等待将count_tmp输出。
实际上这时你最好还有根INT信号通知单片机计数完成,让单片机来读数,否则的话,你只能设计成等待足够长时间后,单片机才读数。

出0入0汤圆

发表于 2008-7-10 11:38:02 | 显示全部楼层
AD827AQ 真是热心肠啊!

我凑凑热闹:
count_num计数达到1000时,作为测试结束条件不好,1KHz以下的信号所需时间太长;建议用clk计数到10M(固定1s)作结束条件比较好,起始点以复位后,被测信号上升沿为准。

出0入0汤圆

 楼主| 发表于 2008-7-10 11:40:18 | 显示全部楼层
谢谢 AD827AQ 我好好体会一下.freq_in一般只是大哟32K

出0入0汤圆

 楼主| 发表于 2008-7-10 12:29:15 | 显示全部楼层
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity count is
port(
        clk:in std_logic;
        freq_in:in std_logic;
        replay_ok :in std_logic;
        en_in:in std_logic;
        count_out:out std_logic_vector(3 downto 0));
end count;
architecture ari of count is
signal en_num:std_logic_vector(2 downto 0):="000";
signal count_temp:std_logic_vector(18 downto 0);
signal count_num:integer range 0 to 1000;
signal timeup:std_logic;
begin
count:process(clk)  
        begin
                        if (clk='1' and clk'event )then
                               if(timeup = '0') then
                                    if(count_num <count_num'high)then
                                        count_temp<=count_temp+1;
                                     end if;
                                end if;
                        end if;
         end process;

process(reply_ok)
begin
     if (reply_ok=1 and reply_ok'event) then
        count_temp<=(others=>'0');  --在这里可以清掉吗.这样偏译得不过吧.
        count_num  <=0;
         timeup=0;
    end if
end process

process(freq_in)
begin
                if(freq_in='1' and freq_in'event) then
                        if(count_num < count_num'high ) then
                                  count_num<=count_num+1;
                        else
                                  timeup=1;---计1000次完成标志
                        end if;
                   end if;

        end process;
                                 
process(en_in)
begin
                if( en_in'event and en_in='1'   )then
                         en_num<=en_num+1;
                end if;                 
end process;

process(en_in)
begin
        if (en_in='1' and en_in'event )then
                        case en_num is
                                        when "001"=>count_out(3 downto 0)<=('0' &count_temp(18 downto 16));
                                        when "010"=>count_out(3 downto 0)<=count_temp(15 downto 12);
                                        when "011"=>count_out(3 downto 0)<=count_temp(11 downto 8);
                                        when "100"=>count_out(3 downto 0)<=count_temp(7  downto 4);
                                        when "101"=>count_out(3 downto 0)<=count_temp(3 downto 0);
                                        when others=>
                        end case;
                end if;
end process;
end ari;
这样象不可以把

出0入0汤圆

发表于 2008-7-10 12:33:16 | 显示全部楼层
看不懂程序
频率计的方法网上很多
什么M T M/T
各种
说白了就是低频测周期 高频测定长时间的脉冲数

出0入4汤圆

发表于 2008-7-10 13:41:03 | 显示全部楼层
freq_in一般只是大哟32K----既然这样, 整个程序里只要clk是时钟就可以了.
用clk来监测freq_in,en_in的上升沿来处理逻辑. 这样就不会有"异步时钟"的问题了.

出0入0汤圆

 楼主| 发表于 2008-7-10 14:15:56 | 显示全部楼层
如何用CLK监测freq_in,en_in的可以说个例子吗

出0入0汤圆

 楼主| 发表于 2008-7-10 15:39:56 | 显示全部楼层
library ieee;  
use ieee.std_logic_1164.all;  
use ieee.std_logic_arith.all;  
use ieee.std_logic_unsigned.all;  
entity count is  
port(  
        clk:in std_logic;  
        freq_in:in std_logic;  
        replay_ok :in std_logic;
        en_in:in std_logic;  
        count_out:out std_logic_vector(3 downto 0));  
end count;  
architecture ari of count is  
signal en_num:std_logic_vector(2 downto 0):="000";  
signal count_temp:std_logic_vector(18 downto 0);  
signal count_num:integer range 0 to 1000;  
signal start_count,end_count,flag:std_logic;
begin  
count:process(clk)   
        begin  
                  if(reply_ok = '1') then
                        if (clk='1' and clk'event )then  
                                   if(flag='1')then
                                              count_temp<=count_temp+1;  
                                    end if;
                                 end if;
                  else
                          count_temp<=(other=>0);
                             
                  end if;  
         end process;  

flag =  start_count and NOT end_count;

process(freq_in)  
begin  
             if(reply_ok ='1') then
                 if(freq_in='1' and freq_in'event) then  
                        if(count_num < count_num'high ) then  
                                  count_num<=count_num+1;
                                  start_count='1';  
                        else
                                  end_count=1;---计1000次完成标志
                        end if;  
                  end if;
             else
                 count_num<=(other=>0);
                 start_count='0'
                 end_count='0'
             end if

        end process;  
                                 
process(en_in)  
begin  
               if(reply_ok ='1') then
                        if( en_in'event and en_in='1'   )then  
                              en_num<=en_num+1;  
                        end if;              
               else
                        en_num="000";
               end if   
end process;  

process(en_in)  
begin  
        if (en_in='1' and en_in'event )then  
                        case en_num is  
                                        when "001"=>count_out(3 downto 0)<=('0' &count_temp(18 downto 16));  
                                        when "010"=>count_out(3 downto 0)<=count_temp(15 downto 12);  
                                        when "011"=>count_out(3 downto 0)<=count_temp(11 downto 8);  
                                        when "100"=>count_out(3 downto 0)<=count_temp(7  downto 4);  
                                        when "101"=>count_out(3 downto 0)<=count_temp(3 downto 0);  
                                        when others=>  
                        end case;  
                end if;  
end process;  
end ari;  
程序改成如上.......

出0入0汤圆

 楼主| 发表于 2008-7-10 23:23:28 | 显示全部楼层
经过各位网友的努力.特别是AD827AQ ,qinxg 热心指点.我终于做出来了.十分感激大家...AD827AQ ,qinxg如果有来深圳.或者在深圳,联系我啊,我一定请吃饭...

出0入0汤圆

 楼主| 发表于 2008-7-21 17:07:32 | 显示全部楼层
library ieee;   
use ieee.std_logic_1164.all;   
use ieee.std_logic_arith.all;   
use ieee.std_logic_unsigned.all;   
entity count is   
port(   
        clk:in std_logic;   
        freq_in:in std_logic;   
        replay_ok :in std_logic;  
        int:out:std_logic;
        en_in:in std_logic;   
        count_out:out std_logic_vector(3 downto 0));   
end count;   
architecture ari of count is   
signal en_num:std_logic_vector(2 downto 0):="000";   
signal count_temp:std_logic_vector(18 downto 0);   
signal count_num:integer range 0 to 1000;   
signal count_wave:integer range 0 to 500;
signal start_count,end_count,flag,flag1:std_logic;  
begin   
process(clk)
begin
     if(replay_ok = '1') then
       if(freq_in ='0') then
         if (clk='1' and clk'event )then --test wave input
            if(flag1 ='0') then
                if(count_wave < count_wave'high) then
                     count_wave<=count_wave+1;
                     flag1=0;
                else
                     flag1=1;
                end if;
            else
                int='1';
                if(count_wave> 0 )then
                    count_wave<=count_wave-10;
                    flag1=1;
                else
                    --flag1=0;
                    int='0';
                end if;                 
            end if;
        end if;
     end if;
   else
       count_wave<=(other=>0);
       flag1<=0;
       int<='1';
   end if;
end process;

count:process(clk)   
        begin   
                  if(reply_ok = '1') then  
                        if (clk='1' and clk'event )then   
                                   if(flag='1')then  
                                              count_temp<=count_temp+1;   
                                    end if;
                                 end if;  
                  else
                          count_temp<=(other=>0);
                              
                  end if;   
         end process;   

flag =  start_count and NOT end_count;  

process(freq_in)   
begin   
             if(reply_ok ='1') then
                 if(freq_in='1' and freq_in'event) then   
                        if(count_num < count_num'high ) then   
                                  count_num<=count_num+1;
                                  start_count='1';   
                        else  
                                  end_count=1;---计1000次完成标志  
                        end if;   
                  end if;  
             else
                 count_num<=(other=>0);
                 start_count='0'
                 end_count='0'
             end if  

        end process;   
                                   
process(en_in)   
begin   
               if(reply_ok ='1') then
                        if( en_in'event and en_in='1'   )then   
                              en_num<=en_num+1;   
                        end if;               
               else
                        en_num="000";
               end if     
end process;   

process(en_in)   
begin   
        if (en_in='1' and en_in'event )then   
                        case en_num is   
                                        when "001"=>count_out(3 downto 0)<=('0' &count_temp(18 downto 16));   
                                        when "010"=>count_out(3 downto 0)<=count_temp(15 downto 12);   
                                        when "011"=>count_out(3 downto 0)<=count_temp(11 downto 8);   
                                        when "100"=>count_out(3 downto 0)<=count_temp(7  downto 4);   
                                        when "101"=>count_out(3 downto 0)<=count_temp(3 downto 0);   
                                        when others=>   
                        end case;   
                end if;   
end process;   
end ari;

出0入0汤圆

发表于 2009-6-29 23:24:37 | 显示全部楼层
哈哈,学教了啊

出0入0汤圆

发表于 2009-7-2 20:11:44 | 显示全部楼层
【20楼】 zcl843 起航

library ieee;   
use ieee.std_logic_1164.all;   
use ieee.std_logic_arith.all;   
use ieee.std_logic_unsigned.all;   
----------------------------------
开头的代码是什么来的,是Verilog的代码还是SystemVerilog的?

出0入0汤圆

 楼主| 发表于 2009-7-3 11:12:08 | 显示全部楼层
是VHDL

出0入0汤圆

发表于 2011-9-21 23:17:12 | 显示全部楼层
各种高手啊

出0入0汤圆

发表于 2011-10-12 23:03:48 | 显示全部楼层
其实,做到高精度的频率计,还要关心的时间基准晶振的稳定度,
学习中,,,
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-24 11:13

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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