728x90
반응형
[오류 수정]
동작 중에 echo wire를 뺴버리면, 동작이 중단되고 pedge를 기다리는 상태에 갇혀서 못 빠져나온다.
따라서 이러한 에러가 발생했을 경우에 에러 처리를 하는 코드를 추가해보자.
S_WAIT_PEDGE : begin
LED_bar[2] <= 1;
if(echo_pedge) begin
old_usec <= count_usec;
count_usec_e <= 1;
next_state <= S_WAIT_NEDGE;
end
else begin // 따지고 보면, pedge 발생 안 하면 아무 것도 안 하는 상태이다. 사실 아무 것도 안 아면, else 생략 가능
if(count_usec < 22'd80_000) begin
count_usec_e <= 1;
next_state <= S_WAIT_PEDGE;
end
else begin // 80ms동안 pedge가 안 나오면, 초기상태로 돌아가라.
next_state <= S_IDLE;
count_usec_e <= 0;
end
end
end
S_WAIT_NEDGE : begin
LED_bar[3] <= 1;
if(echo_nedge) begin
// temp_value[0] <= count_usec; // 0번 index에 접근
temp_value[index] <= count_usec - old_usec;
index <= index + 1; // 2의 거듭제곱 쓰면 if문 써서 조건 추가할 필요가 없다. 15다음 16, 7다음8이니까~ 자동적으로 1더하면 0으로 초기화됨
count_usec_e <= 0;
next_state <= S_IDLE;
end
else begin // 안 써줘도 되는 건데, 가독성을 위해 작성
if(count_usec < 22'd80_000) begin
count_usec_e <= 1;
next_state <= S_WAIT_NEDGE;
end
else begin // 80ms동안 nedge 안 나오면, 초기상태로 돌아가라
next_state <= S_IDLE;
count_usec_e <= 0;
end
end
end
위와 같이 Echo핀을 빼도 trig 신호가 정상적으로 동작한다.
[FSM를 쓰지 않고 구현]
📌 Main module
module Ultrasonic_not_fsm(
input clk, rst,
input echo,
output reg trig,
output reg [15:0] distance,
output reg [7:0] LED_bar
);
reg [16:0] count_usec_ch, count_usec_tr, count_usec_idle; // 넉넉히 주면 좋다. 메뉴얼에는 60ms의 여유를 주라 했는데, 실제로는 70ms 넘어서도 걸린다.
wire clk_usec;
reg count_usec_ch_e, count_usec_tr_e, count_usec_idle_e;
clock_usec usec_clk(.clk(clk), .rst(rst), .clk_usec(clk_usec));
// usec Counter
always @(negedge clk, posedge rst) begin
if(rst) begin
count_usec_ch = 0; // 리셋 누르면 출력이 0되도록 설계
end
else begin
// data가 들어올 때 동안만 count
if(clk_usec && count_usec_ch_e) count_usec_ch = count_usec_ch + 1; // enable이 1이고, clk_usec가 들어올 때만 count++
else if(!count_usec_ch_e) count_usec_ch = 0;
end
end
// usec Counter
always @(negedge clk, posedge rst) begin
if(rst) begin
count_usec_tr = 0;
end
else begin
// data가 들어올 때 동안만 count
if(clk_usec && count_usec_tr_e) count_usec_tr = count_usec_tr + 1;
else if(!count_usec_tr_e) count_usec_tr = 0;
end
end
// usec Counter
always @(negedge clk, posedge rst) begin
if(rst) begin
count_usec_idle = 0;
end
else begin
// data가 들어올 때 동안만 count
if(clk_usec && count_usec_idle_e) count_usec_idle = count_usec_idle + 1;
else if(!count_usec_idle_e) count_usec_idle = 0;
end
end
//Edge를 보내서 쓰는 걸로 clk 동기화
wire echo_pedge, echo_nedge;
edge_detector_n edg_echo(.clk(clk), .cp_in(echo), .rst(rst), .p_edge(echo_pedge), .n_edge(echo_nedge)); // Edge Detector
// trigger
always @(posedge clk, posedge rst) begin
if(rst) begin
trig = 0;
count_usec_tr_e = 0;
count_usec_idle_e = 0;
LED_bar = 8'b0000_0000;
end
else begin
// IDLE
if(count_usec_idle < 22'd80_000) begin
// if(count_usec_idle < 22'd5000) begin
count_usec_idle_e = 1;
LED_bar[0] = 1;
end
else begin
// trigger
if(count_usec_tr < 22'd12) begin
trig = 1;
count_usec_tr_e = 1;
end
else begin
trig = 0;
count_usec_tr_e = 0;
count_usec_idle_e = 0;
LED_bar[1] = 1;
end
end
end
end
//echo
reg [16:0] temp_value [15:0], old_time;
reg [20:0] sum_value;
reg [3:0] index;
always @(posedge clk, posedge rst) begin
if(rst) begin
count_usec_ch_e = 0;
index = 0;
old_time = 0;
LED_bar = 8'b0000_0000;
end
else begin
if(echo_pedge) begin
old_time = count_usec_ch;
end
else if(echo_nedge) begin // 1 clk(8ns) 안에 pedge와 nedge가 둘 다 High가 되지 않으므로, els
temp_value[index] = (count_usec_ch - old_time);
index = index + 1;
count_usec_ch_e = 0;
end
else begin
if(count_usec_ch < 22'd23_200) begin
count_usec_ch_e = 1;
end
else begin
count_usec_ch_e = 0;
end
end
end
end
// calculate
reg [5:0] i;
always @(posedge clk_usec, posedge rst) begin
if(rst) begin
sum_value = 0;
i = 0;
end
else begin
LED_bar[7] = 1;
sum_value = 0;
for(i = 0 ; i < 16 ; i = i+1) begin
sum_value = sum_value + temp_value[i];
end
end
end
// distance
always @(posedge clk_usec, posedge rst) begin
if(rst) begin
distance = 0;
end
else begin
distance = sum_value[20:4] / 58;
end
end
endmodule
📌 Top module
module Ultrasonic_Top_not_fsm(
input clk, rst,
input echo,
output trig,
output [7:0] LED_bar,
output [3:0] com,
output [7:0] seg_7
);
wire [15:0] distance;
Ultrasonic_not_fsm SR04_not(clk, rst, echo, trig, distance, LED_bar);
wire [15:0] distance_dec;
bin_to_dec ultra_b2d(.bin(distance[11:0]), .bcd(distance_dec)); // 400cm 충분히 받으므로 12bit로 짤라버려도 된다.
FND_4digit_cntr fnd_cntr(.clk(clk), .rst(rst), .value(distance_dec), .com(com), .seg_7(seg_7));
endmodule
[Testbench]
module tb_Ultrasonic_profsr();
reg clk, rst;
reg echo;
wire trig;
wire [15:0] distance_cm;
// wire [7:0] LED_bar;
UltraSonic_Profsr DUT(clk, rst, echo, trig, distance_cm, LED_bar);
parameter data1 = 58 * 10 * 1000; // 10cm, usec으로 바꿔주려면 1000 곱해줘야 한다.
parameter data2 = 58 * 23 * 1000; // 23cm
initial begin
clk = 0;
rst = 1;
echo = 0;
end
always #4 clk = ~clk;
// data1 16번 보내고, data2 16번 보낼 것이다.
integer i;
initial begin
#8;
rst = 0; #8;
for(i = 0 ; i < 16 ; i = i+1) begin
wait(trig);
wait(!trig);
#28000; // 28ms동안 burst 대기
echo = 1; #data1;
echo = 0;
end
for(i = 0 ; i < 16 ; i = i+1) begin
wait(trig);
wait(!trig);
#28000; // 28ms동안 burst 대기
echo = 1; #data2;
echo = 0;
end
#28000; // FND에 출력될 시간은 줘야 된다.
$stop;
end
endmodule
728x90
반응형