赞
踩
闲来无事整个小车玩玩,设想的小车可以有蓝牙模块来控制模式切换,通过发送指令来更改相对应的功能,当避障的时候可以自动规避障碍物,当处于红外循迹时,可以跟随规划的轨迹前线,当手动遥控时可以控制前进后退左右转向停止等功能。
先介绍一下使用的红外模块,其上有四个管脚,vcc接电源,gnd接地,D0传输红外线是否被吸收,A0传输模拟信号主要是不同距离输出不同的电压,但是此脚一般可以不接.
然后思路就是通过判断D0传过来的电平信号来判断小车有没有接触到黑线,当红外线被吸收,也就是触碰到黑线,D0会持续输出高电平,直到它检测到红外线返回才会回归低电平,基于对管脚传回的电平检测,可以判断是否接触到黑线。

这部分代码很好写,可以参考如下代码:
- `timescale 1ns / 1ps
-
-
- module red_line(
- input sysclk ,///系统时钟
- input rst_n ,///复位
- input [1:0] D0 ,///红外探测模块的电平输入
- output reg [3:0] car//输出轮子控制
- );
- always @(posedge sysclk)
- if(!rst_n)
- car<=4'b1001;
- else if( D0[0]==1 && D0[1]==1 )
- car<=4'b0000;
- else if(D0[0]==1) //左边的红外探测模块
- car<=4'b0101;
- else if(D0[1]==1) //右边的红外探测模块
- car<=4'b1010;
- else
- car<=4'b1001; //保持状态
- endmodule

输入系统时钟,复位,红外探测模块的电平输入,然后输出小车轮子一个怎么走,就只有一个简单的判断语句。
然后是超声波模块,超声波模块的应用,之前写过了,这里就不再赘述。
超声波模块的距离还要输入到一个避障模块中,这个模块只负责成立输入的距离信息,判断是否达到阈值。
- `timescale 1ns / 1ps
-
-
- module car_c(
- input sysclk,
- input rst_n,
- input [13:0] distance,
- output reg [3:0] car
- );
- always @(posedge sysclk)
- if(!rst_n)
- car<=4'b1001;
- else if(distance>=15)
- car<=4'b1001;
- else if(distance<15)
- car<=4'b1010 ;
- else
- car<=car;
- //assign car=4'b1001; //1010 左转 0101 右转 1001 前进 0110 后退
-
-
- endmodule

然后是蓝牙模块,蓝牙模块包括两部分,接收的rx,这里是基于蓝牙模块来说的,对蓝牙模块的接收和发送,我们需要通过蓝牙模块来进行指令控制,输入特定的十六进制代码输出特定的控制信息:
这里我们定义了开发板的振动频率也就是一秒震动多少次,然后是波特率,这里没有涉及到其他的模块,如果是不同的蓝牙模块之间通信,波特率要设置的一样。
- //串口读取,可调整波特率,运行频率,本次设计不可以修改数据传输的长度//
- `timescale 1ns / 1ps
- module uart_RX_car
- #(
- parameter SYSCLK = 50_000_000 ,//系统时钟
- parameter Baud = 9600 //波特率
- )
- (
- input sysclk ,
- input rst_n ,
- input RX ,
- output reg vaild ,//数据有效
- output reg [7:0] Data
- );
- localparam CLK_DELAY = SYSCLK/Baud;
- localparam CLK_MID = CLK_DELAY/2;
- localparam IDLE=2'd0;//空闲状态,等待RX信号被拉低
- localparam START=2'd1;//起始状态
- localparam DATA=2'd2;//数据接收
- localparam STOP=2'd3;//停止状态
- reg [1:0] cur_state;
- reg [1:0] next_state;
- reg [1:0] rx_flag = 2'b11;
- reg [4:0] cnt_bit;//传输数据个数
- reg [31:0] cnt;//记录波特率,即记录何时让cnt_bit加1
- ******开始信号寄存*****
- always@(posedge sysclk)
- if(!rst_n)
- rx_flag<=2'b11;
- else
- rx_flag<={rx_flag[0],RX};
-
- ******state1*****
- always@(posedge sysclk)
- if(!rst_n)
- cur_state<=IDLE;
- else
- cur_state<=next_state;
- ******state2*****
- always@(*) begin
- next_state = IDLE;
- case(cur_state)
- IDLE:begin
- if(rx_flag==2'b10)
- next_state = START;
- else
- next_state = IDLE;
- end
- START:begin
- if(cnt_bit==5'd1)
- next_state = DATA;
- else
- next_state = START;
- end
- DATA:begin
- if(cnt_bit==5'd9)
- next_state = STOP;
- else
- next_state = DATA;
- end
- STOP:begin
- if(cnt_bit==5'd9 && rx_flag == 2'b11)
- next_state = IDLE;
- else
- next_state = STOP;
- end
- default:begin
- next_state = IDLE;
- end
- endcase
- end
- ******state3*****
- always@(posedge sysclk)
- if(!rst_n) begin
- cnt_bit <= 5'd0;
- cnt <= 32'd0;
- Data <= 8'd0;
- vaild <= 32'd0;
- end
- else
- case(next_state)
- IDLE:begin
- cnt_bit <= 5'd0;
- cnt <= 32'd0;
- vaild <= 32'd0;
- Data <= Data;//可以为0,也可以保持上一次的数据
- end
- START:begin
- if(cnt >= CLK_DELAY-1)begin
- cnt <= 32'd0;
- cnt_bit <= cnt_bit + 32'd1;
- end
- else begin
- cnt_bit <= cnt_bit;
- cnt <= cnt + 32'd1;
- end
- Data <= Data;
- vaild <= 0;
- end
- DATA:begin
- if(cnt >= CLK_DELAY-1)begin
- cnt <= 32'd0;
- cnt_bit <= cnt_bit + 32'd1;
- end
- else begin
- cnt_bit <= cnt_bit;
- cnt <= cnt + 32'd1;
- end
- if(cnt == CLK_MID-1) //中点的时候进行数据的采集,这样能保证数据采集比较稳定//
- Data <= {RX,Data[7:1]};
- else
- Data <= Data;
- vaild <= 0;
- end
- STOP:begin
- if(cnt >= CLK_DELAY-1)begin
- cnt <= 32'd0;
- cnt_bit <= cnt_bit + 32'd1;
- end
- else begin
- cnt_bit <= cnt_bit;
- cnt <= cnt + 32'd1;
- end
- Data <= Data;
- if(cnt == CLK_MID-1)
- vaild <= 1;
- else
- vaild <= 0;
- end
- default:begin
- cnt_bit <= 5'd0;
- cnt <= 32'd0;
- Data <= 8'd0;
- vaild <= 32'd0;
- end
- endcase
- endmodule

然后是接收控制信息的模块,rx传出来的Data会输入到这个模块里面,根据输入的控制信息输出
对应的小车控制信息。
- module rx_ctrl(
- input sysclk ,
- input rst_n ,
- input [7:0] Data ,
- output reg [3:0] car_ctrl_2
- );
-
- always@(posedge sysclk)
- if(!rst_n)
- car_ctrl_2 <= 4'b0000;
- else
- case(Data)
- 8'h47 : car_ctrl_2 <= 4'b1001;//前进
- 8'h4b : car_ctrl_2 <= 4'b0110;//后退
- 8'h4a : car_ctrl_2 <= 4'b1010;//右转
- 8'h48 : car_ctrl_2 <= 4'b0101;//左转
- 8'h49 : car_ctrl_2 <= 4'b0000;//停止
- default :car_ctrl_2 <= 4'b0000;
- endcase
- endmodule

然后是TOP模块,我们需要将所有的模块都都连接起来。这里顶层加了一个led的输出,这样方便我们观察我们当前处于什么状态,也可以方便我们切换状态,通过判断led处于什么状态,将小车的控制输出交给相对应的控制输出模块。在这个里面,数码管和led都可以不用加,这里加入了只是因为可以更好的帮助我们观察小车的状态。
- `timescale 1ns / 1ps
-
-
- module TOP8(
- input sysclk,
- input rst_n,
- input echo,//输出的超声波
- input [1:0] D0,
- input RX,
- output trig ,//产生高电平
- output reg [3:0] led ,
- output [7:0] seg ,
- output [3:0] dig ,
- output reg [3:0] car
- );
-
- //assign car=4'b1010;
- wire [13:0] distance;
- wire [7:0] Data;
- wire [3:0] car_ctrl0;//避障
- wire [3:0] car_ctrl1;//循迹
- wire [3:0] car_ctrl2;//蓝牙
- always @(posedge sysclk)
- if(!rst_n)
- led<=4'b0000;
- else
- case(Data)
- 8'h41:led<=4'b0001;//避障
- 8'h42:led<=4'b0010;//循迹
- //8'h43:led=4'b0100;//蓝牙
- default :led<=4'b0100;
- endcase
- always @(posedge sysclk)
- if(!rst_n)
- car<=4'b0000;
- else
- case(led)
- 4'b0001:car<=car_ctrl0;//避障
- 4'b0010:car<=car_ctrl1;//循迹
- 4'b0100:car<=car_ctrl2;//蓝牙
- default :car<=4'b0000;
- endcase
- csb csb1(
- .sysclk (sysclk ),
- .rst_n (rst_n ),
- .trig (trig ),//产生高电平
- .echo (echo ),//输出的超声波
- .distance(distance)
- );
- seg seg1(
- . sysclk (sysclk) ,
- . rst_n (rst_n ) ,
- . num (distance ) , //数码管上显示的数字0-9999
- . seg (seg ) ,//段选8个灯
- . dig (dig ) //位选4个数码管
- );
- car_c car1(
- . sysclk (sysclk) ,
- . rst_n (rst_n ) ,
- . distance (distance) ,
- . car (car_ctrl0 )
- );
- red_line red1(
- .sysclk (sysclk),
- .rst_n (rst_n ),
- .D0 (D0 ),
- .car (car_ctrl1 )
- );
- uart_RX_car
- #(
- . SYSCLK(50_000_000 ) ,//系统时钟
- . Baud (9600 ) //波特率
- )
- uart1(
- . sysclk ( sysclk ) ,
- . rst_n ( rst_n ) ,
- . RX ( RX ) ,
- . vaild ( vaild ) ,//数据有效
- . Data ( Data )
- );
- rx_ctrl rx1(
- . sysclk ( sysclk ) ,
- . rst_n ( rst_n ) ,
- . Data ( Data ) ,
- .car_ctrl_2 (car_ctrl2 )
- );
-
-
-
-
- endmodule

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。