2021年“暑假一起练”——使用小脚丫FPGA综合技能训练平台制作数字电压表
该项目基于小脚丫FPGA的综合技能训练板,利用ADC制作一个数字电压表,具体功能为将电压值在板上的OLED屏幕上显示出来,LED屏幕上也有显示,范围在0-3V之间。
标签
FPGA
数字逻辑
显示
xn15170778670
更新2021-09-11
871

项目背景

   目的是提高同学们在暑假对于数字电路和FPGA的理解,培养学生掌握核心技术的创新意识,硬禾学堂开展了“暑假一起练”活动。通过免费获得板卡、提升技能的方式,为了让更多的同学通过一系列有趣的项目挑战提升自己的综合技能。而FPGA综合技能训练板基于STEP-MXO2核心板。STEP-MXO2第二代是小脚丫团队推出的最新一款FPGA开发板,选用了Lattice公司的MXO2系列的4000HC,逻辑资源较第一代产品提升了近4倍。同时,在板卡的背面集成了编程器,通过USB数据线即可完成FPGA的编程和下载,使用硬禾学堂的小脚丫训练板,可以实现多种不同方式的输入输出功能。除此以外,这个项目可以说是从零开始做,所以可以适合广大零基础的学生学习。

项目描述及需要实现的功能

  1. 旋转电位计可以产生0-3.3V的电压

  2. 利用板上的串行ADC对电压进行转换

  3. 将电压值在板上的OLED屏幕上显示出来

项目逻辑图

FtELa1_u1I7_ece2rNO-DhM_5_kz

系统构成:

  1. ADC模块,将从可变电位计(0-3.3V)得到的模拟电压转化成数字电压,数字电压的精度则有编写的代码模块决定,最后在OLED上输出的精度在小数点后三位数。
  2. BCD模块,为了将得到的数字电压显示在显示屏上,且可以便于展示也需要一些文字说明,所以需要一个BCD模块来编码,之后编码之后的二进制数据才可以显示在OLED的屏幕之上,可以在其中编写二进制代码到简单数字和字母的一一对应。
  3. OLED模块,根据所需要的显示要求和从BCD模块处得到的数据将所有内容显示在OLED屏幕上,一共4位的电压,分别使用4个变量进行显示,其他的则是一些文字说明。

项目计划:

  1、电位计手动旋转产生不同电压

  2、由ADC模块将产生的电压进行数字化

  3、通过BCD编码模块将电压转化为BCD码

  4、将编码后的结果显示在OLED上

  5、最后综合整理,完成顶层文件编写

项目框架:

ADC模块实现

   该模块的制作直接使用了电子森林里面的源代码,功能为ADC数据的采样,并将其传输给后面的BCD模块,以便编码。

module ADS7868
(
input				clk,		//系统时钟
input				rst_n,  	//系统复位,低有效

output	reg			adc_cs,		//SPI总线CS
output	reg			adc_clk,	//SPI总线SCK
input				adc_dat,	//SPI总线SDA

output	reg			adc_done,	//ADC采样完成标志
output	reg [7:0]	adc_data	//ADC采样数据
);

localparam	HIGH = 1'b1;
localparam	LOW  = 1'b0;

reg [7:0] cnt; //计数器
always @(posedge clk or negedge rst_n)
	if(!rst_n) cnt <= 1'b0;
	else if(cnt >= 8'd34) cnt <= 1'b0;
	else cnt <= cnt + 1'b1;
	
reg [7:0] data;
always @(posedge clk or negedge rst_n)
	if(!rst_n) begin
		adc_cs <= HIGH; adc_clk <= HIGH; 
		data <= 1'b0; adc_data <= 1'b0; adc_done <= LOW;
	end else case(cnt)
		8'd0 :  begin adc_cs <= HIGH; adc_clk <= HIGH; end
		8'd1 :  begin adc_cs <= LOW;  adc_clk <= HIGH; end
		8'd2,8'd4,8'd6,8'd8,8'd10,8'd12,8'd14,8'd16,
		8'd18,8'd20,8'd22,8'd24,8'd26,8'd28,8'd30,8'd32:	
				begin adc_cs <= LOW;  adc_clk <= LOW;  end
		8'd3 :  begin adc_cs <= LOW;  adc_clk <= HIGH; end 						//0
		8'd5 :  begin adc_cs <= LOW;  adc_clk <= HIGH; end 						//1
		8'd7 :  begin adc_cs <= LOW;  adc_clk <= HIGH; end 						//2
		8'd9 :  begin adc_cs <= LOW;  adc_clk <= HIGH; data[7] <= adc_dat; end 	//3
		8'd11 : begin adc_cs <= LOW;  adc_clk <= HIGH; data[6] <= adc_dat; end	//4
		8'd13 : begin adc_cs <= LOW;  adc_clk <= HIGH; data[5] <= adc_dat; end 	//5
		8'd15 : begin adc_cs <= LOW;  adc_clk <= HIGH; data[4] <= adc_dat; end 	//6
		8'd17 : begin adc_cs <= LOW;  adc_clk <= HIGH; data[3] <= adc_dat; end 	//7
		8'd19 : begin adc_cs <= LOW;  adc_clk <= HIGH; data[2] <= adc_dat; end 	//8
		8'd21 : begin adc_cs <= LOW;  adc_clk <= HIGH; data[1] <= adc_dat; end 	//9
		8'd23 : begin adc_cs <= LOW;  adc_clk <= HIGH; data[0] <= adc_dat; end 	//10
		8'd25 : begin adc_cs <= LOW;  adc_clk <= HIGH; adc_data <= data; end 	//11
		8'd27 : begin adc_cs <= LOW;  adc_clk <= HIGH; adc_done <= HIGH; end 	//12
		8'd29 : begin adc_cs <= LOW;  adc_clk <= HIGH; adc_done <= LOW; end 	//13
		8'd31 : begin adc_cs <= LOW;  adc_clk <= HIGH; end 						//14
		8'd33 : begin adc_cs <= LOW;  adc_clk <= HIGH; end 						//15
		8'd34 : begin adc_cs <= HIGH;  adc_clk <= HIGH; end
		default : begin adc_cs <= HIGH;  adc_clk <= HIGH;  end
	endcase

endmodule

BCD模块

   负责接受来自ADC模块的数据,编码之后在OLED上显示,为电子森林已有代码。

module bin_to_bcd					
(
input						rst_n,	//系统复位,低有效
input		[15:0]			bin_code,	//需要进行BCD转码的二进制数据
output	reg	[19:0]			bcd_code	//转码后的BCD码型数据输出
);

reg		[35:0]		shift_reg; 

always@(bin_code or rst_n)begin
	shift_reg = {20'h0,bin_code};
	if(!rst_n) bcd_code = 0; 
	else begin 
		repeat(16) begin  
			
			if (shift_reg[19:16] >= 5) shift_reg[19:16] = shift_reg[19:16] + 2'b11;
			if (shift_reg[23:20] >= 5) shift_reg[23:20] = shift_reg[23:20] + 2'b11;
			if (shift_reg[27:24] >= 5) shift_reg[27:24] = shift_reg[27:24] + 2'b11;
			if (shift_reg[31:28] >= 5) shift_reg[31:28] = shift_reg[31:28] + 2'b11;
			if (shift_reg[35:32] >= 5) shift_reg[35:32] = shift_reg[35:32] + 2'b11;
			shift_reg = shift_reg << 1; 
		end
		bcd_code = shift_reg[35:16];   
	end  
end

endmodule

OLED模块

   该模块同样是使用电子森林已有代码,在其上进行一定程度的修改,因为代码量过大不将源码放出,只放出修改部分的代码。

input	wire [19:0]	 bcd_code,
wire [7:0] volt1;
wire [7:0] volt2;
wire [7:0] volt3;
wire [7:0] volt4;
MAIN:begin
						if(cnt_main >= 5'd4) cnt_main <= 5'd2;
						else cnt_main <= cnt_main + 1'b1;
						case(cnt_main)	//MAIN状态
							5'd0:	begin state <= INIT; end
							5'd1:	begin y_p <= 8'hb0; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "----Xie Ning----";state <= SCAN; end
							5'd2:	begin y_p <= 8'hb1; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= {"  Volt: ",volt4,8'd46,volt3,volt2,volt1," V "};state <= SCAN; end
							5'd3:	begin y_p <= 8'hb2; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= " programe is ok!";state <= SCAN; end
							5'd4:	begin y_p <= 8'hb3; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "----------------";state <= SCAN; end
							
							5'd5:	begin y_p <= 8'hb0; x_ph <= 8'h15; x_pl <= 8'h00; num <= 5'd 1; char <="                "; state <= SCAN; end
							5'd6:	begin y_p <= 8'hb1; x_ph <= 8'h15; x_pl <= 8'h00; num <= 5'd 1; char <= "                "; state <= SCAN; end
							5'd7:	begin y_p <= 8'hb2; x_ph <= 8'h15; x_pl <= 8'h00; num <= 5'd 1; char <= "                "; state <= SCAN; end
							5'd8:	begin y_p <= 8'hb3; x_ph <= 8'h15; x_pl <= 8'h00; num <= 5'd 1; char <= "                "; state <= SCAN; end

							default: state <= IDLE;
						endcase
					end

这里显示的电压共4位数字,其中有3位为小数点之后。

顶层模块

   在顶层模块中,将上面所写的所有模块实例化并且串联起来。

module TOP
(
    	clk,		
    	rst_n,   
		
    	adc_dat,	
  		adc_cs,		
    	adc_clk,	
		
      	seg1_sel,	
      	seg1_led,	
     	seg2_sel,	
    	seg2_led,	

    	oled_csn,	
  		oled_rst,	
 		oled_dcn,	
   		oled_clk,	
   		oled_dat	
);

	input			clk;		
    input			rst_n;   	
    input			adc_dat;
    output			adc_cs;
    output			adc_clk;

    output  		seg1_sel;	
    output  [7:0]	seg1_led;	
    output  		seg2_sel;	
    output  [7:0]	seg2_led;	

    output			oled_csn;	
    output			oled_rst;	
    output			oled_dcn;	
    output			oled_clk;	
    output			oled_dat;	


wire adc_done;
wire [7:0] adc_data;
//ADC模块模拟转数字
ADS7868 m1
(
.clk				(clk			),	//系统时钟
.rst_n				(rst_n			),	//系统复位,低有效
.adc_cs				(adc_cs			),	//SPI总线CS
.adc_clk			(adc_clk		),	//SPI总线SCK
.adc_dat			(adc_dat		),	//SPI总线SDA
.adc_done			(adc_done		),	//ADC采样完成标志
.adc_data			(adc_data		)	//ADC采样数据
);


wire [15:0]	bin_code = adc_data * 16'd129;
wire [19:0]	bcd_code;

//BCD模块ADC数据进行BCD转码
bin_to_bcd m2
(
.rst_n				(rst_n			),	//系统复位,低有效
.bin_code			(bin_code		),	//需要进行BCD转码的二进制数据
.bcd_code			(bcd_code		)	//转码后的BCD码型数据输出
);

//OLED模块显示编码数据
OLED12832 m3
 (
    .clk				(clk        ),	
    .rst_n				(rst_n		),	
    .oled_csn	        (oled_csn  ),   
    .oled_rst	        (oled_rst  ),   
	.oled_dcn	        (oled_dcn  ),   
	.oled_clk	        (oled_clk  ),   
   .oled_dat           (oled_dat  ),   
    .bcd_code			(bcd_code	)   
);




endmodule

 

结果展示

Fnchq7a7-pOKU1koXE6YbKu2GKSHFvkknMF3Hck0YXDTmhqwFjo5JVFX

   项目目标就是将电位计旋转可以产生0-3.3V的电压这一过程展示到OLED的屏幕上,而这里也给出了结果显示,一张图为电位计产生0V电压的显示,一张为3.289V'的电压显示,从后面的结果也可以看出数字电压表的精度到小数点后三位为止。

项目过程中的困难

   之前虽然有接触过一段时间的Verilog,但是已经是大二的事情了,代码逻辑已经有点搞不清楚了,又花了一些时间才把知识捡起来。同时还请教了一下学习过这个的同学,同样也再次锻炼了自己的学习能力,通过一些简单的代码示例快速的上了手,总体来说没有什么大困难。

 

项目总结与感悟

   在还不熟悉的时候模块之间的数据传输有点困难,但逐渐上手之后,难点反而变成了BCD编码相关的部分,总体来说还是学到了很多,是一次很有意义的活动。

   最后,非常感谢硬禾学堂带给我这次机会,让我对数字逻辑电路、FPGA有了更深入的认识,对Verilog语言的使用也有了不少的提升,同时也给我了一个更加充实的假期。

 
附件下载
diamond_project.rar
团队介绍
北京理工大学信息与电子学院
团队成员
谢宁
北京理工大学信息与电子学院
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号