1.贴上cyclone 10 LP上的芯片引脚绑定:
首先是ADC芯片的:
其次是sm状态机的:
2.贴上代码:内涵注释:
首先是ADC:
module ADC_top(clk_20m_i,clk_500k_o,rst,eoc,d,adda,addb,addc,led_h,led_l,ale,start,oe);
input clk_20m_i,rst,eoc;
//clk20mi是指fpga本身的20mhz时钟,rst是复位信号
//eoc是查询忙标志,为0是忙
input [7:0]d;//表示adc转换结果
output ale,start,oe;
//fpga控制线,ale是允许地址线信号发送标志,1为真
//start是启动转换信号,理论上ale和start可以用一个信号表示;
//oe是允许转换结果输出;以上三个为1时为真
output clk_500k_o;
//adc的工作时钟信号
output adda,addb,addc;//输出控制线
output [3:0] led_h;//高四位数字
output [3:0] led_l;//低四位
wire[7:0]q;
wire clk_5m_o;//状态机时钟
wire lock_t;
PLL PLL_U1(.inclk0(clk_20m_i), .c0(clk_500k_o), .c1(clk_5m_o));
ADC0809 ADC0809_U1(
.d(d),
.clk(clk_5m_o),
.eoc(eoc),
.rst(rst),
.ale(ale),
.start(start),
.oe(oe),
.adda(adda),
.addb(addb),
.addc(addc),
.q(q),
.lock_t(lock_t)
);
seg7 SEG7_U2(
.a(q[7:4]),
.led7s(led_h)
);
seg7 SEG7_U1(
.a(q[3:0]),
.led7s(led_l)
);
endmodule
module seg7(a,led7s);//控制数码管模块
input [3:0]a;
output reg[3:0] led7s;
always@(a)
case(a)
4'b0000:led7s=4'b0000;
4'b0001:led7s=4'b0001;
4'b0010:led7s=4'b0010;
4'b0011:led7s=4'b0011;
4'b0100:led7s=4'b0100;
4'b0101:led7s=4'b0101;
4'b0110:led7s=4'b0110;
4'b0111:led7s=4'b0111;
4'b1000:led7s=4'b1000;
4'b1001:led7s=4'b1001;
4'b1010:led7s=4'b1010;
4'b1011:led7s=4'b1011;
4'b1100:led7s=4'b1100;
4'b1101:led7s=4'b1101;
4'b1110:led7s=4'b1110;
4'b1111:led7s=4'b1111;
default :led7s=4'b0000;
endcase
endmodule
module ADC0809(
d,
clk,
eoc,
rst,
ale,
start,
oe,
adda,
addb,
addc,
q,
lock_t
);//adc模块驱动程序,也是一个状态机程序
parameter s0=5'b00001,
s1=5'b00010,
s2=5'b00100,
s3=5'b01000,
s4=5'b10000;
input [7:0]d;//通过0809转换好的8位数据
input clk,rst,eoc;//输入时状态机时钟,也就是系统时钟,
//rst复位,eoc是转换状态指示,高电平转换完毕,低电平正在转换
output ale,start,oe;
output lock_t;
reg ale,start,oe;
// reg lock_t;
//ale和start是允许和开始标识,
//oe是允许输出信号;
//lock_t是所处测试信号
output adda,addb,addc;//地址线
output [7:0]q;
reg lock;//数据输出时钟信号
reg[4:0] state,next_state;
reg[7:0] regl;//保存数据
assign lock_t=lock;
assign adda=0;
assign addb=0;
assign addc=0;
always@(posedge clk or posedge rst)//状态方程
begin
if(rst)
state<=s0;
else
state<=next_state;
end
//状态机包括了驱动,输出,状态
always@(state or eoc)//驱动方程方程
begin
case(state)
s0://adc状态初始化
begin
ale=0;
start=0;
oe=0;
lock=0;
next_state<=s1;
end
s1://启动测试
begin
ale=1;
start=1;
oe=0;//转换结束,允许输出;
lock=0;
next_state<=s2;
end
s2://
begin
ale=0;
start=0;
oe=0;
lock=0;
if(eoc==1'b1)
next_state<=s3;//eoc=1,转换结束
else
next_state=s2;//eoc=0,正在转换;
end
s3://
begin
ale=0;
start=0;
oe=1;//转换结束,允许输出;
lock=0;
next_state<=s4;
end
s4://启动测试
begin
ale=0;
start=0;
oe=1;//转换结束,允许输出;
lock=1;//保存数据锁存,进一步输出
next_state<=s0;
end
default:next_state=s0;
endcase
end
always@(posedge lock)//输出方程
if(lock)regl<=d;//锁存
assign q=regl;
endmodule
其次是sm101状态机:
module sm(
clk_i,
rst,
seg,
par_i,
en,
speaker
);
input wire clk_i;
input wire rst;
input wire [7:0] par_i;
input wire en;
output wire[31:0] seg;
output speaker;
wire clk_sm;
wire clk_speaker;//蜂鸣器信号
wire x; //依次传入的电平数据
// Add user logic here
sm_check sm_m(
.clk_sm(clk_sm),
.clk_speaker(clk_speaker),
.rst(rst),
.x(x),
.speaker(speaker)
);
// assign speaker=clk_speaker;
// User logic ends
clk_div clk_u1(
.clk_i(clk_i),//系统时钟输入,
.clk_sm(clk_sm),//状态机输入时钟
.clk_speaker(clk_speaker),//蜂鸣器时钟信号
.rst(rst)//复位信号
);
p2s p2s_u1(
.par_i(par_i),//八位输入电平信号
.ser_o(x),//输出要检测的电平信号
.clk(clk_sm),//状态机输入时钟
.en(en)
);
assign seg[3:0] = par_i[0];
assign seg[7:4] = par_i[1];
assign seg[11:8] = par_i[2];
assign seg[15:12] = par_i[3];
assign seg[19:16] = par_i[4];
assign seg[23:20] = par_i[5];
assign seg[27:24] = par_i[6];
assign seg[31:28] = par_i[7];
endmodule
module sm_check(
clk_sm,
clk_speaker,
rst,
x,
speaker
);
parameter s0=2'b00,
s1=2'b01,
s2=2'b11,
s3=2'b10;
input clk_sm,clk_speaker;
input x;
input rst;
reg[1:0] state,next_state;//状态
output reg speaker;//输入
always@(posedge clk_sm or negedge rst)
begin
if(!rst)
begin
state<=s0;
//next_state<=s0;
end
else
state<=next_state;
end
always@(state or x)
begin
case(state)
s0://00
begin//00-01
if(x==1) begin next_state<=s1;end
else begin next_state<=s0;end//00-00
end
s1://01
begin
if(x==1) begin next_state<=s1;end//01-11
else begin next_state<=s2;end//01-10
end
s2://11
begin//101 ,01
if(x==1)begin next_state<=s3;end//可重叠式
else begin next_state<=s0;end//10-0-00
end
s3://10
begin//
if(x==1)begin next_state<=s1; end//11-1->11
else begin next_state<=s2;end//11-0->10
end
default :begin next_state<=s0;end
endcase
end
always@(*)
begin
case(state)
s3: speaker=clk_speaker;
default:speaker=0;
endcase
end
endmodule
3.对上述代码的一些问题补充:
a.首先是关于adc芯片控制程序的,有莫名奇妙的显示bug,问题应该是出在了锁存信号发送上,即变量regl和lock。
b.sm状态机部分注释是有问题的,我一开始是按照自己的思路写的三段式,但是莫名有问题,于是就按照课本上的标准例程抄了一遍,后来发现主要的问题应该是出在了状态机时钟上,即smcheck这个模块传入的时钟信号必须是速度合适的状态机专属的时钟,而这个时钟信号是由另一个专门负责时钟的模块制作的,命名为clk_sm;clk_sm的速度不能快,这是为了保证我们人耳有足够的时间听到蜂鸣器声音。
c.下面贴一下状态机构成的状态图,这部分是数电的知识,遗忘的朋友请翻一翻数电课本;