当前位置:首页 > 技术学院 > 热搜器件
[导读]写串口的Verilog代码关键是要搞明白RS232串口的通信协议,它并不像单片机,直接读写SBUF就可实现串口的收发功能,收发整个字节。而FPGA要一位一位的收发,因此必须了解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,以LED灯的亮灭直观显示接收到数据,按下
//                         相应按键并弹起后,FPGA又将接收到的串口数据发送出去。
// Additional Comments : 
//
////////////////////////////////////////////////////////////////////////////////
module serial_test(clk,rst_n,ena,txd,rxd,data);
input clk;         //系统输入时钟
input rst_n;       //异步复位
input ena;         //FPGA发送使能,即按键输入端
input rxd;         //FPGA接收端
output txd;        //FPGA发送端
output [7:0] data; //至LED显示的数据
wire   [7:0] data;
wire   txd;
wire   clk2;       //PLL输出时钟
wire   clk_baud;   //波特率时钟
PLL  u1(.inclk0(clk),.c0(clk2));                                               //PLL输出低频时钟
clk_baud_gen  u2(.clk(clk2),.rst_n(rst_n),.clk_baud(clk_baud));                //产生波特率时钟
serial_txd  u3(.clk(clk_baud),.rst_n(rst_n),.ena(ena),.data(data),.txd(txd));  //FPGA发送模块
serial_rxd  u4(.clk(clk_baud),.rst_n(rst_n),.rxd(rxd),.data(data));            //FPGA接收模块
endmodule
接收模块
//此模块是FPGA控制模块从串口接收数据,不接收起始位“0”和停止位“1”
//在接收端,若串口没有数据发出,则一直处于高电平,有数据发出时,先发送起始位“0”,即如果
//接收端出现由高到低的跳变,说明串口有数据发出,应开始接收
module  serial_rxd(rst_n,clk,rxd,data);
input   rst_n;          //全局复位
input   clk;            //接收时钟
input   rxd;            //FPGA接收串口数据的接收端
output  [7:0] data;     //FPGA接收的来自串口的数据,输出至LED显示

reg     [3:0] cnt;      //接收数据计数器
reg     rec_reg1;       //起始位检测寄存器1
reg     rec_reg2;       //起始位检测寄存器2
reg     [7:0] data;     //FPGA接收的数据
always @(posedge clk or negedge rst_n)
      if(!rst_n)       
  begin
  rec_reg1<=1'b1;     //起始位检测寄存器置1,
  rec_reg2<=1'b1;     //处于等待接收状态
  data<=8'hzz;        //输出复位,LED全灭
  end
  else if(rec_reg1&&rec_reg2)
  begin
  rec_reg1<=rxd;      //rec_reg1寄存rxd当前周期的值
  rec_reg2<=rec_reg1; //rec_reg2寄存rxd前一周期的值
  end
  else if(!rec_reg1&&rec_reg2)   //检测rxd下降沿,也即是否有低电平到来
  case (cnt)
      4'd0:data[0]<=rxd;  //接收第一位数据
  4'd1:data[1]<=rxd;  //接收第二位数据
  4'd2:data[2]<=rxd;  //接收第三位数据
  4'd3:data[3]<=rxd;  //接收第四位数据
  4'd4:data[4]<=rxd;  //接收第五位数据
  4'd5:data[5]<=rxd;  //接收第六位数据
  4'd6:data[6]<=rxd;  //接收第七位数据
  4'd7:begin
       data[7]<=rxd;  //接收第八位数据
       rec_reg1<=1'b1;//数据接收完毕,起始位检测寄存器复位,
       rec_reg2<=1'b1;//以准备下次接收
       end
      default:begin
          data<=8'hzz;
            rec_reg1<=1'b1;
          rec_reg2<=1'b1;
          end
  endcase
always @(posedge clk or negedge rst_n)
      if(!rst_n)
  cnt<=4'd0;          //复位,接收数据技术器清零
  else if(!rec_reg1&&rec_reg2)
  cnt<=(cnt<4'd7)?cnt+4'd1:4'd0; //检测到起始位后,接收数据计数器启动
endmodule
发送模块
//此模块的作用是FPGA控制模块向串口发送数据,起始位为“0”,停止位为“1”
//延时电路的设计思想为按键按下弹起之后开始计时,时长为1010/11920秒
//延时去抖结束后给出发送标志位,直至FPGA向串口发送完毕
module  serial_txd(rst_n,clk,ena,data,txd);
input    rst_n;           //全局复位
input    clk;             //串口发送时钟
input    ena;             //串口发送使能输入端,即按键输入端
input    [7:0] data;      //FPGA向串口发送的数据
output   txd;             //FPGA向串口发送数据的发送端

reg      txd;            
reg      [3:0] cnt;       //发送数据计数器
reg      [9:0] cnt_delay; //延时去抖计数器,延时时间为1010/11920秒
reg      ena_reg1;        //按键状态寄存器1
reg      ena_reg2;        //按键状态寄存器2
wire     tx_flag;         //发送标志位,高电平表示正在发送串口数据
always @(posedge clk or negedge rst_n)
      if(!rst_n)
  begin
  ena_reg1<=1'b1;
  ena_reg2<=1'b1;
  cnt_delay<=10'd0;
  end
  else if(ena_reg1&!ena_reg2)          //检测按键按下后弹起,即ena的上升沿(因为无动作时连接按键的pin处于高电平)
  case (cnt_delay)           
  10'd1011:begin
          cnt_delay<=10'd0;            //延时去抖结束,计数器清零
      ena_reg1<=1'b1;              //按键状态寄存器置1,等待下次ena上升沿的到来
          ena_reg2<=1'b1;
      end
  default:cnt_delay<=cnt_delay+10'd1;  //检测到上升沿,延时去抖计数器启动
  endcase
  else
   begin
  ena_reg1<=ena;                       //ena_reg1寄存ena当前周期的状态
  ena_reg2<=ena_reg1;                  //ena_reg2寄存ena前一周期的状态
  end
assign  tx_flag=((cnt_delay>=10'd1000)&&   //延时去抖结束后给出发送忙标志,持续10
                 (cnt_delay<=10'd1010));   //个周期,以等待FPGA向串口发送完毕
always @(posedge clk or negedge rst_n)
      if(!rst_n)
     cnt<=4'd0;                        //串口发送计数器复位
  else if(!tx_flag)                   
     cnt<=4'd0;                        //若没有检测到串口发送标志位,则计数器等待
      else
     cnt<=(cnt>=4'd10)?4'd11:cnt+4'd1; //检测到串口发送标志位,启动计数器
always @(posedge clk or negedge rst_n)
      if(!rst_n)
      txd<=1'bz;              //发送端复位,高阻态       
  else
        case (cnt)
    4'd0:txd<=1'bz;        
    4'd1:txd<=1'b0;         //发送起始位
    4'd2:txd<=data[0];      //发送第一位
    4'd3:txd<=data[1];      //发送第二位
    4'd4:txd<=data[2];      //发送第三位
    4'd5:txd<=data[3];      //发送第四位
    4'd6:txd<=data[4];      //发送第五位
    4'd7:txd<=data[5];      //发送第六位
    4'd8:txd<=data[6];      //发送第七位
    4'd9:txd<=data[7];      //发送第八位
    4'd10:txd<=1'b1;        //发送停止位
    default:txd<=1'bz;
  endcase
endmodule
波特率产生模块(此模块的输入时钟来自PLL,频率为12MHz,PLL模块为宏功能函数)
//此模块为波特率生成模块,修改BAUDRATE的值可改变波特率
//串口波特率时钟的高电平仅仅持续一个clk周期
module   clk_baud_gen(clk,rst_n,clk_baud);
input  clk;       //波特率基准时钟,此时钟来自PLL
input  rst_n;     //全局复位
output clk_baud;  //串口波特率时钟
wire   clk_baud; 
reg    [9:0] cnt; //波特率时钟计数器

parameter  BAUDRATE=10'd625;

always @(posedge clk or negedge rst_n)
      if(!rst_n)
     cnt<=10'd0;
  else
     cnt<=(cnt==BAUDRATE-10'd2)?10'd0:cnt+1'b1;  //波特率时钟计数器启动
assign   clk_baud=(cnt==BAUDRATE-10'd2);
endmodule

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

2023年10月18日,中国在第三届“一带一路”国际合作高峰论坛期间发布《全球人工智能治理倡议》,围绕人工智能发展、安全、治理三方面系统阐述了人工智能治理中国方案。

关键字: 人工智能 大模型 代码

我们看到这么多的安全问题,部分原因在于我们对待安全的方式:安全性通常被认为是事后考虑的问题,是在开发结束时才添加到设备上的东西。然而,复杂的系统,尤其是嵌入式系统,有一个很大的攻击面,这让攻击者有机可乘,能够在“盔甲”上...

关键字: 代码 嵌入式系统 软件漏洞

新富人群财务需求多元发展,投顾服务迎来新机遇 上海2023年9月20日 /美通社/ -- 2023年9月19日,上海交通大学上海高级金融学院(高金)与全球领先的金融服务机构嘉信理财(Charles Schwab)联合发...

关键字: BSP ADVANCED INA 代码

北京2023年9月14日 /美通社/ -- 生物医药高科技公司诺诚健华(港交所代码:09969;上交所代码:688428)今日宣布,新型蛋白酪氨酸磷酸酶SHP2变构抑制剂ICP-189联用针对表皮生长因子受体(EGFR)...

关键字: IC HP 代码 ARMA

上海2023年9月1日 /美通社/ -- 2023上半年,安集科技(股票代码:688019)市场拓展规划成效显现,营业收入稳健增长。 全球半导体产业挑战持续存在的情形下,安集科技秉承发扬"克难攻坚,敢打硬...

关键字: 安集科技 BSP 代码 半导体材料

国际酒店运营商升级其在线支付功能 上海2023年8月28日 /美通社/ -- 加拿大金融科技公司Nuvei Corporation(以下简称“Nuvei”或“公司”)(纳斯达克代码:NVEI)(多伦多证券交易所代码:N...

关键字: 代码 IP SE 纳斯达克

2023年上半年收入7.459亿元 同比增长5.1% 毛利率水平上升 海外收入同比增长65.4% 香港2023年8月22日 /美通社/ -- 金邦达宝嘉控股有限公司及其附属公司(以下合称「金邦达」、「...

关键字: 数字化 代码 嵌入式软件 COM

我们经常对正在进行数字化转型的亚马逊云科技客户建议,将云迁移视为其数字化转型的一部分,数字化转型本身必须由业务成果驱动。其中治理计划的有效性决定了云迁移和数字化转型的成功与否。数字化转型中的云迁移总有结束的时候,但是如果...

关键字: 代码 数字化 云服务

广州及苏州生产基地产品均实现"出口"零突破 北京2023年8月21日 /美通社/ -- 百济神州(纳斯达克代码:BGNE;香港联交所代码:06160;上交所代码:688235)是一家全球性生物科技公...

关键字: 神州 代码 TI PD

近年来,国内电子公司和芯片设计企业大举进攻汽车、医疗和工业等高可靠应用(mission-critical)领域,为自己找到了摆脱红海的新领域。但是高可靠应用多数都需要功能安全认证,在许多行业在诸如汽车、航空电子、医疗和工...

关键字: 代码 代码分析工具
关闭
关闭