勇敢的芯伴你玩转altera fpga第10章15个综合进阶实例_第1页
勇敢的芯伴你玩转altera fpga第10章15个综合进阶实例_第2页
勇敢的芯伴你玩转altera fpga第10章15个综合进阶实例_第3页
勇敢的芯伴你玩转altera fpga第10章15个综合进阶实例_第4页
勇敢的芯伴你玩转altera fpga第10章15个综合进阶实例_第5页
已阅读5页,还剩111页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

FPGA的芯指 第10章15个综合进阶实 距离计算实 10.4.1应用背 基于SRAM批量读写的UARTbulk测 基于数码管显示的RTC................................................................................................RTC解 基于UART发送的RTC................................................................................................. 基于UART收发的RTC读 基于UART控制的VGA多模式显 基于LED显示的DA输出驱动实 DA概 IP核CORDIC配置与例 AD接口概 AD和DA联合测 RTC时间的LCD显示和UART设 15个实例,将前面两章所涉及到的简单的、单独控制的工程整合在一起。通基于数码管显示的超声波测距回响脉71pI个实例代码的集成整合,将超声波测距的回响脉冲以时钟周期计数值的形式显示到数码管然后以10us为单位计算超声波测距模块返回的回响信号ECHO的高电平保持时间。到的ECHO高电平脉冲保持周期(10us为单位)将以16进制方式显示到数码管上。10.110us的基准时钟使能信号;ultrasound_controller.v模块对超声波测距模块的回响信号进行高脉冲时间计数;seg7.v模块驱动数码管显示。10.2cy4.v代码中,可以查看其RTLSchematic10.3所示。cy4.v模块主要定clk_25msys_rst_n;clkdiv_generation.v模块产生100KHz频率的一个时钟使能信号,即每10us产生一个保持单个时钟周期的高脉冲;ultrasound_controller.v10us的高脉10.3moduleinputmoduleinputext_clk_25m,//外部输入25MHzinput inputultrasound_echo, output[3:0]dtube_cs_n,//7段数码管位选信号wireclk_12m5;//PLL12.5MHzwire wire wireclk_100m;//PLL100MHzpll_controllerpll_controller_inst.areset(!ext_rst_n.inclk0(ext_clk_25m.c0(clk_12m5.c1(clk_25m.c2(clk_50m.c3(clk_100m.locked(sys_rst_n .rst_n(sys_rst_n),wire[15:0] 打开QuartusII,进入界面,将本实例工程下的cy4.sof文件烧录到FPGA中此时我们在超声波测距模块前面摆放平整的物,可以看到数码管上的16进制数据大家可以通过如下的计算当前数码管显示数据和实际超声波测距模块与物距换为10进制,然后把下述的结果计算出来并显示在数码管上。假设超声波模块与物间的距离为S(单位:m,ECHO输出的高脉冲宽度为T(S=基于均值滤波处理的超声波测距回响10.1节的例程一样,只是在原先的“脉冲计数”和“数码管10.410.410.1节的板级调试的时候已经注意到了,数码管显示的数据还是有些不够时的的8个数据的均值计算。功能如图10.5所示。10.5cy4.v代码中,可以查看其RTLSchematic10.6所示。cy4.v模块主要定clk_25msys_rst_n;clkdiv_generation.v模块产生100KHz频率的一个时钟使能信号,即每10us产生一个保持单个时钟周期的高脉冲;ultrasound_controller.v10us的高脉10.6moduleinputinputinputmoduleinputinputinputinput[15:0]output[15:0]reg[15:0] always@(posedgeclkornegedgerst_n)if(!rst_n)beginpulse_reg[0]<=16'd0;pulse_reg[1]<=16'd0;pulse_reg[2]<=16'd0;pulse_reg[3]<=16'd0;pulse_reg[4]<=16'd0;pulse_reg[5]<=pulse_reg[6]<=pulse_reg[7]pulse_reg[7]<= elseif(echo_pulse_en)pulse_reg[0]<=echo_pulse_num;pulse_reg[1]<=pulse_reg[0];pulse_reg[2]<=pulse_reg[1];pulse_reg[3]<=pulse_reg[2];pulse_reg[4]<=pulse_reg[3];pulse_reg[5]<=pulse_reg[4];pulse_reg[6]<=pulse_reg[5];pulse_reg[7]<=pulse_reg[6];reg[15:0]always@(posedgeclkornegedgerst_n)if(!rst_n)sum_pulse_reg<=16'd0;elsesum_pulse_reg<=assignecho_pulse_filter_num=如图10.7所示,相比于10.2节的实例,本实例将“距离计算&进制换算”功能10.7所谓距离计算,主要是将超声波测距到的ECHO脉冲高电平脉宽值(时间,习惯的10进制方式显示到数码管上。t的单位是秒(s)s346*t/2。s的单位是毫米(mm)t10微秒(10uss*0.001FPGA10.8IP核,它的两4438位就是我们的最终运算结果了。10.810.9clk_25msys_rst_n;clkdiv_generation.v模块产生100KHz频率的一个时钟使能信号,即每10us产生一个保持单个时钟周期的高脉冲;ultrasound_controller.v10us的高脉9.2filter.vseg7.v模块之间增加了pute.v模块,该模块的功能是将超声波测距模块返回的脉冲计数值转换为实际inputinputinput[15:0]output[15:0]mulmul_inst.clock(clk.dataa(16'd443.datab(echo_pulse_filter_num.result(mul_outwire[15:0]thousand_quotint,thousand_fractional;//千位除法运算结果与余数寄存divthousand_div.clock(clk.denom(16'd1000.numer(mul_out[23:8].quotient(thousand_quotint.remain(thousand_fractionalwire[15:0]hundred_quotint,hundred_fractional;divhundred_div.clock(clk.denom(16'd100.numer(thousand_fractional.quotient(hundred_quotint.remain(hundred_fractionalwire[15:0]ten_quotint,ten_fractionaldivdivten_div.clock(clk.denom(16'd10.numer(hundred_fractional.quotient(ten_quotint.remain(ten_fractionalassignecho_pulse_f_mul_num 来看看这个IP核是如何创建、配置并使用的。弹出窗口中选择选择“CreatanewcustommegafunctionvariationNext。在“SelectamegafunctionfromthelistbelowIP核为“ArithmeticM在“Whatdevicefamilywillyoubeusing”后面的下拉栏中选择我们所使用的器件系列为“CycloneIV在“Whattypeofoutputfiledoyouwanttocreate?”下面选择语言为“Verilog在“Whatnamedoyouwantfortheoutputfile?”下面输入工程所在的路径,并且在最后mul,然后点击Next进入下一个页面。这里它所在的路径,实际上是我们在工程文件夹cy4ex14下面创建的ip_core文件夹和其下的mul文件夹。LPM_MULT的第一个配置页面中(即“ParameterSettings➔General”页面10.12IP核General10.13IP核General2outputlatency2clockcycles2个时钟周期,乘法运算结10.14IPPipelining板。最后点击“Finish”完成IP核的配置。 10.16IP测距的脉宽计数寄存器echo_pulse_filter_num,输出结果为32bit的mul_out。 弹出窗口中选择选择“CreatanewcustommegafunctionvariationNext。在“SelectamegafunctionfromthelistbelowIP核为“ArithmeticM_DD在“Whatdevicefamilywillyoubeusing”后面的下拉栏中选择我们所使用的器件系列为“CycloneIV在“Whatnamedoyouwantfortheoutputfile?”下面输入工程所在的路径,并且在最后面创建的ip_core文件夹和其下的divide文件夹。10.19IP核General10.20IP核General2最后点击“Finish”完成IP核的配置。 10.22IP打开QuartusII,进入界面,将本实例工程下的cy4.sof文件烧录到FPGA中mm为单位,实际换算好的距离信息。大家可以很直观的获得当前物和超声波测距模块之间的距离。如图10.24所示,的主要作用是在时,利用超声波原理,由车尾杠上图10.24场示,FPGAtrig脉冲信号,使得超声波模块周期性发出测距脉冲,当这些脉冲我们通过对echo信号的高脉冲保持时间就可以推算出超声波脉冲和物之间的距离。对于不同的距离,我们随后就产生不同的蜂鸣器频率和保持时间。图10.25接口示钟周期数n之间的。t的单位是秒(s)s346*t/2。s的单位是毫米(mm)t10微秒(10uss*0.001=346*t*0.00001/2,即s=1.73*t。s≤40cm<s≤s≤40cm<s≤75cm<s≤125cm<s≤图10.26实例功能框图10.27实例模块层模块的主要功能便是实现超声波测距的距离结果控制相应的蜂鸣器频率。10.28moduleinputmoduleinputinputinput[15:0] outputreg always@(posedgeclkornegedgeif(!rst_n)bcnt<=elseif(bcnt<bcyc)bcnt<=bcnt+1'b1;elsebcnt<=26'd0;always@(posedgeclkornegedgeif(!rst_n)beep<=elseif(dis y_num16'h0400)begin//距离<=400mmbcyc<=26'd12_500000;//2Hz周期beep else y_num>16'h0400)&& y_num<=16'h0750))400mmbcycbcyc26'd12_500000;//2Hzif(bcnt10_00000)beep<= elsebeep<=else y_num>16'h0750)&& y_num<=16'h1250))750mmbcyc26'd25_000000;//1Hzif(bcnt<10_00000)beep<=1'b1; elsebeep<=1'b0;elseif((dis y_num>16'h1250)&&(dis y_num<=16'h2000))begin 1250mm<距离<=2000mmbcyc26'd50_000000;//0.5Hzif(bcnt<10_00000)beep<=1'b1; elsebeep<=1'b0;elsebeep1'b0;//距离>2000mmmm为单位,实际换算好的距离信息。大家可以很直观的获得况下,蜂鸣器会发出不同声调,从我们设计角度看,应该是符合表10.1的规律。基于SRAM批量读写的UARTbulk10.29SRAM128组(7bit地址256个数据(8bit地址SRAM所有地址写入以其地址为首字节数据的递增数据;数据作为地址,读出该组256字节数据到FIFO中缓存,然后依次通过UART发送出去。该工程实例的设计模块层次如图10.30所示。cy4.v代码中,可以查看其RTLSchematic10.31所示。my_uart_rx.v模的使能信号进行波特率控制,并且回送一个数据采样使能信号。my_uart_tx.v模块在my_uart_rx.v模块接收好一个数据后启动运行,它将接收到的数据作为SRAM地址,speed_setting.v(speed_tx)模块产生。sram_controller.vSRAM的基本读写时地址和数据,在接收到UART的读地址后,SRAM对应地址组的256个数据。moduleinputext_clk_25m,//外部输入25MHz时钟信号inputext_rst_n, inputuart_rx, //UART接收数据信号output moduleinputext_clk_25m,//外部输入25MHz时钟信号inputext_rst_n, inputuart_rx, //UART接收数据信号output output[7:0] outputsram_cs_n, //SRAM片选信号,低电平有效。outputsram_we_n, //SRAM写选通信号,低电平有效。outputsram_oe_n, output[14:0]sram_addr,//SRAM地址总线。inout[7:0] assignassignled[7:1]7'b111_1111;//关闭LED7-wireclk_12m5;//PLL12.5MHzwireclk_25m;//PLL25MHzwireclk_50m;//PLL50MHzwireclk_100m;//PLL100MHzpll_controllerpll_controller_inst.areset(!ext_rst_n.inclk0(ext_clk_25m.c0(clk_12m5.c1(clk_25m.c2(clk_50m.c3(clk_100m.locked(sys_rst_nwire wiresramwr_req;//SRAM写请求信号,高电平有效,用于状态机控制。wiresramrd_req;//SRAM读请求信号,高电平有效,用于状态机控制。wire[7:0]sramwr_data;//SRAM写入数据寄存器。wire[7:0]sramrd_data;//SRAM读出数据寄存器。wire[14:0]sramwr_addrSRAMwire[14:0]sramrd_addrSRAMwirefifo_rdrdy;//FIFO读出数据有效信号wire[7:0]fifo_dout;//FIFO.rst_n(sys_rst_n), .sramwr_data(sramwr_data),SRAM.sramrd_data(sramrd_data),SRAM.sramwr_addr(sramwr_addr),SRAM .rst_n(sys_rst_n),.sramwr_data(sramwr_data),//SRAM.sramrd_data(sramrd_data),//SRAM.sramwr_addr(sramwr_addr),//SRAM.sramrd_addr(sramrd_addr),//SRAM.sram_cs_n(sram_cs_n),SRAM.sram_we_n(sram_we_n),SRAM.sram_addr(sram_addr),//SRAM wireclk_bps1,clk_bps2; wire[7:0]rx_data;//接收数据寄存器,保存直至下一个数据来到wirerx_int; .clk(clk_50m),//波特率选择模块 .clk(clk_50m),//接收数据模块 .clk(clk_50m),//波特率选择模块.clk(clk_50m),moduleinput input input moduleinput input input input[6:0]cmd_addr, //UART发送的SRAM读地址outputregfifo_rdrdy, output[7:0]fifo_dout,//FIFO读出数据outputreg outputsramwr_req,//SRAM写请求信号,高电平有效,用于状态机控制。outputsramrd_req,//SRAM读请求信号,高电平有效,用于状态机控制。outputreg[7:0]sramwr_data,SRAM写入数据寄存器。outputreg[14:0]sramwr_addr,//SRAMoutputreg[14:0] always@(posedgeclkornegedgerst_n)if(!rst_n)rcnt<=14'd0;elseif(led)rcnt<=assignsramwr_reqrcnt[5:0] always@(posedgeclkornegedgerst_n)if(!rst_n)sramwr_data<=8'd0;elsesramwr_data<=always@posedgeclkornegedgerst_n)1s1。if(!rst_n)sramwr_addr<=15'd0;elseif(rcnt==14'h3fff)sramwr_addr[14:8]<=elsesramwr_addr[7:0]<=always@(posedgeclkornegedgerst_n)if(!rst_n)led<=1'b1;elseif((rcnt==14'h3ffe)&&(sramwr_addr[14:8]==7'h7f))led<=always@(posedgeclkornegedgeif(!rst_n)wcnt<=elseif(cmd_rden)wcnt<= elseif(wcnt<14'h3fff)wcnt<=always@(posedgeclkornegedgeif(!rst_n)sramrd_addr<=elseif(cmd_rden)sramrd_addr[14:8]<=cmd_addr;elsesramrd_addr[7:0]<=wcnt[13:6];assignsramrd_reqwcnt[5:0] wirecmd_rdrdywcnt[5:0] regfifo_rden;//FIFOwirefifo_empty;//FIFOreg[17:0]fcnt;//5ms定时always@(posedgeclkornegedgerst_n)if(!rst_n)fcnt<=18'd0;elsefcnt<=always@(posedgeclkornegedgeif(!rst_n)fifo_rden<=elseif((fcnt==18'd1)&&!fifo_empty)fifo_rden<=1'b1;elsefifo_rden<=1'b0;always@(posedgeclkornegedgerst_n)if(!rst_n)fifo_rdrdy<=1'b0;elseelsefifo_rdrdy<=fifo_controllerfifo_controller_inst.aclr(!rst_n.clock(clk.data(sramrd_data.rdreq(fifo_rden.wrreq(cmd_rdrdy.empty(fifo_empty.full(.q(fifo_doutmoduleinputclk,

inputsramwr_req,//SRAM写请求信号,高电平有效,用于状态机控制。inputsramrd_req,//SRAM读请求信号,高电平有效,用于状态机控制。input[7:0]sramwr_data,//SRAM写入数据寄存器。outputreg[7:0]sramrd_data,SRAMinput[14:0]sramwr_addr,//SRAMinput[14:0]sramrd_addr,//SRAM outputregsram_cs_n, //SRAM片选信号,低电平有效。outputregsram_we_n, //SRAM写选通信号,低电平有效。outputregsram_oe_n, outputreg[14:0]sram_addr, //SRAM地址总线。inout[7:0] = = = = =reg[3:0]reg[3:0]`define`define`define`definereg[2:0] always@(posedgeclkornegedgerst_n)if(!rst_n)cnt<=3'd0;elseif(cstate==IDLE)cnt<=elsecnt<=always@posedgeclkornegedgerst_n)if(!rst_n)cstate<=IDLE;elsecstate<=always@(cstateorsramwr_reqorsramrd_reqorcnt)begin//组合逻辑控制不同caseIDLEif(sramwr_req)nstate<=WRT0;//进入写状态。elseif(sramrd_req)nstate<=REA0;//进入读状态。elsenstate<=IDLE;WRT0:if(`DELAY_60NS)nstate<=WRT1;elsenstate<=WRT0;WRT1:nstate<=REA0:if(`DELAY_60NS)nstate<=elseelsenstate<=REA0;REA1:nstate<=IDLE;default:nstate<=IDLE;always@(posedgeclkornegedgerst_n)if(!rst_n)sram_addr<=15'd0;elseif(cstate==WRT0)sram_addr<=sramwr_addr;elseif(cstate==WRT1)sram_addr<=15'd0;elseif(cstate==REA0)sram_addr<=sramrd_addr;elseif(cstate==REA1)sram_addr<=15'd0;

reg always@(posedgeclkornegedgeif(!rst_n)sramrd_data<=elseif((cstate==REA0)&&`DELAY_60NS)sramrd_data<=always@(posedgeclkornegedgeif(!rst_n)sdlink<=elseif(cstate==WRT0)sdlink<=1'b1;elseif(cstate==WRT1)sdlink<=assignsram_data=sdlink?sramwr_data:always@(posedgeclkornegedgeif(!rst_n)if(!rst_n)sram_cs_n<=1'b1;elseif(cstate==WRT0)if(`DELAY_00NS)sram_cs_n<=1'b1;elsesram_cs_n<=1'b0;elseif(cstate==REA0)sram_cs_n<=1'b0;elsesram_cs_n<=1'b1;always@(posedgeclkornegedgerst_n)if(!rst_n)sram_oe_n<=1'b1;elseif(cstate==REA0)sram_oe_n<=1'b0;elsesram_oe_n<=1'b1;always@(posedgeclkornegedgerst_n)if(!rst_n)sram_we_n<=1'b1;elseif(cstate==WRT0)beginif(`DELAY_20NS)sram_we_n<=1'b0;elseif(`DELAY_60NS)sram_we_n<=1'b1;UART中运行。接着我们可以使用串口调试助手SRAM数据了。当我们看到D2指示灯亮起来的时候,说明FPGA已经完成了对SRAM所有地址的写数据初始化操作。接着我们可以使用串口调试助手SRAM数据了。10.3210.3416551655打头开始RTC解本实例使用的RTC实时时钟是型号为PCF8563,是PHILIPS公司推出的一款工业级内含IIC总线接口功能的具有极低功耗的多功能时钟/日历。PCF8563的多种功能、提供看门狗功能。内部时钟电路、内部振荡电路、内部低电压检测电路(1.0V)以及两线制IIC总线通讯方式,不但使电路及其简洁,而且也增加了的可靠性。同时每次读写数据后内嵌的字地址寄存器会自动产生增量,因而PCF8563是一款性价比极高的时钟,它已被广泛用于、水表、气表、、传真机、便携式仪器以及电池供电的仪器仪表等产品领域。该主要特性如下。400kHzIIC总线(VDD=1.8-5.5V)0xa30xa2PCF8563的引脚排列及描述如表10.2所示。表10.2PCF8563引脚描1234地5678PCF85631632.768KHz的振程时钟输出,一个定时器,一个器,一个掉电检测器和一个400KHz的IIC总线接口。所有16个寄存器设计成可寻址的8位并行寄存器,但不是所有位都有用。前两个寄存器(00H01H)02H~08H用于时钟计(秒~年计数器地址09H~0CH用于寄存器(定义条件地址0DH控制CLKOUT小时、日、月、年、分钟、小警、日寄存器,编码格式为BCD,星期和星期报警寄存器不以BCD格式编码。RTC寄存器被读时,所有计数器的内容被锁存。因此,在传送条件下,可以禁止对时钟日历的错读。PCF8563共有16个寄存器,其中00H~01H为控制方式寄存器;09H~0CH为功能寄存器;0DH为时钟输出寄存器;0EH0FH为定时器功能寄存器,02H~08H为秒~年时间寄存器。各寄存器的详细功能描述请参考PCF8563的datasheet。并且只能够使用IIC接口来读写这个的各个寄存器,IIC接口有一定的协议,IIC具体读写控制时序,先从宏观角度来正常来说,一个的使用,无外乎设置一下控制寄存器,然后读写相关数据,必要的话产生一个中断,此时可能回去看看状态寄存器。不过,我们这颗RTC更简单,地址0x00和0x01的控制寄存器1和2默认状态即可,我们只需要读写时间便可,其他什么、中对照各个寄存器的定义稍微也就能够。0x07的月份寄存器数据month,在显示时,十位数据为((month&0x10)>>4),当前的时间和实际时间同步,因为我们是由3V的纽扣电池供电的,所以即便我们的电路板下电后,内部的时间计数单元还是在正常工作运转的。如图10.35所示,本实例通过IIC接口定时RTC中的分、秒寄存器,将分、秒数据分别显示在数码管的高2位和低2位。本实例模块划分如图10.36所示。cy4.vRTLSchematic10.37所示。rtc_controller.vRTCiic_controller.v模块实现底层的读写。Iic_controller.v模块产生IIC读写的时序。rtc_top.v模块衔接iic_controller.v模块和rtc_controller.v模块。seg7.v模块产生数码管显示驱动。modulemoduleinputext_clk_25m,25MHzinputext_rst_n, output[3:0]dtube_cs_n,//7段数码管位选信号outputrtc_iic_sck,inout wireclk_12m5;//PLL12.5MHzwireclk_25m;//PLL25MHzwireclk_50m;//PLL50MHzwireclk_100m;//PLL100MHzpll_controllerpll_controller_inst.areset(!ext_rst_n.inclk0(ext_clk_25m.c0(clk_12m5.c1(clk_25m.c2(clk_50m.c3(clk_100m.locked(sys_rst_n wire[7:0rtc_hour;// wire[7:0rtc_mini;// wire[7:0]rtc_secd; uut_rtc_top.rst_n(sys_rst_n), modulemoduleinputinputoutputrtc_iic_sck,inoutrtc_iic_sda,//RTCoutput[7:0]rtc_hour,output[7:0]rtc_mini,output[7:0]IICwireiicwr_req;//IICwireiicrd_req;//IICwire uut_iic_controllermoduleinputclk,

outputregiicwr_req, outputregiicrd_req, outputreg[7:0]iic_addr, //IIC读写地址寄存器outputreg[7:0]iic_wrdb, //IIC写入数据寄存器input[7:0]iic_rddb, //IIC读出数据寄存器input outputreg[7:0]rtc_hour,//RTC读出的时数据,BCDoutputreg[7:0]rtc_mini,//RTC读出的分数据,BCDoutputreg[7:0]rtc_secd//RTC读出的秒数据,BCDreg[17:0]alwaysreg[17:0]always@(posedgeclkornegedgerst_n)if(!rst_n)cnt<=18'd0;elseif(cnt<18'd249_999)cnt<=cnt+1'b1;elsecnt<=18'd0;wiretimer1_10ms=(cnt==wiretimer2_10ms=(cnt==wiretimer3_10ms=(cnt== RIDLE RRDSE=4'd1, RWASE=4'd2, RRDMI=4'd3, RWAMI=4'd4, RRDHO=4'd5; reg[3:0]cstate,nstate;always@(posedgeclkornegedgerst_n)if(!rst_n)cstate<=RIDLE;elsecstate<=always@(cstateortimer1_10msortimer2_10msortimer3_10msoriic_ack)beginRIDLE:if(timer1_10ms)nstate<=RRDSE;elsenstate<=RIDLE;RRDSE:if(iic_ack)nstate<=RWASE;elsenstate<=RRDSE;RWASE:if(timer2_10ms)nstate<=RRDMI;elsenstate<=RWASE;RRDMI:if(iic_ack)nstate<=RWAMI;elsenstate<=RRDMI;RWAMI:if(timer3_10ms)nstate<=RRDHO;elsenstate<=RWAMI;RRDHO:if(iic_ack)nstate<=RIDLE;elsenstate<=RRDHO;default:nstate<=RIDLE;always@(posedgeclkornegedgerst_n)if(!rst_n)beginiicwr_req<=1'b0;//IIC写请求信号,高电平有效iicrd_req<=1'b0;//IIC读请求信号,高电平有效iic_addr<=8'd0; //IIC读写地址寄存器iic_wrdb<=8'd0; //IIC写入数据寄存器elseRRDSE:iicwr_req<=1'b0;//IIC写请求信号,高电平有效iicrd_req<=1'b1;//IIC读请求信号,高电平有效iic_addr<=8'd2; //IIC读写地址寄存器iic_wrdb<=8'd0; //IIC写入数据寄存器RRDMI:iicwr_req<=1'b0;//IIC写请求信号,高电平有效iicrd_req<=1'b1;//IIC读请求信号,高电平有效iic_addr<=8'd3; //IIC读写地址寄存器iic_wrdb<=8'd0; //IIC写入数据寄存器RRDHO:iicwr_req<=1'b0;//IIC写请求信号,高电平有效iicrd_req<=1'b1;//IIC读请求信号,高电平有效iic_addr<=8'd4; //IIC读写地址寄存器iic_wrdb<=8'd0; //IIC写入数据寄存器default:iicwr_req<=1'b0;//IIC写请求信号,高电平有效iicrd_req<=1'b0;//IIC读请求信号,高电平有效iic_addr<=8'd0; //IIC读写地址寄存器iic_wrdb<=8'd0; //IIC写入数据寄存器always@(posedgeclkornegedgeif(!rst_n)rtc_hour8'd0;//RTC读出的时数据,BCDrtc_mini8'd0;//RTC读出的分数据,BCDrtc_secd8'd0;//RTC读出的秒数据,BCDelseRRDSE:if(iic_ack)rtc_secd<={1'b0,iic_rddb[6:0]};else;RRDMI:if(iic_ack)rtc_mini<={1'b0,iic_rddb[6:0]};else;RRDHO:if(iic_ack)rtc_hour<={1'b0,iic_rddb[6:0]};else;该模块实现底层的IIC读写操作。iicwr_req信号拉高,则将数据iic_wrdbmodulemoduleinput input inputiicwr_req, inputiicrd_req, input[7:0]iic_addr, //IIC读写地址寄存器input[7:0]iic_wrdb, //IIC写入数据寄存器outputreg[7:0]iic_rddb, output inout reg[3:0]parameter/*wrdata*/=4'd0,=4'd1,//start=4'd2,//slaveaddr(write=4'd3,=4'd4,//deviceaddr=4'd5,=4'd6,//write=4'd7,/*rd =4'd8,//restart =4'd9,//slaveaddr(readcmd) =4'd10,//ACK4 =4'd11,//readdata =4'd12,//ACK5 =4'd13;//stop ==//writedevice//readdevicereg[8:0]icnt;always@(posedgeclkornegedgeif(!rst_n)icnt<=elseicnt<=//assignsclt[8]|(dcstate== always@(posedgeclkornegedgeif(!rst_n)scl<=elseif(dcstate==DIDLE)scl<=1'b1;elsescl<= wirescl_hs=(icnt==9'd1); //sclhighstartwirescl_hc=(icnt==9'd128);//sclhighcenterwirescl_ls=(icnt==9'd256);//scllowstartwirescl_lc=(icnt==9'd384);//scllowcenterreg[2:0]bcnt;//数据位寄存器,bit0-7regsdar; //sda输出数据寄存器reg always@(posedgeclkornegedgerst_n)if(!rst_n)dnstate<=DIDLE;elsednstate<=always@(dnstateoriicwr_reqoriicrd_reqorscl_hcorbcntorscl_lsorscl_hsorscl_lc)beginDIDLE:if((iicwr_req||iicrd_req)&&scl_hs)dcstate<= elsedcstate<=DIDLE;DSTAR:if(scl_ls)dcstate<=DSABW;elsedcstate<=DSABW:if(scl_lc&&(bcnt==3'd0))dcstate<=D1ACK;elsedcstate<=DSABW;//slaveaddr(writecmd)D1ACK:if(scl_ls&&(bcnt==3'd7))dcstate<=DRABW;elsedcstate<=D1ACK;DRABW:if(scl_lc&&(bcnt==3'd0))dcstate<=D2ACK;elsedcstate<=DRABW;//deviceaddrwriteD2ACK:if(scl_ls&&(bcnt==3'd7)&&iicwr_req)dcstate<=DWRDB;elseif(scl_ls&&(bcnt==3'd7)&&iicrd_req)dcstate<=elsedcstate<= DWRDB:if(scl_lc&&(bcnt==3'd0))dcstate<=D3ACK;elsedcstate<=DWRDB;//writedataD3ACK:if(scl_ls&&(bcnt==3'd7))dcstate<=DSTOP;//DWRDB2;elsedcstate<=D3ACK;/*rd_db*/DRSTA:if(scl_ls)dcstate<=elsedcstate<=DSABR:if(scl_lc&&(bcnt==3'd0))dcstate<=D4ACK;elsedcstate<=DSABR;//slaveaddr(readD4ACK:if(scl_ls&&(bcnt==3'd7))dcstate<=DRDDB;elsedcstate<=D4ACK;DRDDB:if(scl_hc&&(bcnt==3'd7))dcstate<=D5ACK;elsedcstate<=DRDDB;//readdataD5ACK:if(scl_ls&&(bcnt==3'd6))dcstate<=DSTOP;elsedcstate<=D5ACK;DSTOP:if(scl_ls)dcstate<=DIDLE;elsedcstate<=DSTOP;default:dcstate<=DIDLE;always@(posedgeclkornegedgerst_n)if(!rst_n)bcnt<=3'd0;elseDIDLE:bcnt<=DSABW,DRABW,DWRDB,DSABR:if(scl_hs)bcnt<=bcnt-1'b1;DRDDB:if(scl_hs)bcnt<=bcnt-1'b1;D1ACK,D2ACK,D3ACK:if(scl_lc)bcnt<=3'd7;D4ACK:if(scl_ls)bcnt<=3'd7;D5ACK:if(scl_lc)bcnt<=bcnt-1'b1;default:;always@(posedgeclkornegedgerst_n)if(!rst_n)beginsdar<=sdalink<=1'b1; iic_rddb<=8'd0;DIDLE:sdar<=sdalink<= if(scl_hc)sdar<=if(scl_lc)sdar<=if(scl_lc)sdar<=1'b1;sdalink<=1'b0;DRABW:beginif(scl_lc)sdar<=iic_addr[bcnt];sdalink<=1'b1;D2ACK:beginif(scl_lc)sdar<=1'b1;sdalink<=1'b0;/*wr_db*/DWRDB:if(scl_lc)sdar<=iic_wrdb[bcnt];sdalink<=1'b1;D3ACK:beginif(scl_lc)sdar<=1'b1;sdalink<=1'b0;/*rd_db*/DRSTA:if(scl_hc)sdar<=1'b0;elseif(scl_lc)beginsdar<=1'b1;sdalink<=1'b1;DSABR:begin

if(scl_lc)sdar<=D4ACK:if(scl_lc&&(bcnt==3'd7))sdalink<= if(scl_hc)iic_rddb[bcnt+1'b1]<=sda;sdar<=1'b1;D5ACK:beginif(scl_lc)sdar<=1'b0;sdalink<=1'b1;DSTOP:beginif(scl_lc)sdalink<= sdarsdar<=elseif(scl_hc)sdar<=assignsda=sdalink?sdar:assigniic_ackdnstateDSTOP)&&scl_hs;//IICUART分、秒数据通过UART发送到PC上的串口调试助手进行实时的显示。本实例模块划分如图10.39所示。cy4.v代码中,可以查看其RTLSchematic10.40所示。rtc_top.v模块衔秒寄存器。speed_tx.v模块产生串口波特率的分频以及相关控制信号。my_uart_tx.v模块产PCUART数据协议,即并串转换处理。tx_bridge.vRTC读出秒数据是否有变化,若发送变化则产生一个发送到PC的字符串。moduleinputinputinput[7:0]outputregtxen,outputreg[7:0]moduleinputinputinput[7:0]outputregtxen,outputreg[7:0]reg[7:0] reg always@(posedgertc_secd_r<=always@(posedgeclkornegedgeif(!rst_n)dif_flag<=elseelseif(rtc_secd_r!=rtc_secd)dif_flag<=elsedif_flag<=reg[21:0] always@(posedgeclkornegedgerst_n)if(!rst_n)fcnt<=22'd0;elseif(dif_flag)fcnt<=elseif(fcnt!=22'd0)fcnt<=always@(posedgeclkornegedgerst_n)if(!rst_n)begintxen<=txdb<=22'd50_000:begin txen<=1'b1;txdb<=22'd100_000:begintxen<=1'b1;txdb<=22'd150_000:begin//":"txen<=1'b1;txdb<=22'd200_000:begintxen<=1'b1;txdb<=22'd250_000:begintxentxen<=txdb<=22'd300_000:begin//":"txen<=1'b1;txdb<=22'd350_000:begintxen<=1'b1;txdb<=22'd400_000:begintxen<=1'b1;txdb<=33'd450_000:begintxen<=1'b1;txdb<=default:txen<=1'b0;UART打开QuartusII,进入界面,将本实例工程下的cy4.sof文件烧录到FPGA中,10.41不断更新的数据就是我们从RTC中的时间信息。10.42分、秒数据通过UARTPC上的串口调试助手进行实时的显示;此外,PC上的串口调本实例模块划分如图10.44所示。UART数据接收模块my_uart_rx.vPC端发送的UART数据;时、分、秒数据,并且发出控制信号传递给rtc_top.v模块,实现RTC的寄存器更新。(rtc_wrhour(rtc_wrminiRTC,rtc_wrack则是rtc_top.v模块在执行完一次数据写入后的指示信号。表示该模块moduleinputclk,inputrxen,

input[7:0] inputrtc_wrack, outputregrtc_wren, outputreg[7:0]rtc_wrhour,//RTC 写入的时数据,BCD格式outputreg[7:0]rtc_wrmini, outputreg[7:0]rtc_wrsecd WIDLE WRXAA4'd1,//接收串口数据WRXHR4'd2,//接收串口数据-BCDWRXMT4'd3,//接收串口数据-BCDWRXSD4'd4,//接收串口数据-BCDWRX554'd5;//接收串口数据reg[3:0]always@(posedgeclkornegedgerst_n)if(!rst_n)cstate<=WIDLE;elsecstate<=always@(cstateorrxenorrxdborrtc_wrack)beginWIDLE: if(rxen&&(rxdb==8'haa))nstate<=WRXAA;elsenstate<=WIDLE;WRXAA:if(rxen)nstate<=WRXHR;elsenstate<=WRXAA;WRXHR:if(rxen)nstate<=WRXMT;elsenstate<=WRXHR;WRXMT:if(rxen)nstate<=WRXSD;elsenstate<=WRXMT;WRXSD: if(rxen&&(rxdb==8'h55))nstate<=elseelsenstate<=WRX55:begin//等待RTC写入响应if(rtc_wrack)nstateWIDLE;elsenstate<=WRX55;default:nstate<=WIDLE;always@(posedgeclkornegedgerst_n)if(!rst_n)beginrtc_wren<=1'b0; rtc_wrhour<=8'd0;//RTC 写入的时数据,BCD格式rtc_wrmini<=8'd0;//RTC 写入的分数据,BCD格式rtc_wrsecd8'd0; elseWIDLE:rtc_wren<=WRXAA:if(rxen)rtc_wrhour<=rxdb;else;WRXHR:if(rxen)rtc_wrmini<=rxdb;else;WRXMT:if(rxen)rtc_wrsecd<=elseWRX55:rtc_wren<=1'b1;default:;UARTCOM口为准96008,校验位为不断更新的数据就是我们从RTC中的时间信息。10.4610.4710.48VGAVGA线,VGACY4J1插座和显示器。PC端通过串口调试助手发送不同串口指令给屏绿色,0x03--全屏蓝色,0x04--全屏白色,0x05--8colorbar。cy4.v代码中,可以查看其RTLSchematic10.50所示。my_uart_rx.v用同的显示画面。speed_setting.v模块产生FPGA本地串口波特率。vga_controller.v模块产生ColorBar和VGA时序。现以绿色为边界轮廓的8原色ColorBar。COM口为准96008,校验位为None,停止位为1。点击“打开串口”。10.520x02--全屏绿色,0x03--全屏蓝色,0x04--全屏白色,0x058colorbarDA概DADAC5571的控制使用了标准模式,它的接口是大家耳熟能详的IIC接口,关于所示,FPGA作为IIC总线的主机,若要控制DAC5571完成一次转换,则一共需要传输(R\W#;第4bit4bit4bit4bit是有效数据的低4bit,第三个字节的低4bit无效。图10.53DA通信协这样,我们的DADAC5571的模拟电压输出就直接作为D14指示灯的正端,它的电压值D14指示灯的亮暗与否。FPGA0-255IIC接口不断的写入到DAC中,输出的模拟电压可以控制LED的亮暗变化本实例模块划分如图10.55所示。cy4.v代码中,可以查看其RTLSchematic10.56所示。dac_dbgene.v模块连续递增的DAC数据。dac_controller.v模块实现DAC5571的IIC接口协议,不断写入新的DA转换数据。modulemoduleinputext_clk_25m,//外部输入25MHz时钟信号inputext_rst_n, outputdac_iic_sck, //DAC5571的IIC接口SCLinoutdac_iic_sda //DAC5571的IIC接口SDAwireclk_12m5;//PLL12.5MHzwireclk_25m;//PLL25MHzwireclk_50m;//PLL50MHzwireclk_100m;//PLL100MHzwirepll_controllerpll_controller_inst.areset(!ext_rst_n.inclk0(ext_clk_25m.c0(clk_12m5.c1(clk_25m.c2(clk_50m.c3(clk_100m.locked(sys_rst_n变化,则通过IICDAC转换数据写入操作,建议该数据变化速率不要超过.rst_n(sys_rst_n), moduleinputclk,

outputreg[7:0] reg[17:0]cnt;//10msalways@(posedgeclkornegedgerst_n)if(!rst_n)cnt<=18'd0;elseif(cnt<18'd249_999)cnt<=elsecnt<=always@(posedgeclkornegedgerst_n)if(!rst_n)dac_data<=18'd0;elseif(cnt==18'd249_999)dac_data<=作,将新的dac_data通过IIC接口写入到DA中。其接口如下。modulemoduleinputinput[7:0]outputscl, inout reg[7:0]regreg[7:0]reg always@(posedgeclkornegedgeif(!rst_n)dac_datar<=elsedac_datar<=always@(posedgeclkornegedgeif(!rst_n)dac_en<=elseif(dac_datar!=dac_data)dac_en<=1'b1;elsedac_en<=1'b0;reg[8:0]always@(posedgeclkornegedgeif(!rst_n)cnti<=elseif(cnti<9'd499&&cstate!=IDLE)cnti<=cnti+1'b1;elsecnti<=9'd0;wirescl_low=(cnti==wirescl_high=(cnti==assignassignscl=//IIC写操作状态机parameterIDLE =4'd0;parameterSTART =4'd1;parameter =parameter =parameter =parameter =parameter =parameter =parameter =parameter =parameterDEVICE_ADDR =8'b1001_1000;wire[7:0]dac_mdata={4'b0000,dac_data[7:4]};wire[7:0]dac_ldata=regsdar;regsdlink;always@(posedgeclkornegedgerst_n)if(!rst_n)cstate<=IDLE;elsecstate<=always@(cstateordac_enorscl_highorscl_loworbcnt)begin if(dac_en)nstate<=START;elsenstate<=IDLE;START:if(scl_high)nstate<=ADDR;elsenstate<=START; if(scl_low&&bcnt==3'd0)nstate<=ACK1;elsenstate<=ADDR; if(scl_low)nstate<=elsenstate<= if(scl_low&&bcnt==3'd0)nstate<=ACK2;elsenstate<=CMSB; if(scl_low)nstate<=LSBI;elsenstate<=ACK2; if(scl_low&&bcnt==3'd0)nstate<=ACK3;elsenstate<=LSBI; if(scl_low)nstate<=ACK4;elsenstate<=ACK3; if(scl_low)nstate<=STOP;elsenstate<=ACK4; if(scl_high)nstate<=IDLE;elsenstate<=STOP;default:nstate<=IDLE;always@(posedgeclkornegedgerst_n)if(!rst_n)beginsdar<=1'b1;sdlink<=1'b1;IDLE:sdar<=1'b1;sdlink<=1'b1;START:if(scl_high)sdar<=1'b0;sdlink<=1'b1;ADDR:if(scl_low)sdar<=DEVICE_ADDR[bcnt];sdlink<=1'b1;CMSB:if(scl_low)sdar<=sdlink<=LSBI:if(scl_low)sdar<=dac_ldata[bcnt];sdlink<=1'b1;ACK1,ACK2,ACK3:if(scl_low)beginsdar<=1'b0;sdlink<=ACK4:if(scl_low)sdar<=1'b0;sdlink<=1'b1;STOP:if(scl_high)sdar<=1'b1;sdlink<=1'b1;assignsda=sdlink?sdar:always@(posedgeclkornegedgerst_n)if(!rst_n)bcnt<=3'd0;elseADDR,CMSB,LSBI:if(scl_low)bcnt<=bcnt-1'b1;else;

default:bcnt<=3'd7;的cy4.sof文件烧录到FPGA中运行。是我们输出的给DAC的数据递增值。图10.57DA输出模拟信号波DA输10.59在顶层模块cy4.vRTLSchematic10.60所示。key_check.v模块DA数据。seg7.v模块驱动数码管显示当前期望输出的DA数据。dac_controller.v模块实现DAC5571的IIC接口协议,判断有不同的cy4.sof文件烧录到FPGA中运行。的电压值也会发生变化,大家可以使用万用表测量P9插座的PIN1PIN2。10.610V 3.3V 1Hz1Hz1Hz注:X表示任意状态,ONOFF10.62模块根据输入的拨码开关状态,相应的产生不同的波形数据给DA,其下有一个接口协议,判断有不同的DA数据输入则执行一次DA转换操作。cy4.v模块的接口如下所示。拨码开关信号switch控制输出波形,IIC接口信号modulemoduleinputext_clk_25m,//外部输入25MHzinput input[3:0]switch,//拨码开关SW3ON;OFFoutputdac_iic_sck, inout wireclk_12m5;//PLL12.5MHzwireclk_25m;//PLL25MHzwireclk_50m;//PLL50MHzwireclk_100m;//PLL100MHzpll_controllerpll_controller_inst.areset(!ext_rst_n.inclk0(ext_clk_25m.c0(clk_12m5.c1(clk_25m.c2(clk_50m.c3(clk_100m.locked(sys_rst_n变化,则通过IICDAC转换数据写入操作,建议该数据变化速率不要超过 .rst_n(sys_rst_n),.dac_data(dac_data),//DAC该数据变化速率不要超过1.5KHz.scl(dac_iic_sck),//DAC5571IIC.sda(dac_iic_sda)//DAC5571IICmoduleinputmoduleinputinputinput[3:0]波形,bit2--,bit1--三角波,bit0outputreg[7:0]dac_data//DAC化速率不要超过1.5KHzsin_controller.v模块,该模块使用CORDICIP8bitreg[11:0]uut_sin_controlleralwaysalways@(posedgeclkornegedgerst_n)if(!rst_n)sin_tmp<=12'd0;elseif((sin_out>=12'hc00)||(sin_out<12'h400))sin_tmp<=sin_out+assignsin_wave=reg[15:0]tcnt;//2msreg[8:0]reg[7:0]triangle_wavealways@(posedgeclkornegedgerst_n)if(!rst_n)tcnt<=16'd0;elseif(tcnt<16'd48827)tcnt<=tcnt+1'b1;elsetcnt<=16'd0;always@(posedgeclkornegedgeif(!rst_n)triangle_tmp<=elseif(tcnt==16'd48827)triangle_tmp<=always@(posedgeclkornegedgerst_n)if(!rst_n)triangle_wave<=8'd0;elseelseif(triangle_tmp<9'd256)triangle_wave<=elsetriangle_wave<=reg[24:0]scnt;//1sreg[7:0] always@(posedgeclkornegedgerst_n)if(!rst_n)scnt<=25'd0;elseif(scnt<25'd24_99

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论