当前位置:   article > 正文

基于FPGA的蓝牙遥控,超声波避障,红外循迹的智能小车_基于fpga智能小车的设计 红外避障,数码管 循迹 遥控

基于fpga智能小车的设计 红外避障,数码管 循迹 遥控

        闲来无事整个小车玩玩,设想的小车可以有蓝牙模块来控制模式切换,通过发送指令来更改相对应的功能,当避障的时候可以自动规避障碍物,当处于红外循迹时,可以跟随规划的轨迹前线,当手动遥控时可以控制前进后退左右转向停止等功能。

        先介绍一下使用的红外模块,其上有四个管脚,vcc接电源,gnd接地,D0传输红外线是否被吸收,A0传输模拟信号主要是不同距离输出不同的电压,但是此脚一般可以不接.

        然后思路就是通过判断D0传过来的电平信号来判断小车有没有接触到黑线,当红外线被吸收,也就是触碰到黑线,D0会持续输出高电平,直到它检测到红外线返回才会回归低电平,基于对管脚传回的电平检测,可以判断是否接触到黑线。

这部分代码很好写,可以参考如下代码:

  1. `timescale 1ns / 1ps
  2. module red_line(
  3. input sysclk ,///系统时钟
  4. input rst_n ,///复位
  5. input [1:0] D0 ,///红外探测模块的电平输入
  6. output reg [3:0] car//输出轮子控制
  7. );
  8. always @(posedge sysclk)
  9. if(!rst_n)
  10. car<=4'b1001;
  11. else if( D0[0]==1 && D0[1]==1 )
  12. car<=4'b0000;
  13. else if(D0[0]==1) //左边的红外探测模块
  14. car<=4'b0101;
  15. else if(D0[1]==1) //右边的红外探测模块
  16. car<=4'b1010;
  17. else
  18. car<=4'b1001; //保持状态
  19. endmodule

输入系统时钟,复位,红外探测模块的电平输入,然后输出小车轮子一个怎么走,就只有一个简单的判断语句。

然后是超声波模块,超声波模块的应用,之前写过了,这里就不再赘述。

超声波模块的距离还要输入到一个避障模块中,这个模块只负责成立输入的距离信息,判断是否达到阈值。

  1. `timescale 1ns / 1ps
  2. module car_c(
  3. input sysclk,
  4. input rst_n,
  5. input [13:0] distance,
  6. output reg [3:0] car
  7. );
  8. always @(posedge sysclk)
  9. if(!rst_n)
  10. car<=4'b1001;
  11. else if(distance>=15)
  12. car<=4'b1001;
  13. else if(distance<15)
  14. car<=4'b1010 ;
  15. else
  16. car<=car;
  17. //assign car=4'b1001; //1010 左转 0101 右转 1001 前进 0110 后退
  18. endmodule

然后是蓝牙模块,蓝牙模块包括两部分,接收的rx,这里是基于蓝牙模块来说的,对蓝牙模块的接收和发送,我们需要通过蓝牙模块来进行指令控制,输入特定的十六进制代码输出特定的控制信息:

这里我们定义了开发板的振动频率也就是一秒震动多少次,然后是波特率,这里没有涉及到其他的模块,如果是不同的蓝牙模块之间通信,波特率要设置的一样。

  1. //串口读取,可调整波特率,运行频率,本次设计不可以修改数据传输的长度//
  2. `timescale 1ns / 1ps
  3. module uart_RX_car
  4. #(
  5. parameter SYSCLK = 50_000_000 ,//系统时钟
  6. parameter Baud = 9600 //波特率
  7. )
  8. (
  9. input sysclk ,
  10. input rst_n ,
  11. input RX ,
  12. output reg vaild ,//数据有效
  13. output reg [7:0] Data
  14. );
  15. localparam CLK_DELAY = SYSCLK/Baud;
  16. localparam CLK_MID = CLK_DELAY/2;
  17. localparam IDLE=2'd0;//空闲状态,等待RX信号被拉低
  18. localparam START=2'd1;//起始状态
  19. localparam DATA=2'd2;//数据接收
  20. localparam STOP=2'd3;//停止状态
  21. reg [1:0] cur_state;
  22. reg [1:0] next_state;
  23. reg [1:0] rx_flag = 2'b11;
  24. reg [4:0] cnt_bit;//传输数据个数
  25. reg [31:0] cnt;//记录波特率,即记录何时让cnt_bit加1
  26. ******开始信号寄存*****
  27. always@(posedge sysclk)
  28. if(!rst_n)
  29. rx_flag<=2'b11;
  30. else
  31. rx_flag<={rx_flag[0],RX};
  32. ******state1*****
  33. always@(posedge sysclk)
  34. if(!rst_n)
  35. cur_state<=IDLE;
  36. else
  37. cur_state<=next_state;
  38. ******state2*****
  39. always@(*) begin
  40. next_state = IDLE;
  41. case(cur_state)
  42. IDLE:begin
  43. if(rx_flag==2'b10)
  44. next_state = START;
  45. else
  46. next_state = IDLE;
  47. end
  48. START:begin
  49. if(cnt_bit==5'd1)
  50. next_state = DATA;
  51. else
  52. next_state = START;
  53. end
  54. DATA:begin
  55. if(cnt_bit==5'd9)
  56. next_state = STOP;
  57. else
  58. next_state = DATA;
  59. end
  60. STOP:begin
  61. if(cnt_bit==5'd9 && rx_flag == 2'b11)
  62. next_state = IDLE;
  63. else
  64. next_state = STOP;
  65. end
  66. default:begin
  67. next_state = IDLE;
  68. end
  69. endcase
  70. end
  71. ******state3*****
  72. always@(posedge sysclk)
  73. if(!rst_n) begin
  74. cnt_bit <= 5'd0;
  75. cnt <= 32'd0;
  76. Data <= 8'd0;
  77. vaild <= 32'd0;
  78. end
  79. else
  80. case(next_state)
  81. IDLE:begin
  82. cnt_bit <= 5'd0;
  83. cnt <= 32'd0;
  84. vaild <= 32'd0;
  85. Data <= Data;//可以为0,也可以保持上一次的数据
  86. end
  87. START:begin
  88. if(cnt >= CLK_DELAY-1)begin
  89. cnt <= 32'd0;
  90. cnt_bit <= cnt_bit + 32'd1;
  91. end
  92. else begin
  93. cnt_bit <= cnt_bit;
  94. cnt <= cnt + 32'd1;
  95. end
  96. Data <= Data;
  97. vaild <= 0;
  98. end
  99. DATA:begin
  100. if(cnt >= CLK_DELAY-1)begin
  101. cnt <= 32'd0;
  102. cnt_bit <= cnt_bit + 32'd1;
  103. end
  104. else begin
  105. cnt_bit <= cnt_bit;
  106. cnt <= cnt + 32'd1;
  107. end
  108. if(cnt == CLK_MID-1) //中点的时候进行数据的采集,这样能保证数据采集比较稳定//
  109. Data <= {RX,Data[7:1]};
  110. else
  111. Data <= Data;
  112. vaild <= 0;
  113. end
  114. STOP:begin
  115. if(cnt >= CLK_DELAY-1)begin
  116. cnt <= 32'd0;
  117. cnt_bit <= cnt_bit + 32'd1;
  118. end
  119. else begin
  120. cnt_bit <= cnt_bit;
  121. cnt <= cnt + 32'd1;
  122. end
  123. Data <= Data;
  124. if(cnt == CLK_MID-1)
  125. vaild <= 1;
  126. else
  127. vaild <= 0;
  128. end
  129. default:begin
  130. cnt_bit <= 5'd0;
  131. cnt <= 32'd0;
  132. Data <= 8'd0;
  133. vaild <= 32'd0;
  134. end
  135. endcase
  136. endmodule

然后是接收控制信息的模块,rx传出来的Data会输入到这个模块里面,根据输入的控制信息输出

对应的小车控制信息。

  1. module rx_ctrl(
  2. input sysclk ,
  3. input rst_n ,
  4. input [7:0] Data ,
  5. output reg [3:0] car_ctrl_2
  6. );
  7. always@(posedge sysclk)
  8. if(!rst_n)
  9. car_ctrl_2 <= 4'b0000;
  10. else
  11. case(Data)
  12. 8'h47 : car_ctrl_2 <= 4'b1001;//前进
  13. 8'h4b : car_ctrl_2 <= 4'b0110;//后退
  14. 8'h4a : car_ctrl_2 <= 4'b1010;//右转
  15. 8'h48 : car_ctrl_2 <= 4'b0101;//左转
  16. 8'h49 : car_ctrl_2 <= 4'b0000;//停止
  17. default :car_ctrl_2 <= 4'b0000;
  18. endcase
  19. endmodule

然后是TOP模块,我们需要将所有的模块都都连接起来。这里顶层加了一个led的输出,这样方便我们观察我们当前处于什么状态,也可以方便我们切换状态,通过判断led处于什么状态,将小车的控制输出交给相对应的控制输出模块。在这个里面,数码管和led都可以不用加,这里加入了只是因为可以更好的帮助我们观察小车的状态。

  1. `timescale 1ns / 1ps
  2. module TOP8(
  3. input sysclk,
  4. input rst_n,
  5. input echo,//输出的超声波
  6. input [1:0] D0,
  7. input RX,
  8. output trig ,//产生高电平
  9. output reg [3:0] led ,
  10. output [7:0] seg ,
  11. output [3:0] dig ,
  12. output reg [3:0] car
  13. );
  14. //assign car=4'b1010;
  15. wire [13:0] distance;
  16. wire [7:0] Data;
  17. wire [3:0] car_ctrl0;//避障
  18. wire [3:0] car_ctrl1;//循迹
  19. wire [3:0] car_ctrl2;//蓝牙
  20. always @(posedge sysclk)
  21. if(!rst_n)
  22. led<=4'b0000;
  23. else
  24. case(Data)
  25. 8'h41:led<=4'b0001;//避障
  26. 8'h42:led<=4'b0010;//循迹
  27. //8'h43:led=4'b0100;//蓝牙
  28. default :led<=4'b0100;
  29. endcase
  30. always @(posedge sysclk)
  31. if(!rst_n)
  32. car<=4'b0000;
  33. else
  34. case(led)
  35. 4'b0001:car<=car_ctrl0;//避障
  36. 4'b0010:car<=car_ctrl1;//循迹
  37. 4'b0100:car<=car_ctrl2;//蓝牙
  38. default :car<=4'b0000;
  39. endcase
  40. csb csb1(
  41. .sysclk (sysclk ),
  42. .rst_n (rst_n ),
  43. .trig (trig ),//产生高电平
  44. .echo (echo ),//输出的超声波
  45. .distance(distance)
  46. );
  47. seg seg1(
  48. . sysclk (sysclk) ,
  49. . rst_n (rst_n ) ,
  50. . num (distance ) , //数码管上显示的数字0-9999
  51. . seg (seg ) ,//段选8个灯
  52. . dig (dig ) //位选4个数码管
  53. );
  54. car_c car1(
  55. . sysclk (sysclk) ,
  56. . rst_n (rst_n ) ,
  57. . distance (distance) ,
  58. . car (car_ctrl0 )
  59. );
  60. red_line red1(
  61. .sysclk (sysclk),
  62. .rst_n (rst_n ),
  63. .D0 (D0 ),
  64. .car (car_ctrl1 )
  65. );
  66. uart_RX_car
  67. #(
  68. . SYSCLK(50_000_000 ) ,//系统时钟
  69. . Baud (9600 ) //波特率
  70. )
  71. uart1(
  72. . sysclk ( sysclk ) ,
  73. . rst_n ( rst_n ) ,
  74. . RX ( RX ) ,
  75. . vaild ( vaild ) ,//数据有效
  76. . Data ( Data )
  77. );
  78. rx_ctrl rx1(
  79. . sysclk ( sysclk ) ,
  80. . rst_n ( rst_n ) ,
  81. . Data ( Data ) ,
  82. .car_ctrl_2 (car_ctrl2 )
  83. );
  84. endmodule

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

闽ICP备14008679号