插曲2——如何在Quartus II里面进行模块例化(以基于EP2C5T144C8的人体红外检测装置项目为例)

实现功能

        当红外传感器检测器检测到周围有人时,传感器会通过DO口传回高电平,同时蜂鸣器报警,数码管显示3.3V,串口打印FF 。若无人,则DO口传回低电平,蜂鸣器不响,数码管显示0V,串口打印00。

环境搭建

        因为EP2C5T144C8芯片在Quartus II 9以上版本无法被识别,所以我选择的是Quartus II 9来作为编译平台。

编译语言

        Verilog HDL语言

硬件设备

(1)大西瓜的EP2C5T144C8开发板

(2)型号D-SUN人体红外传感器

模块例化问答

什么是模块例化?

        我只能说,还好我学过32,这和32里面的子函数调用很像很像,不过还是有区别的。模块例化就是就是将实现各个功能的函数逐个放在单独的文件里面,需要的时候就调用,
不需要时就不调用。就相当于是32的库函数。在32里面无论是调用什么函数,都是要在主函数里面调用的,而FPGA要调用各个封装函数,就需要利用顶层文件来将各个封装
函数联系起来。

什么是顶层文件?

我觉得顶层文件就像是一个总的接线器,是开发板和功能代码的一个联系中介,比如,一个实现ad采集的封装函数需要用到开发板的ad引脚,在封装函数中,将ad引脚直接
传回的值定义为ad_harst,那么,就也在顶层文件里定义一个ad_harst,编译一次,成功后,就在添加引脚处指定这个ad_harst所对应的引脚。这样,ad函数就和开发板的这条
线路就打通了。如下图,光标定位处为顶层文件,一般有个”TOP“字样

顶层文件怎么命名?

这个很简单,顶层文件所对应的文件名是什么,那顶层文件就命名为什么,其实不仅是顶层文件,其余的封装函数命名也是要和其所在的文件命名相同,其实这也不是什么
硬性要求,这只是为了方便代码阅读理解而已。

顶层文件怎么设置输入输出口?

很简单,封装函数里面如果定义了output ad,那么就在顶层文件里定义output ad,定义了input ad,那么就在顶层文件里定义input ad。

例如下面这张图为子函数端口

这张图为顶层函数中对端口的定义

怎么把子函数文件里的端口和顶层文件里的端口联系起来?

这个直接看下图,这算是Verilog HDL的死规定。

按照如上规则,在顶层文件里调用需要用到的各个子函数

如何在一个子函数模块里调用另一个子函数模块的结果?

        这个有点绕,但也很简答。核心就是通过顶层模块,在顶层模块定义wire型变量,名字随便取,用来充当一根线的作用。假如我要在beep.v模块里调用ad.v里面读取的ad值,
如果ad>10,就蜂鸣器报警,否则就不报警。那么就执行下面步骤:
(1)在ad.v文件里定义输出变量output [7:0]addata

这个ad值是按下图方式进行数据转换的

(2)在beep.v文件里也定义一个输出变量output[7:0]addata


(3)在顶层文件里定义线网型变量wire [7:0]addata

(4)在顶层文件里将ad.v里面的addata与beep.v里面的addata用顶层文件里的addata连接,这样两个子函数模块的连线就打通了,只要ad.v里的addata发生变化,那么,beep.v里面的addata就跟着发生变化。

代码部分

顶层代码

//这个.v文件十分重要,是所有.v文件的头文件,在这个文件里定义了所有.v模块的输入口和输出口,
//然后就配置引脚,这个.v文件有点像Modesim里的_tb,其余.v文件就相当于普通文件

module shujucaiji_top (
 //数据采集的输入输出端口
input reset,
input clk,     //50MHZ时钟的输入
input data,     //AD TLC549的数据口
output cs,        //AD TLC549的片选择
output ioclk,       //AD TLC549的时钟
output[7:0]segdata,   //数码管的7段码
output[3:0]segcs,    //数码管的为选择
//显示屏的输入输出端口1602
output RS,RW,E,  //1602的控制信号使能,数据/命令,读/写
output [7:0]Data2,//数据端
output back_light,//背光
//蜂鸣器的输入输出端口beep
output	beep,							//蜂鸣器输出端
//txd的输入输出端口,这里只定义txd,因为clk可以重复利用,前面已经定义过了,所以可以不用再定义
output txd                                //txd 


 );
wire [7:0]txd_data;//lianjiexie
wire wr_en;//lianjiexie
wire  pll_clk; //link-ad
wire [7:0] ad_data2;
ADC_TLC549 u_ADC_TLC549(
			.clk(clk),     //系统50MHZ时钟
			.ioclk(ioclk),   //AD TLC549的时钟
			.data(data),    //AD TLC549的数据口
			.cs(cs),      //AD TLC549的片选择
			.segcs(segcs),   //数码管的为选择
			.segdata(segdata), //数码管的7段码
			.dataout(ad_data2)
 );

	
my1602 u_my1602(
				.clk(clk),
				.ad_data(ad_data2),
				.RS(RS),
				.RW(RW),
				.E(E),
				.Data(Data2),
				.back_light(back_light)
 );
 
 // beep u_beep(
// .clk(clk),
// .beep(beep),
// .ad_song(ad_data2)
// );
 
//fp_txdclk 
fp_txdclk u_fp_txdclk(
.inclk0(clk),
.c0(pll_clk)
);

//txd_g
txd_g u_txd_g(
.reset(~reset),
.clock(pll_clk),
.wr(wr_en),
.ad_data(txd_data),
.txd(txd));

//data_sltgg
data_sltgg u_data_sltgg(
.clk(clk),
.data_in(ad_data2),
.datao(txd_data),
.clk_10hz(wr_en));

endmodule

ad采集代码

//这个.v文件是用来采集数据的,采集的数据是8位二进制,为了在数码管上显示,需要将二进制转换成10进制
//红外模块搭配这个.v文件使用,只需要将红外模块插进板子里就可以了
module ADC_TLC549
(
clk,     //系统50MHZ时钟
ioclk,   //AD TLC549的时钟
data,    //AD TLC549的数据口
cs,      //AD TLC549的片选择
segcs,   //数码管的为选择
segdata,  //数码管的7段码
output[7:0]segdata; 
); 

input clk;
input data; 
output cs;
output ioclk; 

output[3:0]segcs; 
//gaidong
output reg[7:0] dataout; 
//
reg cs,ioclk,clk1k,clk1ms; 
reg[15:0] count; 
reg[24:0]count1ms; 
reg[3:0] cnt; 
reg[2:0]number; 
reg[1:0] state; 
reg[3:0] segcs; 
reg ledcs; 
reg [7:0]segdata; 
//reg[7:0]dataout; 
reg[16:0]tenvalue; 


parameter sample=2'b00, 
          display=2'b01; 

/**********产生100k的采集时钟信号*********/ 
always@(posedge clk) 
  begin 
    if(count<=250)  
      count<=count+1'b1;     
    else 
      begin  
      count<=0;  
      ioclk<=~ioclk;  
      end 
 end 

/*******产生周期为1ms即1kHz的信号*********/ 
always@(posedge clk) 
  begin  
    if(count1ms>25'd25000)
      begin 
      clk1ms<=~clk1ms; 
      count1ms<=0; 
      end 
    else 
      count1ms<=count1ms+1; 
  end 

/*********AD采样程序**************/ 
always@(negedge ioclk) 
   begin 
     case(state) 
      sample: 
       begin 
        cs<=0; 
        dataout[7:0]<={dataout[6:0],data};  
        if(cnt>4'd7)  
           begin 
           cnt<=0; 
           state<=display;   
           end   
        else 
           begin 
           cnt<=cnt+1; 
           state<=sample; 
           end 
        end 
       display:
          begin 
           cs<=1;//关AD片选  
           tenvalue<=(tendata((dataout>>4)&8'b0000_1111)*16+ tendata(dataout&8'b0000_1111))*129;// 
           //得到采集的数据
           state<=sample; 
          end 
      default: state<=display; 
    endcase 
  end 

/***********2进制转十进制函数*************/ 
function[7:0] tendata;//返回一个4位的数字 
input[7:0]   datain; 
begin 
 case(datain) 
    4'b00000000: tendata=4'd0;//0 
    4'b00000001: tendata=4'd1;//1 
 	4'b00000010: tendata=4'd2;//2 
    4'b00000011: tendata=4'd3;//3 
    4'b00000100: tendata=4'd4;//4 
    4'b00000101: tendata=4'd5;//5 
    4'b00000110: tendata=4'd6;//6 
    4'b00000111: tendata=4'd7;//7 
    4'b00001000: tendata=4'd8;//8 
    4'b00001001: tendata=4'd9;//9 
    4'b00001010: tendata=4'd10;// 
    4'b00001011: tendata=4'd11;// 
    4'b00001100: tendata=4'd12; 
    4'b00001101: tendata=4'd13; 
    4'b00001110: tendata=4'd14; 
    4'b00001111: tendata=4'd15; 
   default:tendata=4'bzzzz_zzzz; 
 endcase 
end 
endfunction 
 
/*********十进制转LED段选函数*********/ 
function[7:0] leddata;//返回一个8位的数字 
input[3:0]    datain; 
begin 
  case(datain) 
    4'd0: leddata=8'b11000000;//0 
    4'd1: leddata=8'b11111001;//1 
    4'd2: leddata=8'b10100100;//2 
    4'd3: leddata=8'b10110000;//3 
    4'd4: leddata=8'b10011001;//4 
    4'd5: leddata=8'b10010010;//5 
    4'd6: leddata=8'b10000010;//6 
    4'd7: leddata=8'b11111000;//7 
    4'd8: leddata=8'b10000000;//8 
    4'd9: leddata=8'b10010000;//9 
    4'd10: leddata=8'b10111111;//- 
    4'd11: leddata=8'b01111111;//. 
    default:leddata=8'bzzzz_zzzz; 
   endcase 
end 
endfunction 
 
/********数码管扫描函数*************/ 
always@(posedge clk1ms) 
 begin 
    if(number==5) number<=0; 
    else  
    begin  
	    number<=number+1; 
	    case(number)  
	     4'd0: 
	     begin 
	     segdata<=leddata((tenvalue/10)%10);//个位 
	     segcs<=4'b1110; 
	     end 
	     4'd1: 
	     begin 
	     segdata<=leddata((tenvalue/100)%10);//十位 
	     segcs<=4'b1101; 
	     end 
	     4'd2: 
	     begin 
	     segdata<=leddata((tenvalue/1000)%10); //百位 
	     segcs<=4'b1011; 
	     end 
	     4'd3: 
	     begin 
	     segdata<=leddata(tenvalue/10000);//千位 
	     segcs<=4'b0111; 
	     end 
	     4'd4: 
	     begin 
	     segdata<=leddata(4'd11);//.   显示小数点
	     segcs<=4'b0111; 
	     end 
		endcase 
	end 
end     
  
endmodule

 因为代码部分较多,所以我只展示顶层模块代码和ad采样代码,如果要完整代码,可前往百度网盘下载:

链接:https://pan.baidu.com/s/1Hb51DtN5xM6Xe7I8V4rc8w?pwd=1234 
提取码:1234

感谢大家的支持!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值