Verilog串口通讯设计
基于verilog的很基础的RS232串口收发代码
基于verilog的很基础的RS232串口收发代码写代码,记笔记,防忘记,须牢记。
写串口的Verilog代码关键是要搞明白RS232串口的通信协议,它并不像单片机,直接读写SBUF就可实现串口的收发功能,收发整个字节。
而FPGA要一位一位的收发,因此必须了解RS232的数据格式。
起始位:RS232约定一位起始位“0”。
停止位:约定停止位为“1”。
可选一位或两位停止位。
奇偶校验位:可选。
通过串口发送数据时,要严格遵守RS232的数据格式,先发送起始位,然后是数据,最后是停止位(无奇偶校验的情况)。
通过串口接收数据时,若接收端无数据输入,会一直处于高电平,若开始接收数据,会首先收到来自串口的起始位“0”,然后是要接收的数据,最后为停止位(无奇偶校验的情况)。
所以对于接收模块,可如此设计,FPGA一直检测接收端是否有下降沿到来,直到检测到下降沿,才开始接收数据。
波特率设置的重要性不言而喻,毋庸赘述。
此设计为最基础的串口收发代码,控制逻辑简单,适合编写第一次编写串口代码的朋友。
此设计收发的数据格式为1位起始位,1位停止位,无奇偶校验位,8位数据位。
波特率为19200,代码中可随意更改。
具体Verilog代码如下:顶层模块`timescale 1ns / 1ps/////////////////////////////////////////////////////////////////// /////////////// Company : 杭州电子科技大学// Engineer : 晓晓川// Create Date : 2012.08.26// Design Name : serial_test// Module Name : serial_test// Project Name: serial_test// Target Device: CycloneII EP2C5T144C8// Tool versions: Quartus II 11.0// Revision : V1.0// Description : 一个极为简单的串口收发工程,适于串口收发的入门。
基于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。
【VerilogHDL】Verilog的端口类型以及端口连接规则
【VerilogHDL】Verilog的端⼝类型以及端⼝连接规则Verilog中的端⼝类型 共分为 input、output、和 inout 三种类型,所有的端⼝在声明时默认为 wire 型。
Verilog中的变量类型 reg :本质是存储器,具有寄存功能; net :本质是⼀条没有逻辑的连线(wire);Verilog的端⼝连接规则 端⼝连接规则分为模块描述时和模块调⽤时两种情况。
1、模块描述时 模块描述时在模块内部对模块的端⼝进⾏描述,是从内部⾓度出发,因此将 input 端⼝看作外界引申进来的⼀条线,只能为 net 型变量;同理 inout 端⼝作为有输⼊功能的端⼝,也应该看作 net 型变量。
⽽ output 端⼝被看作模块的输出,既可以直接输出(如组合逻辑),也可以寄存后输出(如时序逻辑),因此 output 端⼝应该设为 reg 型变量。
2、模块调⽤时 模块被调⽤时是在上级模块中对下级模块的例化,描述了其采⽤何种信号与芯⽚(即底层模块)连接,进⾏驱动或得到输出。
此时是从外部⾓度出发,上级模块对下级模块的输⼊既可以想输⼊什么就输⼊什么,也可以想什么时候输⼊就什么时候输⼊,所以 input 端⼝可以为 net/reg 型变量。
⽽ output 端⼝是上级模块对下级模块的被动接收,是下级模块的⼀根输出导线,因此 output 端⼝只能是 net 型变量;同理 inout 端⼝也只能是 net 型变量。
综上所述 模块描述时,input 端⼝只能为 net,output 端⼝可以为 net/reg,inout 端⼝只能为 net; 模块调⽤时,连接模块input端⼝的信号可以为 net/reg 型,连接模块 output 端⼝的信号只能为 net,连接模块 inout 端⼝的信号也只能为 net;。
Verilog实现串口接收多帧数据
Verilog实现串口接收多帧数据`timescale 1ns / 1ps/////////////////////////////////////////////////////////////////// ///////////////// Company:// Engineer://// Create Date: 19:50:45 04/19/2015// Design Name:// Module Name: Serial_Decoder// Project Name:// Target Devices:// Tool versions:// Description://// Dependencies://// Revision:// Revision 0.01 - File Created// Additional Comments:///////////////////////////////////////////////////////////////////// ///////////////module Serial_Decoder(input wire clk_seri, //串口时钟,用于从串口发送命令给FPGA input wire rst,input wire RxD,output reg[1:0] modu_sel, //BPSK,QPSK,8PSK选择output reg[13:0] ser_asf, //由串口发过来的asfoutput reg[31:0] ser_ftw, //由串口发过来的ftwoutput reg cmd_done, //上位机给FPGA发送指令结束output reg[31:0] dina, //ROM存储器,用于存储外部PN码output reg wea,output reg[1:0] addra);reg cmd_rdy;//指令接收完成reg [3:0] instr_code;//用于分辨命令,是asf还是ftw还是外部PN码reg [31:0] cmd_data; //接收从上层发过来的命令wire RxD_data_ready;wire [7:0] RxD_data;reg [1:0] instr_cnt;reg data_rec_valid;reg data_rec_busy;reg [1:0] data_cnt;//instancereceiver i_receiver(.clk(clk_seri),.RxD(RxD),.RxD_data_ready(RxD_data_ready),.RxD_data_error(),.RxD_data(RxD_data));//*********上位机发命令给FPGA************//always @ (posedge clk_seri)beginif(rst)begininstr_cnt <= 0;endelse if(RxD_data_ready && !data_rec_busy) case(instr_cnt)2'd0:if(RxD_data == 8'h55)begininstr_cnt <= 2'd1;data_rec_valid <= 0;endelsebegininstr_cnt <= 2'd0;data_rec_valid <= 0;end2'd1:if(RxD_data == 8'h55)begininstr_cnt <= 2'd2;data_rec_valid <= 0;endelsebegininstr_cnt <= 2'd0;data_rec_valid <= 0;end2'd2:if(RxD_data == 8'h55)begininstr_cnt <= 2'd3;endelsebegininstr_cnt <= 2'd0;data_rec_valid <= 0;end2'd3:if(RxD_data == 8'h55)begininstr_cnt <= 2'd3;data_rec_valid <= 0;endelsebegininstr_cnt <= 2'd0;data_rec_valid <= 1;instr_code <= RxD_data[3:0]; //用来分辨各命令enddefault:begininstr_cnt <= 2'd0;data_rec_valid <= 0;endendcaseelsedata_rec_valid <= 0;endalways @ (posedge clk_seri)beginif(rst)begindata_cnt <= 2'd0;data_rec_busy <= 0;cmd_rdy <= 0;endelse if(data_rec_valid)begindata_cnt <= 0;data_rec_busy <= 1;cmd_rdy <= 0;endelse if(RxD_data_ready && data_rec_busy) case(data_cnt)2'd0:begindata_cnt <= 2'd1;data_rec_busy <= 1;cmd_rdy <= 0;cmd_data[31:24]<= RxD_data;end2'd1:begindata_cnt <= 2'd2;data_rec_busy <= 1;cmd_rdy <= 0;cmd_data[23:16]<= RxD_data;end2'd2:begindata_cnt <= 2'd3;data_rec_busy <= 1;cmd_rdy <= 0;cmd_data[15:8] <= RxD_data; end2'd3:begindata_cnt <= 2'd0;data_rec_busy <= 0;cmd_rdy <= 1; //命令接收完毕cmd_data[7:0] <= RxD_data; enddefault:begindata_cnt <= 2'd0;data_rec_busy <= 0;cmd_rdy <= 0;endendcaseelsecmd_rdy <= 0;end//*********分辨命令*********// always @ (posedge clk_seri) beginif(rst)begincmd_done <= 0;modu_sel <= 0;ser_asf <= 0;ser_ftw <= 0;endelse if(cmd_rdy)begincase(instr_code)4'h6:beginser_ftw <= cmd_data;cmd_done <= 0;end4'h7:beginmodu_sel <= cmd_data[25:24];cmd_done <= 0;end4'h8:beginser_asf <= cmd_data[13:0];cmd_done <= 0;end4'hF:cmd_done <= 1; //上位机命令发送结束default:; endcaseendelsebeginser_ftw <= ser_ftw;ser_asf <= ser_asf;modu_sel<= modu_sel;cmd_done<= cmd_done;endendalways @ (posedge clk_seri)beginif(rst)begindina <= 0;wea <= 1;addra <= 0;endelse if(cmd_rdy)begincase(instr_code)//********A--D是外部PN码,将其存入ROM中********// 4'hA:begindina <= cmd_data;wea <= 1;addra <= 2'd0;end4'hB:begindina <= cmd_data;wea <= 1;addra <= 2'd1;end4'hC:begindina <= cmd_data;wea <= 1;addra <= 2'd2; end4'hD:begindina <= cmd_data; addra <= 2'd3; wea <= 0;enddefault:; endcaseendelsebegindina <= dina; addra <= addra; wea <= wea;endend endmodule。
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 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
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;
FPGA模拟串口自收发-Verilog
实现功能,FPGA 里实现从PC 串口接收数据,接着把接收到的数据发回去。
波特率可选 9600bps,可调1bit 起始位,8bit 数据,1bit 停止位,无校验位。
参考《VHDL 硬件描述语言与和数字逻辑电路设计》模块介绍如下一、串口数据接收模块: 特别注意一个数据位占 4个clk_bps_4时钟周期。
串口数据接收控制当数据接收端rxd 出现起始位低电平,启动接收控制计数器rx_cnt,置位为 8' b0111_00(28),即 rx_cnt[5:2]== 4 ' b0111(7),rx_cnt[1:0]== 2'b00(0); —个计数周期开始,伴随clk_bps_4, rx_cnt 加1 (每一个数据位加 4) 串口接收数据移位控制(关键采样点的选取)每当rx_cnt[1:0] == 2'b01, 为了保证在 rxd 一位数据靠近中间位置采样;每 4个 clk_bps_4, rx_cnt[5:2] 力口 1 当 rx_cnt[5:2] == 8,9,10….15,完成 8 位的数据采样,串并变换置位标志位rxdF 数据接收标志rxd 出现起始位低电平,rxdF 置1 ,表示数据接收开始;当rx_cnt 计数到rxdflk reserr<scido hichF1 fr冲'豔K/ tt/ L J弃L--XrdbLLLCLK RESETI rrpset|EMPTY8'b1111_11( 63), 数据接收完成,rxdF 置0置位标志位rdFULL; 5,完成一位起始位,8 位的数据位发送,随后txd 置1(停止位),完成并串转换置位标志位txdF ,tdEMPTY st_n(rst_n),.clk_bps_4(clk_bps_4),.wr(wr),.tdEMPTY(tdEMPTY),.DATA(DATA),.txd(txd));st_n(rst_n),.clk_bps_4(clk_bps_4),.rd(rd),.rdFULL(rdFULL),.do_latch(do_latch),.rxd(rxd));/* 针对9600bps ,生成的时钟信号,用于接收数据采样与数据发送*/ Baudrate baud(.clk(clk),.rst_n(rst_n), .clk_bps_4(clk_bps_4));Endmodule串口数据接收模块:module Uart_RX(rst_n, clk_bps_4, rd, rdFULL, do_latch, rxd);input rst_n; // 低电平复位input clk_bps_4; //4 倍于波特率时钟信号即一个数据位占4 个时钟周期input rd;// 接收使能, 低电平有效output reg[7:0] do_latch;// 接收数据锁存output reg rdFULL;// 接收锁存器满标志input rxd;// 串口引脚输入reg[7:0] data_r = 8'bx; // 接收数据寄存器reg[5:0] rx_cnt;reg rxdF;// 数据接收标志,RX模块内部信号/* 当数据接收端rxd 出现起始位低电平,启动接收控制计数器rx_cnt, 置位为b0111_00(28),8'即rx_cnt[5:2]== 4 'b0111(7),rx_cnt[1:0] == 2'b00(0);一个计数周期开始,伴随clk_bps_4, rx_cnt 加1(每一个数据位加4) */ always@(posedgeclk_bps_4 or negedge rst_n)beginif(!rst_n)begin rx_cnt <= 0; endelse if(rx_cnt <= 27 && rxd == 0)begin rx_cnt <= 28; endelse if(rx_cnt <= 27 && rxd == 1)// 串口无数据时,rx_cnt 保持0 begin rx_cnt <= 0;endelsebegin rx_cnt <= rx_cnt + 1;endend/* 空闲时rdFULL 置0,当数据接收完成,数据锁存到do_latch,同时rdFULL置1,向上层模块表示数据以准备0K可以来读取;rd 置0, 表示上层模块开始读取数据,rdFULL 置0,表示数据已读走*/ always@(posedgeclk_bps_4 or negedge rst_n)// 置位标志位rdFULL beginif(!rst_n)begin rdFULL <= 0; endelse if(rd == 0)begin rdFULL <= 0; endelse if(rxdF == 1 && rx_cnt == 63)begindo_latch <= data_r;// 数据锁存rdFULL <= 1;// 锁存器数据准备0Kendend/*rxd 出现起始位低电平, rxdF 置1 ,表示数据接收开始;当rx_cnt计数到8' b1111_11(63),数据接收完成,rxdF置0* always@(posedge clk_bps_4 or negedge rst_n)// 置位标志位rxdFendcaseend endmodule串口数据发送模块:module Uart_TX(rst_n, clk_bps_4,wr,tdEMPTY, DATA, txd); input rst_n; // 低电平复位 input clk_bps_4; //4 倍于波特率时钟信号 input [7:0]DATA;beginif(!rst_n)begin rxdF <= 0; endelse if(rxd == 0)// 拉低表示有数据来begin rxdF <= 1;endelse if(rxdF == 1 && rx_cnt == 63)begin rxdF <= 0;endend/* 每当 rx_cnt[1:0] == 2'b01, 每 4 个 clk_bps_4, rx_cnt[5:2] 串并变换 */ always@(posedge clk_bps_4)// beginif( rx_cnt[1:0] == 2'b01 )case(rx_cnt[5:2]) //4'd7:rxd==0; 起始位 4'd8:data_r[0] <= rxd;// 4'd9:data_r[1] <= rxd;// 4'd10:data_r[2] <= rxd;// 4'd11:data_r[3] <= rxd;// 4'd12:data_r[4] <= rxd;// 4'd13:data_r[5] <= rxd;// 4'd14:data_r[6] <= rxd;// 4'd15:data_r[7] <= rxd;//为了保证在 力口 1 当rx_cnt[5:2]数据接收rxd 一位数据靠近中间位置采样 ; ==8,9,10…15,完成8位的数据采样,低第 1 位 第 2 位 第 3 位 第 4 位 第5位 第 6 位 第 7 位 高第 8 位input wr;// 发送使能信号output reg tdEMPTY;// 发送寄存器空标志对外输出output txd;// 串口引脚输出reg txdF;// 发送完成标志模块内部信号reg txd_r; // 发送寄存器reg[7:0] din_latch;// 发送数据锁存reg[5:0] tx_cnt;// 发送计数器/* 空闲时wr 置1,数据发送时wr 产生低电平脉冲,wr 上升沿将数据锁存到din_latch;*/ always@(posedge wr)begin//din_latch <= 8'hAB; din_latch <= DATA;end/*wr 由0 跳变为1 后,启动发送控制计数器tx_cnt, 置位为8'b0111_00(28), 即tx_cnt[5:2]== 4 'b0111(7), tx_cnt[1:0] == 2'b00(0);一个计数周期开始,伴随clk_bps_4, tx_cnt 加1(每一个数据位加4) */always@(posedge clk_bps_4 or negedge rst_n) beginif(!rst_n)begin tx_cnt <= 0; endelse if(tx_cnt <= 27)beginif(tdEMPTY == 0 && wr == 1)begin tx_cnt <= 28;endelse begin tx_cnt <= 0; endendelsebegin tx_cnt <= tx_cnt + 1;endend/*当写数据到发送寄存器din_latch 时,txdF , tdEMPTY置0;当tx_cnt 计数到8' b1111_11(63),数据发送完成,txdF , tdEMPTY置1; */ always@(posedge clk_bps_4 or negedge rst_n)beginif(!rst_n)begintxdF <= 1;tdEMPTY <= 1;endelse if(wr == 0)begintxdF <= 0;tdEMPTY <= 0;endelse if(txdF == 0 && tx_cnt == 63)begintxdF <= 1; tdEMPTY <= 1;endend/* 每4 个clk_bps_4, tx_cnt[5:2] 力口1 当tx_cnt[5:2] ==7,8,9,10 …15,完成一位起始位,8位的数据位发送,随后txd 置1(停止位) ,完成并串转换*/ always@(posedge clk_bps_4 or negedge rst_n)if(!rst_n)begintxd_r <= 1;endelsebegincase(tx_cnt[5:2])4'd7:txd_r <= 1'b0; // 起始位04'd8:txd_r <= din_latch[0]; // 低第1 位4'd9:txd_r <= din_latch[1]; // 第2位4'd10:txd_r <= din_latch[2];// 第3位4'd11:txd_r <= din_latch[3];// 第4位4'd12:txd_r <= din_latch[4];// 第5位4'd13:txd_r <= din_latch[5];// 第6位4'd14:txd_r <= din_latch[6];// 第7位4'd15:txd_r <= din_latch[7];// 高第 8 位 default:txd_r <= 1; endcase endassign txd = txd_r; endmodule波特率发生模块:/* 针对 9600bps ,生成 4 倍于波特率的时钟信号,用于采样 */ module Baudrate(clk, rst_n,clk_bps_4); input clk; // 时钟周期 50MHzinput rst_n; // 低电平复位reg clk_bps_4;always@(posedge clk or negedge rst_n) beginif(!rst_n) begin clk_bps_4 <= 0; bps_cnt <= 0;end elsebeginif(bps_cnt == N/2 - 1)begin clk_bps_4 <= ~clk_bps_4; bps_cnt <= 0;end elsebegin bps_cnt <= bps_cnt + 1;end endend endmoduleoutput clk_bps_4; //时钟信号 9600*4 reg [12:0] bps_cnt; // parameter N=1302;//波特率产生时计数 分频系数 9600bpsModelsim 仿真波形图:rxd 端输入数据 01010101 , txd 发送01010101 'i LUU'JUITJ J..ULU If.'UU- J LLbllJUJ Jlf_ L L_LLUUJllUL.LLUlllniL j.jiirjuJJUJuuLuirjiiiiiiiniLL'UU'.J J ipunnLiii 2 LJ^,ULX5tl hrjuEJumninnrLuiJiJui JirjinmfjujnLWTnimfnr TTTD 】门丁q■■nr '1 tfejarli danaj U.-UmJlfiLLfUlTJUlJ ja —i 暫主诞OfnEMJini'jinjrL'ULrjiLri I 咼岂巫:HS3E 1SS«二.■UITJXJ ifL :ui^.:jioiwwirjinr. i连接PC 串口助手。
串口通讯设计之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;由输入输出波形图可以看出:本段程序实现了对输入数据的有效数据位的提取,并按照一定的波特率进行串行输出;程序中,波特率可以根据需要通过分频程序进行改动;硬件电路搭建简单,程序代码书写容易;数据传输稳定可靠,可以满足串口通信的要求;。
基于Verilog HDL的信号处理板卡中双向端口的设计
文章编号:1002—8692(2008)S1-0062-03基于V er i l og H D L的信号处理板卡中双向端口的设计术实用设计陈美燕.王丹(西南交通大学电子信息科学与技术学院,四川成都610031)【摘要J选用X i l i n x的V i r t ex--4芯片和11公司C6000的D SP—TM S320C6713,设计一个高速信号(采集)处理板,介绍了其系统构成和各模块的逻辑框图。
应用V er i l og H D L语言对双向端口进行了描述。
同时给出仿真初始化双向端口的方法。
【关键词】双向端口;FPG A;D SP处理器;V er i l og H D L语言【中图分类号】T N911.22【文献标识码】AD es i gn of I,o PO r t B a se d o n V er i l og H D L i n Si gn al Pr oces s i ng B oa r dC H EN M ei-yan,W A N GD an(Sch ool of I n f or m at i o n Sci e nce&T ec hnol ogy,Sor t hwest J i aot o ng U ni vers渺,Chengh610031,C hi n a)【A bs t ra ct】Sel e ct i ng X i l i nx V i r t ex-4chi p,and Texas I ns t r um ent s c om pa ny7s C6000D SP-1M S320C6713,a hi gh-spee d s i g nal (c ol l ec t i on)pr oc ess i ng boa r d i s de si gne d i n t hi s pa pe r,i nt r oduc i ng i t s sys t em co nst i t ut es,a8w el l a8t he di a gr am of t he l ogi c m odul es.I/O pert i s de scr i bed by V er i l og H D L。
verilog语言及程序设计
verilog语言及程序设计Verilog语言及程序设计什么是Verilog语言?Verilog是一种硬件描述语言(HDL),用于描述数字系统的行为和结构。
它最初是由Gateway Design Automation公司(现在是Cadenza Design Automation公司的一部分)于1984年开发的,用于模拟和验证集成电路设计。
Verilog不仅可以用于模拟和验证电路设计,还可以用于编写可综合的硬件描述。
可综合的硬件描述可以通过合成工具转换成实际的硬件电路,在FPGA(现场可编程门阵列)和ASIC(应用特定集成电路)中实现。
Verilog的应用领域Verilog广泛应用于数字系统的设计、验证和实现。
它可以用于设计各种数字电路,包括处理器、存储器、通信接口、数字信号处理器等。
Verilog还被用于编写可综合的程序,用于验证电路设计的正确性。
Verilog的基本语法Verilog语言的基本语法与C语言类似,包括模块定义、端口声明、信号声明、组合逻辑、时序逻辑等。
下面是一个简单的Verilog模块的例子:verilogmodule MyModule (input wire clk,input wire rst,input wire in_data,output wire out_data);reg [7:0] reg1;always (posedge clk or posedge rst) beginif (rst)reg1 <= 8'b0;elsereg1 <= reg1 + in_data;endassign out_data = reg1;endmodule上面的例子定义了一个名为`MyModule`的Verilog模块,有4个端口:`clk`(时钟),`rst`(复位),`in_data`(输入数据),`out_data`(输出数据)。
其中的`reg1`是一个8位的寄存器,使用时序逻辑进行更新。
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)线,在连接到总线的器件间传递信息。
《FPGA设计与应用》实验指导书全(Verilog版)
《FPGA设计与应用》实验指导书某某编武汉理工大学华夏学院2011年9月前言一、实验课目的数字电路与系统设计实验课是电子工程类专业教学中重要的实践环节,包括了ISE开发环境基本操作及FPGA的基本原理、基带传输系统的设计、Uart串口控制器电路的设计、PS/2接口的设计、VGA显示接口设计。
要求学生通过实验学会正确使用EDA技术,掌握FPGA器件的开发,熟练使用ISE开发环境,掌握Verilog语言的编程,掌握数字电路和系统的设计。
通过实验,使学生加深对课堂专业教学内容的理解,培养学生理论联系实际的能力,实事求是,严谨的科学作风,使学生通过实验结果,利用所学的理论去分析研究EDA技术。
培养学生使用Basys 2开发板的能力以及运用实验方法解决实际问题的能力。
二、实验要求:1.课前预习①认真阅读实验指导书,了解实验内容;②认真阅读有关实验的理论知识;③读懂程序代码。
2.实验过程①按时到达实验室;②认真听取老师对实验内容及实验要求的讲解;③认真进行实验的每一步,观察程序代码与仿真结果是否相符;④将实验过程中程序代码和仿真结果提交给老师审查;⑤做完实验后,整理实验设备,关闭实验开发板电源、电脑电源后方可离开。
3.实验报告①按要求认真填写实验报告书;②认真分析实验结果;③按时将实验报告交给老师批阅。
三、实验学生守则1.保持室内整洁,不准随地吐痰、不准乱丢杂物、不准大声喧哗、不准吸烟、不准吃东西;2.爱护公务,不得在实验桌及墙壁上书写刻画,不得擅自删除电脑里面的文件;3.安全用电,严禁触及任何带电体的裸露部分,严禁带电接线和拆线;4.任何规章或不按老师要求操作造成仪器设备损坏须论价赔偿。
目录实验一Uart通用串口接口的设计 (4)实验二PS/2接口的设计 (28)实验三VGA显示接口设计 (30)附录一 basys 2开发板资料 (36)实验一 Uart串口控制接口电路的设计一、实验目的1.掌握分频模块的设计方法。
毕业设计——基于FPGA的RS-422串口通信软件设计与调试.doc
五、主要参考书及参考资料
【1】林灶生,刘绍汉. V erilog FPGA 芯片设计. 北京:北京航空航天大学出版社,2006.
【2】王冠,黄熙,王鹰. Verilog HDL 与数字电路设计. 北京:机械工业出版社,2006.
【3】俞一鸣,唐薇,陈正茂. Altera可编程逻辑器件的应用与设计. 北京:机械工业出版社,2007.
【4】RS-232和RS-422串口资料:由互联网获得.
学生_____________ 指导老师_____________ 系主任_____________
毕业
任务书
一、题目
基于FPGA的RS-422串口通信软件设计与调试
二、指导思想和目的要求
通过毕业设计,使学生掌握RS-232和RS-422串行通信的基本原理与电路设计的基本方法,掌握用VHDL语言编制串行通信程序的基本技能,调试出正确的串行通信软件。
并通过哦设计与调试等实践环节,提高学生综合运用所学知识去分析问题、解决问题的能力。
三、主要技术指标
掌握RS-232和RS-422串行通信的基本原理与电路设计的基本方法
完成RS-422串行通信程序的设计与调试
完成16位计数器程序的设计与调试
四、进度和要求
03~04周:完成翻译,查找、消化有关设计资料
05~06周:掌握串行通信的基本原理
07~08周:掌握用FPGA设计数字电路的方法
09~10周:完成16位计数器电路的设计与调试
11~12周:完成RS-422串行通信程序的设计与调试
13~14周:撰写毕业设计
15~16周:答辩。
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代码串行器(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的串口通信电路设计[摘要]串行通信接口是一种应用广泛的通信接口。
目前,大部分处理器都集成了支持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实现FPGA作为从机与STM32进行SPI协议通信
FPGA作为从机与STM32进行SPI协议通信Verilog实现一.SPI协议简要介绍SPI,是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接口。
SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议。
SPI总线是Motorola公司推出的三线同步接口,同步串行3线方式进行通信:一条时钟线SCK,一条数据输入线MOSI,一条数据输出线MISO;用于 CPU 与各种外围器件进行全双工、同步串行通讯。
SPI主要特点有:可以同时发出和接收串行数据;可以当作主机或从机工作;提供频率可编程时钟;发送结束中断标志;写冲突保护;总线竞争保护等。
SPI总线有四种工作方式(SP0, SP1, SP2, SP3),其中使用的最为广泛的是SPI0和SPI3方式。
SPI模块为了和外设进行数据交换,根据外设工作要求,其输出串行同步时钟极性和相位可以进行配置,时钟极性(CPOL)对传输协议没有重大的影响。
如果CPOL=0,串行同步时钟的空闲状态为低电平;如果CPOL=1,串行同步时钟的空闲状态为高电平。
时钟相位(CPHA)能够配置用于选择两种不同的传输协议之一进行数据传输。
如果 CPHA=0,在串行同步时钟的第一个跳变沿(上升或下降)数据被采样;如果CPHA=1,在串行同步时钟的第二个跳变沿(上升或下降)数据被采样。
SPI主模块和与之通信的外设时钟相位和极性应该一致。
以下是SPI时序图:主要讲解一下广泛使用的两种方式设置:SPI0方式:CPOL=0,CPHA=0;SCK空闲状态为低电平,第一个跳变沿(上升沿)采样数据,无论对Master还是Slaver都是如此。
SPI3方式:CPOL=1,CPHA=1;SCK空闲状态为高电平,第二个跳变沿(上升沿采样数据,无论对Master还是Slaver都是如此。
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电路模块的端口描述
verilog电路模块的端口描述Verilog电路模块的端口描述在Verilog语言中,模块是电路设计的基本单元。
模块定义了电路的功能和接口,其中端口描述了模块与外部环境的交互方式。
本文将围绕Verilog电路模块的端口描述展开讨论,介绍常见的端口类型和其功能。
一、输入端口(Input Port)输入端口用于接收外部信号输入到模块中,以供模块内部进行处理。
输入端口通常用于接收控制信号、数据信号等。
例如,一个简单的输入端口描述如下:input reg clk;input [7:0] data_in;在上述描述中,input关键字表示该端口为输入端口,reg关键字表示该端口是一个寄存器类型的信号。
clk是一个时钟信号,data_in 是一个8位的数据输入端口。
二、输出端口(Output Port)输出端口用于将模块内部处理的结果输出到外部环境中。
输出端口通常用于输出计算结果、状态信号等。
例如,一个简单的输出端口描述如下:output reg [7:0] data_out;在上述描述中,output关键字表示该端口为输出端口,reg关键字表示该端口是一个寄存器类型的信号。
data_out是一个8位的数据输出端口。
三、双向端口(Inout Port)双向端口可以实现输入和输出的双向传输。
它可以在一个时钟周期内既作为输入端口接收信号,又作为输出端口输出信号。
例如,一个简单的双向端口描述如下:inout [7:0] data_io;在上述描述中,inout关键字表示该端口为双向端口。
data_io是一个8位的双向数据端口,可以同时作为输入和输出。
四、时钟端口(Clock Port)时钟端口用于接收时钟信号,是数字电路设计中非常重要的一个端口。
时钟信号用于同步电路中的时序操作。
例如,一个简单的时钟端口描述如下:input reg clk;在上述描述中,input关键字表示该端口为输入端口,reg关键字表示该端口是一个寄存器类型的信号。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
1 串口通信基本特点随着多微机系统的应用和微机网络的发展,通信功能越来越显得重要。
串行通信是在一根传输线上一位一位地传送信息.这根线既作数据线又作联络线。
串行通信作为一种主要的通信方式,由于所用的传输线少,并且可以借助现存的电话网进行信息传送,因此特别适合于远距离传送。
在串行传输中,通信双方都按通信协议进行,所谓通信协议是指通信双方的一种约定。
约定对数据格式、同步方式、传送速度、传送步骤、纠错方式以及控制字符定义等问题做出统一规定,通信双方必须共同遵守。
异步起止式的祯信息格式为:每祯信息由四部分组成:a.1位起始位。
b.5~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串口标准的低功耗半双工收发器件,有3.3V和5V两种,在本设计中选用了3.3V的器件SP3485。
SP3485的内部结构示意图如图2所示在本设计中。
485的7脚和8脚与前端信号相连接,用于接收输入的数据。
数据格式是这样的:一帧数据有25位,报头是16个高电平和1个低电平,接下来是 8位有效的数据。
传输速率为700k波特率。
2脚是使能端,与FPGA的I/O口相连,由FPGA提供逻辑控制信号。
1脚和4脚也与FPGA相连,由 FPGA对输入数据进行处理。
图1异步串行通信硬件接口功能框图图2 SP3485的内部结构示意图FPGA串口模块是将由RS-485发送过来的数据进行处理,提取出8位有效数据,并按异步串口通讯的格式要求输出到MAX3223的12脚。
FPGA选用Xilinx 公司的Spartan II系列xc2s50。
此部分为该设计的主体。
如上所述,输入数据的传输速率为700k波特率。
为了使FPGA能够正确地对输入数据进行采样,提高分辨率能力和抗干扰能力,采样时钟必须选用比波特率更高的时钟,理论上至少是波特率时钟的2倍。
在本设计中选用4倍于波特率的时钟,利用这种4倍于波特率的接收时钟对串行数据流进行检测和定位采样,接收器能在一个位周期内采样4次。
如果没有这种倍频关系,定位采样频率和传送波特率相同,则在一个位周期中,只能采样一次,分辨率会差。
比如,为了检测起始位下降沿的出现,在起始位的前夕采样一次之后,下次采样要到起始位结束前夕才进行。
而假若在这个周期期间,因某种原因恰恰使接收时钟往后偏移了一点点,就会错过起始位。
造成整个后面位的检测和识别错误。
针对本设计,FPGA的软件共分了三个模块: 1.时钟分频模块。
模块的功能是用来产生所需要的数据采集时钟和数据传输时钟。
系统主频是40M的。
数据采集时钟是2.8M的,发送时钟是11.2k。
2. 提取数据模块。
由RS485发送过来的数据共有25位,其中只有8位是有效数据。
为了发送这8位有效数据。
必须先将其提取出来。
提取的办法是这样的:通过连续检测到的16个高电平和一个低电平。
判断8位有效数据的到来。
然后按照串行数据传输的格式,在加上起始位和停止位后,将其存储于输出缓冲寄存器中。
在这里,我们的串行数据输出格式是这样规定的,一位起始位,八位数据位,一位停止位,无校验位。
3.串行数据输出模块。
这一模块相对比较简单,波特率选为11.2k,模块的功能是在移位输出脉冲的作用下,将输出缓冲寄存器中的数据移位输出。
MAX3223是实现电平转换的芯片。
由于RS-232c是用正负电压来表示逻辑状态。
与TTL以高低电平表示逻辑状态的规定不同。
因此,为了能够同计算机接口或终端的TTL器件连接,必须在RS-232与TTL电路之间进行电平和逻辑关系的变换。
实现这种变换的方法可用分立元件,也可用集成电路芯片。
MAXIM公司的MAX3223是为满足RS-232c的标准而设计的具有功耗低、波特率高、价格低等优点,外接电容仅为0.1uF或1uF,为双组 RS232收发器。
由MAX3223的12脚输入的数据,经过电平转换后由8脚输出,再经过DB9的TxD端输出,由PC机接收并做后续处理。
3 系统软件设计FPGA模块是本设计的主体,使用Verilog硬件描述语言进行编写,本段代码共有两个子模块,分别实现提取八位数据和串行数据发送的功能。
下面是verilog 源代码module SIMO(din,clk,rst,dout_ser);input din; //串行输入数据input clk; //时钟信号input vat; 复位信号reg[7:0] indata_buf; //输入缓冲寄存器,存提取的有效位reg[9:0] dout_buf; //输出缓冲寄存器,加了起停位output reg dout_ser; //串行数据输出reg nclk; //提取八位有效数据的采样时钟.是4倍于波特率的时钟reg txclk; //发送数据时钟。
发数据取11.2k的波特率integer bitpos="7"; //当前位parameter s0=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)beginstate<=0;counter<=0;tag1=0;tag="0";indata_buf<=8'bz;dout_buf<=1 0'bz;bitpos="7";cnt3<=0;endelse case(state)s0:begintag="0";//表示数据没有装好if(din)begincounter<=counter+1;state<=s0;if(counter==15)//如果检测到16个1则转入s1状态检测接下来的是不是0beginstate<=s1;counter<=0;endendelse begincounter<=0;state<=s0;endends1: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;endendelsecnt3<=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;endendcaseend//***********发送数据模块reg[3:0] state_tx=0;always@(posedge txclk or posedge rst)beginif(rst)begindout_ser<=1'bz;state_tx<=0;txdone=1;endelsecase(state_tx)0: begindout_ser<=dout_buf[0];state_tx<=state_tx+1;txdone=1'b0;end1:begindout_ser<= dout_buf[1];state_tx<=state_tx+1;end2:begindout_ser<=dout_buf[2];state_tx<=state _tx+1;end3:begindout_ser<=dout_buf[3];state_tx<=state_tx+1;end4:begindout_ser<=d out_buf[4];state_tx<=state_tx+1;end5:begindout_ser<=dout_buf[5];state_tx<=state_ tx+1;end6:begindout_ser<=dout_buf[6];state_tx<=state_tx+1;end7:begindout_ser<=do ut_buf[7];state_tx<=state_tx+1;end8:begindout_ser<=dout_buf[8];state_tx<=state_t x+1;end9:begindout_ser<=dout_buf[9];state_tx<=state_tx+1;endendcaseendendmodule 注:两个频率信号nclk、txclk由相应的分频程序产生。
由于篇幅所限未在文中列出。
FPGA 模块接收从RS-485发送过来的串行数据。
25位为一个字符。
数据的传输速率是700kbps,用四倍于波特率的速率进行采样,这样可以大大降低系统的噪声。
数据的串行输出波特率选为11200bps。
由输入输出波形图可以看出:本段程序实现了对输入数据的有效数据位的提取,并按照一定的波特率进行串行输出。