首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

Verilog编写的Uart程序

Verilog编写的Uart程序

串口通信是目前比较重要的一种通信方式,主要是用于计算机和外部的通信。
    程序思想:(本程序主要是采用特权同学视频教程的程序,本人只是做一个简单的思路总结)
           1. 通过ISE开发工具,新建4个模块,分别为串口接收波特率产生模块,串口接收模块,串口发送波特率产生模块,串口接收模块,另外再加一个顶层模块。
          2. 顶层模块中只是做模块的声明和端口声明,不做任何的逻辑处理。
          3. 波特率产生模块(两个模块都一样):主要是通过计数来实现波特率产生,并对数据进行采样。此处采用9600bps,由于1s中有104166个us,系统时钟为50M,即20us,即需要计数为104166/20=5208,因此循环计数0~5207,并且在计数到2603时对数据进行采样。
         4. 串口接收模块:当接收到接收信号置位时,对数据进行采集。
         5. 串口发送模块:当接收到发送信号置位时,对数据进行发送。
    具体程序如下:
/=============================顶层模块=====================================
module uart_top(clk,,rst_n,rs232_rx,rs232_tx,led);
input clk;    //时钟信号50M
input rst_n;   //复位信号,低有效
input rs232_rx;  //数据输入信号
output rs232_tx;  //数据输出信号
output [7:0] led;

wire bps_start1,bps_start2;//
wire clk_bps1,clk_bps2;
wire [7:0] rx_data;   //接收数据存储器,用来存储接收到的数据,直到下一个数据接收
wire rx_int;     //接收数据中断信号,接收过程中一直为高,

///////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////子模块端口申明///////////////////////////////////
speed_select_rx     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),
         .bps_start(bps_start1),
         .clk_bps(clk_bps1),
         .rs232_rx(rs232_rx),
         .rx_data(rx_data),
         .rx_int(rx_int),
         .led(led)
        );

speed_select_tx  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),
         .bps_start(bps_start2),
         .clk_bps(clk_bps2),
         .rs232_tx(rs232_tx),
         .rx_data(rx_data),
         .rx_int(rx_int)        
        );

endmodule
/=================================波特率产生模块=====================================

module speed_select_rx(clk,rst_n,bps_start,clk_bps);//波特率设定
input clk;   //50M时钟
input rst_n;  //复位信号
input bps_start; //接收到信号以后,波特率时钟信号置位,当接收到uart_rx传来的信号以后,模块开始运行
output clk_bps; //接收数据中间采样点,

// `define BPS_PARA 5207;//9600波特率分频计数值
// `define BPS_PARA_2 2603;//计数一半时采样

reg[12:0] cnt;//分频计数器
reg clk_bps_r;//波特率时钟寄存器

reg[2:0] uart_ctrl;//波特率选择寄存器

always @(posedge clk or negedge rst_n)
  if(!rst_n)
   cnt<=13'd0;
  else if((cnt==5207)|| !bps_start)//判断计数是否达到1个脉宽
   cnt<=13'd0;
  else
   cnt<=cnt+1'b1;//波特率时钟启动
   
always @(posedge clk or negedge rst_n) begin
  if(!rst_n)
   clk_bps_r<=1'b0;
  else if(cnt== 2603)//当波特率计数到一半时,进行采样存储
   clk_bps_r<=1'b1;
  else
   clk_bps_r<=1'b0;
end
assign clk_bps = clk_bps_r;//将采样数据输出给uart_rx模块
endmodule
//================================数据接收模块==========================================

module uart_rx(
     clk,
     rst_n,
     bps_start,
     clk_bps,
     rs232_rx,
     rx_data,
     rx_int,
     led
     );
input clk;   //时钟
input rst_n;  //复位
input rs232_rx; //接收数据信号
input clk_bps;  //高电平时为接收信号中间采样点
output bps_start; //接收信号时,波特率时钟信号置位
output [7:0] rx_data;//接收数据寄存器
output rx_int;  //接收数据中断信号,接收过程中为高
output [7:0] led;
reg [7:0] led;
reg rs232_rx0,rs232_rx1,rs232_rx2,rs232_rx3;//接收数据寄存器
wire neg_rs232_rx;//表示数据线接收到下沿

always @(posedge clk or negedge rst_n) begin
  if(!rst_n) begin
   rs232_rx0 <= 1'b0;
   rs232_rx1 <= 1'b0;
   rs232_rx2 <= 1'b0;
   rs232_rx3 <= 1'b0;
  end
  
  else begin
   rs232_rx0 <= rs232_rx;
   rs232_rx1 <= rs232_rx0;
   rs232_rx2 <= rs232_rx1;
   rs232_rx3 <= rs232_rx2;
  end
end

assign neg_rs232_rx = rs232_rx3 & rs232_rx2 & ~rs232_rx1 & ~rs232_rx0;//串口传输线的下沿标志
reg bps_start_r;
reg [3:0] num;//移位次数
reg rx_int;  //接收中断信号

always @(posedge clk or negedge rst_n)
  if(!rst_n) begin
   bps_start_r <=1'bz;
   rx_int <= 1'b0;
  end
  else if(neg_rs232_rx) begin//
  bps_start_r <= 1'b1;  //启动串口,准备接收数据
   rx_int <= 1'b1;   //接收数据中断使能
  end
  else if(num==4'd12) begin //接收完有用的信号,
   bps_start_r <=1'b0;  //接收完毕,改变波特率置位,方便下次接收
   rx_int <= 1'b0;   //接收信号关闭
  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)
   if(!rst_n) begin
     rx_temp_data <= 8'd0;
     num <= 4'd0;
     rx_data_r <= 8'd0;
   end
   else if(rx_int) begin //接收数据处理
    if(clk_bps) begin
     num <= num+1'b1;
     case(num)
       4'd1: rx_temp_data[0] <= rs232_rx;
       4'd2: rx_temp_data[1] <= rs232_rx;
       4'd3: rx_temp_data[2] <= rs232_rx;
       4'd4: rx_temp_data[3] <= rs232_rx;
       4'd5: rx_temp_data[4] <= rs232_rx;
       4'd6: rx_temp_data[5] <= rs232_rx;
       4'd7: rx_temp_data[6] <= rs232_rx;
       4'd8: rx_temp_data[7] <= rs232_rx;
       default: ;
     endcase
     led <= rx_temp_data;
    end
    else if(num==4'd12) begin
     num <= 4'd0;   //数据接收完毕
     rx_data_r <= rx_temp_data;
    end         
   end
  assign rx_data = rx_data_r;
endmodule
//=================================数据发送模块=========================================

module uart_tx(
     clk,
     rst_n,
     bps_start,
     clk_bps,
     rs232_tx,
     rx_data,
     rx_int
    );


input clk;
input rst_n;
input clk_bps;//中间采样点
input [7:0] rx_data;//接收数据寄存器
input rx_int;//数据接收中断信号
output rs232_tx;//发送数据信号
output bps_start;//发送信号置位

reg rx_int0,rx_int1,rx_int2;//信号寄存器,捕捉下降沿
wire neg_rx_int;    //下降沿标志

always @(posedge clk or negedge rst_n) begin
  if(!rst_n) begin
   rx_int0 <= 1'b0;
   rx_int1 <= 1'b0;
   rx_int2 <= 1'b0;
  end
  else begin
    rx_int0 <= rx_int;
    rx_int1 <= rx_int0;
    rx_int2 <= rx_int1;
  end
end

  assign neg_rx_int = ~rx_int1 & rx_int2;//捕捉下沿
  
  reg [7:0] tx_data;//待发送数据
  reg bps_start_r;
  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_int) begin//当检测到下沿的时候,数据开始传送
   bps_start_r <= 1'b1;
   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
   num<=4'd0;
   rs232_tx_r <= 1'b1;
  end
  else if(tx_en) begin
   if(clk_bps) begin
    num<=num+1'b1;
    case(num)
      4'd0: rs232_tx_r <= 1'b0;//起始位
      4'd1: rs232_tx_r <= tx_data[0];//数据位 开始
      4'd2: rs232_tx_r <= tx_data[1];
      4'd3: rs232_tx_r <= tx_data[2];
      4'd4: rs232_tx_r <= tx_data[3];
      4'd5: rs232_tx_r <= tx_data[4];
      4'd6: rs232_tx_r <= tx_data[5];
      4'd7: rs232_tx_r <= tx_data[6];
      4'd8: rs232_tx_r <= tx_data[7];
      4'd9: rs232_tx_r <= 1'b1;//数据结束位,1位
      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
返回列表