基于FPAG的坐姿调整灯(Verilog测距、四位数码管、伺服电机驱动)

本文介绍了一种基于FPGA的智能坐姿调整灯设计,该设计使用Verilog实现测距传感、四位数码管显示和伺服电机驱动等功能,能够根据使用者的坐姿调整灯光高度,并具备蜂鸣报警和维护模式。

@基于FPAG的坐姿调整灯(Verilog测距、四位数码管、伺服电机驱动)

核心功能(基于EGO1)

1.Verilog测距传感(利用HC-SR04测距传感器)
2.Verilog四位数码管显示
3.Verilog伺服电机驱动(包含维护模式)
4.蜂鸣报警、及各种传感器维护模式

主函数

// module onic_detect(clk_100m, rst, Trig, Echo,kaiguan,
an,bn,code_out,code_out2,
q,q2,LED2,LED1,LED0,fengmingqi);//主模块输入输出
input clk_100m, rst, Echo;
input [2:0]kaiguan;
output Trig;
output [3:0]an;
output [3:0]bn;
output [7:0]code_out;/*  out  */
output [7:0]code_out2;
output q,q2;
output LED2;
output LED1;
output LED0;
output fengmingqi;
reg fengmingqi;
wire [15:0]N;
reg  [50:0]high;
wire [50:0]low;
reg [50:0]cnt = 0;
reg [50:0]cnt2 = 0;
reg [15:0]dis;
reg [3:0]an;
reg [3:0]bn;
reg [7:0]code_out;
//控制右边四位数码管显示的数字
reg [7:0]code_out2;
//控制左边四位数码管显示的数字
reg [50:0] count=0;
reg q;
//输出不同占空比控制台灯的升降
reg q2;
reg LED2;
reg LED1;
reg LED0;
reg led;
//控制呼吸灯有强到弱再由弱到强
reg [10:0]cntus=0;
reg [10:0]cntms=0;
reg [10:0]cnts=0;
reg [2:0]cnt2s=0;
wire clk_1m;
wire[15:0] dis0; // 回波高电平持续时间us 
wire[15:0] d;   // 距离(单位cm),5位十进制,包括两位小数

##为HC-SR04测距传感器(50分频)

Clk_1M u0(.clk_out(clk_1m),.clk_in(clk_100m), .rst(rst)); // 50分频
TrigSignal u1(.clk_1m(clk_1m),.trig(Trig));
PosCounter u2(.clk_1m(clk_1m), .rst(rst), .echo(Echo), .dis_count(dis0));
assign low = 2000000-high;
assign d[15:12] = dis0/1000%10;  // 十位
assign d[11:8]  = dis0/100%10;   // 个位
assign d[7:4]   = dis0/10%10;    // 0.1
assign d[3:0]   = dis0%10;       // 0.01
parameter T1US = 8'd100;
parameter T1MS = 10'd1000;
parameter T1S = 10'd1000;
always @ (posedge clk_100m)
begin
q2<=q;
end

##伺服电机维护模式
拨动三个开关 分别控制电机三种工作模式

always @ (posedge clk_100m or negedge rst)
if(kaiguan==3'b001)
//维护模式中使电机降到最低位置
begin
code_out2 <= code_out;
bn <= an;
if(!rst)
       begin
             cnt <= 0;
       end
else if(cnt2==100000000)
       begin
             cnt2 <=0;
       end
else if(cnt==400000)
       begin
             cnt<=0;
       end
else
       begin
             cnt=cnt+1;
             cnt2=cnt2+1;
        end
if ((cnt2<=50000000)&&(cnt2>=1))
        begin
        dis <=16'b1011101110111011;
        end
else if((cnt2>50000000)&&(cnt2<100000000))
        begin 
        dis <=16'b1010101010101010;
        end
end
else if(kaiguan==3'b010)
//维护模式中使电机降到中间位置
begin
bn <= an;
code_out2 <= code_out;
if(!rst)
       begin
             cnt <= 0;
       end
else if(cnt2==100000000)
       begin
             cnt2 <=0;
       end
else if(cnt==400000)
       begin
             cnt<=0;
       end
else
       begin
             cnt=cnt+1;
             cnt2=cnt2+1;
        end
if ((cnt2<=50000000)&&(cnt2>=1))
        begin
        dis <=16'b1100110011001100;
        end
else if((cnt2>50000000)&&(cnt2<100000000))
        begin 
        dis <=16'b1010101010101010;
        end
end
else if(kaiguan==3'b100)
//维护模式中使电机降到最高位置
begin
bn <= an;
code_out2 <= code_out;
if(!rst)
       begin
             cnt <= 0;
       end
else if(cnt2==100000000)
       begin
             cnt2 <=0;
       end
else if(cnt==400000)
       begin
             cnt<=0;
       end
else
       begin
             cnt=cnt+1;
             cnt2=cnt2+1;
        end
if ((cnt2<=50000000)&&(cnt2>=1))
        begin
        dis <=16'b1101110111011101;
        end
else if((cnt2>50000000)&&(cnt2<100000000))
        begin 
        dis <=16'b1010101010101010;
        end
end



else//数码管部分维护
begin
bn <= an;
code_out2<=8'b00111111;
if(!rst)
       begin
             cnt <= 0;
       end
else if(cnt==400000)
       begin
             cnt<=0;
       end
else
       begin
             cnt=cnt+1;
             dis<=d;
       end
end

##四位数码管显示

always @ (posedge clk_100m)
//通过数码管显示出距离
if ((1<cnt)&(cnt<=100000))
begin
an <= 4'b0001;
case(dis[15:12])
0 :code_out<= 8'b00111111;
1 :code_out<= 8'b00000110;
2 :code_out <=8'b01011011;
3 : code_out<=8'b01001111;
4 : code_out<=8'b01100110;
5 : code_out<=8'b01101101;
6 :code_out<= 8'b01111101;
7 : code_out<=8'b00000111;
8 :code_out<= 8'b01111111;
9 : code_out<=8'b01101111;
10 : code_out<=8'b0;
11 : code_out<=8'b00001000;
12 : code_out<=8'b01000000;
13 : code_out<=8'b00000001;
endcase
end
else if ((100000<cnt)&(cnt<=200000))
begin
an<=4'b0010;
case(dis[11:8])
0 :code_out<= 8'b10111111;
1 :code_out<= 8'b10000110;
2 :code_out <=8'b11011011;
3 : code_out<=8'b11001111;
4 : code_out<=8'b11100110;
5 : code_out<=8'b01101101;
6 :code_out<= 8'b11111101;
7 : code_out<=8'b10000111;
8 :code_out<= 8'b11111111;
9 : code_out<=8'b11101111;
10 : code_out<=8'b0;
11 : code_out<=8'b00001000;
12 : code_out<=8'b01000000;
13 : code_out<=8'b00000001;
endcase
end
else if ((200000<cnt)&(cnt<=300000))
begin
an<=4'b0100;
case(dis[7:4])
0 :code_out<= 8'b00111111;
1 :code_out<= 8'b00000110;
2 :code_out <=8'b01011011;
3 : code_out<=8'b01001111;
4 : code_out<=8'b01100110;
5 : code_out<=8'b01101101;
6 :code_out<= 8'b01111101;
7 : code_out<=8'b00000111;
8 :code_out<= 8'b01111111;
9 : code_out<=8'b01101111;
10 : code_out<=8'b0;
11 : code_out<=8'b00001000;
12 : code_out<=8'b01000000;
13 : code_out<=8'b00000001;
endcase
end
else if ((300000<cnt)&(cnt<400000))
begin
an<=4'b1000;
case(dis[3:0])
0 :code_out<= 8'b00111111;
1 :code_out<= 8'b00000110;
2 :code_out <=8'b01011011;
3 : code_out<=8'b01001111;
4 : code_out<=8'b01100110;
5 : code_out<=8'b01101101;
6 :code_out<= 8'b01111101;
7 : code_out<=8'b00000111;
8 :code_out<= 8'b01111111;
9 : code_out<=8'b01101111;
10 : code_out<=8'b0;
11 : code_out<=8'b00001000;
12 : code_out<=8'b01000000;
13 : code_out<=8'b00000001;
endcase
end

##四位数码管显示

always @ (posedge clk_100m)
//通过数码管显示出距离
if ((1<cnt)&(cnt<=100000))
begin
an <= 4'b0001;
case(dis[15:12])
0 :code_out<= 8'b00111111;
1 :code_out<= 8'b00000110;
2 :code_out <=8'b01011011;
3 : code_out<=8'b01001111;
4 : code_out<=8'b01100110;
5 : code_out<=8'b01101101;
6 :code_out<= 8'b01111101;
7 : code_out<=8'b00000111;
8 :code_out<= 8'b01111111;
9 : code_out<=8'b01101111;
10 : code_out<=8'b0;
11 : code_out<=8'b00001000;
12 : code_out<=8'b01000000;
13 : code_out<=8'b00000001;
endcase
end
else if ((100000<cnt)&(cnt<=200000))
begin
an<=4'b0010;
case(dis[11:8])
0 :code_out<= 8'b10111111;
1 :code_out<= 8'b10000110;
2 :code_out <=8'b11011011;
3 : code_out<=8'b11001111;
4 : code_out<=8'b11100110;
5 : code_out<=8'b01101101;
6 :code_out<= 8'b11111101;
7 : code_out<=8'b10000111;
8 :code_out<= 8'b11111111;
9 : code_out<=8'b11101111;
10 : code_out<=8'b0;
11 : code_out<=8'b00001000;
12 : code_out<=8'b01000000;
13 : code_out<=8'b00000001;
endcase
end
else if ((200000<cnt)&(cnt<=300000))
begin
an<=4'b0100;
case(dis[7:4])
0 :code_out<= 8'b00111111;
1 :code_out<= 8'b00000110;
2 :code_out <=8'b01011011;
3 : code_out<=8'b01001111;
4 : code_out<=8'b01100110;
5 : code_out<=8'b01101101;
6 :code_out<= 8'b01111101;
7 : code_out<=8'b00000111;
8 :code_out<= 8'b01111111;
9 : code_out<=8'b01101111;
10 : code_out<=8'b0;
11 : code_out<=8'b00001000;
12 : code_out<=8'b01000000;
13 : code_out<=8'b00000001;
endcase
end
else if ((300000<cnt)&(cnt<400000))
begin
an<=4'b1000;
case(dis[3:0])
0 :code_out<= 8'b00111111;
1 :code_out<= 8'b00000110;
2 :code_out <=8'b01011011;
3 : code_out<=8'b01001111;
4 : code_out<=8'b01100110;
5 : code_out<=8'b01101101;
6 :code_out<= 8'b01111101;
7 : code_out<=8'b00000111;
8 :code_out<= 8'b01111111;
9 : code_out<=8'b01101111;
10 : code_out<=8'b0;
11 : code_out<=8'b00001000;
12 : code_out<=8'b01000000;
13 : code_out<=8'b00000001;
endcase
end

##目前看不懂。。。

always @ (posedge clk_100m)
begin
if(kaiguan==3'b001)
begin
high<=60000;
end
else if(kaiguan==3'b010)
begin
high<=150000;
end
else if(kaiguan==3'b100)
begin
high<=250000;
end
else 
    begin
    if(d[15:12]>=4)
    high<=250000;
    else if(d[15:12]>=2)
      high<=150000; 
    else 
    begin
    fengmingqi<=(high<=150000)?1:0;
    high<=60000;
    end
    end
       if (rst) 
            begin
                if (count <high) 
                    begin
                        count <= count+1'b1;
                        q <= 1;
                    end
                if (count >= high) 
                    begin
                        count <= count+1'b1;
                        q <= 0;
                    end
                if (count == high+low) 
                    begin
                        q <= 0;
                        count <= 1'b0;
                    end
            end
    
end

##呼吸灯相关。。。

always @ ( posedge clk_100m)
//呼吸灯控制程序
begin
 if (!rst)
 begin
 cntus <= 10'd0;
 cntms <= 10'd0;
 cnts <= 10'd0;
 end
 else if (cntus < 100 )
 cntus <= cntus + 1'b1;
 else
 cntus<= 6'd1;
 if(cntms<1000)
 begin
 if(cntus==100)
 cntms <= cntms + 1'b1;
 end
 else
 cntms<=10'd0;
 if(cnts<1000)
 begin
 if(cntms==1000)
 cnts <= cnts+1'b1;
 end
 else
 cnts<=0;
 if(cnt2s<2)
 begin
 if(cnts==1000)
 cnt2s<=cnt2s+1;
 end
 else
 cnt2s<=0;
 led<=(cnt2s==0)?((cntms<=cnts)?1:0):((cntms<=cnts)?0:1);
 end
 
 
 
 
always @ ( posedge clk_100m)
//维护模式中呼吸灯模块
if (kaiguan[2]==0)
LED2=0;
else
LED2=led;
always @ ( posedge clk_100m)
if (kaiguan[1]==0)
LED1=0;
else
LED1=led;
always @ ( posedge clk_100m)
if (kaiguan[0]==0)
LED0=0;
else
LED0=led;
Endmodule


##测距传感器控制部分(三个主要控制部分)

module Clk_1M (clk_in, rst, clk_out);
//进行分频(1Mhz)程序
    input clk_in;
    input rst;
    output reg clk_out;
    parameter high = 50, low =100-high;
	 reg [50:0] count=0;
    always @ (posedge clk_in)
        begin
            if (rst) 
                begin
                    if (count <high) 
                        begin
                            count <= count+1'b1;
                            clk_out <= 1;
                        end
                    if (count >= high) 
                        begin
                            count <= count+1'b1;
                            clk_out<= 0;
                        end
                    if (count == high+low) 
                        begin
                            clk_out <= 0;
                            count <= 1'b0;
                        end
                end
        end
  

endmodule



module TrigSignal(clk_1m,  trig); //产生10us的触发信号
input clk_1m;
    
    output reg trig;
    parameter high = 10, low =1000000-high;
	 reg [50:0] count=0;
    always @ (posedge clk_1m)
     
            
                begin
                    if (count <high) 
                        begin
                            count <= count+1'd1;
                            trig <= 1;
                        end
                    if (count >= high) 
                        begin
                            count <= count+1'd1;
                            trig<= 0;
                        end
                    if (count == high+low) 
                        begin
                            trig <= 0;
                            count <= 1'd0;
                        end
                end


module PosCounter(clk_1m, rst, echo, dis_count); // 检测回波高电平持续时间
input clk_1m, rst, echo;
output[15:0] dis_count;
parameter S0 = 2'b00, S1 = 2'b01, S2 = 2'b10; // 状态定义 S0:闲置, S1:开始测距计数, S2:结束测距计数
reg[1:0] curr_state, next_state;
reg echo_reg1, echo_reg2;
wire start;
wire finish;
assign start = echo_reg1&~echo_reg2;  //检测posedge
assign finish = ~echo_reg1&echo_reg2; //检测negedge
reg[15:0] count, dis_reg;
wire[15:0] dis_count; //测距计数
always@(posedge clk_1m, posedge rst)
begin
    if(!rst)
    begin
        echo_reg1 <= 0;
        echo_reg2 <= 0;
        count <= 0;
        dis_reg <= 0;
        curr_state <= S0;
    end
    else
    begin
        echo_reg1 <= echo;          // 当前
        echo_reg2 <= echo_reg1;     // 后一个
        case(curr_state)
        S0:begin
                if (start) // 检测到上升沿
                    curr_state <= next_state; //S1
                else
                    count <= 0;
            end
        S1:begin
                if (finish) // 检测到下降沿
                    curr_state <= next_state; //S2
                else
                    begin
                        count <= count + 1;
                    end
            end
        S2:begin
                dis_reg <= count; // 缓存计数结果
                count <= 0;
                curr_state <= next_state; //S0
            end
        endcase
    end
end
always@(curr_state)
begin
    case(curr_state)
    S0:next_state <= S1;
    S1:next_state <= S2;
    S2:next_state <= S0;
    endcase
end
assign dis_count = dis_reg * 100 / 58; // 距离,乘100取小数部分
endmodule

##数码管显示

module       cnt2=cnt2+1;
        end
if ((cnt2<=50000000)&&(cnt2>=1))
        begin
        dis <=16'b1011101110111011;
        end
else if((cnt2>50000000)&&(cnt2<100000000))
        begin 
        dis <=16'b1010101010101010;
        end
end




else if(kaiguan==3'b010)
begin
bn <= an;
code_out2 <= code_out;
if(!rst)
       begin
             cnt <= 0;
       end
else if(cnt2==100000000)
       begin
             cnt2 <=0;
       end
else if(cnt==400000)
       begin
             cnt<=0;
       end
else
       begin
             cnt=cnt+1;
             cnt2=cnt2+1;
        end
if ((cnt2<=50000000)&&(cnt2>=1))
        begin
        dis <=16'b1100110011001100;
        end
else if((cnt2>50000000)&&(cnt2<100000000))
        begin 
        dis <=16'b1010101010101010;
        end
end




else if(kaiguan==3'b100)
begin
bn <= an;
code_out2 <= code_out;
if(!rst)
       begin
             cnt <= 0;
       end
else if(cnt2==100000000)
       begin
             cnt2 <=0;
       end
else if(cnt==400000)
       begin
             cnt<=0;
       end
else
       begin
             cnt=cnt+1;
             cnt2=cnt2+1;
        end
if ((cnt2<=50000000)&&(cnt2>=1))
        begin
        dis <=16'b1101110111011101;
        end
else if((cnt2>50000000)&&(cnt2<100000000))
        begin 
        dis <=16'b1010101010101010;
        end
end



else
begin
bn <= an;
code_out2<=8'b00111111;
if(!rst)
       begin
             cnt <= 0;
       end
else if(cnt==400000)
       begin
             cnt<=0;
       end
else
       begin
             cnt=cnt+1;
             dis<=d;
       end
end

always @ (posedge clk_1m)
if ((1<cnt)&(cnt<=100000))
begin
an <= 4'b0001;
case(dis[15:12])
0 :code_out<= 8'b00111111;
1 :code_out<= 8'b00000110;
2 :code_out <=8'b01011011;
3 : code_out<=8'b01001111;
4 : code_out<=8'b01100110;
5 : code_out<=8'b01101101;
6 :code_out<= 8'b01111101;
7 : code_out<=8'b00000111;
8 :code_out<= 8'b01111111;
9 : code_out<=8'b01101111;
10 : code_out<=8'b0;
11 : code_out<=8'b00001000;
12 : code_out<=8'b01000000;
13 : code_out<=8'b00000001;
endcase
end
else if ((100000<cnt)&(cnt<=200000))
begin
an<=4'b0010;
case(dis[11:8])
0 :code_out<= 8'b10111111;
1 :code_out<= 8'b10000110;
2 :code_out <=8'b11011011;
3 : code_out<=8'b11001111;
4 : code_out<=8'b11100110;
5 : code_out<=8'b01101101;
6 :code_out<= 8'b11111101;
7 : code_out<=8'b10000111;
8 :code_out<= 8'b11111111;
9 : code_out<=8'b11101111;
10 : code_out<=8'b0;
11 : code_out<=8'b00001000;
12 : code_out<=8'b01000000;
13 : code_out<=8'b00000001;
endcase
end
else if ((200000<cnt)&(cnt<=300000))
begin
an<=4'b0100;
case(dis[7:4])
0 :code_out<= 8'b00111111;
1 :code_out<= 8'b00000110;
2 :code_out <=8'b01011011;
3 : code_out<=8'b01001111;
4 : code_out<=8'b01100110;
5 : code_out<=8'b01101101;
6 :code_out<= 8'b01111101;
7 : code_out<=8'b00000111;
8 :code_out<= 8'b01111111;
9 : code_out<=8'b01101111;
10 : code_out<=8'b0;
11 : code_out<=8'b00001000;
12 : code_out<=8'b01000000;
13 : code_out<=8'b00000001;
endcase
end
else if ((300000<cnt)&(cnt<400000))
begin
an<=4'b1000;
case(dis[3:0])
0 :code_out<= 8'b00111111;
1 :code_out<= 8'b00000110;
2 :code_out <=8'b01011011;
3 : code_out<=8'b01001111;
4 : code_out<=8'b01100110;
5 : code_out<=8'b01101101;
6 :code_out<= 8'b01111101;
7 : code_out<=8'b00000111;
8 :code_out<= 8'b01111111;
9 : code_out<=8'b01101111;
10 : code_out<=8'b0;
11 : code_out<=8'b00001000;
12 : code_out<=8'b01000000;
13 : code_out<=8'b00000001;
endcase
end





    always @ (posedge clk_1m)
begin
if(kaiguan==3'b001)
begin
high<=60000;
end
else if(kaiguan==3'b010)
begin
high<=150000;
end
else if(kaiguan==3'b100)
begin
high<=250000;
end
else 
    begin
    if(d>=35)
    high<=250000;
    else if(d>=20)
      high<=150000; 
    else 
    begin
    fengmingqi<=1;
    high<=60000;
    end
    end


        if (rst) 
            begin
                if (count <high) 
                    begin
                        count <= count+1'b1;
                        q <= 1;
                    end
                if (count >= high) 
                    begin
                        count <= count+1'b1;
                        q <= 0;
                    end
                if (count == high+low) 
                    begin
                        q <= 0;
                        count <= 1'b0;
                    end
            end
    
end

always @ ( posedge clk_1m)
begin
 if (!rst)
 begin
 cntus <= 10'd0;
 cntms <= 10'd0;
 cnts <= 10'd0;
 end
 else if (cntus < 100 )
 cntus <= cntus + 1'b1;
 else
 cntus<= 6'd1;
 if(cntms<1000)
 begin
 if(cntus==100)
 cntms <= cntms + 1'b1;
 end
 else
 cntms<=10'd0;
 if(cnts<1000)
 begin
 if(cntms==1000)
 cnts <= cnts+1'b1;
 end
 else
 cnts<=0;
 if(cnt2s<2)
 begin
 if(cnts==1000)
 cnt2s<=cnt2s+1;
 end
 else
 cnt2s<=0;
 led<=(cnt2s==0)?((cntms<=cnts)?1:0):((cntms<=cnts)?0:1);
 end
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值