串口通信:是一种通用串行数据传输总线,可以实现全双工传输。是一种很常见的通信协议,此次写的程序在基于rs-232通信协议,以前在单片机里也用C51语言写过它的驱动程序,不过现在是用Verilog语言来写它的驱动程序,一种全新的思维模式来驱动它,和单片机大不一样。
//程序功能:在上位机(串口调试助手)上发送数据给下位机(PFGA), //下位机接收到数据后,控制LED灯亮灭,并且以原数据返回给上位机; module uart_top ( clk, rst_n, rs232_rx, rs232_tx, led ); input clk; //系统时钟,50MZH; input rst_n; //复位信号,低电平有效; input rs232_rx; //RS232数据接收信号; output rs232_tx; //RS232数据发送信号; output [3:0] led; //LED 灯; wire bps_start1, bps_start2; //接收到数据后,波特率时钟信号启动位; 1:启动;0:停止; wire clk_bps1,clk_bps2; //波特率时钟; wire rx_done ; //数据接收完毕信号,接收到数据期间始终为高电平; wire[7:0] rx_data; //接收数据寄存器; speed_select speed_rx //波特率选择接收模块; ( .clk(clk), .rst_n(rst_n), .bps_start(bps_start1), .clk_bps(clk_bps1) ); uart_rx uart_rx //串口接收模块; ( .clk(clk), .rst_n(rst_n), .clk_bps(clk_bps1), .rs232_rx(rs232_rx), .bps_start(bps_start1), .rx_done(rx_done), .rx_data(rx_data), .led(led) ); speed_select speed_tx // 波特率选择发送模块; ( .clk(clk), .rst_n(rst_n), .bps_start(bps_start2), .clk_bps(clk_bps2) ); uart_tx uart_tx ( .clk(clk), .rst_n(rst_n), .clk_bps(clk_bps2), .rx_done(rx_done), .rx_data(rx_data), .bps_start(bps_start2), .rs232_tx(rs232_tx) ); endmodule module speed_select ( clk, rst_n, bps_start, clk_bps ); input clk; //系统时钟,50MZH; input rst_n; //复位信号,低电平有效; input bps_start; // 接收到数据后,波特率时钟信号启动位; 1:启动;0:停止; output clk_bps; //波特率时钟; wire clk; wire rst_n; wire bps_start; wire clk_bps; parameter BPS =5207; //波特率为9600bps的分频计数值; (10_0000_0000/9600)ns/20ns=5208 parameter BPS_2=2603; //波特率为9600bps的一半,用于采样; reg [15:0] cnt; always @ (posedge clk or negedge rst_n) begin if(!rst_n) cnt<=16'd0; else if((!bps_start)||(cnt==BPS)) cnt<=16'd0; else cnt<=cnt+1'b1; end reg clk_bps_r; always @ (posedge clk or negedge rst_n) begin if(!rst_n) clk_bps_r<=1'b0; else if(cnt==BPS_2) //clk_bps_r 高电平时为接收数据位的中间采样点,同时也作为发送数据的数据改变点; clk_bps_r<=1'b1; else clk_bps_r<=1'b0; end assign clk_bps=clk_bps_r; endmodule module uart_rx //接收模块,注:接收和发送是相对于下位机而言的; ( clk, rst_n, clk_bps, rs232_rx, bps_start, rx_done, rx_data, led ); input clk; //系统时钟:50MHZ; input rst_n; //复位信号,低电平有效; input clk_bps; //波特率时钟; input rs232_rx; //RS232数据接收信号; output bps_start; //接收到数据后,波特率时钟信号启动位; 1:启动;0:停止; output rx_done; //数据接收完毕信号,接收到数据期间始终为高电平; output[7:0] rx_data; //接收数据寄存器; output[3:0] led; reg rs232_rx0; always @ (posedge clk or negedge rst_n) begin if(!rst_n) rs232_rx0<=1'b0; else rs232_rx0<=rs232_rx; end reg rs232_rx1; always @ (posedge clk or negedge rst_n) begin if(!rst_n) rs232_rx1<=1'b0; else rs232_rx1<=rs232_rx0; end wire neg_rs232_rx; assign neg_rs232_rx=rs232_rx1&(~rs232_rx0); //当rs232_rx有1变到0时,说明起始位有效,开始启动串口接收; reg bps_start_r; reg rx_done; reg [3:0] num; always @ (posedge clk or negedge rst_n) begin if(!rst_n) begin bps_start_r<=1'bz; rx_done<=1'b0; end else if(neg_rs232_rx) begin bps_start_r<=1'b1; //启动串口准备接收数据; rx_done<=1'b1; //接收数据中断信号时能 end else if(num==4'd12) //接收完一帧数据; begin bps_start_r<=1'b0; //数据接收完毕,释放波特率启动信号; rx_done<=1'b0; //数据接收完毕,接收数据中断信号关闭; end end assign bps_start=bps_start_r; reg[7:0] rx_data_r; reg[7:0] rx_temp_data; always @ (posedge clk or negedge rst_n) begin if(!rst_n) begin rx_data_r<=8'b0; num<=4'd0; rx_temp_data<=8'b0; end else if(rx_done) //接收数据处理; begin if(clk_bps) //读取并保存数据,接收数据为:一个起始位,8bit数据,1或2个结束位; begin num<=num+1'b1; case(num) 4'h1 : rx_temp_data[0]<=rs232_rx; 4'h2 : rx_temp_data[1]<=rs232_rx; 4'h3 : rx_temp_data[2]<=rs232_rx; 4'h4 : rx_temp_data[3]<=rs232_rx; 4'h5 : rx_temp_data[4]<=rs232_rx; 4'h6 : rx_temp_data[5]<=rs232_rx; 4'h7 : rx_temp_data[6]<=rs232_rx; 4'h8 : rx_temp_data[7]<=rs232_rx; default: ; endcase end else if(num==4'd12) begin num<=4'd0; //接收到stop位后结束,num清0; rx_data_r<=rx_temp_data; //把数据锁存到数据寄存器rx_data_r中 end end end assign rx_data=rx_data_r; assign led=rx_data_r[3:0]; endmodule module uart_tx //发送模块,注:接收和发送是相对于下位机而言的 ( clk, rst_n, clk_bps, rx_done, rx_data, bps_start, rs232_tx ); input clk; input rst_n; input clk_bps; input rx_done; input[7:0] rx_data; output bps_start; output rs232_tx; reg rx_done0; always @ (posedge clk or negedge rst_n) begin if(!rst_n) rx_done0<=1'h0; else rx_done0<=rx_done; end reg rx_done1; always @ (posedge clk or negedge rst_n) begin if(!rst_n) rx_done1<=1'h0; else rx_done1<=rx_done0; end wire neg_rx_done; assign neg_rx_done=rx_done1&(~rx_done0); reg bps_start_r; reg[7:0] tx_data; //发送数据寄存器; reg tx_en; //发送使能信号; reg[3:0] num; always @(posedge clk or negedge rst_n) begin if(!rst_n) begin bps_start_r<=1'bz; tx_en<=1'b0; tx_data<=8'd0; end else if(neg_rx_done) begin bps_start_r<=1'b1; //当rx_dnoe有1变为0时,表示接收数据已完毕,开始发送数据; tx_data<=rx_data; tx_en<=1'b1; end else if(num==4'd11) begin bps_start_r<=1'b0; tx_en<=1'b0; end end assign bps_start=bps_start_r; reg rs232_tx_r; always @ (posedge clk or negedge rst_n) begin if(!rst_n) begin rs232_tx_r<=1'b1; num<=4'd0; end else if(tx_en) begin if(clk_bps) begin num<=num+1'b1; case(num) 4'h0 : rs232_tx_r<=1'h0; //发送起始位; 4'h1 : rs232_tx_r<=tx_data[0]; 4'h2 : rs232_tx_r<=tx_data[1]; 4'h3 : rs232_tx_r<=tx_data[2]; 4'h4 : rs232_tx_r<=tx_data[3]; 4'h5 : rs232_tx_r<=tx_data[4]; 4'h6 : rs232_tx_r<=tx_data[5]; 4'h7 : rs232_tx_r<=tx_data[6]; 4'h8 : rs232_tx_r<=tx_data[7]; 4'h9 : rs232_tx_r<=1'b1; //发送结束位; default: rs232_tx_r<=1'b1; endcase end else if(num==4'd11) num=4'd0; end end assign rs232_tx=rs232_tx_r; endmodule