串口通讯设计之Verilog实现

合集下载

rs串口verilog代码

rs串口verilog代码

UART是通用异步收发器的简称,其中有一种电平规范较RS232规范,它用-3~-15V表示正逻辑,3~15V表示负逻辑,通过FPGA芯片实现RS232通信首先要解决的就是FPGA电平和RS232电平之间的矛盾,通常采用MAX3232作为物理层的电平接口,根据MAX3232提供的标准配制方式把物理电路设计好后,接下来的通信就是要实现逻辑的接收和发送……设计最简单的RS232通信逻辑,FPGA实现将接收到的数据会发出去,总共两个数据传输引脚,一收一发。

将此通信模块分为三个部分:接收模块,波特率控制模块,发送模块。

工作原理:此模块接收MAX3232传过来的串行数据,对齐进行判断采样,校验,最后将数据流中的串行数据转换为八位并行数据,将此八位数据储存,或送给发送模块发送出去。

根据RS232通信标准器串行数据分为起始位、数据位、校验位、停止位,空闲时为高电平,起始位通常为低电平,数据位通常为8位,校验位分为奇校验、偶校验等,停止位一位或两位且为高电平。

FPGA接收模块对此数据进行异步接收,首先就要检测其数据传输开始标识,当然就是检测开始位,于是要有下降沿检测电路,检测到下降沿是输出一高脉冲,此电路可以用两个D触发器加上基本门电路实现,脉冲触发开始进入接收状态,输出接收状态标志位,使其为1,此标志位使能波特率控制模块输出采样脉冲,此计数脉冲触发接收模块中的计数器计数,加到相应的位就把当前的串行总线上的值赋给缓冲器,或对其判断,当计数完成11次计数后,已将8位串行数据转成并行数据到缓冲器中,且进行了校验的判断和停止位的判别,这是接收状态结束,接收状态位置0,计数器清零。

对于波特率产生模块用于控制采样数据脉冲的周期,其周期就为串行数据传送一个bit所用的时间,根据此时间和时钟周期设置计数值。

当接收模块完成工作时,接收状态位为0时可以触发发送模块,发送模块检测接收状态的下降沿,由此产生一高脉冲,与发送模块类似,根据波特率控制模块产生的计数脉冲将并行数据转成串行数据,并加上开始位、校验位、停止位。

基于Verilog HDL数字电位器ADN2850的串口控制

基于Verilog HDL数字电位器ADN2850的串口控制

龙源期刊网
基于VerilogHDL数字电位器ADN2850的串口控制
作者:陈厚来吴志明罗凤武
来源:《现代电子技术》2009年第08期
摘要:数字电位器由于可调精度高,更稳定,定位更准确,操作更方便,数据可长期保存和随时刷新等优点,在某些场合具有模拟电位器不可比拟的优势。

论述对数字电位器
ADN2850的一种方便的控制方法,通过计算机上的串口直接对ADN2850进行写入和控制。

该方法简洁、高效,明显提高了调试效率。

给出用Verilog HDL实现该方法的关键程序。

该程序已经通过前仿真和板级调试,达到了预期的效果。

关键词:数字电位器;SPI;ADN2850串口;Verilog HDL。

verilog 串口时钟相位控制字-概述说明以及解释

verilog 串口时钟相位控制字-概述说明以及解释

verilog 串口时钟相位控制字-概述说明以及解释1.引言1.1 概述概述部分的内容可以包括对verilog 串口时钟相位控制字的简要介绍和重要性的提及。

可以参考以下内容进行编写:在现代通信领域中,串口通信起到了至关重要的作用。

而在串口通信中,时钟相位控制字是一个非常关键的概念。

verilog 串口时钟相位控制字是指通过调节时钟信号的相位来进行数据传输的一种技术。

时钟相位控制字的作用在于确保在数据传输过程中,接收方能够正确地识别发送方发送的数据。

通过调整时钟信号的相位,可以使得接收方在正确的时间点对数据进行采样,从而减少数据传输过程中可能会出现的误差。

时钟相位控制字的设计和调整对于串口通信的稳定性和可靠性具有非常重要的意义。

合理地设置时钟相位控制字可以提高数据传输的成功率,并减少传输过程中可能出现的错误。

因此,了解verilog 串口时钟相位控制字的原理和作用对于串口通信的设计和实现是至关重要的。

在本篇文章中,将详细介绍verilog 串口时钟相位控制字的原理和作用,希望能够为读者提供一个全面的了解,并为未来的研究和应用提供有益的参考。

1.2文章结构1.2 文章结构本文将围绕Verilog串口时钟相位控制字展开讨论,主要分为以下几个部分:第一部分是引言,包括概述、文章结构和目的。

在概述部分,将介绍串口通信的基本原理和应用领域。

文章结构部分将简要介绍本文的章节安排和内容要点。

目的部分将说明本文的研究目的和意义。

第二部分是正文,主要包括串口通信原理和时钟相位控制字的作用。

在串口通信原理部分,将介绍串口通信的基本原理,包括数据传输的方式、波特率的定义和选择。

时钟相位控制字的作用部分将详细探讨时钟相位控制字在串口通信中的作用及其实现原理。

第三部分是结论,主要总结本文的主要内容和研究成果。

在总结部分,将回顾本文的研究目的和主要内容,并对所得出的结论进行归纳和概括。

对未来研究的展望部分将提出一些关于Verilog串口时钟相位控制字相关研究的展望和建议,以促进相关领域的进一步研究和发展。

基于FPGA Verilog RS232串口回环测试例程,附源程序仿真源码及测试图片

基于FPGA Verilog RS232串口回环测试例程,附源程序仿真源码及测试图片

FPGA Verilog RS232串口回环测试基于FPGA Verilog RS232串口回环测试例程,支持多byte数据传输,附源程序仿真源码及测试图片。

测试基于SSCOM/友善之臂上位机软件测试,测试结果如下图一图二所示。

图一SSCOM图二图三连续发送仿真截图图四连续接收仿真截图后附verilog源程序代码及testbech仿真例程,注释欠。

重点:多byte回环测试要点,上位机串口多位数据连续发送停止位和起始位之间无间隔,回环程序在接收和发送都需要具备在停止位后能立马跳转到下一个起始位的能力。

重点关注cnt_bit的处理方式。

附录1 顶层例化uart_txd uart_txd(.clk_50m(sys_clk_50m),.reset_n(sys_rst_n),.tx_data(rx_data),.baud_set(3'd4),.send_en(rx_done),.send_done(),.send_busy(send_busy),.uart_tx(uart_tx));uart_rxd uart_rxd(.clk_50m(sys_clk_50m),.reset_n(sys_rst_n),.rx_data(rx_data),.baud_set(3'd4),.rx_done(rx_done),.rx_busy(rx_busy),.uart_rx(uart_rx));附录2 串口发送源程序`timescale1ns/1ps///////////////////////////////////////////////////////////////////// /////////////// Company:// Engineer://// Create Date: 2020/06/21 09:45:23// Design Name:// Module Name: uart_txd// Project Name:// Target Devices:// Tool Versions:// Description://// Dependencies:// Revision:// Revision 0.01 - File Created// Additional Comments://///////////////////////////////////////////////////////////////////// /////////////module uart_txd(clk_50m,reset_n,tx_data,baud_set,send_en,send_done,send_busy,uart_tx);input clk_50m;input reset_n;input[7:0] tx_data;input[2:0] baud_set;input send_en;output reg send_done;output reg send_busy;output reg uart_tx;reg[12:0] cnt;reg[12:0] baud_rate_cnt_max;reg[3:0] cnt_bit;reg[7:0] tx_data_r;localparam baud_rate_9600 =13'd5207;localparam baud_rate_19200 =13'd2603;localparam baud_rate_38400 =13'd1301;localparam baud_rate_57600 =13'd867;localparam baud_rate_115200 =13'd433;always@(posedge clk_50m or negedge reset_n)if(!reset_n)baud_rate_cnt_max <= baud_rate_115200;elsecase(baud_set)3'd0:baud_rate_cnt_max = baud_rate_9600;3'd1:baud_rate_cnt_max = baud_rate_19200;3'd2:baud_rate_cnt_max = baud_rate_38400;3'd3:baud_rate_cnt_max = baud_rate_57600;3'd4:baud_rate_cnt_max = baud_rate_115200;default:baud_rate_cnt_max = baud_rate_115200;endcasealways@(posedge clk_50m or negedge reset_n)if(!reset_n)tx_data_r <=8'd0;else if(send_en)tx_data_r <= tx_data;elsetx_data_r <= tx_data_r;always@(posedge clk_50m or negedge reset_n)if(!reset_n)send_busy <=1'b0;else if(send_en)send_busy <=1'b1;else if(cnt == baud_rate_cnt_max)beginif(cnt_bit ==4'd10)send_busy <=1'b0;elsesend_busy <= send_busy;endelsesend_busy <= send_busy;always@(posedge clk_50m or negedge reset_n)if(!reset_n)send_done <=1'b0;else if(cnt == baud_rate_cnt_max)beginif(cnt_bit ==4'd10)send_done <=1'b1;elsesend_done <=1'b0;endelsesend_done <=1'b0;always@(posedge clk_50m or negedge reset_n)if(!reset_n)cnt <=13'd0;else if(send_busy)beginif(cnt == baud_rate_cnt_max)cnt <=13'd0;elsecnt <= cnt +1'b1;endelsecnt <= cnt;/****************************************always@(posedge clk_50m or negedge reset_n)if(!reset_n)cnt_bit <= 4'd0;else if(send_en) //send_en needs to be 1 clock high pulse cnt_bit <= 4'd1;else if(cnt == baud_rate_cnt_max)beginif(cnt_bit == 4'd10)cnt_bit <= 4'd0;elsecnt_bit <= cnt_bit + 1'b1;endelsecnt_bit <= cnt_bit;******************************************/always@(posedge clk_50m or negedge reset_n)if(!reset_n)cnt_bit <=4'd0;else if(send_busy &&(cnt_bit ==4'd11))cnt_bit <=4'd1;else if(cnt ==1)cnt_bit <= cnt_bit +1'b1;elsecnt_bit <= cnt_bit;always@(posedge clk_50m or negedge reset_n)if(!reset_n)beginuart_tx <=1'b1;endelsecase(cnt_bit)4'd0:;4'd1: uart_tx <=1'b0;//start4'd2: uart_tx <= tx_data_r[0];//bit 04'd3: uart_tx <= tx_data_r[1];4'd4: uart_tx <= tx_data_r[2];4'd5: uart_tx <= tx_data_r[3];4'd6: uart_tx <= tx_data_r[4];4'd7: uart_tx <= tx_data_r[5];4'd8: uart_tx <= tx_data_r[6];4'd9: uart_tx <= tx_data_r[7];//bit 84'd10: uart_tx <=1'b1;//stopdefault:;endcaseendmodule附录3 串口发送testbench`timescale1ns/1ps///////////////////////////////////////////////////////////////////// /////////////// Company:// Engineer://// Create Date: 2020/06/21 11:38:04// Design Name:// Module Name: uart_txd_tb// Project Name:// Target Devices:// Tool Versions:// Description://// Dependencies://// Revision:// Revision 0.01 - File Created// Additional Comments://///////////////////////////////////////////////////////////////////// /////////////module uart_txd_tb();reg clk_50m;reg reset_n;reg[7:0] tx_data;reg[2:0] baud_set;reg send_en;wire send_done;wire send_busy;wire uart_tx;parameter CLK_PERIOD =20;initial clk_50m =0;always#(CLK_PERIOD /2) clk_50m =~clk_50m;initial begintx_data =8'h55;baud_set =4;reset_n =0;send_en =0;#(CLK_PERIOD *100);reset_n =1;# CLK_PERIOD;send_en =1;#(CLK_PERIOD );send_en =0;#(CLK_PERIOD *4340);send_en =1;#(CLK_PERIOD );send_en =0;#(CLK_PERIOD *4340);#(CLK_PERIOD *100);$stop;enduart_txd uart_txd(.clk_50m(clk_50m),.reset_n(reset_n),.tx_data(tx_data),.baud_set(baud_set),.send_en(send_en),.send_done(send_done),.send_busy(send_busy),.uart_tx(uart_tx));endmodule附录4 串口接收源程序`timescale1ns/1ps///////////////////////////////////////////////////////////////////// /////////////// Company:// Engineer://// Create Date: 2020/06/21 15:30:30// Design Name:// Module Name: uart_rxd// Project Name:// Target Devices:// Tool Versions:// Description://// Dependencies://// Revision:// Revision 0.01 - File Created// Additional Comments://///////////////////////////////////////////////////////////////////// /////////////module uart_rxd(clk_50m,reset_n,rx_data,baud_set,rx_done,rx_busy,uart_rx);input clk_50m;input reset_n;output reg[7:0] rx_data;input[2:0] baud_set;output reg rx_done;output reg rx_busy;input uart_rx;reg[12:0] cnt;reg[12:0] baud_rate_cnt_max;reg[3:0] cnt_bit;reg uart_rx_r1;reg uart_rx_r2;wire nedge;localparam baud_rate_9600 =13'd5207;localparam baud_rate_19200 =13'd2603;localparam baud_rate_38400 =13'd1301;localparam baud_rate_57600 =13'd867;localparam baud_rate_115200 =13'd433;always@(posedge clk_50m or negedge reset_n)if(!reset_n)baud_rate_cnt_max <= baud_rate_115200;elsecase(baud_set)3'd0:baud_rate_cnt_max = baud_rate_9600;3'd1:baud_rate_cnt_max = baud_rate_19200;3'd2:baud_rate_cnt_max = baud_rate_38400;3'd3:baud_rate_cnt_max = baud_rate_57600;3'd4:baud_rate_cnt_max = baud_rate_115200;default:baud_rate_cnt_max = baud_rate_115200;endcasealways@(posedge clk_50m or negedge reset_n)if(!reset_n)beginuart_rx_r1 <=8'd0;uart_rx_r2 <=8'd0;endelse beginuart_rx_r1 <= uart_rx;uart_rx_r2 <= uart_rx_r1;endassign nedge = uart_rx_r2 &(!uart_rx_r1);always@(posedge clk_50m or negedge reset_n) if(!reset_n)rx_busy <=1'b0;else if(nedge)rx_busy <=1'b1;else if(cnt == baud_rate_cnt_max)begin if(cnt_bit ==4'd10)rx_busy <=1'b0;elserx_busy <= rx_busy;endelserx_busy <= rx_busy;always@(posedge clk_50m or negedge reset_n) if(!reset_n)rx_done <=1'b0;else if(cnt == baud_rate_cnt_max)begin if(cnt_bit ==4'd10)rx_done <=1'b1;elserx_done <=1'b0;endelserx_done <=1'b0;always@(posedge clk_50m or negedge reset_n) if(!reset_n)cnt <=13'd0;else if(rx_busy)beginif(cnt == baud_rate_cnt_max)cnt <=13'd0;elsecnt <= cnt +1'b1;endelsecnt <= cnt;always@(posedge clk_50m or negedge reset_n) if(!reset_n)cnt_bit <=4'd1;else if(cnt == baud_rate_cnt_max )begin if(cnt_bit ==4'd10)cnt_bit <=4'd1;elsecnt_bit <= cnt_bit +1'b1;endelsecnt_bit <= cnt_bit;always@(posedge clk_50m or negedge reset_n)if(!reset_n)beginrx_data <=8'd0;endelse if(cnt == baud_rate_cnt_max /2)case(cnt_bit)4'd1:;//start4'd2: rx_data[0]<= uart_rx_r2;//bit 04'd3: rx_data[1]<= uart_rx_r2;4'd4: rx_data[2]<= uart_rx_r2;4'd5: rx_data[3]<= uart_rx_r2;4'd6: rx_data[4]<= uart_rx_r2;4'd7: rx_data[5]<= uart_rx_r2;4'd8: rx_data[6]<= uart_rx_r2;4'd9: rx_data[7]<= uart_rx_r2;//bit 74'd10:;//stopdefault:;endcaseelserx_data <= rx_data;endmodule附录5串口接收testbench`timescale1ns/1ps///////////////////////////////////////////////////////////////////// /////////////// Company:// Engineer://// Create Date: 2020/06/21 19:44:29// Design Name:// Module Name: uart_rxd_tb// Project Name:// Target Devices:// Tool Versions:// Description://// Dependencies://// Revision:// Revision 0.01 - File Created// Additional Comments://///////////////////////////////////////////////////////////////////// /////////////module uart_rxd_tb();reg clk_50m;reg reset_n;wire[7:0] rx_data;wire rx_done;wire rx_busy;reg uart_rx;parameter CLK_PERIOD =20;initial clk_50m =0;always#(CLK_PERIOD /2) clk_50m =~clk_50m;initial beginreset_n =0;uart_rx =1;//idle#(CLK_PERIOD *100);reset_n =1;# CLK_PERIOD;uart_rx =0;//start#(CLK_PERIOD *434);uart_rx =1;//bit0#(CLK_PERIOD *434);uart_rx =0;//bit1#(CLK_PERIOD *434);uart_rx =1;//bit2#(CLK_PERIOD *434);uart_rx =0;//bit3#(CLK_PERIOD *434);uart_rx =1;//bit4#(CLK_PERIOD *434);uart_rx =0;//bit5#(CLK_PERIOD *434);uart_rx =1;//bit6#(CLK_PERIOD *434);uart_rx =0;//bit7#(CLK_PERIOD *434);uart_rx =1;//stop#(CLK_PERIOD *434);uart_rx =1;//idle#(CLK_PERIOD *434);#(CLK_PERIOD *434);#(CLK_PERIOD *434);uart_rx =0;//start #(CLK_PERIOD *434);uart_rx =0;//bit0#(CLK_PERIOD *434);uart_rx =1;//bit1#(CLK_PERIOD *434);uart_rx =0;//bit2#(CLK_PERIOD *434);uart_rx =1;//bit3#(CLK_PERIOD *434);uart_rx =0;//bit4#(CLK_PERIOD *434);uart_rx =1;//bit5#(CLK_PERIOD *434);uart_rx =0;//bit6#(CLK_PERIOD *434);uart_rx =1;//bit7#(CLK_PERIOD *434);uart_rx =1;//stop#(CLK_PERIOD *434);uart_rx =1;//idle#(CLK_PERIOD *434);#(CLK_PERIOD *434);#(CLK_PERIOD *434);$stop;enduart_rxd uart_rxd(.clk_50m(clk_50m),.reset_n(reset_n),.rx_data(rx_data),.baud_set(3'd4),.rx_done(rx_done),.rx_busy(rx_busy),.uart_rx(uart_rx));endmodule。

基于Verilog HDL设计的UART模块

基于Verilog HDL设计的UART模块

1 UART原理串行通信是指外部设备和计算机间使用一根数据线(另外需要地线,可能还需要控制线)进行数据传输的方式。

数据在一根数据线上一位一位传输,每一位数据都占据一个固定的时间长度。

与并行通信方式相比,串行通信方式的传输速度较慢,但这种通信方式使用的数据线少,在远距离通信中可以节约通信成本,因此得到了广泛的应用。

基本的UART只需要发送和接收两条数据线就可以完成数据的全双工通信,其基本功能是在发送端将控制器通过总线传过来的并行数据,以设定的格式,设定的频率串行地传输出去,并同时在接收端将串行接收到的数据,转换成相应的并行数据发送出去。

UART的基本帧格式如图1所示。

其中,起始位总是逻辑O状态,停止位总是逻辑l状态,其持续时间可选为1位、1.5位或2位,其数据位可为5、6、7、8位,校验位可根据需要选择奇校验位,偶校验位或无校验位。

2 UART的设计现今复杂的数字系统的设计往往采用自顶向下的设计方案,利用层次化结构化的方法,将一个设计方案划分为若干模块,在不同层次的模块都可以进行仿真,可以很方便地查看某一层次的代码以改正仿真时发现错误。

在本设计中UART主要由波特率发生器、接收模块、发送模块3部分组成,并具有l位停止位和无校验位。

波特率发生器实现波特率的变换,利用外部时钟信号产生一个所需波特率16倍的波特率时钟,用来控制UART的接收与发送。

接收模块是用于接收串行信号,并将其转化为并行数据;而发送模块则将准备输出的并行数据按照UART的帧格式转化为串行数据输出。

图2为UART结构图。

2.1 波特率发生器波特率表示的是每秒钟传送的二进制数据的位数,即单位时间内传送的信息量。

在串行异步传送中,常用到的波特率为1 200、2 400、4 800、9 600、19 200等。

波特率发生器实际上是一个分频器,主要是产生和。

RS-232通信所采用的波特率同步的时钟。

由于串行数据帧与接收数据时钟是异步的,所以存UA RT的接收端在什么时刻将数据移入寄存器,怎样选择可靠的采样点是非常关键的。

verilog编写的uart程序

verilog编写的uart程序

// UART_FPGA.v 顶层模块,实现由ARM控制FPGA读取串口数据,经过ARM返回给FPGA串口发送出去;`timescale 1ns/1nsmodule UART_FPGA(//EMIF PINinput wire [10:0] EADDR_pin /* synthesis syn_noclockbuf = 1 */,inout wire [15:0] EDATA_pin ,input wire EnOE_pin /* synthesis syn_noclockbuf = 1 */,input wire EnWE_pin /* synthesis syn_noclockbuf = 1 */,input wire EnGCS1_pin /* synthesis syn_noclockbuf = 1 */,output wire EINT2_pin ,//LED_runoutput wire LED_run_pin ,//UARToutput wire UART_TXD0 ,input wire UART_RXD0 /* synthesis syn_noclockbuf = 1 */,//test signaloutput wire TXD_test,output wire RXD_test,output reg TXD_start,output wire EINT2_test,output wire TXD_over_test,output wire uart_send_WR,//FPGA SYSTEM PINinput wire nRESET_pin /* synthesis syn_noclockbuf = 1 */,input wire CLK_50M_pin);wire [15:0] write_data;//-------------------DSP ARM uart to EMIF---------------------- reg [7:0] ARM_DSP_data;wire [7:0] DSP_ARM_data;reg uart_send_WR_reg;//reg [7:0] T_data;//reg [1:0] TXD_start_cnt;wire [7:0] R_data;wire R_ready;reg [2:0] UART_INT_cnt;wire TXD_over;wire [1:0] baud_select;reg [12:0] baud_devide;//wire clkrec;parameter baud_9600 = 5208; //50M/9600 parameter baud_19200 = 2604;parameter baud_38400 = 1302;parameter baud_115200 = 434;assign TXD_test = UART_TXD0;assign RXD_test = UART_RXD0;assign EINT2_test = EINT2_pin;assign TXD_over_test=TXD_over;/*--------------Program start-------------------*//*----------baud select------------*/always @( negedge nRESET_pin or posedge CLK_50M_pin ) beginif( !nRESET_pin )beginbaud_devide <= 'h1FFF;endelsebegincase ( baud_select )'d0 : baud_devide <= baud_9600 ;'d1 : baud_devide <= baud_19200 ;'d2 : baud_devide <= baud_38400 ;'d3 : baud_devide <= baud_115200 ;endcaseendend/*----------INT generator------------*/always @( negedge nRESET_pin or posedge R_ready )beginif( !nRESET_pin )beginARM_DSP_data <= 8'd0;endelsebeginARM_DSP_data <= R_data;endendalways @( negedge nRESET_pin or negedge R_ready or posedge CLK_50M_pin ) beginif( !nRESET_pin )beginUART_INT_cnt <= 3'd5;endelse if( !R_ready )beginUART_INT_cnt <= 3'd0;endelse if( UART_INT_cnt < 3'd5 )beginUART_INT_cnt <= UART_INT_cnt + 1'b1;endassign EINT2_pin = ( UART_INT_cnt >= 3'd1 && UART_INT_cnt <= 3'd4 ) ? 1'b0 : 1'b1 ;/*---------------DSP to ARM data---------------*/always@(negedge nRESET_pin or posedge CLK_50M_pin) //当接收了一个数据后,把数据加1后发回PC机,注意串口一个一个数据发beginif( !nRESET_pin )beginuart_send_WR_reg <= 1'b0;TXD_start <= 1'b0;endelse if( uart_send_WR_reg != uart_send_WR )beginif( TXD_over )beginTXD_start <= 1'b1;uart_send_WR_reg <= uart_send_WR;endendelsebeginTXD_start <= 1'b0;endend//----------------EMIF read ,fpga TO ARM---------------------------EMIF_R EMIF_R_M(.EADDR_pin (EADDR_pin ),.EDA TA_pin (EDA TA_pin ),.EnOE_pin (EnOE_pin ),.EnGCS1_pin (EnGCS1_pin ),.write_data (write_data ),.ARM_DSP_data (ARM_DSP_data ),.nRESET_pin (nRESET_pin )// .CLK_50M_pin (CLK_50M_pin )//----------------EMIF write,ARM to fpga---------------------------EMIF_W EMIF_W_M(.EADDR_pin (EADDR_pin ),.EDA TA_pin (EDATA_pin ),.EnWE_pin (EnWE_pin ),.EnGCS1_pin (EnGCS1_pin ),//uart.DSP_ARM_data (DSP_ARM_data ),.uart_send_WR (uart_send_WR ),.write_data (write_data ),.baud_select (baud_select ),//LED run.LED_run_pin (LED_run_pin ),.nRESET_pin (nRESET_pin )// .CLK_50M_pin (CLK_50M_pin ) );UART_rec UART_rec_M (//input.RXD (UART_RXD0 ),.baud_devide (baud_devide ),//output.R_data (R_data ),.R_ready (R_ready ),//FPGA sys pin.nRESET_pin (nRESET_pin ),.CLK_50M_pin (CLK_50M_pin));UART_txd UART_txd_M (//input.TXD_start (TXD_start ),.T_data (DSP_ARM_data ),.baud_devide (baud_devide ),//output.TXD (UART_TXD0 ),.TXD_over (TXD_over ),//FPGA sys pin.nRESET_pin (nRESET_pin ),.CLK_50M_pin (CLK_50M_pin));Endmodule// UART_rec.v`timescale 1ns/1nsmodule UART_rec (//inputRXD,baud_devide,//outputR_data,R_ready,//FPGA sys pinnRESET_pin,CLK_50M_pin);input wire RXD;input wire [12:0] baud_devide;output reg [7:0] R_data;output reg R_ready;input wire nRESET_pin;input wire CLK_50M_pin;reg [1:0] RXD_sync;reg [2:0] RXD_cnt;reg RXD_bit;reg [3:0] rec_bit_cnt;//reg [8:0] baud_16_reg;reg [12:0] baud_cnt;reg [8:0] baud_16_cnt;wire baud_tick_16;wire baud_tick;wire [11:0] baud_devide_2;wire [8:0] baud_devide_16;/*----------Program start------------*/assign baud_devide_2 = baud_devide / 2;assign baud_devide_16 = baud_devide / 16;/*--------------baud 16 devided clk used in sample-----------*/ always @( negedge nRESET_pin or posedge CLK_50M_pin ) beginif( !nRESET_pin )beginbaud_16_cnt <= 'd0;endelsebeginif( baud_16_cnt < baud_devide_16 )beginbaud_16_cnt <= baud_16_cnt + 1'b1;endelsebeginbaud_16_cnt <= 'd0;endendendassign baud_tick_16 = ( baud_16_cnt == baud_devide_16 );//--------baud clk used in receiving data-------always @( negedge nRESET_pin or posedge CLK_50M_pin )beginif( !nRESET_pin )beginbaud_cnt <= 'd0;endelsebeginif( !R_ready )beginif( baud_cnt < baud_devide - 1'b1 )beginbaud_cnt <= baud_cnt + 1'b1;endelsebeginbaud_cnt <= 'd0;endendelsebeginbaud_cnt <= 'd0;endendendassign baud_tick = ( baud_cnt == baud_devide_2 );/*-----------jitter filter--------------*/always @( negedge nRESET_pin or posedge CLK_50M_pin )beginif( !nRESET_pin )beginRXD_sync <= 2'd0;endelsebeginRXD_sync <= {RXD_sync[0], RXD};endendalways @( negedge nRESET_pin or posedge baud_tick_16 ) beginif( !nRESET_pin )beginRXD_cnt <= 3'd7;endelsebeginif( RXD_sync[1] && RXD_cnt != 3'd7 )beginRXD_cnt <= RXD_cnt + 1;endelsebeginif( ~RXD_sync[1] && RXD_cnt != 3'd0 )beginRXD_cnt <= RXD_cnt - 1;endendendendalways @( negedge nRESET_pin or posedge baud_tick_16 ) beginif( !nRESET_pin )beginRXD_bit <= 1'b1;endelsebeginif( RXD_cnt == 3'd7)beginRXD_bit <= 1'b1;endelse if( RXD_cnt == 3'd0 )beginRXD_bit <= 1'b0;endendend/*---------------receive data cnt---------------*/always @( negedge nRESET_pin or posedge CLK_50M_pin ) beginif( !nRESET_pin )beginR_ready <= 1'b1;rec_bit_cnt <= 4'd0;endelsebeginif( R_ready )beginrec_bit_cnt <= 4'd0;if( !RXD_bit )beginR_ready <= 1'b0;endendelse if( baud_tick )beginif( rec_bit_cnt < 4'd9 )beginrec_bit_cnt <= rec_bit_cnt + 1'b1;R_ready <= 1'b0;endelsebeginrec_bit_cnt <= 4'd0;R_ready <= 1'b1;endendendendalways @( negedge nRESET_pin or posedge baud_tick ) beginif( !nRESET_pin )beginR_data <= 8'd0;endelse if( !R_ready )beginif( rec_bit_cnt == 0 )beginR_data <= 8'd0;endelsebeginif( rec_bit_cnt >= 4'd1 && rec_bit_cnt<= 4'd8 )R_data[rec_bit_cnt - 1'b1 ] <= RXD_bit;endendendendmodule// UART_TXD.v`timescale 1ns/1nsmodule UART_txd (//inputbaud_devide,TXD_start,T_data,//outputTXD,TXD_over,//FPGA sys pinnRESET_pin,CLK_50M_pin);input wire TXD_start;input wire [7:0] T_data;input wire [12:0] baud_devide;output reg TXD;output reg TXD_over;input wire nRESET_pin;input wire CLK_50M_pin;//regs & wireswire baud_tick;//reg baud_ctrl;reg [3:0] T_state;reg [7:0] T_data_reg;reg [12:0] baud_cnt;/*----------Program start---------------*//*-----------------Baud generator------------------------*/assign baud_tick = ( baud_cnt == baud_devide - 1'b1 );always @( negedge nRESET_pin or posedge CLK_50M_pin ) beginif( !nRESET_pin )beginbaud_cnt <= 'd0;endelse if( baud_cnt < baud_devide - 1'b1 )beginbaud_cnt <= baud_cnt + 1'b1;endelsebeginbaud_cnt <= 'd0;endend/*----------transmit state machine---------------*/always @( negedge nRESET_pin or posedge CLK_50M_pin ) beginif( !nRESET_pin )beginT_state <= 4'd0;endelsebegincase(T_state)4'd0: if(TXD_start) T_state <= 4'd1;4'd1: if(baud_tick) T_state <= 4'd2; // 开始位04'd2: if(baud_tick) T_state <= 4'd3; // bit 04'd3: if(baud_tick) T_state <= 4'd4; // bit 14'd4: if(baud_tick) T_state <= 4'd5; // bit 24'd5: if(baud_tick) T_state <= 4'd6; // bit 34'd6: if(baud_tick) T_state <= 4'd7; // bit 44'd7: if(baud_tick) T_state <= 4'd8; // bit 54'd8: if(baud_tick) T_state <= 4'd9; // bit 64'd9: if(baud_tick) T_state <= 4'd10; // bit 74'd10: if(baud_tick) T_state <= 4'd0; // 停止位1default: if(baud_tick) T_state <= 4'd0;endcaseendendalways @(negedge nRESET_pin or posedge baud_tick ) beginif( !nRESET_pin )beginTXD <= 1'b1;T_data_reg <= 8'd0;endelsebegincase(T_state)// 4'd0: TXD <= 1'b1;4'd1: beginTXD <= 1'b0;T_data_reg <= T_data;end4'd2: TXD <= T_data_reg[0];4'd3: TXD <= T_data_reg[1];4'd4: TXD <= T_data_reg[2];4'd5: TXD <= T_data_reg[3];4'd6: TXD <= T_data_reg[4];4'd7: TXD <= T_data_reg[5];4'd8: TXD <= T_data_reg[6];4'd9: TXD <= T_data_reg[7];4'd10: TXD <= 1'b1;default: TXD <= 1'b1;endcaseendend//assign TXD = TXD;always @( negedge nRESET_pin or posedge CLK_50M_pin ) beginif( !nRESET_pin )beginTXD_over <= 1'b0;endelsebeginif( T_state ==4'd0 )TXD_over <= 1'b1;elseTXD_over <= 1'b0;endendendmodule。

Verilog双向口的使用和仿真

Verilog双向口的使用和仿真

Verilog in out 双向口使用和仿真2007-12-01 11:11芯片外部引脚很多都使用in out类型的,为的是节省管腿。

一般信号线用做总线等双向数据传输的时候就要用到INOUT类型了。

就是一个端口同时做输入和输出。

inout 在具体实现上一般用三态门来实现。

三态门的第三个状态就是高阻'Z' 0当in out端口不输出时,将三态门置高阻。

这样信号就不会因为两端同时输出而出错了,更详细的内容可以搜索一下三态门tri-state 的资料.1使用in out类型数据,可以用如下写法:inout data」no ut;in put data_i n;reg data_reg;//data_i nout 的映象寄存器reg lin k_data;assign data_inout=link_data?data_reg:1 ' bz;//link_data 控制三态门//对于data_reg,可以通过组合逻辑或者时序逻辑根据data_in对其赋值.通过控制link_data 的高低电平,从而设置data」nout是输出数据还是处于高阻态,如果处于高阻态,则此时当作输入端口使用.link_data 可以通过相关电路来控制.2编写测试模块时,对于in out类型的端口,需要定义成wire类型变量,而其它输入端口都定义成reg类型,这两者是有区别的.当上面例子中的data」nout用作输入时,需要赋值给data」nout,其余情况可以断开.此时可以用assign 语句实现:assign data_inout=link?data_in_t:1 ' bz; 其中的link ,data_in_t 是reg类型变量,在测试模块中赋值.另外,可以设置一个输出端口观察data_inout用作输出的情况:Wire data_out;Assign data_out_t=(!link)?data_inout:1 ' bz;else , in RTLinout use in top module(PAD)dont use ino ut(tri) in sub module也就是说,在内部模块最好不要出现inout,如果确实需要,那么用两个port 实现,到顶层的时候再用三态实现。

verilog RS232 串口通信 verilog

verilog RS232 串口通信 verilog
//=============================顶层模块=====================================
module uart_top(clk,rs232_rx,rs232_tx);
input clk; //时钟信号50M
input rs232_rx; //数据输入信号
bps_start,
clk_bps,
rs232_rx,
rx_data,
rx_int
);
input clk; //50MHz时钟
input rst_n; //低电平复位信号
input rs232_rx; //接收数据信号
);
uart_rx uart_rx(//数据接收模块
.clk(clk),
.rst_n(rst_n),
.bps_start(bps_start1),
.clk_bps(clk_bps1),
.rs232_rx(rs232_rx),
.rx_data(rx_data),
else
begin
if(int_cnt<250) int_cnt<=int_cnt+1'b1;
end
end
assign data_flg=(int_cnt==10)?1'b1:1'b0;
always @(posedge data_flg or negedge rst_n)
output rs232_tx; //数据输出信号
wire clk_bps1,clk_bps2;
wire bps_start1,bps_start2;
wire [7:0] rx_data;

串口通讯设计之Verilog实现

串口通讯设计之Verilog实现

串口通讯设计之V e r i l o g实现FPGA串口模块是将由RS-485发送过来的数据进行处理,提取出8位有效数据,并按异步串口通讯的格式要求输出到MAX3223的12脚;FPGA选用Xilinx公司的SpartanII系列xc2s50;此部分为该设计的主体;如上所述,输入数据的传输速率为700k波特率;为了使FPGA能够正确地对输入数据进行采样,提高分辨率能力和抗干扰能力,采样时钟必须选用比波特率更高的时钟,理论上至少是波特率时钟的2倍;1 串口通信基本特点随着多微机系统的应用和微机网络的发展,通信功能越来越显得重要;串行通信是在一根传输线上一位一位地传送信息.这根线既作数据线又作联络线;串行通信作为一种主要的通信方式,由于所用的传输线少,并且可以借助现存的电话网进行信息传送,因此特别适合于远距离传送;在串行传输中,通信双方都按通信协议进行,所谓通信协议是指通信双方的一种约定;约定对数据格式、同步方式、传送速度、传送步骤、纠错方式以及控制字符定义等问题做出统一规定,通信双方必须共同遵守;异步起止式的祯信息格式为:每祯信息由四部分组成:位起始位;~8位数据位;传送顺序是低位在前,高位在后.依次传送;c.一位校验位,也可以没有;d.最后是1位或是2位停止位;FPGAField Pmgrammable Gate Array现场可编程门阵列在数字电路的设计中已经被广泛使用;这种设计方式可以将以前需要多块集成芯片的电路设计到一块大模块可编程逻辑器件中,大大减少了电路板的尺寸,增强了系统的可靠性和设计的灵活性;本文详细介绍了已在实际项目中应用的基于FPGA的串口通讯设计;本设计分为硬件电路设计和软件设计两部分,最后用仿真验证了程序设计的正确性;2 系统的硬件设计本方案的异步串行通信的硬件接口电路图如图1所示,主要由四部分组成:RS-485数据发送模块、FPGA 串口模块、MAX3223和DB9;各部分功能简述如下:RS-485数据发送模块是将前续电路的数据发送到FPGA,供本电路处理,亦即本电路的输入;RS485是符合RS-485和RS-4225串口标准的低功耗半双工收发器件,有和5V两种,在本设计中选用了的器件SP3485;在本设计中;485的7脚和8脚与前端信号相连接,用于接收输入的数据;数据格式是这样的:一帧数据有25位,报头是16个高电平和1个低电平,接下来是8位有效的数据;传输速率为700k波特率;2脚是使能端,与FPGA的I/O 口相连,由FPGA提供逻辑控制信号;1脚和4脚也与FPGA相连,由FPGA对输入数据进行处理;FPGA串口模块是将由RS-485发送过来的数据进行处理,提取出8位有效数据,并按异步串口通讯的格式要求输出到MAX3223的12脚;FPGA选用Xilinx公司的Spartan II系列xc2s50;此部分为该设计的主体;如上所述,输入数据的传输速率为700k波特率;为了使FPGA能够正确地对输入数据进行采样,提高分辨率能力和抗干扰能力,采样时钟必须选用比波特率更高的时钟,理论上至少是波特率时钟的2倍;在本设计中选用4倍于波特率的时钟,利用这种4倍于波特率的接收时钟对串行数据流进行检测和定位采样,接收器能在一个位周期内采样4次;如果没有这种倍频关系,定位采样频率和传送波特率相同,则在一个位周期中,只能采样一次,分辨率会差;比如,为了检测起始位下降沿的出现,在起始位的前夕采样一次之后,下次采样要到起始位结束前夕才进行;而假若在这个周期期间,因某种原因恰恰使接收时钟往后偏移了一点点,就会错过起始位;造成整个后面位的检测和识别错误;针对本设计,FPGA的软件共分了三个模块:1.时钟分频模块;模块的功能是用来产生所需要的数据采集时钟和数据传输时钟;系统主频是40M的;数据采集时钟是2.8M的,发送时钟是;2. 提取数据模块;由RS485发送过来的数据共有25位,其中只有8位是有效数据;为了发送这8位有效数据;必须先将其提取出来;提取的办法是这样的:通过连续检测到的16个高电平和一个低电平;判断8位有效数据的到来;然后按照串行数据传输的格式,在加上起始位和停止位后,将其存储于输出缓冲寄存器中;在这里,我们的串行数据输出格式是这样规定的,一位起始位,八位数据位,一位停止位,无校验位;3.串行数据输出模块;这一模块相对比较简单,波特率选为,模块的功能是在移位输出脉冲的作用下,将输出缓冲寄存器中的数据移位输出;MAX3223是实现电平转换的芯片;由于RS-232c是用正负电压来表示逻辑状态;与TTL以高低电平表示逻辑状态的规定不同;因此,为了能够同计算机接口或终端的TTL器件连接,必须在RS-232与TTL电路之间进行电平和逻辑关系的变换;实现这种变换的方法可用分立元件,也可用集成电路芯片; MAXIM公司的MAX3223是为满足RS-232c 的标准而设计的具有功耗低、波特率高、价格低等优点,外接电容仅为或1uF,为双组RS232收发器;由MAX3223的12脚输入的数据,经过电平转换后由8脚输出,再经过DB9的TxD端输出,由PC机接收并做后续处理;3 系统软件设计FPGA模块是本设计的主体,使用Verilog硬件描述语言进行编写,本段代码共有两个子模块,分别实现提取八位数据和串行数据发送的功能;下面是verilog源代码module SIMOdin,clk,rst,dout_ser;input din; 4倍于波特率的时钟reg txclk; //发送数据时钟;发数据取的波特率integer bitpos="7"; //当前位parameters0=0,s1=1,s2=2,s3=3;reg2:0state;reg4:0counter; //用来计算报头报尾中1的个数reg tag,tag1;reg2:0cnt3;reg txdone="1"''''b1;//一个字节数据传输完毕标志提取有效数据位并按串行通讯格式装载数据always posedge nclk or posedge rstbegin ifrst begin state<=0; counter<=0; tag1=0; tag="0"; indata_buf<=8''''bz; dout_buf<=10''''bz; bitpos ="7"; cnt3<=0; end else casestate s0:begin tag="0";//表示数据没有装好ifdinbegin counter<=counter+1; state<=s0; ifcounter==15//如果检测到16个1则转入s1状态检测接下来的是不是0begin state<=s1; counter<=0;end endelse begin counter<=0; state<=s0;end end s1:ifdin//如果是0的话,转入s2状态,提取八位有效数据state<=s2; else //否则转到s0状态重新检测state<=s0; s2:ifcnt3==3//是否采集四次数据begin cnt2<=0; indata_bufbitpos<=din; //先进来的是高位数据bitpos="bitpos-1"; ifbitpos==-1begin bitpos=7;state<=s3;endend elsecnt3<=cnt3+1; s3:begin tag1=tag; tag=1''''b1; //标志输入寄存器满;表明已把有用数据装入寄存器iftag&&~tag1&&txdone //检测到tag的上升沿以及txdone为高才把输入缓冲数据放到输出缓冲去dout_buf<={1''''b1,indata_buf7:0,1''''b0};//停止位,高位,低位,起始位state<=s0; end endcaseend//发送数据模块reg3:0 state_tx=0;txclk or posedge rstbegin ifrst begindout_ser<=1''''bz;state_tx<=0;txdone=1; end elsecasestate_tx0:begin dout_ser<=dout_buf0;state_tx<=state_tx+1;txdone=1''''b0;end 1:begin dout_ser<=dout_buf1;s tate_tx<=state_tx+1;end 2:begin dout_ser<=dout_buf2;state_tx<=state_tx+1;end 3:begin dout_ser<=dout_buf 3;state_tx<=state_tx+1;end 4:begin dout_ser<=dout_buf4;state_tx<=state_tx+1;end 5:begin dout_ser<=dout_ buf5;state_tx<=state_tx+1;end 6:begin dout_ser<=dout_buf6;state_tx<=state_tx+1;end 7:begin dout_ser<=do ut_buf7;state_tx<=state_tx+1;end 8:begin dout_ser<=dout_buf8;state_tx<=state_tx+1;end 9:begin dout_ser< =dout_buf9;state_tx<=state_tx+1;end endcase endendmodule注:两个频率信号nclk、txclk由相应的分频程序产生;由于篇幅所限未在文中列出;FPGA模块接收从RS-485发送过来的串行数据;25位为一个字符;数据的传输速率是700kbps,用四倍于波特率的速率进行采样,这样可以大大降低系统的噪声;数据的串行输出波特率选为11200bps;由输入输出波形图可以看出:本段程序实现了对输入数据的有效数据位的提取,并按照一定的波特率进行串行输出;程序中,波特率可以根据需要通过分频程序进行改动;硬件电路搭建简单,程序代码书写容易;数据传输稳定可靠,可以满足串口通信的要求;。

SPI总线接口的verilog的实现

SPI总线接口的verilog的实现

十二SPI总线接口的verilog的实现1.实验目的项目中使用的许多器件需要SPI接口进行配置,比如PLL:ADF4350,AD:AD9627,VGA:AD8372等,本实验根据SPI协议,编写了一个简单的SPI读写程序,可以进行32位数据的读写,可以设置SPI SCLK相对于主时钟的分频比。

2.实验原理SPI总线系统是一种同步串行外设接口,它可以使MCU与各种外围设备以串行方式进行通信以交换信息。

外围设置FLASHRAM、网络控制器、LCD显示驱动器、A/D转换器和MCU等。

SPI总线系统可直接与各个厂家生产的多种标准外围器件直接接口,该接口一般使用4条线:串行时钟线(SCK)、主机输入/从机输出数据线MISO、主机输出/从机输入数据线MOST和低电平有效的从机选择线SS(有的SPI接口芯片带有中断信号线INT、有的SPI接口芯片没有主机输出/从机输入数据线MOSI)。

SPI的通信原理很简单,它以主从方式工作,这种模式通常有一个主设备和一个或多个从设备,需要至少4根线,事实上3根也可以(单向传输时)。

也是所有基于SPI的设备共有的,它们是SDI(数据输入),SDO(数据输出),SCK(时钟),CS(片选)。

(1)MOSI –主设备数据输出,从设备数据输入(2)MISO –主设备数据输入,从设备数据输出(3)SCLK –时钟信号,由主设备产生(4)CS –从设备使能信号,由主设备控制其中CS是控制芯片是否被选中的,也就是说只有片选信号为预先规定的使能信号时(高电位或低电位),对此芯片的操作才有效。

这就允许在同一总线上连接多个SPI设备成为可能。

接下来就是负责通讯的3根线了。

通讯是通过数据交换完成的,这里先要知道SPI是串行通讯协议,也就是说数据是一位一位的传输的。

这就是SCK时钟线存在的原因,由SCK 提供时钟脉冲,SDI,SDO则基于此脉冲完成数据传输。

数据输出通过 SDO线,数据在时钟上升沿或下降沿时改变,在紧接着的下降沿或上升沿被读取。

I_2C总线串行数据接口的Verilog实现

I_2C总线串行数据接口的Verilog实现

邮局订阅号:82-946360元/年技术创新嵌入式网络技术应用《PLC技术应用200例》您的论文得到两院院士关注I2C总线串行数据接口的Verilog实现TheVerilogachievementofI2CSerialBusadapter(华南理工大学)林健磊殷瑞祥LINJIANLEIYINRUIXIANG摘要:本文介绍了I2C总线规范,并根据该规范对I2C进行模块化设计,用VerilogHDL语言对每个模块进行具体描述,并通过模块之间的调用,基本实现了I2C的主机从机的发送和接收功能。

关键词:I2C总线;VerilogHDL;模块化设计中图分类号:TN87文献标识码:BAbstract:ThispaperintroducesthestandardofI2CBus,carrysouttheI2Cmodulardesignaccordingtothisstandard,givesthespe-cificdescriptionofeverymoduleinVerilogHDL,bycallingbetweenmodules,achievesthesendingandreceivingfunctionsofI2CMaster/SlaveMachinebasically.Keyword:I2Cbus,VerilogHDL,Modulardesign文章编号:1008-0570(2007)08-2-0043-021引言I2C(Inter-IntegratedCircuit)是由Philip开发的一种简单的双向两线总线。

I2C只要求两条总线路:串行数据线SDA和串行时钟线SCL,来实现有效的IC之间的控制,而且使硬件效益最大而电路最简单。

同时,通过一个CPU的接口来和片上的总线进行数据交换,可以实现对控制寄存器和数据寄存器的读写。

2I2C总线的工作原理2.1.基本结构总线的串行数据(SDA)和串行时钟(SCL)线,在连接到总线的器件间传递信息。

Verilog--SPI协议

Verilog--SPI协议

Verilog--SPI协议Verilog -- SPI协议简介SPI是⼀种全双⼯通信,并且是⼀种同步传输⽅式(slave的接收clk需要master给出)SPI总线是⼀种4线总线,因其硬件功能很强,所以与SPI有关的软件就相当简单,使中央处理器(Central Processing Unit,CPU)有更多的时间处理其他事务。

正是因为这种简单易⽤的特性,越来越多的芯⽚集成了这种通信协议,⽐如AT91RM9200。

SPI是⼀种⾼速、⾼效率的串⾏接⼝技术。

通常由⼀个主模块和⼀个或多个从模块组成,主模块选择⼀个从模块进⾏同步通信,从⽽完成数据的交换。

SPI是⼀个环形结构,通信时需要⾄少4根线(事实上在单向传输时3根线也可以)。

SPI的通信原理很简单,它以主从⽅式⼯作,这种模式通常有⼀个主设备和⼀个或多个从设备,需要⾄少4根线,事实上3根也可以(单向传输时)。

也是所有基于SPI的设备共有的,它们是MISO(主设备数据输⼊)、MOSI(主设备数据输出)、SCLK(时钟)、CS(⽚选)。

(1)MISO– Master Input Slave Output,主设备数据输⼊,从设备数据输出;(2)MOSI– Master Output Slave Input,主设备数据输出,从设备数据输⼊;(3)SCLK – Serial Clock,时钟信号,由主设备产⽣;(4)CS – Chip Select,从设备使能信号,由主设备控制。

其中,CS是从芯⽚是否被主芯⽚选中的控制信号,也就是说只有⽚选信号为预先规定的使能信号时(⾼电位或低电位),主芯⽚对此从芯⽚的操作才有效。

这就使在同⼀条总线上连接多个SPI设备成为可能。

(以上来⾃百度百科)SPI最⼤传输速率SPI是⼀种事实标准,由Motorola开发,并没有⼀个官⽅标准。

已知的有的器件SPI已达到50Mbps。

具体到产品中SPI的速率主要看主从器件SPI控制器的性能限制。

串行器verilog代码

串行器verilog代码

串行器verilog代码串行器(Serializer)是一种电子设备,用于将并行数据转换为串行数据,以便在单个通道上进行传输。

以下是一个简单的串行器的 Verilog 代码示例:verilogmodule Serializer (input wire clk, // 时钟信号input wire reset, // 复位信号input wire [7:0] parallel_data, // 并行数据输入output reg serial_data // 串行数据输出);reg [2:0] shift_reg; // 移位寄存器,用于存储并行数据的位reg [2:0] count; // 计数器,用于控制移位寄存器的移位次数always @(posedge clk or posedge reset) beginif (reset) begin// 当复位信号为高电平时,将计数器和移位寄存器清零count <= 0;shift_reg <= 0;serial_data <= 0;end else beginif (count == 3'd7) begin// 当计数器达到最大值时,将并行数据的最低位存入移位寄存器,并将计数器清零shift_reg <= {parallel_data[0], shift_reg[2:1]};count <= 0;end else begin// 否则,将移位寄存器向左移动一位,并将计数器加1shift_reg <= {shift_reg[1:0], serial_data};count <= count + 1;end// 将移位寄存器的最低位作为串行数据输出serial_data <= shift_reg[0];endendendmodule需要注意的是,上述代码中的计数器 count 用于控制移位寄存器的移位次数,当计数器达到最大值时,将并行数据的最低位存入移位寄存器,并将计数器清零。

基于FPGA的串口通信电路设计

基于FPGA的串口通信电路设计

基于FPGA的串口通信电路设计[摘要]串行通信接口是一种应用广泛的通信接口。

目前,大部分处理器都集成了支持rs-232接口的通用异步收发器,本文基于fpga开发板设计了一个串口数据采集和处理程序,介绍了用verilog hdl硬件描述语言来开发波特率发生器、接收模块和发送模块这三个模块,以及系统各个模块的具体设计方法和原理,用quartus ii软件进行仿真并给出结果,分别验证各个模块的正确性及用fpga实现串行通信的可行性。

[关键词]串行通信 rs-232 verilog hdl fpga中图分类号:tn 文献标识码:a 文章编号:1009-914x(2013)08-320-011.fpga概述fpga现场可编程逻辑门阵列是数字系统设计的主要硬件平台,其主要特点是完全由用户通过软件进行配置和编程,从而完成某种特定的功能,且可以反复擦写。

fpga具有运算速度快、根据需求在内部嵌入硬/软ip核,以及反复编程,擦写,使用的特点,被广泛应用于通信,数字信号处理,工业控制等领域。

2.rs232串口通信接口串口即串行数据接口主要用于网管控制或主业务数据的传输,支持数据的双向传输,速率9600-115200bps,即可以完成和pc的通信,也可以完成与带有标准串口的外设相连。

其中串口接口分为带插孔和带插针的两种,其中插针端称为dce,插孔端称为dte。

3.串口通信的verilog hdl实现本设计要求在fpga开发板上实现波特率为115200bps,停止位为1比特、1比特校验位的串口通信,并要求和pc机通过串口调试助手完成双向通信。

3.1波特率发生器模块的verilog hdl实现波特率发生器实际上是一个分频器,从给定的系统时钟频率得到要求的波特率。

一般来讲,为了提高系统的容错性处理,要求波特率发生器的输出时钟为实际串口数据波特率的n倍,n可以取值为8、16、32、64等。

在本设计中,系统的时钟为50mhz,取n为16,则分频系数为50000000/(16*115200)=27.127,取整为27。

verilog编程实例

verilog编程实例

verilog编程实例我们需要明确这个电路的功能和设计要求。

假设我们需要实现一个4位二进制加法器,即输入两个4位的二进制数,输出它们的和。

为了简化问题,我们先考虑只有无符号整数的加法,即只需要实现两个正整数的相加。

接下来,我们可以使用Verilog语言来描述这个电路的结构和行为。

我们首先声明输入端口和输出端口的位宽,即4位。

然后,我们定义一个module,命名为"binary_adder"。

在这个module中,我们定义了两个4位的输入信号a和b,以及一个4位的输出信号sum。

同时,我们还定义了一个内部信号carry,用于记录进位信息。

在module的主体部分,我们使用assign语句来实现信号之间的逻辑关系。

具体地,我们可以通过逐位相加的方式,将输入信号a和b的每一位与进位carry相加,并将结果存储在输出信号sum的对应位上。

同时,我们还需要更新进位carry的值,以确保加法运算的正确性。

为了实现这个逻辑,我们可以使用Verilog中的加法运算符"+"和逻辑与运算符"&"。

通过对输入信号的每一位进行逐位运算,我们可以得到输出信号sum的每一位的值。

同时,我们还需要根据输入信号和进位carry的值,计算出新的进位carry的值。

在实际的Verilog编程中,我们需要注意信号的声明和赋值的顺序。

一般而言,我们需要先声明信号,然后再通过assign语句对信号进行赋值。

这样可以确保信号的值能够正确传递和计算。

完成Verilog代码的编写后,我们需要使用相应的仿真工具来验证电路的功能。

常用的仿真工具有ModelSim和Xilinx ISE等。

通过仿真工具,我们可以为输入信号a和b设置不同的值,并观察输出信号sum的变化。

通过比较输出信号sum和预期的结果,我们可以验证电路的正确性。

除了验证电路的正确性外,我们还可以通过综合工具将Verilog代码转换成对应的门级电路。

板级通信总线之SPI及其Verilog实现

板级通信总线之SPI及其Verilog实现

板级通信总线之SPI及其Verilog实现打算写⼏篇专题,系统总结下常⽤的⽚上总线、现场总线,就先从最常⽤的SPI开始吧。

1. SPI是⼲什么的?除了SPI还有那些其它电路板及的通讯总线?有何差别?相信接触过MCU的同学对SPI都不陌⽣,详细定义就不罗嗦了。

SPI常⽤的场合包括ADC读写、存储芯⽚读写、MCU间通讯等等。

可以⼀主多从(通过⽚选来选择Slave),也可以做成菊花链等等形式的拓扑。

与SPI类似的总线还有IIC、UART等,甚⾄还有很多单根线的总线,原理都是基于简单的串⾏通信,区别在于收发时序和连接拓扑。

要熟练使⽤这些总线,关键在于理解其时序图,在此基础上创造各种变种的总线形式也不是难事(当然为了设计的通⽤性不建议这么做)。

以下维基百科的SPI词条介绍⾮常全⾯,推荐阅读。

2. SPI是什么样的?在此借⽤⼀张维基百科上的图,SPI通常有4根线,SS⽤于选定当前通信的slave,SCLK为通信的基准时钟,采样/发送都在时钟边沿执⾏,MOSI、MISO为串⾏的数据线。

以下是⼀个典型的SPI时序图,Master和Slave均在时钟上升沿采样,下降沿发送数据。

数据从最⾼位(MSB)开始发送。

需要注意图中所有的时序关系都要被满⾜,包括CS下降沿到第1个时钟上升沿间隔(t sclk_su)、数据的建⽴时间(t SU)、保持时间(t HD)等等。

通常这些参数由具体的器件决定,如果不满⾜则有通信失败的风险。

3. 如何使⽤SPI?SPI有哪⼏种配置模式(相位、极性)?根据SPI时钟信号的空闲状态、是上升沿采样还是下降沿采样,SPI有四种模式。

CPOL=0表⽰时钟空闲时为低电平,反之为⾼电平;CPHA=0表⽰时钟信号第⼀个边沿是采样边沿,反之表⽰第2个边沿是采样边沿。

对于带SPI接⼝的MCU⽽⾔,通常可由软件配置CPOL(Clock Polarity)、CPHA(Clock Phase),以适应和不同类型器件的通信。

Verilog实现串口通信

Verilog实现串口通信

FPGA实现串行接口RS232时间:2007-06-29 来源: 作者: 点击:26463 字体大小:【大中小】-串行接口(RS-232)串行接口是连接FPGA和PC机的一种简单方式。

这个项目向大家展示了如果使用FPGA来创建RS-232收发器。

整个项目包括5个部分RS232是怎样工作的如何产生需要的波特率发送模块接收模块应用实例RS-232接口是怎样工作的作为标准设备,大多数的计算机都有1到2个RS-232串口。

特性RS-232有下列特性:使用9针的"DB-9"插头(旧式计算机使用25针的"DB-25"插头).允许全双工的双向通讯(也就是说计算机可以在接收数据的同时发送数据).最大可支持的传输速率为10KBytes/s.DB-9插头你可能已经在你的计算机背后见到过这种插头它一共有9个引脚,但是最重要的3个引脚是:引脚2: RxD (接收数据).引脚3: TxD (发送数据).引脚5: GND (地).仅使用3跟电缆,你就可以发送和接收数据.串行通讯数据以每次一位的方式传输;每条线用来传输一个方向的数据。

由于计算机通常至少需要若干位数据,因此数据在发送之前先“串行化”。

通常是以8位数据为1组的。

先发送最低有效位,最后发送最高有效位。

异步通讯RS-232使用异步通讯协议。

也就是说数据的传输没有时钟信号。

接收端必须有某种方式,使之与接收数据同步。

对于RS-232来说,是这样处理的:串行线缆的两端事先约定好串行传输的参数(传输速度、传输格式等)当没有数据传输的时候,发送端向数据线上发送"1"每传输一个字节之前,发送端先发送一个"0"来表示传输已经开始。

这样接收端便可以知道有数据到来了。

开始传输后,数据以约定的速度和格式传输,所以接收端可以与之同步每次传输完成一个字节之后,都在其后发送一个停止位("1")让我们来看看0x55是如何传输的:0x55的二进制表示为:01010101。

Verilog的双向IO口的实现(

Verilog的双向IO口的实现(

Verilog的双向IO口的实现(最近有一个项目要用到FPGA,还要用硬件描述语言综合出一个双向IO口用作地址数据总线。

一直没能够实现,在实验过程中遇到了或这或那的问题,终于在今天有所突破!能够正确的读写CAN控制芯片SJA1000的测试寄存器。

在试验中也总结了一些东西,如下:1、Inout口,一般要放在最顶层的V文件中,我试验过放到下面的v文件中,没能够成功(更正一下:inout并非一定要在最顶层,也可以在底层设置。

具体可参见黑金开发板建模篇实验13 DS1302实时时钟驱动。

)。

2、在一个module中,可以将输出定义为reg型,然后直接与要驱动module的wire型输入相连,没有问题。

3、在调试程序的过程中,尽量借助于工具,如quartus内部的Signal Tap。

之前一直不会使用,现在也在慢慢学习。

用来模拟的是intel模式的总线读写其时序图如下:代码包括下面的及部分:can_top.vmodule can_top(CLK,RSTn,Row_scan,Column_scan,can_pin,can_ALE,can_WR,can_RD,can_CS,can_dir,can_rst_out);input CLK;input RSTn;output [7:0] Row_scan; output [1:0] Column_scan; inout [7:0] can_pin;output can_ALE;output can_WR;output can_RD;output can_CS;output can_dir;output can_rst_out;wire [7:0] data_in;wire rmd;wire wmd;wire [7:0] adr;wire [7:0] data_tx;wire [7:0] data_rx;wire rd_flag;wire wr_flag;trans_control U3(.CLK(CLK),.RSTn(RSTn),.data_in(data_in),.Row_scan(Row_scan),.Column_scan(Column_scan) ); wire can_rst;can_ctr U1(.CLK(CLK),.RSTn(RSTn),.rd_flag(rd_flag),.wr_flag(wr_flag),.data_rx(data_rx),.data_display(data_in), .rmd(rmd), .wmd(wmd),.adr(adr),.data_tx(data_tx),.can_rst(can_rst));can_op U2(.CLK(CLK),.RSTn(RSTn),.can_rst_in(can_rst),.rmd(rmd),.wmd(wmd),.adr(adr),.data_tx(data_tx),.can_in(can_in_temp),.en_out(en_out),.can_out(can_out),.read_cmd(read_cmd),.data_rx(data_rx),.can_ALE(can_ALE),.can_WR(can_WR),.can_RD(can_RD),.can_CS(can_CS),.can_dir(can_dir),.rd_flag(rd_flag),.wr_flag(wr_flag),.can_rst_out(can_rst_out));wire en_out;wire [7:0] can_out;// wire [7:0] can_in;reg [7:0] can_in_temp;wire read_cmd;always @ ( posedge CLK or negedge RSTn )beginif(!RSTn)can_in_temp<=8'b1000_1001;elsebeginif(read_cmd==1'b1)can_in_temp <= can_pin;endend// assign can_in = can_in_temp;assign can_pin = (en_out==1'b1)?can_out:8'bZZZZZZZZ; //双向口设置endmodulecan_ctr.vmodule can_ctr(CLK,RSTn,rd_flag,data_rx,data_display,rmd,wmd,adr,data_tx,can_rst);input CLK;input RSTn;input rd_flag;input wr_flag;input [7:0] data_rx;output [7:0] data_display;output rmd;output wmd;output [7:0] adr;output [7:0] data_tx;output can_rst;reg [7:0] data_display_temp;reg rmd_temp;reg wmd_temp;reg [7:0] adr_temp;reg [7:0] data_tx_temp;reg can_rst_temp;reg rst_flag;parameter TS = 26'd29_999_999; parameter T1S = 26'd49_999_999;always @ ( posedge CLK or negedge RSTn )if(!RSTn)begincan_rst_temp<=1'b1;rst_flag<=1'b1;endelse if (Count_Sec==26'd100 && rst_flag == 1'b1) begin can_rst_temp<=1'b0;rst_flag<=1'b0;endendalways @ ( posedge CLK or negedge RSTn )beginif(!RSTn)beginrmd_temp<=1'b0;wmd_temp<=1'b0;adr_temp<=8'b0000_0000;data_display_temp<= 8'b1000_1000;data_tx_temp<=8'b0000_0000;endelsebeginif (Count_Sec==TS)beginwmd_temp<=1'b1;adr_temp<=8'b0001_0000;data_tx_temp<=8'b0001_0010;endif (Count_Sec==T1S)rmd_temp<=1'b1;adr_temp<=8'b0001_0000; //读测试寄存器endif (wr_flag==1'b1)beginwmd_temp<=1'b0;endif (rd_flag==1'b1)beginrmd_temp<=1'b0;data_display_temp<= data_rx;endendendreg [25:0]Count_Sec;always @ ( posedge CLK or negedge RSTn ) if( !RSTn )Count_Sec <= 26'd0;else if( Count_Sec == T1S )Count_Sec <= 26'd0;elseCount_Sec <= Count_Sec + 1'b1;assign data_display=data_display_temp; assign rmd=rmd_temp;assign wmd=wmd_temp;assign adr=adr_temp;assign data_tx=data_tx_temp;assign can_rst=can_rst_temp;endmodulecan_op.vmodule can_op (CLK,RSTn,can_rst_in, rmd,wmd,adr,data_tx,can_in,en_out,can_out,read_cmd,data_rx,can_ALE,can_WR,can_RD,can_CS,can_dir,rd_flag,wr_flag,can_rst_out);input CLK;input RSTn; input can_rst_in; input rmd;input wmd; input [7:0]adr; input [7:0]data_tx;input [7:0]can_in;output en_out;output [7:0] can_out;output read_cmd;output [7:0]data_rx;output can_ALE;output can_WR;output can_RD;output can_CS;output can_dir;output rd_flag;output wr_flag;output can_rst_out;reg [7:0] can_out_temp;reg en_out_temp; //这两个变量来组成双向口输出控制reg read_cmd_temp;reg [7:0] data_rx_temp;reg can_ALE_temp;reg can_WR_temp;reg can_RD_temp;reg can_CS_temp;reg can_dir_temp;reg rd_flag_temp;reg wr_flag_temp;reg [3:0] count;always @ ( posedge CLK or negedge RSTn ) beginif ( !RSTn )beginrd_flag_temp<=1'b0;wr_flag_temp<=1'b0;can_WR_temp<=1'b1;can_RD_temp<=1'b1;can_CS_temp<=1'b1;can_dir_temp<=1'b0;data_rx_temp<=8'd221;count<= 4'd0;en_out_temp<=1'b1;can_out_temp<=8'd0;read_cmd_temp<=1'b0;endelsebeginif (rmd)begincase(count)4'd0,4'd1,4'd6: count<= count+1'b1; 4'd2: begincan_out_temp<= adr;en_out_temp<=1'b1;can_ALE_temp<= 1'b1;count<= count+1'b1;end4'd3:begincan_ALE_temp<=1'b0;count<= count+1'b1;end4'd4:begincan_CS_temp<= 1'b0;en_out_temp<=1'b0; end4'd5:begincan_RD_temp<= 1'b0; can_dir_temp=1'b1; count<= count+1'b1; end4'd7:beginread_cmd_temp<=1'b1; count<= count+1'b1; end4'd8:begincount<= count+1'b1; read_cmd_temp<=1'b0; end4'd9:begindata_rx_temp <= can_in; can_RD_temp<= 1'b1; count<= count+1'b1; can_dir_temp <= 1'b0; en_out_temp<=1'b1; end4'd10:begincan_CS_temp<= 1'b1;rd_flag_temp<=1'b1;end4'd11:begincount<=4'd0;rd_flag_temp<=1'b0;endendcaseendif (wmd)begincase(count)4'd0,4'd1: count<= count+1'b1; 4'd2: begincan_out_temp<= adr;en_out_temp<=1'b1;can_ALE_temp<= 1'b1;count<= count+1'b1;end4'd3:begincan_ALE_temp<=1'b0;count<= count+1'b1;end4'd4:begincan_CS_temp<= 1'b0;count<= count+1'b1;endbegincan_WR_temp<= 1'b0; count<= count+1'b1; end4'd6:begincan_out_temp<= data_tx; count<= count+1'b1; end 4'd7:begincount<= count+1'b1; end4'd8:begincan_WR_temp<= 1'b1; count<= count+1'b1; end4'd9:begincan_CS_temp<= 1'b1; can_ALE_temp<=1'b1; count<= count+1'b1;wr_flag_temp<=1'b1; end4'd10:begincount<= 1'b0;wr_flag_temp<=1'b0; end endcaseendendassign data_rx=data_rx_temp;assign can_ALE=can_ALE_temp;assign can_WR=can_WR_temp;assign can_RD=can_RD_temp;assign can_CS=can_CS_temp;assign can_dir=can_dir_temp;assign wr_flag=wr_flag_temp;assign rd_flag=rd_flag_temp;assign can_rst_out=can_rst_in;assign can_out=can_out_temp;assign en_out=en_out_temp;assign read_cmd=read_cmd_temp;endmoduletrans_control.v 这个与下面两个v文件是用来将接收到的数据显示到数码管上module trans_control(CLK,RSTn,data_in,Row_scan,Column_scan);input CLK;input RSTn;input [7:0] data_in;output [7:0] Row_scan;output [1:0] Column_scan;wire [7:0] data1_temp;wire [7:0] data2_temp;trans_module U1(.CLK (CLK),.RSTn (RSTn),.data_in (data_in),.out_data1 (data1_temp), .out_data2 (data2_temp) );scan_module U2(.CLK (CLK),.RSTn (RSTn),.scan_data1 (data1_temp), .scan_data2 (data2_temp), .Row_scan (Row_scan),.Column_scan (Column_scan) );endmoduletrans_module.vmodule trans_module(CLK,RSTn,data_in,out_data1,out_data2);input CLK;input RSTn;input [7:0] data_in;output [7:0] out_data1; output [7:0] out_data2;reg [7:0] out_data1_temp; reg [7:0] out_data2_temp;reg [3:0] temp1;reg [3:0] temp2;parameter _0 = 8'b1100_0000, _1 = 8'b1111_1001, _2 = 8'b1010_0100, _3 = 8'b1011_0000, _4 = 8'b1001_1001, _5 = 8'b1001_0010, _6 = 8'b1000_0010, _7 = 8'b1111_1000, _8 = 8'b1000_0000,_9 = 8'b1001_0000, _A = 8'b1000_1000, _B = 8'b1000_0011, _C = 8'b1100_0110, _D = 8'b1010_0001, _E = 8'b1000_0100, _F = 8'b1000_1110;always @ ( posedge CLK or negedge RSTn )if( !RSTn )beginout_data1_temp<= 8'b1100_0000;out_data2_temp<= 8'b1100_0000;temp1 <= 4'd0;temp2 <= 4'd0;endelsebegintemp1 <= data_in[3:0];temp2 <= data_in[7:4];case(temp1)4'h0 : out_data1_temp <= _0;4'h1 : out_data1_temp <= _1;4'h2 : out_data1_temp <= _2;4'h3 : out_data1_temp <= _3;4'h4 : out_data1_temp <= _4;4'h5 : out_data1_temp <= _5;4'h6 : out_data1_temp <= _6;4'h7 : out_data1_temp <= _7;4'h8 : out_data1_temp <= _8;4'h9 : out_data1_temp <= _9;4'hA : out_data1_temp <= _A;4'hB : out_data1_temp <= _B;4'hC : out_data1_temp <= _C;4'hD : out_data1_temp <= _D;4'hE : out_data1_temp <= _E;4'hF : out_data1_temp <= _F; endcasecase(temp2)4'h0 : out_data2_temp <= _0;4'h1 : out_data2_temp <= _1;4'h2 : out_data2_temp <= _2;4'h3 : out_data2_temp <= _3;4'h4 : out_data2_temp <= _4;4'h5 : out_data2_temp <= _5;4'h6 : out_data2_temp <= _6;4'h7 : out_data2_temp <= _7;4'h8 : out_data2_temp <= _8;4'h9 : out_data2_temp <= _9;4'hA : out_data2_temp <= _A;4'hB : out_data2_temp <= _B;4'hC : out_data2_temp <= _C;4'hD : out_data2_temp <= _D;4'hE : out_data2_temp <= _E;4'hF : out_data2_temp <= _F; endcaseendassign out_data1 = out_data1_temp; assign out_data2 = out_data2_temp;endmodulescan_module.vmodule scan_module(CLK,RSTn,scan_data1,scan_data2,Column_scan,Row_scan);input CLK;input RSTn;input [7:0] scan_data1;input [7:0] scan_data2;output [7:0] Row_scan;output [1:0] Column_scan;parameter T10MS = 19'd499_999;//50M*0.01-1=499_999 reg [18:0]Count1;always @ ( posedge CLK or negedge RSTn )if( !RSTn )Count1 <= 19'd0;else if( Count1 == T10MS )Count1 <= 19'd0;elseCount1 <= Count1 + 19'b1;reg [1:0]t;always @ ( posedge CLK or negedge RSTn )if( !RSTn )t <= 2'd0;else if( t == 2'd2 )t <= 2'd0;else if( Count1 == T10MS )t <= t + 1'b1;reg [7:0] Row_scan_temp;reg [1:0] Column_scan_temp;always @ ( posedge CLK or negedge RSTn )if( !RSTn )beginColumn_scan_temp <= 2'b01;Row_scan_temp <= 8'hd0;endelse if( Count1 == T10MS )case( t )2'd0 : begin Column_scan_temp <= 2'b01; Row_scan_temp <= scan_data1; end 2'd1 : begin Column_scan_temp <= 2'b10; Row_scan_temp <= scan_data2; end endcaseassign Column_scan = Column_scan_temp;assign Row_scan = Row_scan_temp;endmodule代码就这些,还有TCL引脚说明#------------------GLOBAL--------------------#set_global_assignment -name RESERVE_ALL_UNUSED_PINS "AS INPUT TRI-STATED" set_global_assignment -name ENABLE_INIT_DONE_OUTPUT OFF#复位引脚set_location_assignment PIN_M1 -to RSTn#时钟引脚set_location_assignment PIN_R9 -to CLK#数码管对应的引脚set_location_assignment PIN_M8 -to Row_scan[0] set_location_assignment PIN_L7 -to Row_scan[1] set_location_assignment PIN_P9 -to Row_scan[2] set_location_assignment PIN_N9 -to Row_scan[3] set_location_assignment PIN_M9 -to Row_scan[4] set_location_assignment PIN_M10 -to Row_scan[5] set_location_assignment PIN_P11 -to Row_scan[6] set_location_assignment PIN_N11 -to Row_scan[7] set_location_assignment PIN_N8 -to Column_scan[0] set_location_assignment PIN_P8 -to Column_scan[1] #CAN控制信号对应引脚set_location_assignment PIN_R1 -to can_pin[0]set_location_assignment PIN_R3 -to can_pin[1]set_location_assignment PIN_L3 -to can_pin[2]set_location_assignment PIN_K5 -to can_pin[3]set_location_assignment PIN_P3 -to can_pin[4]set_location_assignment PIN_L8 -to can_pin[5]set_location_assignment PIN_N5 -to can_pin[6]set_location_assignment PIN_K6 -to can_pin[7]set_location_assignment PIN_L6 -to can_ALEset_location_assignment PIN_T3 -to can_WRset_location_assignment PIN_L4 -to can_RDset_location_assignment PIN_N3 -to can_CSset_location_assignment PIN_T2 -to can_dirset_location_assignment PIN_P2 -to can_rst_out。

iic协议--Verilog及仿真

iic协议--Verilog及仿真

iic协议--Verilog及仿真1、协议原理:IIC(Inter-Integrated Circuit),i2c总线由数据线sda和时钟线scl这两条构成的串⾏总线,主机和从机可以在i2c总线上发送和接收数据。

scl时钟线作为控制,sda则包含有ack、nack、设备地址、字节地址、8bits数据。

起始信号(scl为⾼电平时,sda变成低电平)与结束信号(scl为⾼电平时,sda变成⾼电平)的状态:IIC单字节写时序有两种:1字节地址段器件单字节写时序、2字节地址段器件单字节写时序。

IIC单字节读时序有两种:1字节地址段器件单节读时序、2字节地址段器件单节读时序字节地址⾼三位xxx:这⾥使⽤的EEPROM的存储容量只有8192bits(1024bits*8)=210*23=213,所以16位的字节地址就多余了三位。

2、协议代码:1、这⾥实现的是2字节单次读写。

2、开始和结束时,虽然scl为⾼电平,sda仍要变化;接下来传输字节,scl为低电平,sda才能变化。

这⾥采取在scl⾼电平和低电平中线产⽣标志。

3、通过状态机来实现读写。

综合代码:module IIC_AT24C64(input sys_clk,input sys_rst_n,input iic_en,input [2:0]cs_bit,//可编程地址input [12:0]byte_address,//字节地址input write,input read,input [7:0]write_data,output reg[7:0]read_data,output reg scl,inout sda,output reg done);parameterSYS_CLK=50_000_000,//系统时钟50MHzSCL_CLK=200_000;//scl时钟200KHzreg [7:0]scl_cnt;//时钟计数parameter div_cnt=SYS_CLK/SCL_CLK;always @(posedge sys_clk or negedge sys_rst_n)beginif(!sys_rst_n)scl_cnt<=8'd0;else if(scl_cnt == div_cnt-1'b1)scl_cnt<=8'd0;elsescl_cnt<=scl_cnt+1'b1;end//⽣成scl时钟线always @(posedge sys_clk or negedge sys_rst_n)beginif(!sys_rst_n)scl<=1'b1;else if(scl_cnt == (div_cnt>>1)-1'b1)scl<=1'b0;else if(scl_cnt == div_cnt-1'b1)scl<=1'b1;elsescl<=scl;end//scl电平中线reg scl_high_middle;//scl⾼电平中线reg scl_low_middle;//scl低电平中线always @(posedge sys_clk or negedge sys_rst_n)beginscl_high_middle<=1'b0;scl_low_middle<=1'b0;endelse if(scl_cnt == (div_cnt>>2))scl_high_middle<=1'b1;else if(scl_cnt == (div_cnt>>1)+(div_cnt>>2))scl_low_middle<=1'b1;else beginscl_high_middle<=1'b0;scl_low_middle<=1'b0;endendreg [15:0]state;parameteridle=16'd1,//空闲状态w_or_r_start=16'd2,//设备地址device_ADDR=16'd3,//发送ACK1=16'd4,byte_ADDR_high=16'd5,//字节地址⾼8位ACK2=16'd6,byte_ADDR_low=16'd7,//字节地址低8位ACK3=16'd8,w_data=16'd9,//写数据ACK4=16'd10,r_start=16'd11,//读开始device_ADDR_r=16'd12,//设备地址读ACK5=16'd13,r_data=16'd14,//读数据NACK=16'd15,//⾮应答位stop=16'd16;reg sda_en;//sda数据线使能reg sda_reg;//sda数据暂存位reg [7:0]sda_data_out;//sda数据发给从机暂存reg [7:0]sda_data_in;//sda数据取之从机暂存reg [3:0]bit_cnt;//每⼀bitassign sda=sda_en?sda_reg:1'bz;//读写标志位reg w_flag;reg r_flag;always @(posedge sys_clk or negedge sys_rst_n)beginif(!sys_rst_n)beginstate<=idle;w_flag<=1'b0;r_flag<=1'b0;sda_reg<=1'b1;done<=1'b0;sda_en<=1'b0;endelse begincase(state)idle:beginsda_reg<=1'b1;w_flag<=1'b0;r_flag<=1'b0;sda_en<=1'b0;sda_reg<=1'b1;done<=1'b0;if(iic_en && write)beginw_flag<=1'b1;sda_en<=1'b1;sda_reg<=1'b1;state<=w_or_r_start;endelse if(iic_en && read)beginr_flag<=1'b1;sda_en<=1'b1;sda_reg<=1'b1;state<=w_or_r_start;endelsestate<=idle;endw_or_r_start:beginif(scl_high_middle)beginsda_reg<=1'b0;sda_data_out<={4'b1010,cs_bit,1'b0};//在这⾥装好设备地址bit_cnt<=4'd8;state<=device_ADDR;endelse beginsda_reg<=1'b1;state<=w_or_r_start;endenddevice_ADDR:beginif(scl_low_middle)beginsda_reg<=sda_data_out[7];sda_data_out<={sda_data_out[6:0],1'b0};//在这⾥发出设备地址。

CRC算法及Verilog实现

CRC算法及Verilog实现

CRC算法原理及其Verilog实现1CRC简介CRC校验是一种在数据通信系统和其它串行传输系统中广泛使用的错误检测手段。

通用的CRC标准有CRC-8、CRC-16、CRC-32、CRC-CCIT,其中在网络通信系统中应用最广泛的是CRC-32标准。

本文将以CRC-32为例,说明CRC编码的实现方式以及如何用verilog语言对CRC编码进行描述。

2二.模2运算在说明CRC编码方式之前,首先介绍一下模2运算法则,在CRC运算过程中会使用到模2除法运算。

模2运算是一种二进制运算法则,与四则运算相同,模2运算也包括模2加、模2减、模2乘、模2除四种运算。

模2运算用“+”表示加法运算,用“-”、“×”或“.”、“/”分别表示减法、乘法和除法运算。

与普通四则运算法则不同的是,模2加法是不带进位的二进制加法运算,模2减法是不带借位的二进制减法运算。

同时,模2乘法在累加中间结果时采用的是模2加法运算;模2除法求商过程中余数减除数采用的是模2减法运算。

因此,两个二进制数进行模2加减法运算时,相当于两个二进制数进行按位异或运算,每一位的结果只与两个数的当前位有关。

模2除法在确定商时,与普通二进制除法也略有区别。

普通二进制除法中,当余数小于除数时,当前位的商为0,当余数大于等于除数时,当前位的商为1。

模2除法在确定当前位的商时,只关心余数的首位,首位为1则商为1,首位为0则商为0。

1.模2加法的定义:0+0=0,0+1=1,1+0=1,1+1=0。

举例如下:1010+0110=1100。

2.模2减法的定义:0-0=0,0-1=1,1-0=1,1-1=0。

举例如下:1010-0110=1100。

3.模2乘法的定义:0×0=0,0×1=0,1×0=0,1×1=1。

举例如下:1011×101=100111列竖式计算:1011× 101——————101100001011——————100111其中横线之间的累加过程,采用的是2进制加法,不进位。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

串口通讯设计之V e r i l o g实现 Revised as of 23 November 2020串口通讯设计之V e r i l o g实现FPGA串口模块是将由RS-485发送过来的数据进行处理,提取出8位有效数据,并按异步串口通讯的格式要求输出到MAX3223的12脚。

FPGA选用Xilinx公司的SpartanII系列xc2s50。

此部分为该设计的主体。

如上所述,输入数据的传输速率为700k波特率。

为了使FPGA能够正确地对输入数据进行采样,提高分辨率能力和抗干扰能力,采样时钟必须选用比波特率更高的时钟,理论上至少是波特率时钟的2倍。

1 串口通信基本特点随着多微机系统的应用和微机网络的发展,通信功能越来越显得重要。

串行通信是在一根传输线上一位一位地传送信息.这根线既作数据线又作联络线。

串行通信作为一种主要的通信方式,由于所用的传输线少,并且可以借助现存的电话网进行信息传送,因此特别适合于远距离传送。

在串行传输中,通信双方都按通信协议进行,所谓通信协议是指通信双方的一种约定。

约定对数据格式、同步方式、传送速度、传送步骤、纠错方式以及控制字符定义等问题做出统一规定,通信双方必须共同遵守。

异步起止式的祯信息格式为:每祯信息由四部分组成:位起始位。

~8位数据位。

传送顺序是低位在前,高位在后.依次传送。

c.一位校验位,也可以没有。

d.最后是1位或是2位停止位。

FPGA(Field Pmgrammable Gate Array)现场可编程门阵列在数字电路的设计中已经被广泛使用。

这种设计方式可以将以前需要多块集成芯片的电路设计到一块大模块可编程逻辑器件中,大大减少了电路板的尺寸,增强了系统的可靠性和设计的灵活性。

本文详细介绍了已在实际项目中应用的基于FPGA的串口通讯设计。

本设计分为硬件电路设计和软件设计两部分,最后用仿真验证了程序设计的正确性。

2 系统的硬件设计本方案的异步串行通信的硬件接口电路图如图1所示,主要由四部分组成:RS-485数据发送模块、FPGA 串口模块、MAX3223和DB9。

各部分功能简述如下:RS-485数据发送模块是将前续电路的数据发送到FPGA,供本电路处理,亦即本电路的输入。

RS485是符合RS-485和RS-4225串口标准的低功耗半双工收发器件,有和5V两种,在本设计中选用了的器件SP3485。

在本设计中。

485的7脚和8脚与前端信号相连接,用于接收输入的数据。

数据格式是这样的:一帧数据有25位,报头是16个高电平和1个低电平,接下来是 8位有效的数据。

传输速率为700k波特率。

2脚是使能端,与FPGA的I/O口相连,由FPGA提供逻辑控制信号。

1脚和4脚也与FPGA相连,由 FPGA对输入数据进行处理。

FPGA串口模块是将由RS-485发送过来的数据进行处理,提取出8位有效数据,并按异步串口通讯的格式要求输出到MAX3223的12脚。

FPGA选用Xilinx公司的Spartan II系列xc2s50。

此部分为该设计的主体。

如上所述,输入数据的传输速率为700k波特率。

为了使FPGA能够正确地对输入数据进行采样,提高分辨率能力和抗干扰能力,采样时钟必须选用比波特率更高的时钟,理论上至少是波特率时钟的2倍。

在本设计中选用4倍于波特率的时钟,利用这种4倍于波特率的接收时钟对串行数据流进行检测和定位采样,接收器能在一个位周期内采样4次。

如果没有这种倍频关系,定位采样频率和传送波特率相同,则在一个位周期中,只能采样一次,分辨率会差。

比如,为了检测起始位下降沿的出现,在起始位的前夕采样一次之后,下次采样要到起始位结束前夕才进行。

而假若在这个周期期间,因某种原因恰恰使接收时钟往后偏移了一点点,就会错过起始位。

造成整个后面位的检测和识别错误。

针对本设计,FPGA的软件共分了三个模块:1.时钟分频模块。

模块的功能是用来产生所需要的数据采集时钟和数据传输时钟。

系统主频是40M的。

数据采集时钟是2.8M的,发送时钟是。

2. 提取数据模块。

由RS485发送过来的数据共有25位,其中只有8位是有效数据。

为了发送这8位有效数据。

必须先将其提取出来。

提取的办法是这样的:通过连续检测到的16个高电平和一个低电平。

判断8位有效数据的到来。

然后按照串行数据传输的格式,在加上起始位和停止位后,将其存储于输出缓冲寄存器中。

在这里,我们的串行数据输出格式是这样规定的,一位起始位,八位数据位,一位停止位,无校验位。

3.串行数据输出模块。

这一模块相对比较简单,波特率选为,模块的功能是在移位输出脉冲的作用下,将输出缓冲寄存器中的数据移位输出。

MAX3223是实现电平转换的芯片。

由于RS-232c是用正负电压来表示逻辑状态。

与TTL以高低电平表示逻辑状态的规定不同。

因此,为了能够同计算机接口或终端的TTL器件连接,必须在RS-232与TTL电路之间进行电平和逻辑关系的变换。

实现这种变换的方法可用分立元件,也可用集成电路芯片。

MAXIM公司的MAX3223是为满足RS-232c的标准而设计的具有功耗低、波特率高、价格低等优点,外接电容仅为或1uF,为双组 RS232收发器。

由MAX3223的12脚输入的数据,经过电平转换后由8脚输出,再经过DB9的TxD端输出,由PC机接收并做后续处理。

3 系统软件设计FPGA模块是本设计的主体,使用Verilog硬件描述语言进行编写,本段代码共有两个子模块,分别实现提取八位数据和串行数据发送的功能。

下面是verilog源代码module SIMO(din,clk,rst,dout_ser);input din; 4倍于波特率的时钟reg txclk; //发送数据时钟。

发数据取的波特率integer bitpos="7"; //当前位parameters0=0,s1=1,s2=2,s3=3;reg[2:0]state;reg[4:0]counter; //用来计算报头报尾中1的个数reg tag,tag1;reg[2:0]cnt3;reg txdone="1"''''b1;//一个字节数据传输完毕标志*********提取有效数据位并按串行通讯格式装载数据********always@ (posedge nclk or posedge rst) beginif(rst) begin state<=0; counter<=0; tag1=0; tag="0"; indata_buf<=8''''bz; dout_buf<=10''''bz; bitpos="7";cnt3<=0; endelse case(state) s0:begin tag="0";//表示数据没有装好if(din)begincounter<=counter+1;state<=s0;if(counter==15)//如果检测到16个1则转入s1状态检测接下来的是不是0beginstate<=s1;counter<=0;end endelse begincounter<=0;state<=s0;end end s1:if(!din)//如果是0的话,转入s2状态,提取八位有效数据state<=s2; else //否则转到s0状态重新检测state<=s0; s2:if(cnt3==3)//是否采集四次数据begincnt2<=0;indata_buf[bitpos]<=din; //先进来的是高位数据 bitpos="bitpos-1"; if(bitpos==-1)beginbitpos=7;state<=s3;endend else cnt3<=cnt3+1; s3:begintag1=tag;tag=1''''b1; //标志输入寄存器满。

表明已把有用数据装入寄存器if(tag&&~tag1)&&txdone) //检测到tag的上升沿以及txdone为高才把输入缓冲数据放到输出缓冲去dout_buf<={1''''b1,indata_buf[7:0],1''''b0};//停止位,高位,低位,起始位state<=s0; end endcaseend//***********发送数据模块reg[3:0] state_tx=0;txclk or posedge rst)beginif(rst) begindout_ser<=1''''bz;state_tx<=0;txdone=1; endelsecase(state_tx)0:begin dout_ser<=dout_buf[0];state_tx<=state_tx+1;txdone=1''''b0;end 1:begindout_ser<=dout_buf[1];state_tx<=state_tx+1;end 2:begin dout_ser<=dout_buf[2];state_tx<=state_tx+1;end 3:begin dout_ser<=dout_buf[3];state_tx<=state_tx+1;end 4:begin dout_ser<=dout_buf[4];state_tx<=state_tx+1;end 5:begin dout_ser<=dout_buf[5];state_tx<=state_tx+1;end 6:begin dout_ser<=dout_buf[6];state_tx<=state_tx+1;end 7:begin dout_ser<=dout_buf[7];state_tx<=state_tx+1;end 8:begin dout_ser<=dout_buf[8];state_tx<=state_tx+1;end 9:begin dout_ser<=dout_buf[9];state_tx<=state_tx+1;end endcaseendendmodule注:两个频率信号nclk、txclk由相应的分频程序产生。

相关文档
最新文档