FPGA入门实验-基于状态机实现超声波避障小车

任务目标

基于状态机实现超声波避障小车。最近生产实习的FPGA培训课程内容,还是挺简单的。具体原理其他文章应该都烂大街了,重点是状态机的写法,还是很少博主写,没怎么看到,基本上都是时序机写的模块功能。

电机驱动用的L298N,默认全速拉满,没用PWM调制速度。

实现代码

整改TOP逻辑涉及电机控制,超声波测距,数码管显示超声波读数。后面两个模块之前的文章都写了代码的。这里我就直接引用吧,不做过多篇幅了。

数码管显示seg.v和超声波测距trasonic.v:

FPGA入门实验-基于状态机实现4位共阴极数码管显示超声波模块读数_星羽空间的博客-CSDN博客FPGA基于状态机实现4位共阴极数码管显示超声波模块读数https://blog.csdn.net/qq_25662827/article/details/125213391这里增添了L298N电机驱动代码:

module MOTOR(
    input sysclk,
    input rst_n,
	input ENA,
	input ENB,
	input	[1:0]	ATRUN,
	input	[1:0]	BTRUN,
	output	reg	[1:0]	EN,
	output	reg	[1:0]	AIN,
	output	reg	[1:0]	BIN
);

always@(posedge sysclk)	begin
    if(!rst_n) begin
        EN <= 2'b00;
        AIN <= 2'b00;
        BIN <= 2'b00;
        end
    else
        begin
        EN <= {ENB ,ENA};
        AIN <= ATRUN;
        BIN <= BTRUN;
        end
	end

endmodule

最后就剩顶层逻辑了。也是状态机实现的。并且做了二阶均值滤波,让超声波读数平滑一点,减少噪声,TOP.v:

module top(
    input           sysclk      ,
    input           rst_n       ,
    input           Echo        ,
    output          Trig        ,
    output  [7:0]   SEG         ,
    output  [3:0]   DIG         ,
    output  [1:0]   AIN         ,
    output  [1:0]   BIN
    );

wire    [15:0]  numtemp ;
reg     [15:0]  num     ;
reg     [1:0]   ATRUN   ;
reg     [1:0]   BTRUN   ;
wire    [1:0]   MOTOREN ;

reg     [31:0]  cnt     ;
reg     [1:0]   cur_state, next_state;
parameter   IDLE    =   2'b00;
parameter   GO      =   2'b01;
parameter   STOP    =   2'b10;
parameter   TRUN    =   2'b11;
parameter   DELAY   =   32'd62_500_000;
parameter   THRESHHOLD   =   15'd25;
reg             goflag;

seg
#(
     .SYSCLK    (125_000_000)   ,
     .TIME      (1000)          ,
     .MODE      (0)
)a(
       .sysclk  (sysclk)    ,
       .rst_n   (rst_n)     ,
       .set     (10)        ,
       .number  (num)       ,
       .DIG     (DIG)       ,
       .SEG     (SEG)
    );

trasonic
#(
    .SYSCLK  (125_000_000)      ,
    .TIME1   (5000       )      ,
    .TIME2   (20_000_000 )
)b(
    .sysclk  (sysclk)  ,
    .rst_n   (rst_n)   ,
    .Echo    (Echo)    ,
    .Trig    (Trig)    ,
    .distence(numtemp)
    );

MOTOR c(
    .sysclk(sysclk),
    .rst_n(rst_n),
	.ENA(1'b1),
	.ENB(1'b1),
	.ATRUN(ATRUN),
	.BTRUN(BTRUN),
	.EN(MOTOREN),
	.AIN(AIN),
	.BIN(BIN)
);

//____________________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
            next_state = GO;
        end
        GO:begin
            if(num < THRESHHOLD)
                next_state = STOP;
            else
                next_state = GO;
        end
        STOP:begin
            if(cnt >= DELAY - 1)
                if(goflag)
                    next_state = TRUN;
                else if(num >= THRESHHOLD)
                    next_state = GO;
                else
                    next_state = TRUN;
            else
                next_state = STOP;
        end
        TRUN:begin
            if(num>= THRESHHOLD)
                next_state = STOP;
            else
                next_state = TRUN;
        end
    endcase
    end

//________________________state3______________________//
always@(posedge sysclk)
    if(!rst_n)begin
        cnt <= 32'd0;
        ATRUN <= 2'b00;
        BTRUN <= 2'b00;
        goflag <= 1'b0;
        num <=  numtemp;
    end
    else begin
        case(cur_state)
        IDLE:begin
            cnt <= 32'd0;
            ATRUN <= 2'b00;
            BTRUN <= 2'b00;
            goflag <= 1'b0;
            num <=  numtemp;
            end
        GO:begin
            cnt <= 32'd0;
            ATRUN <= 2'b01;
            BTRUN <= 2'b01;
            goflag <= 1'b1;
            num <=  (num + numtemp)/2;
            end
        STOP:begin
            cnt <= cnt + 1;
            ATRUN <= 2'b00;
            BTRUN <= 2'b00;
            goflag <= goflag;
            num <=  (num + numtemp)/2;
            end
        TRUN:begin
            goflag <= 1'b0;
            ATRUN <= 2'b01;
            BTRUN <= 2'b10;
            cnt <= 32'd0;
            num <=  (num + numtemp)/2;
            end
        endcase
    end


endmodule

结语

这个代码量对于新手来说还是有点吃不消的吧。不过反反复复踏踏实实地去理解每个模块的实现方法,和代码逻辑,也就能通透许多了。

在装车过程中,尽量装得标准一点。单侧车轮正反转方向一致,方向前后设定明确(以超声波一侧为车头,除非将此模块作为倒车检测),布线尽量简约一点。

你可能感兴趣的:(fpga开发)