当前位置:   article > 正文

5—基于FPGA(ZYNQ-Z2)的多功能小车—软件设计—蓝牙串口_zynq蓝牙

zynq蓝牙

目录

1.蓝牙模块介绍

2.UART介绍

3.Verilog代码:

3.1Uart_RX模块:

3.2 分频模块:

3.3 Uart驱动模块

3.4 Uart控制模块

4. 总览


1.蓝牙模块介绍

  我使用的是JDY-31蓝牙模块,在连线中,要注意RX-TX,TX-RX。

  即FPGA约束的TX对应蓝牙模块的RX,约束的RX对应蓝牙模块的TX。


2.UART介绍

蓝牙模块使用UART串口通信协议,具体介绍如下:

UART(通用异步收发器)是一种常见的串口通信协议。

UART协议的主要特点如下:

  1. 异步通信:UART使用异步通信方式,不需要时钟同步信号。数据的传输以字符为单位,每个字符由起始位、数据位、校验位(可选)和停止位组成。

  2. 数据格式:UART可以支持不同的数据格式。常见的数据位数包括5位、6位、7位和8位,常见的停止位数为1位或2位,常见的校验位有奇校验、偶校验和无校验。

  3. 波特率:波特率是指每秒钟传输的比特数。UART支持不同的波特率,常见的波特率有9600、115200等。发送和接收的设备必须以相同的波特率进行通信。

  4. 帧同步:UART通过起始位和停止位来确定数据帧的边界。起始位用于标识数据传输的开始,停止位用于标识数据传输的结束。

  5. 单工或半双工通信:UART通信可以是单向的(只有发送或只有接收)或半双工的(同时具有发送和接收功能)。

232通信时序图如下:


3.Verilog代码:

具体Verilog的实现代码如下:

3.1顶层模块:

  1. module rs232(
  2. input wire clk,
  3. input wire rst_n,
  4. input wire rx,
  5. output wire tx
  6. );
  7. wire rx_flag;
  8. wire [7:0] rx_data;
  9. wire [7:0] tx_data;
  10. Uart_TX uart_tx(
  11. .clk(clk),
  12. .rst_n(rst_n),
  13. .data(rx_data),
  14. .start_flag(rx_flag),
  15. .tx(tx)
  16. );
  17. Uart_RX uart_rx(
  18. .clk(clk),
  19. .rst_n(rst_n),
  20. .rx(rx),
  21. .rx_data(rx_data),
  22. .rx_flag(rx_flag)
  23. );
  24. endmodule

这段代码是RS232顶层模块。

其中包含一个发送器(Uart_TX)和一个接收器(Uart_RX)。实现了上位机发送信息后,FPGA将上位机的信息的返回。


3.2 Uart_TX模块:

  1. `timescale 1ns / 1ps
  2. module Uart_TX(
  3. input wire clk,
  4. input wire rst_n,
  5. input wire [7:0] data,
  6. input wire start_flag,
  7. output wire tx
  8. );
  9. /******************内部变量**********************/
  10. parameter N=13021; //N=系统时钟频率/波特率;f=125Mhz,baud=9600。表示N个系统时钟一个数据位
  11. reg work_en;//工作使能
  12. reg [31:0] baud_cnt;//波特计数器
  13. reg bit_flag;//比特标志
  14. reg [3:0] bit_cnt;//数据位计数,0-8
  15. reg tx_reg;
  16. assign tx=tx_reg;
  17. /******************工作使能**********************/
  18. always@(posedge clk or negedge rst_n)
  19. begin
  20. if(!rst_n)
  21. work_en<=0;
  22. else if(start_flag==1)//开始迟滞一个clk,工作使能
  23. work_en<=1;
  24. else if((bit_cnt==4'd9)&&(bit_flag==1))
  25. work_en<=0;
  26. else
  27. work_en<=work_en;
  28. end
  29. /*******************波特计数器**********************/
  30. always@(posedge clk or negedge rst_n)
  31. begin
  32. if(!rst_n)
  33. baud_cnt<=0;
  34. else if((baud_cnt==N-1)||(work_en==0))
  35. baud_cnt<=0;
  36. else if(work_en==1)
  37. baud_cnt<=baud_cnt+1;
  38. end
  39. /*******************比特标志**********************/
  40. always@(posedge clk or negedge rst_n)
  41. begin
  42. if(!rst_n)
  43. bit_flag<=0;
  44. else if(baud_cnt==1)
  45. bit_flag<=1;
  46. else
  47. bit_flag<=0;
  48. end
  49. /*******************数据位计数**********************/
  50. always@(posedge clk or negedge rst_n)
  51. begin
  52. if(!rst_n)
  53. bit_cnt<=0;
  54. else if((bit_cnt==4'd9)&&(bit_flag==1))
  55. bit_cnt<=0;
  56. else if(bit_flag==1)
  57. bit_cnt<=bit_cnt+1;
  58. end
  59. /*******************数据输出**********************/
  60. always@(posedge clk or negedge rst_n)
  61. begin
  62. if(!rst_n)
  63. tx_reg<=1;
  64. else if(bit_flag==1)
  65. case(bit_cnt)
  66. 0:tx_reg<=0;
  67. 1:tx_reg<=data[0];
  68. 2:tx_reg<=data[1];
  69. 3:tx_reg<=data[2];
  70. 4:tx_reg<=data[3];
  71. 5:tx_reg<=data[4];
  72. 6:tx_reg<=data[5];
  73. 7:tx_reg<=data[6];
  74. 8:tx_reg<=data[7];
  75. 9:tx_reg<=1;
  76. default:tx_reg<=1;
  77. endcase
  78. end
  79. endmodule

首先根据系统时钟和波特率计算出N(我的FPGA是125Mhz,需要波特率9600)。

之后根据RS232的时序图写出各个模块,即可实现串口发送。


3.3 Uart_RX模块
 

  1. `timescale 1ns / 1ps
  2. module Uart_RX(
  3. input wire clk,
  4. input wire rst_n,
  5. input wire rx,
  6. output reg [7:0] rx_data,
  7. output reg rx_flag
  8. );
  9. /******************内部变量**********************/
  10. parameter N=13021; //N=系统时钟频率/波特率;f=125Mhz,baud=9600。表示N个系统时钟一个数据位
  11. reg rx_reg1;//打排数据
  12. reg rx_reg2;//打排数据
  13. reg rx_reg3;//打排数据
  14. reg start_flag;//起始标志
  15. reg work_en;//工作使能
  16. reg [31:0] baud_cnt;//波特计数器
  17. reg bit_flag;//比特标志
  18. reg [3:0] bit_cnt;//数据位计数,0-8
  19. reg [7:0] rx_data_reg;//数据寄存器
  20. reg rx_flag_reg;//数据标识符寄存器
  21. /*******************数据打拍**********************/
  22. //数据打拍,避免亚稳态
  23. always@(posedge clk or negedge rst_n)
  24. begin
  25. if(!rst_n)
  26. rx_reg1<=1;
  27. else
  28. rx_reg1<=rx;
  29. end
  30. always@(posedge clk or negedge rst_n)
  31. begin
  32. if(!rst_n)
  33. rx_reg2<=1;
  34. else
  35. rx_reg2<=rx_reg1;
  36. end
  37. always@(posedge clk or negedge rst_n)
  38. begin
  39. if(rst_n==0)
  40. rx_reg3<=1;
  41. else
  42. rx_reg3<=rx_reg2;
  43. end
  44. /*******************起始标志**********************/
  45. always@(posedge clk or negedge rst_n)
  46. begin
  47. if(!rst_n)
  48. start_flag<=0;
  49. else if((rx_reg3==1)&&(rx_reg2==0)&&(work_en==0))//迟滞reg3一个clk
  50. start_flag<=1;
  51. else
  52. start_flag<=0;
  53. end
  54. /*******************工作使能**********************/
  55. always@(posedge clk or negedge rst_n)
  56. begin
  57. if(!rst_n)
  58. work_en<=0;
  59. else if(start_flag==1)//开始迟滞一个clk,工作使能
  60. work_en<=1;
  61. else if((bit_cnt==8)&&(bit_flag==1))
  62. work_en<=0;
  63. else
  64. work_en<=work_en;
  65. end
  66. /*******************波特计数器**********************/
  67. always@(posedge clk or negedge rst_n)
  68. begin
  69. if(!rst_n)
  70. baud_cnt<=0;
  71. else if((baud_cnt==N-1)||(work_en==0))
  72. baud_cnt<=0;
  73. else
  74. baud_cnt<=baud_cnt+1;
  75. end
  76. /*******************比特标志**********************/
  77. always@(posedge clk or negedge rst_n)
  78. begin
  79. if(!rst_n)
  80. bit_flag<=0;
  81. else if(baud_cnt==(N/2-1))
  82. bit_flag<=1;
  83. else
  84. bit_flag<=0;
  85. end
  86. /*******************数据位计数**********************/
  87. always@(posedge clk or negedge rst_n)
  88. begin
  89. if(!rst_n)
  90. bit_cnt<=0;
  91. else if((bit_cnt==8)&&(bit_flag==1))
  92. bit_cnt<=0;
  93. else if(bit_flag==1)
  94. bit_cnt<=bit_cnt+1;
  95. end
  96. /*******************数据寄存器**********************/
  97. always@(posedge clk or negedge rst_n)
  98. begin
  99. if(!rst_n)
  100. rx_data_reg<=0;
  101. else if((bit_cnt>=1)&&(bit_cnt<=8)&&(bit_flag==1))
  102. rx_data_reg<={rx_reg3,rx_data_reg[7:1]};
  103. end
  104. /*******************数据标识符寄存器**********************/
  105. always@(posedge clk or negedge rst_n)
  106. begin
  107. if(!rst_n)
  108. rx_flag_reg<=0;
  109. else if((bit_cnt==8)&&(bit_flag==1))
  110. rx_flag_reg<=1;
  111. else
  112. rx_flag_reg<=0;
  113. end
  114. /*******************数据输出**********************/
  115. always@(posedge clk or negedge rst_n)
  116. begin
  117. if(!rst_n)
  118. rx_data<=0;
  119. else if(rx_flag_reg==1)
  120. rx_data<=rx_data_reg;
  121. end
  122. always@(posedge clk or negedge rst_n)
  123. begin
  124. if(!rst_n)
  125. rx_flag<=0;
  126. else
  127. rx_flag<=rx_flag_reg;
  128. end
  129. endmodule

依然是首先计算N,之后根据时序图实现。


4. 总览

效果如下:

具体结构如下:

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

闽ICP备14008679号