@基于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
本文介绍了一种基于FPGA的智能坐姿调整灯设计,该设计使用Verilog实现测距传感、四位数码管显示和伺服电机驱动等功能,能够根据使用者的坐姿调整灯光高度,并具备蜂鸣报警和维护模式。
&spm=1001.2101.3001.5002&articleId=86727187&d=1&t=3&u=8e369d3d4a614544bbce69ff6eed383e)
7606

被折叠的 条评论
为什么被折叠?



