FPGA基础实验:驱动ADC0809芯片并显示十六进制数据;另外扩展sm101状态机检测。

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.下面贴一下状态机构成的状态图,这部分是数电的知识,遗忘的朋友请翻一翻数电课本;

 

 

 

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值