当前位置:   article > 正文

FPGA开发基础篇之一(接口篇)UART串口_fpga接口开发

fpga接口开发

写在前面

从本文开始,将连载fpga开发基础知识,将这几年浅显的fpga开发经验整理出来,一是梳理一下这几年给别人做fpga的经历,同时也是分享给大家,也希望大牛批评指正。

一、UART串口通信基本概念

串口通信是非常基本且应用十分广泛的低速通信接口,无论是在dsp、单片机、arm还是在fpga中,编写uart串口通信程序是必备的基础。

首先要先了解UART串口通信的基本概念,UART串口通信是全双工的,支持发送和接收通信同时进行。硬件上UART串口只需要两条线tx和rx,分别进行发送和接收。UART串口通信没有同步时钟线,这就需要引入一个概念波特率来区分两位数据实现串行通信,波特率是指每秒传输的位数。常见的有9600bps、115200bps、460800bps等等。在fpga实现中,只需要理解每一位的时间长度是1/波特率,计数长度是时钟频率/波特率就可以了。

UART串口通信基本协议,一次UART串口发送和接收一般包含10bit或11bit,包含校验位是11bit,不包含则是10bit。有效数据位一般是8bit。依次为起始位、数据位、校验位(可选)、停止位。

起始位:首先发送的第一位,必须为0,提示接收方开始接收有效数据。

数据位:一般为8位,有效数据位。

校验位:可选位,一般为奇校验、偶校验、固定校验。校验位由数据位中1的个数来决定

停止位:最后发送的一位,必须为1,提示接收方结束接收。

包含以上所有位为一帧数据,经过一个间隔后发送或接收第二帧。由以上的内容我们可以知道如何发送和接收一帧数据了。接下来就是用fpga实现。

二、UART串口通信FPGA实现

首先编写发送模块,先将发送数据缓存,状态机由空闲状态转为发送状态,空闲状态指示信号拉低,通知上层模块发送正在进行不要更新待发送字节。根据波特率进行计数,依次发送一帧数据的所有位,发送完成后状态机转入空闲拉高空闲状态,一次发送就完成了。

  1. //
  2. // //
  3. // //
  4. // This source file is part of uart module. //
  5. // module features: 1.config bits number of one byte //
  6. // 2.config bitrate //
  7. // module function: transmit uart bits //
  8. // copyright of this source file belongs to mayidianzi in CSDN blog //
  9. // contact the author by e-mail 1061165280@qq.com //
  10. // //
  11. //
  12. //================================================================================
  13. // Revision History:
  14. // Date By Revision Change Description
  15. //--------------------------------------------------------------------------------
  16. // 2023/2/26 mayidianzi 1.0 Original
  17. //*******************************************************************************/
  18. module uart_tx
  19. #(
  20. parameter CLK_FRE = 50, //module clock frequency(MHz)
  21. parameter BAUD_RATE = 115200, //serial baud rate
  22. parameter TRANSMIT_BITS = 9 //bits number per byte
  23. )
  24. (
  25. input clk, //clock input
  26. input rst_n, //asynchronous reset input, low active
  27. input[TRANSMIT_BITS-1:0] tx_data, //data to send
  28. input tx_data_valid, //data to be sent is valid
  29. output reg tx_data_ready, //send ready
  30. output tx_pin //serial data output
  31. );
  32. / parameter config \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
  33. //calculates the clock cycle for baud rate
  34. localparam CYCLE = CLK_FRE * 1000000 / BAUD_RATE;
  35. //state machine code
  36. localparam C_IDLE = 1;//wait for transmit
  37. localparam C_START = 2;//start bit
  38. localparam C_SEND_BYTE = 3;//data bits
  39. localparam C_STOP = 4;//stop bit
  40. localparam C_WAIT = 5;//blank between two bytes transmit
  41. // register define \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
  42. reg[2:0] state;
  43. reg[15:0] cycle_cnt; //baud counter
  44. reg[3:0] bit_cnt;//bit counter
  45. reg[TRANSMIT_BITS-1:0] tx_data_latch; //latch data to send
  46. reg tx_reg; //serial data output
  47. assign tx_pin = tx_reg;
  48. // main code \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
  49. //state machine
  50. always@(posedge clk or negedge rst_n)
  51. begin
  52. if(!rst_n)
  53. begin
  54. state <= C_IDLE;
  55. cycle_cnt <= 0;
  56. bit_cnt <= 0;
  57. end
  58. else
  59. case(state)
  60. C_IDLE:
  61. if(tx_data_valid == 1'b1)
  62. state <= C_START;
  63. else
  64. state <= C_IDLE;
  65. C_START:
  66. if(cycle_cnt == CYCLE - 1)
  67. begin
  68. cycle_cnt <= 0;
  69. state <= C_SEND_BYTE;
  70. end
  71. else
  72. cycle_cnt <= cycle_cnt + 1;
  73. C_SEND_BYTE:
  74. if(cycle_cnt == CYCLE - 1 && bit_cnt == TRANSMIT_BITS-1)
  75. begin
  76. state <= C_STOP;
  77. cycle_cnt <= 0;
  78. bit_cnt <= 0;
  79. end
  80. else if(cycle_cnt == CYCLE - 1)
  81. begin
  82. cycle_cnt <= 0;
  83. bit_cnt <= bit_cnt + 1;
  84. end
  85. else
  86. cycle_cnt <= cycle_cnt + 1;
  87. C_STOP:
  88. if(cycle_cnt == CYCLE - 1)
  89. begin
  90. state <= C_WAIT;
  91. cycle_cnt <= 0;
  92. end
  93. else
  94. cycle_cnt <= cycle_cnt + 1;
  95. C_WAIT:
  96. if(cycle_cnt == 10*CYCLE - 1)
  97. begin
  98. state <= C_IDLE;
  99. cycle_cnt <= 0;
  100. end
  101. else
  102. cycle_cnt <= cycle_cnt + 1;
  103. default:
  104. state <= C_IDLE;
  105. endcase
  106. end
  107. //data output
  108. always@(posedge clk or negedge rst_n)
  109. begin
  110. if(rst_n == 1'b0)
  111. tx_data_ready <= 1'b0;
  112. else if(state == C_IDLE)
  113. if(tx_data_valid == 1'b1)
  114. tx_data_ready <= 1'b0;
  115. else
  116. tx_data_ready <= 1'b1;
  117. else if(state == C_WAIT && cycle_cnt == 10*CYCLE - 1)
  118. tx_data_ready <= 1'b1;
  119. end
  120. always@(posedge clk or negedge rst_n)
  121. begin
  122. if(rst_n == 1'b0)
  123. begin
  124. tx_data_latch <= 0;
  125. end
  126. else if(state == C_IDLE && tx_data_valid == 1'b1)
  127. tx_data_latch <= tx_data;
  128. end
  129. always@(posedge clk or negedge rst_n)
  130. begin
  131. if(rst_n == 1'b0)
  132. tx_reg <= 1'b1;
  133. else
  134. case(state)
  135. C_IDLE,C_STOP:
  136. tx_reg <= 1'b1;
  137. C_START:
  138. tx_reg <= 1'b0;
  139. C_SEND_BYTE:
  140. tx_reg <= tx_data_latch[bit_cnt];
  141. default:
  142. tx_reg <= 1'b1;
  143. endcase
  144. end
  145. endmodule

然后再来编写接收模块,接收模块状态机要检测起始位,发现信号拉低后进入接收状态,按照波特率进行计数依次接收所有位,之后转入空闲状态等待下一个起始位,同时拉高数据接收完毕信号提示上层锁存接收数据。

  1. //
  2. // //
  3. // //
  4. // This source file is part of uart module. //
  5. // module features: 1.config bits number of one byte //
  6. // 2.config bitrate //
  7. // module function: receive uart bits //
  8. // copyright of this source file belongs to mayidianzi in CSDN blog //
  9. // contact the author by e-mail 1061165280@qq.com //
  10. // //
  11. //
  12. //================================================================================
  13. // Revision History:
  14. // Date By Revision Change Description
  15. //--------------------------------------------------------------------------------
  16. // 2023/2/26 mayidianzi 1.0 Original
  17. //*******************************************************************************/
  18. module uart_rx
  19. #(
  20. parameter CLK_FRE = 50, //module clock frequency(MHz)
  21. parameter BAUD_RATE = 115200, //serial baud rate
  22. parameter RECEIVE_BITS = 9 //bits number per byte
  23. )
  24. (
  25. input clk, //clock input
  26. input rst_n, //asynchronous reset input, low active
  27. output reg[RECEIVE_BITS-1:0] rx_data, //received serial data
  28. output reg rx_data_valid, //received serial data is valid
  29. input rx_pin //serial data input
  30. );
  31. / parameter config \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
  32. //calculates the clock cycle for baud rate
  33. localparam CYCLE = CLK_FRE * 1000000 / BAUD_RATE;
  34. //state machine
  35. localparam C_WAIT = 0; //blank between two bytes
  36. localparam C_IDLE = 1; //wait for start bit
  37. localparam C_START = 2; //start bit
  38. localparam C_REC_BYTE = 3; //data bits
  39. localparam C_STOP = 4; //stop bit
  40. localparam C_DATA = 5; //data pack
  41. // register define \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
  42. reg[2:0] state;
  43. reg[RECEIVE_BITS-1:0] rx_bits; //temporary storage of received data
  44. reg[15:0] cycle_cnt; //baud counter
  45. reg[3:0] bit_cnt; //bit counter
  46. // main code \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
  47. //state machine
  48. always@(posedge clk or negedge rst_n)
  49. begin
  50. if(!rst_n)
  51. begin
  52. state <= C_WAIT;
  53. cycle_cnt <= 0;
  54. bit_cnt <= 0;
  55. end
  56. else
  57. case(state)
  58. C_WAIT: //wait for blank between two bytes
  59. if(cycle_cnt > CYCLE & rx_pin == 1)
  60. begin
  61. cycle_cnt <= 0;
  62. state <= C_IDLE;
  63. bit_cnt <= 0;
  64. end
  65. else if(rx_pin == 1)
  66. cycle_cnt <= cycle_cnt + 1;
  67. else
  68. cycle_cnt <= 0;
  69. C_IDLE: //wait for first start bit
  70. if(rx_pin == 0)
  71. state <= C_START;
  72. else
  73. state <= C_IDLE;
  74. C_START: //start bit
  75. if(cycle_cnt == CYCLE - 1) //one data cycle
  76. begin
  77. state <= C_REC_BYTE;
  78. cycle_cnt <= 0;
  79. end
  80. else
  81. cycle_cnt <= cycle_cnt + 1;
  82. C_REC_BYTE:
  83. if(cycle_cnt == CYCLE - 1 && bit_cnt == RECEIVE_BITS-1) //receive bits data
  84. begin
  85. state <= C_STOP;
  86. bit_cnt <= 0;
  87. cycle_cnt <= 0;
  88. end
  89. else if(cycle_cnt == CYCLE - 1)
  90. begin
  91. cycle_cnt <= 0;
  92. bit_cnt <= bit_cnt + 1;
  93. end
  94. else
  95. cycle_cnt <= cycle_cnt + 1;
  96. C_STOP:
  97. if(cycle_cnt == CYCLE - 1)
  98. begin
  99. state <= C_DATA;
  100. cycle_cnt <= 0;
  101. end
  102. else
  103. cycle_cnt <= cycle_cnt + 1;
  104. C_DATA: //data receive complete
  105. state <= C_IDLE;
  106. default:
  107. state <= C_WAIT;
  108. endcase
  109. end
  110. //data ready signal
  111. always@(posedge clk or negedge rst_n)
  112. begin
  113. if(rst_n == 1'b0)
  114. rx_data_valid <= 1'b0;
  115. else if(state == C_STOP)
  116. rx_data_valid <= 1'b1;
  117. else if(state == C_DATA)
  118. rx_data_valid <= 1'b0;
  119. end
  120. //data output
  121. always@(posedge clk or negedge rst_n)
  122. begin
  123. if(rst_n == 1'b0)
  124. rx_data <= 8'd0;
  125. else if(state == C_STOP)
  126. rx_data <= rx_bits;//latch received data
  127. end
  128. //receive serial data bit data
  129. always@(posedge clk or negedge rst_n)
  130. begin
  131. if(rst_n == 1'b0)
  132. rx_bits <= 8'd0;
  133. else if(state == C_REC_BYTE && cycle_cnt == CYCLE/2 - 1)
  134. rx_bits[bit_cnt] <= rx_pin;
  135. else
  136. rx_bits <= rx_bits;
  137. end
  138. endmodule

三、后记

以上所有内容均记载在我的串口通用模块内,可以直接下载测试工程了解,或根据自己的工程需要进行改编。如果不想在串口通信方面耽误时间,集中力量开发高级功能,可直接调用我编写的通用串口模块,可直接进行例化实现串口通信功能。通用串口模块可分别自定义收发波特率、收发校验种类,具备串口通信常用的全部功能,可根据实际需求设置,减少您的开发周期,本通用串口模块经过仿真模拟和硬件测试,附有测试报告和开发说明,方便使用,传送门:

通用串口模块

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/467780
推荐阅读
相关标签
  

闽ICP备14008679号