CPLD开发板焊好后,首先大致熟悉了一下板上的外设——其实也就是数码管和按键。只基于熟悉外设考虑,按键的检测我完全没有加消抖,用起来的确很抖(按下一次偶尔能响应若干次)。刚才看到论坛里有对消抖的讨论
http://forum.eepw.com.cn/thread/234045/1待会去观摩一下。
熟悉完外设之后我决定做一个频率计,采用在规定时间内记上升沿个数的方法,测量信号的频率。虽然这种方法一般只适于频率稍高的信号,但是实测发现精度惊人,在100Hz~1MHz除了末尾的一个字误差之外基本木有抖动。下面是我的具体做法:
1、引脚设置为施密特触发输入,verilog代码里写作上升沿触发。
之前下好代码开始加信号之后,发现了一个有意思的现象:方波信号测得非常准,但是正弦波,三角波等信号测的就完全是乱码。后来是听同学说,CPLD引脚可配置为“施密特触发输入”,即内部自带施密特反相器,也就相当于内部自带了一个迟滞比较器,配置选项在分配引脚的PinPlanner菜单里,如图:
顺带也能发现CPLD支持的电平确实很多,不过一般使用的话,什么CMOS,TTL电平貌似可以通用。
2、设置采集时间长度:0.1s
由于CPLD不能做乘除,所以这个时间长度就只能是10的倍数。1s太长,就只好0.1s了,用verilog可以轻易实现这样的分频:
parameter M5=23'd5_000_000;
always @(posedge SYS_CLK,negedge SYS_RST)
if(!SYS_RST)//低电平复位
begin
timer<=23'b0;
_time_up<=1'b0;
end
else
begin
timer<=timer+1'b1;
_time_up<=1'b1;
if(timer==M5)
begin
timer<=23'b0;
_time_up<=1'b0;
end
end
3、采用BCD码计数
由于CPLD不能做乘除,所以下面这段极其简单的代码居然不能直接使用……
always @(posedge in , negedge(SYS_RST & _time_up)
if(!(SYS_RST & _time_up))
freq<=0;
else
freq<=freq+1;
由于需要点亮数码管,为了查表的方便,被迫使用BCD 码计数——为了折腾那个进位,写了7层if-else ……代码不放了,太长。
4、数据锁存,数码管扫描
当 _time_up 低电平时,触发一个锁存操作,在BCD码即将回零时,将当前计数值锁进一个寄存器。这全拜托了verilog特色的非阻塞赋值。
always @(negedge _time_up,negedge SYS_RST)
if(!SYS_RST)
begin
hold[0]<=4'b0;
……
end
else if(!_time_up)
begin
hold[0]<=bcdf[0];
……
end
接下来进行数码管扫描,定时 - 循环扫段 - 查表显示数字
{verilog的大括号实在太好用了,本来我循环左移还写了好半天,后来发现使用大括号:
always @(posedge in,negedge (SYS_RST&_time_up))
完美解决,真不知道verilog还提供左移右移运算符是干什么的……}
//扫描时钟
always @(posedge SYS_CLK,negedge SYS_RST)
if(!SYS_RST) diverled<=16'b0;
else diverled<=diverled+16'b1;
//段扫描
always @(posedge diverled[15],negedge SYS_RST)
if(!SYS_RST)
begin
dig<=8'hfe;
tempd<=3'b0;
end
else
begin
dig<={dig[6:0],dig[7]};
tempd<=tempd+3'b1;
end
assign temps=hold[tempd];
//查表显示
always @(temps)
begin
case(temps)
4'd0:seg=8'b1100_0000;
……
default:seg=8'b0111_1111;
endcase
end
以上就是这个频率计的做法