사용 코드 _radar_system_top
module radar_system_top(
input clk, reset_p,
input [4:0] btn,
input echo_1, echo_2,
output trig_1, trig_2,
output tx_uart,
output servo,
output scl, sda,
output [7:0] seg_7,
output [3:0] com,
output [15:0] led_debug
);
wire btn_nedge;
wire en_sonic;
wire [7:0] angle;
wire [11:0] dist1, dist2;
wire packet_sent;
wire [15:0] bcd_angle, bcd_dist1, bcd_dist2;
wire [15:0] sel_bcd;
reg [1:0] disp_st;
reg [7:0] en_graph;
reg data_ready, data_ready_d;
wire cg_pulse;
assign led_debug = {4'b0, disp_st, en_sonic, cg_pulse, en_graph};
// 버튼 엣지 검출
button_cntr u_btn (
.clk(clk),
.reset_p(reset_p),
.btn(btn[0]),
.btn_pedge(),
.btn_nedge(btn_nedge)
);
// 서보 PWM + 각도 생성
servo_pwm_top u_srv (
.clk(clk),
.reset_p(reset_p),
.en_sonic(en_sonic),
.pwm(servo),
.angle_cur(angle),
.seg_7(),
.com()
);
// 초음파 센서 1, 2
ultrasonic_top u_s1 (
.clk(clk),
.reset_p(reset_p),
.en(en_sonic),
.echo(echo_1),
.trig(trig_1),
.dist(dist1),
.seg_7(),
.com(),
.led_debug()
);
ultrasonic_top u_s2 (
.clk(clk),
.reset_p(reset_p),
.en(en_sonic),
.echo(echo_2),
.trig(trig_2),
.dist(dist2),
.seg_7(),
.com(),
.led_debug()
);
// UART 송신 핸드셰이크
always @(posedge clk or posedge reset_p) begin
if (reset_p) begin
data_ready <= 1'b0;
data_ready_d <= 1'b0;
end else begin
if (!data_ready && (dist1 != 0) && (dist2 != 0))
data_ready <= 1'b1;
else if (packet_sent)
data_ready <= 1'b0;
data_ready_d <= data_ready;
end
end
assign cg_pulse = data_ready && !data_ready_d;
// LCD 그래프
always @(posedge clk or posedge reset_p) begin
if (reset_p)
en_graph <= 8'd0;
else if (dist1 < 15) en_graph <= 8'b0000_0001;
else if (dist1 < 30) en_graph <= 8'b0000_0011;
else if (dist1 < 45) en_graph <= 8'b0000_0111;
else if (dist1 < 60) en_graph <= 8'b0000_1111;
else if (dist1 < 75) en_graph <= 8'b0001_1111;
else if (dist1 < 90) en_graph <= 8'b0011_1111;
else if (dist1 < 105) en_graph <= 8'b0111_1111;
else en_graph <= 8'b1111_1111;
end
// I2C LCD
i2c_txtlcd_top u_lcd (
.clk(clk),
.reset_p(reset_p),
.btn(btn[4:1]),
.en_cg(cg_pulse),
.en_graph(en_graph),
.scl(scl),
.sda(sda)
);
// UART 송신
uart_packet_sender u_uart (
.clk(clk),
.reset_p(reset_p),
.angle(angle),
.distance1(dist1),
.distance2(dist2),
.send_packet(data_ready),
.tx(tx_uart),
.packet_sent(packet_sent)
);
// BCD 변환
bin_to_dec u_b2d_ang (
.bin(angle),
.bcd(bcd_angle)
);
bin_to_dec u_b2d_d1 (
.bin(dist1),
.bcd(bcd_dist1)
);
bin_to_dec u_b2d_d2 (
.bin(dist2),
.bcd(bcd_dist2)
);
// FND 디스플레이 선택
always @(posedge clk or posedge reset_p) begin
if (reset_p)
disp_st <= 2'd0;
else if (btn_nedge) begin
if (disp_st == 2)
disp_st <= 0;
else
disp_st <= disp_st + 1;
end
end
assign sel_bcd = (disp_st == 0) ? bcd_angle :
(disp_st == 1) ? bcd_dist1 : bcd_dist2;
fnd_4digit_cntr u_fnd (
.clk(clk),
.reset_p(reset_p),
.value(sel_bcd),
.seg_7(seg_7),
.com(com)
);
endmodule
사용 코드 _ servo_pwm_top
module servo_pwm_top (
input clk,
input reset_p,
output en_sonic, // 1 system clock cycle (trigger)
output pwm, // 서보 PWM
output [7:0] angle_cur,
output [7:0] seg_7,
output [3:0] com
);
parameter SYS_CLK_FREQ = 100_000_000;
parameter MYCLK_FREQ = 2; // period = 500ms
parameter VALUE_COUNT_SEC = SYS_CLK_FREQ / (2 * MYCLK_FREQ);
parameter WIDTH_SEC = $clog2(VALUE_COUNT_SEC);
parameter CNT_MIN = 4; // 0.44ms
parameter CNT_MAX = 22; // 2.44ms
parameter VALUE_COUNT = CNT_MAX - CNT_MIN; // 18 (count) -> 180 (degree)
reg [2*VALUE_COUNT-1:0] r_cnt;
reg [4:0] r_cnt_pwm;
reg [WIDTH_SEC-1:0] r_cnt_sysclk;
reg r_clk_sec;
wire [15:0] duty_bcd;
wire clk_sec_nedge;
// Sonic 트리거 펄스
assign en_sonic = clk_sec_nedge;
assign angle_cur = ((r_cnt_pwm - CNT_MIN) << 3) + ((r_cnt_pwm - CNT_MIN) << 1);
// 0.5초 주기 펄스 생성 및 네거티브 엣지
always @(posedge clk or posedge reset_p) begin
if(reset_p) begin
r_cnt_sysclk <= 0;
r_clk_sec <= 0;
end else if(r_cnt_sysclk == VALUE_COUNT_SEC-1) begin
r_cnt_sysclk <= 0;
r_clk_sec <= ~r_clk_sec;
end else begin
r_cnt_sysclk <= r_cnt_sysclk + 1;
end
end
edge_detector ed_sec (
.clk(clk),
.reset_p(reset_p),
.sig(r_clk_sec),
.p_edge(), // 미사용
.n_edge(clk_sec_nedge)
);
// 1초 주기로 각도 변화(180도 왕복)
always @(posedge clk or posedge reset_p) begin
if(reset_p) begin
r_cnt <= 0;
r_cnt_pwm <= CNT_MIN;
end else if(clk_sec_nedge) begin
if(r_cnt >= VALUE_COUNT*2-1) begin
r_cnt <= 0;
r_cnt_pwm <= CNT_MIN;
end else if(r_cnt >= VALUE_COUNT) begin
r_cnt <= r_cnt + 1;
r_cnt_pwm <= r_cnt_pwm - 1;
end else begin
r_cnt <= r_cnt + 1;
r_cnt_pwm <= r_cnt_pwm + 1;
end
end
end
pwm_servo_180 servo_inst (
.clk(clk),
.reset_p(reset_p),
.duty(r_cnt_pwm),
.pwm(pwm)
);
bin_to_dec bcd_conv (
.bin({4'b0000, (r_cnt_pwm - CNT_MIN)}), // 8비트
.bcd(duty_bcd)
);
fnd_4digit_cntr fnd_disp (
.clk(clk),
.reset_p(reset_p),
.value(duty_bcd),
.seg_7(seg_7),
.com(com)
);
endmodule
사용 코드 _ pwm_servo_180
module pwm_servo_180 (
input clk,
input reset_p,
input [7:0] duty, // 0~179 입력 (180 step)
output pwm // PWM 출력
);
parameter SYS_CLK_FREQ = 100_000_000;
parameter PWM_FREQ = 50;
parameter DUTY_STEP = 180;
parameter VALUE_COUNT_PWM = SYS_CLK_FREQ / (2 * PWM_FREQ) / DUTY_STEP;
parameter WIDTH_PWM = $clog2(VALUE_COUNT_PWM);
reg [WIDTH_PWM-1:0] cnt_sysclk;
reg pwm_freq_180;
reg [7:0] cnt_duty;
reg pwm_r;
assign pwm = pwm_r;
// 180Hz 분주 파형 생성 (duty 마다 2번)
always @(posedge clk or posedge reset_p) begin
if (reset_p) begin
cnt_sysclk <= 0;
pwm_freq_180 <= 0;
end else if (cnt_sysclk == VALUE_COUNT_PWM-1) begin
cnt_sysclk <= 0;
pwm_freq_180 <= ~pwm_freq_180;
end else begin
cnt_sysclk <= cnt_sysclk + 1;
end
end
wire pwm_freq_180_nedge;
edge_detector ed_pwm (
.clk(clk),
.reset_p(reset_p),
.sig(pwm_freq_180),
.p_edge(), // 미사용
.n_edge(pwm_freq_180_nedge)
);
always @(posedge clk or posedge reset_p) begin
if (reset_p) begin
cnt_duty <= 0;
pwm_r <= 0;
end else if (pwm_freq_180_nedge) begin
if (cnt_duty >= DUTY_STEP-1)
cnt_duty <= 0;
else
cnt_duty <= cnt_duty + 1;
if (cnt_duty < duty)
pwm_r <= 1;
else
pwm_r <= 0;
end
end
endmodule
사용 코드 _ fnd_4digit_cntr
module fnd_4digit_cntr (
input clk,
input reset_p,
input [15:0] value,
output [7:0] seg_7,
output [3:0] com
);
reg [3:0] hex_value;
wire [3:0] com_wire;
ring_counter u_ring_counter (
.clk(clk),
.reset_p(reset_p),
.q(com_wire)
);
assign com = com_wire;
always @(posedge clk or posedge reset_p) begin
if (reset_p)
hex_value <= 0;
else begin
case (com_wire)
4'b1110: hex_value <= value[3:0];
4'b1101: hex_value <= value[7:4];
4'b1011: hex_value <= value[11:8];
4'b0111: hex_value <= value[15:12];
default: hex_value <= 0;
endcase
end
end
decoder_7seg_hex u_decoder (
.iHEX_VALUE(hex_value),
.oSEG_7(seg_7)
);
endmodule
사용 코드 _ ring_counter
module ring_counter (
input clk, reset_p,
output reg [3:0] q
);
parameter CNT_VALUE = 100_000;
parameter WIDTH = $clog2(CNT_VALUE);
reg [WIDTH-1:0] clk_div;
wire clk_div_msb;
always @(posedge clk or posedge reset_p) begin
if (reset_p) clk_div <= 0;
else clk_div <= clk_div + 1;
end
edge_detector ed (
.clk(clk),
.reset_p(reset_p),
.sig(clk_div[WIDTH-1]),
.p_edge(clk_div_msb),
.n_edge()
);
always @(posedge clk or posedge reset_p) begin
if (reset_p)
q <= 4'b1110;
else if (clk_div_msb)
q <= {q[2:0], q[3]};
end
endmodule
사용 코드 _decoder_7seg
module decoder_7seg(
input [3:0] hex_value, // 4비트 입력 (0~F)
output reg [7:0] seg_7 // 7세그먼트(8비트, a~g, dp)
);
always @(*) begin
case (hex_value)
4'h0 : seg_7 = 8'b0000_0011; // 0
4'h1 : seg_7 = 8'b1001_1111; // 1
4'h2 : seg_7 = 8'b0010_0101; // 2
4'h3 : seg_7 = 8'b0000_1101; // 3
4'h4 : seg_7 = 8'b1001_1001; // 4
4'h5 : seg_7 = 8'b0100_1001; // 5
4'h6 : seg_7 = 8'b0100_0001; // 6
4'h7 : seg_7 = 8'b0001_1011; // 7
4'h8 : seg_7 = 8'b0000_0001; // 8
4'h9 : seg_7 = 8'b0001_1001; // 9
4'hA : seg_7 = 8'b0001_0001; // A
4'hB : seg_7 = 8'b1100_0001; // b
4'hC : seg_7 = 8'b0110_0011; // C
4'hD : seg_7 = 8'b1000_0101; // d
4'hE : seg_7 = 8'b0110_0001; // E
4'hF : seg_7 = 8'b0111_0001; // F
default: seg_7 = 8'b0000_0000;
endcase
end
endmodule
사용 코드_ultrasonic_top
module ultrasonic_top (
input clk, reset_p,
input en,
input echo,
output trig,
output [11:0] dist,
output [7:0] seg_7,
output [3:0] com,
output [15:0] led_debug
);
wire [15:0] fnd_dist;
ultrasonic_sensor u_sensor (
.clk(clk),
.reset_p(reset_p),
.en(en),
.echo(echo),
.trig(trig),
.dist(dist),
.led_debug(led_debug)
);
bin_to_dec u_bcd (
.bin(dist),
.bcd(fnd_dist)
);
fnd_4digit_cntr u_fnd (
.clk(clk),
.reset_p(reset_p),
.value(fnd_dist),
.seg_7(seg_7),
.com(com)
);
endmodule
사용 코드_ultrasonic_sensor
module ultrasonic_sensor(
input clk, reset_p,
input en, echo,
output reg trig,
output reg [11:0] dist,
output [15:0] led_debug
);
parameter S_IDLE = 3'd0,
S_TRIG = 3'd1,
S_WAIT_R = 3'd2,
S_WAIT_F = 3'd3,
S_CALC = 3'd4;
reg [2:0] state, next_state;
reg [15:0] cnt_us;
reg [5:0] elap_us;
reg [11:0] cm_cnt;
reg prev_en;
wire clk_us;
clock_div_1us clkdiv(
.clk(clk),
.reset_p(reset_p),
.clk_us(clk_us) // 포트명 일치
);
assign led_debug[2:0] = state;
assign led_debug[15:3] = 0;
always @(posedge clk or posedge reset_p) begin
if (reset_p) begin
state <= S_IDLE;
prev_en <= 1'b0;
end else begin
state <= next_state;
prev_en <= en;
end
end
always @(*) begin
next_state = state;
case(state)
S_IDLE: if (~prev_en && en) next_state = S_TRIG;
S_TRIG: if (cnt_us >= 10) next_state = S_WAIT_R;
S_WAIT_R: if (echo) next_state = S_WAIT_F;
S_WAIT_F: if (~echo) next_state = S_CALC;
S_CALC: next_state = S_IDLE;
endcase
end
always @(posedge clk or posedge reset_p) begin
if (reset_p) begin
trig <= 0;
cnt_us <= 0;
elap_us <= 0;
cm_cnt <= 0;
dist <= 0;
end else begin
case(state)
S_IDLE: begin
trig <= 0; cnt_us <= 0; elap_us <= 0; cm_cnt <= 0;
end
S_TRIG: begin
trig <= 1;
if (clk_us) cnt_us <= cnt_us + 1;
end
S_WAIT_R: begin
trig <= 0; cnt_us <= 0;
end
S_WAIT_F: begin
if (clk_us) begin
elap_us <= elap_us + 1;
if (elap_us == 57) begin
elap_us <= 0;
cm_cnt <= cm_cnt + 1;
end
end
end
S_CALC: begin
dist <= cm_cnt;
end
endcase
end
end
endmodule
사용 코드 _ i2c_txtlcd_top
module i2c_txtlcd_top (
input clk, reset_p,
input [3:0] btn,
input en_cg,
input [7:0] en_graph,
output scl, sda,
output [15:0] led_debug
);
localparam VALUE_COUNT = 8_000_000;
localparam WIDTH = $clog2(VALUE_COUNT);
localparam S_IDLE = 7'b0000001,
S_INIT = 7'b0000010,
S_BYTE = 7'b0000100,
S_SH_R = 7'b0001000,
S_SH_L = 7'b0010000,
S_STRING = 7'b0100000,
S_SEND_CG = 7'b1000000;
// --- 그래프 데이터 --- //
reg [7:0] graph_line_0 [0:7];
reg [7:0] graph_line_1 [0:7];
reg [7:0] graph_line_2 [0:7];
reg [7:0] graph_line_3 [0:7];
reg [7:0] graph_line_4 [0:7];
reg [7:0] graph_line_5 [0:7];
reg [7:0] graph_line_6 [0:7];
reg [7:0] graph_line_7 [0:7];
integer i;
initial begin
for(i=0;i<8;i=i+1) begin
graph_line_0[i]=8'h00; graph_line_1[i]=8'h00; graph_line_2[i]=8'h00; graph_line_3[i]=8'h00;
graph_line_4[i]=8'h00; graph_line_5[i]=8'h00; graph_line_6[i]=8'h00; graph_line_7[i]=8'h00;
end
graph_line_0[7]=8'h1F;
graph_line_1[6]=8'h1F; graph_line_1[7]=8'h1F;
graph_line_2[5]=8'h1F; graph_line_2[6]=8'h1F; graph_line_2[7]=8'h1F;
graph_line_3[4]=8'h1F; graph_line_3[5]=8'h1F; graph_line_3[6]=8'h1F; graph_line_3[7]=8'h1F;
graph_line_4[3]=8'h1F; graph_line_4[4]=8'h1F; graph_line_4[5]=8'h1F; graph_line_4[6]=8'h1F; graph_line_4[7]=8'h1F;
graph_line_5[2]=8'h1F; graph_line_5[3]=8'h1F; graph_line_5[4]=8'h1F; graph_line_5[5]=8'h1F; graph_line_5[6]=8'h1F; graph_line_5[7]=8'h1F;
graph_line_6[1]=8'h1F; graph_line_6[2]=8'h1F; graph_line_6[3]=8'h1F; graph_line_6[4]=8'h1F; graph_line_6[5]=8'h1F; graph_line_6[6]=8'h1F; graph_line_6[7]=8'h1F;
for(i=0;i<8;i=i+1) graph_line_7[i]=8'h1F;
end
reg [WIDTH-1:0] cnt_clk;
reg [6:0] state, next_state;
reg en_cnt_clk;
reg send, rs;
reg [3:0] cnt_data, cnt_cg;
reg init_flag;
reg [7:0] send_buffer;
reg [39:0] hello;
reg [2:0] cnt_string;
wire [4:0] btn_pedge;
wire busy;
reg [3:0] col_idx;
assign led_debug = {7'b0, init_flag, en_cnt_clk, state};
// 버튼 엣지 검출 인스턴스
button_cntr u_btn0 (.clk(clk), .reset_p(reset_p), .btn(btn[0]), .btn_pedge(btn_pedge[0]), .btn_nedge());
button_cntr u_btn1 (.clk(clk), .reset_p(reset_p), .btn(btn[1]), .btn_pedge(btn_pedge[1]), .btn_nedge());
button_cntr u_btn2 (.clk(clk), .reset_p(reset_p), .btn(btn[2]), .btn_pedge(btn_pedge[2]), .btn_nedge());
button_cntr u_btn3 (.clk(clk), .reset_p(reset_p), .btn(btn[3]), .btn_pedge(btn_pedge[3]), .btn_nedge());
// I2C 송신 모듈
i2c_lcd_send_byte u_i2c (
.clk(clk),
.reset_p(reset_p),
.addr(7'h3F),
.send_buffer(send_buffer),
.send(send),
.rs(rs),
.scl(scl),
.sda(sda),
.busy(busy)
);
// 타이머 카운터
always @(posedge clk or posedge reset_p)
if (reset_p) cnt_clk <= 0;
else if (en_cnt_clk) cnt_clk <= cnt_clk + 1;
else cnt_clk <= 0;
// FSM 상태 전이
always @(posedge clk or posedge reset_p)
if (reset_p) state <= S_IDLE;
else state <= next_state;
// FSM 본체
always @(posedge clk or posedge reset_p) begin
if (reset_p) begin
next_state <= S_IDLE;
en_cnt_clk <= 0; cnt_data <= 0; cnt_string <= 5; cnt_cg <= 0;
init_flag <= 0; send <= 0; send_buffer <= 0; rs <= 0;
hello <= "Hello";
end else begin
case (state)
S_IDLE: begin
if (!init_flag) begin
if (cnt_clk == VALUE_COUNT-1) begin
next_state <= S_INIT; en_cnt_clk <= 0;
end else en_cnt_clk <= 1;
end else begin
if (btn_pedge[0]) next_state <= S_BYTE;
if (btn_pedge[1]) next_state <= S_SH_R;
if (btn_pedge[2]) next_state <= S_SH_L;
if (btn_pedge[3]) next_state <= S_STRING;
if (en_cg) begin next_state <= S_SEND_CG; cnt_data <= 0; end
end
end
S_INIT: begin
if (busy) begin
send <= 0;
if (cnt_data >= 6) begin cnt_data <= 0; init_flag <= 1; next_state <= S_IDLE; end
end else if (!send) begin
send <= 1; cnt_data <= cnt_data + 1;
case (cnt_data)
0: send_buffer <= 8'h33;
1: send_buffer <= 8'h32;
2: send_buffer <= 8'h28;
3: send_buffer <= 8'h0c;
4: send_buffer <= 8'h01;
5: send_buffer <= 8'h06;
endcase
end
end
S_BYTE: begin
if (busy) begin
next_state <= S_IDLE; send <= 0;
if (cnt_data >= 9) cnt_data <= 0; else cnt_data <= cnt_data + 1;
end else begin
rs <= 1; send_buffer <= "0" + cnt_data; send <= 1;
end
end
S_SH_R: begin
if (busy) begin next_state <= S_IDLE; send <= 0; end
else begin rs <= 0; send_buffer <= 8'h1c; send <= 1; end
end
S_SH_L: begin
if (busy) begin next_state <= S_IDLE; send <= 0; end
else begin rs <= 0; send_buffer <= 8'h18; send <= 1; end
end
S_STRING: begin
if (busy) begin
send <= 0;
if (!cnt_string) begin cnt_string <= 5; next_state <= S_IDLE; end
end else if (!send) begin
rs <= 1; send <= 1; cnt_string <= cnt_string - 1;
case (cnt_string)
5: send_buffer <= hello[39:32];
4: send_buffer <= hello[31:24];
3: send_buffer <= hello[23:16];
2: send_buffer <= hello[15:8];
1: send_buffer <= hello[7:0];
endcase
end
end
S_SEND_CG: begin
if (busy) begin
send <= 0;
if (cnt_cg == 11) begin cnt_cg <= 0; next_state <= S_IDLE; end
end else if (!send) begin
send <= 1;
case (cnt_cg)
0: begin rs <= 0; send_buffer <= 8'h40; end
1,2,3,4,5,6,7,8: begin
rs <= 1;
if (en_graph[0]) send_buffer <= graph_line_0[cnt_cg-1];
else if (en_graph[1]) send_buffer <= graph_line_1[cnt_cg-1];
else if (en_graph[2]) send_buffer <= graph_line_2[cnt_cg-1];
else if (en_graph[3]) send_buffer <= graph_line_3[cnt_cg-1];
else if (en_graph[4]) send_buffer <= graph_line_4[cnt_cg-1];
else if (en_graph[5]) send_buffer <= graph_line_5[cnt_cg-1];
else if (en_graph[6]) send_buffer <= graph_line_6[cnt_cg-1];
else send_buffer <= graph_line_7[cnt_cg-1];
end
9: begin rs <= 0; send_buffer <= 8'h80; end
10: begin rs <= 1; send_buffer <= 8'h00; end
endcase
cnt_cg <= cnt_cg + 1;
end
end
default: next_state <= S_IDLE;
endcase
end
end
endmodule
사용 코드_ i2c_lcd_send_byte
module i2c_lcd_send_byte (
input clk, reset_p,
input [6:0] addr,
input [7:0] send_buffer,
input send, rs,
output scl, sda,
output reg busy,
output [15:0] led_debug
);
localparam IDLE = 6'b00_0001;
localparam SEND_HIGH_NIBBLE_DIS = 6'b00_0010;
localparam SEND_HIGH_NIBBLE_EN = 6'b00_0100;
localparam SEND_LOW_NIBBLE_DIS = 6'b00_1000;
localparam SEND_LOW_NIBBLE_EN = 6'b01_0000;
localparam SEND_DISABLE = 6'b10_0000;
reg [5:0] state, next_state;
reg [7:0] data;
reg comm_start;
reg [21:0] cnt_us;
reg en_cnt_us;
wire send_pedge;
wire clk_us;
//assign led_debug = {8'b0, en_cnt_us, comm_start, state};
clock_div_1us u_clkdiv (
.clk(clk),
.reset_p(reset_p),
.clk_us(clk_us)
);
always @(posedge clk or posedge reset_p) begin
if (reset_p)
cnt_us <= 0;
else if (clk_us && en_cnt_us)
cnt_us <= cnt_us + 1;
else if (!en_cnt_us)
cnt_us <= 0;
end
edge_detector UED_send (
.clk(clk),
.reset_p(reset_p),
.sig(send),
.p_edge(send_pedge),
.n_edge()
);
I2C_master master (
.clk(clk),
.reset_p(reset_p),
.addr(addr),
.data(data),
.rd_wr(1'b0),
.comm_start(comm_start),
.scl(scl),
.sda(sda),
.led_debug(led_debug)
);
always @(posedge clk or posedge reset_p) begin
if (reset_p)
state <= IDLE;
else
state <= next_state;
end
always @(posedge clk or posedge reset_p) begin
if (reset_p) begin
next_state <= IDLE;
data <= 0;
busy <= 0;
en_cnt_us <= 0;
comm_start <= 0;
end else begin
case (state)
IDLE: begin
if (send_pedge) begin
next_state <= SEND_HIGH_NIBBLE_DIS;
busy <= 1;
end
end
SEND_HIGH_NIBBLE_DIS: begin
if (cnt_us <= 200) begin
data <= {send_buffer[7:4], 3'b100, rs};
comm_start <= 1;
en_cnt_us <= 1;
end else begin
next_state <= SEND_HIGH_NIBBLE_EN;
en_cnt_us <= 0;
comm_start <= 0;
end
end
SEND_HIGH_NIBBLE_EN: begin
if (cnt_us <= 200) begin
data <= {send_buffer[7:4], 3'b110, rs};
comm_start <= 1;
en_cnt_us <= 1;
end else begin
next_state <= SEND_LOW_NIBBLE_DIS;
en_cnt_us <= 0;
comm_start <= 0;
end
end
SEND_LOW_NIBBLE_DIS: begin
if (cnt_us <= 200) begin
data <= {send_buffer[3:0], 3'b100, rs};
comm_start <= 1;
en_cnt_us <= 1;
end else begin
next_state <= SEND_LOW_NIBBLE_EN;
en_cnt_us <= 0;
comm_start <= 0;
end
end
SEND_LOW_NIBBLE_EN: begin
if (cnt_us <= 200) begin
data <= {send_buffer[3:0], 3'b110, rs};
comm_start <= 1;
en_cnt_us <= 1;
end else begin
next_state <= SEND_DISABLE;
en_cnt_us <= 0;
comm_start <= 0;
end
end
SEND_DISABLE: begin
if (cnt_us <= 200) begin
data <= {send_buffer[3:0], 3'b100, rs};
comm_start <= 1;
en_cnt_us <= 1;
end else begin
next_state <= IDLE;
en_cnt_us <= 0;
comm_start <= 0;
busy <= 0;
end
end
endcase
end
end
endmodule
사용 코드 _uart_transmitter
module uart_transmitter(
input wire clk,
input wire reset_p,
input wire [7:0] data_in,
input wire send,
output reg tx,
output reg busy
);
// 115200 baud rate, 100MHz 클록
// Baud rate divisor = 100MHz / 115200 ≈ 868
parameter BAUD_DIVISOR = 868;
parameter IDLE = 2'b00;
parameter START = 2'b01;
parameter DATA = 2'b10;
parameter STOP = 2'b11;
reg [1:0] state;
reg [31:0] baud_counter;
reg [2:0] bit_counter;
reg [7:0] shift_reg;
always @(posedge clk or posedge reset_p) begin
if (reset_p) begin
state <= IDLE;
tx <= 1'b1;
busy <= 1'b0;
baud_counter <= 32'b0;
bit_counter <= 3'b0;
shift_reg <= 8'b0;
end else begin
case (state)
IDLE: begin
tx <= 1'b1;
busy <= 1'b0;
baud_counter <= 32'b0;
bit_counter <= 3'b0;
if (send) begin
shift_reg <= data_in;
busy <= 1'b1;
state <= START;
end
end
START: begin
tx <= 1'b0; // Start bit
baud_counter <= baud_counter + 1;
if (baud_counter >= BAUD_DIVISOR) begin
baud_counter <= 32'b0;
state <= DATA;
end
end
DATA: begin
tx <= shift_reg[0];
baud_counter <= baud_counter + 1;
if (baud_counter >= BAUD_DIVISOR) begin
baud_counter <= 32'b0;
shift_reg <= {1'b0, shift_reg[7:1]};
bit_counter <= bit_counter + 1;
if (bit_counter >= 7) begin
bit_counter <= 3'b0;
state <= STOP;
end
end
end
STOP: begin
tx <= 1'b1; // Stop bit
baud_counter <= baud_counter + 1;
if (baud_counter >= BAUD_DIVISOR) begin
baud_counter <= 32'b0;
state <= IDLE;
end
end
default: state <= IDLE;
endcase
end
end
endmodule
사용 코드 _ bin_to_dec
module bin_to_dec (
input [11:0] bin, // 이진 입력 (최대 4095)
output reg [15:0] bcd // 변환된 4자리 BCD 출력
);
reg [3:0] i;
always @(bin) begin
bcd = 0;
for (i = 0; i < 12; i = i + 1) begin
bcd = {bcd[14:0], bin[11 - i]};
if(i < 11 && bcd[3:0] > 4) bcd[3:0] = bcd[3:0] + 3;
if(i < 11 && bcd[7:4] > 4) bcd[7:4] = bcd[7:4] + 3;
if(i < 11 && bcd[11:8] > 4) bcd[11:8] = bcd[11:8] + 3;
if(i < 11 && bcd[15:12] > 4) bcd[15:12] = bcd[15:12] + 3;
end
end
endmodule
사용 코드_clock_div_1us
module clock_div_1us (
input clk, reset_p,
output cp_div_100, // clock pulse (1us 기준 펄스)
output edge_n_div_100 // 1us 네거티브 엣지 펄스
);
localparam CNT_VALUE_100 = 100; // 10ns * 100 = 1us (100MHz 기준)
localparam WIDTH = $clog2(CNT_VALUE_100);
reg [WIDTH-1:0] cnt_sysclk;
always @(posedge clk or posedge reset_p) begin
if (reset_p) cnt_sysclk <= 0;
else if (cnt_sysclk == CNT_VALUE_100 - 1) cnt_sysclk <= 0;
else cnt_sysclk <= cnt_sysclk + 1;
end
assign cp_div_100 = (cnt_sysclk < CNT_VALUE_100/2) ? 1'b0 : 1'b1;
edge_detector ed (
.clk(clk),
.reset_p(reset_p),
.sig(cp_div_100),
.p_edge(), // (포지티브 엣지는 미사용)
.n_edge(edge_n_div_100)
);
endmodule
사용 코드_fnd_4digit_cntr
module fnd_4digit_cntr (
input clk, reset_p,
input [15:0] value,
output [7:0] seg_7,
output [3:0] com
);
reg [3:0] hex_value;
// 4자리 순환 제어 (One-hot)
ring_counter ring_com(
.clk (clk),
.reset_p (reset_p),
.q (com)
);
always @(posedge clk or posedge reset_p) begin
if (reset_p)
hex_value <= 0;
else begin
case (com)
4'b1110: hex_value <= value[3:0];
4'b1101: hex_value <= value[7:4];
4'b1011: hex_value <= value[11:8];
4'b0111: hex_value <= value[15:12];
default: hex_value <= 0;
endcase
end
end
decoder_7seg dec(
.hex_value(hex_value),
.seg_7(seg_7)
);
endmodule
사용 코드 _button_cntr
module button_cntr (
input clk, reset_p,
input btn,
output btn_pedge, btn_nedge
);
localparam CNT_VALUE = 100_000; // clk period = 10ns, 1ms count
localparam WIDTH = $clog2(CNT_VALUE);
reg [WIDTH-1:0] clk_div;
reg debounced_btn;
wire clk_div_msb;
// 1ms 분주 카운터
always @(posedge clk or posedge reset_p) begin
if (reset_p) clk_div <= 0;
else clk_div <= clk_div + 1;
end
// 1ms마다 펄스 생성 (엣지 디텍터)
edge_detector ed_div (
.clk(clk),
.reset_p(reset_p),
.sig(clk_div[WIDTH-1]),
.p_edge(clk_div_msb),
.n_edge() // 사용안함
);
// 디바운스: 1ms마다 샘플링
always @(posedge clk or posedge reset_p) begin
if (reset_p) debounced_btn <= 0;
else if (clk_div_msb) debounced_btn <= btn;
end
// 버튼 엣지 검출기
edge_detector ed_btn (
.clk(clk),
.reset_p(reset_p),
.sig(debounced_btn),
.p_edge(btn_pedge),
.n_edge(btn_nedge)
);
endmodule
사용 코드 _XDC 파일
## Basys3 rev B Board XDC (Radar Project 전용)
## Clock signal
set_property -dict { PACKAGE_PIN W5 IOSTANDARD LVCMOS33 } [get_ports clk]
create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports clk]
## Reset (SW0)
set_property -dict { PACKAGE_PIN V17 IOSTANDARD LVCMOS33 } [get_ports reset_p]
## LEDs (16bit)
set_property -dict { PACKAGE_PIN U16 IOSTANDARD LVCMOS33 } [get_ports {led_debug[0]}]
set_property -dict { PACKAGE_PIN E19 IOSTANDARD LVCMOS33 } [get_ports {led_debug[1]}]
set_property -dict { PACKAGE_PIN U19 IOSTANDARD LVCMOS33 } [get_ports {led_debug[2]}]
set_property -dict { PACKAGE_PIN V19 IOSTANDARD LVCMOS33 } [get_ports {led_debug[3]}]
set_property -dict { PACKAGE_PIN W18 IOSTANDARD LVCMOS33 } [get_ports {led_debug[4]}]
set_property -dict { PACKAGE_PIN U15 IOSTANDARD LVCMOS33 } [get_ports {led_debug[5]}]
set_property -dict { PACKAGE_PIN U14 IOSTANDARD LVCMOS33 } [get_ports {led_debug[6]}]
set_property -dict { PACKAGE_PIN V14 IOSTANDARD LVCMOS33 } [get_ports {led_debug[7]}]
set_property -dict { PACKAGE_PIN V13 IOSTANDARD LVCMOS33 } [get_ports {led_debug[8]}]
set_property -dict { PACKAGE_PIN V3 IOSTANDARD LVCMOS33 } [get_ports {led_debug[9]}]
set_property -dict { PACKAGE_PIN W3 IOSTANDARD LVCMOS33 } [get_ports {led_debug[10]}]
set_property -dict { PACKAGE_PIN U3 IOSTANDARD LVCMOS33 } [get_ports {led_debug[11]}]
set_property -dict { PACKAGE_PIN P3 IOSTANDARD LVCMOS33 } [get_ports {led_debug[12]}]
set_property -dict { PACKAGE_PIN N3 IOSTANDARD LVCMOS33 } [get_ports {led_debug[13]}]
set_property -dict { PACKAGE_PIN P1 IOSTANDARD LVCMOS33 } [get_ports {led_debug[14]}]
set_property -dict { PACKAGE_PIN L1 IOSTANDARD LVCMOS33 } [get_ports {led_debug[15]}]
## 7-Segment Display (FND)
set_property -dict { PACKAGE_PIN W7 IOSTANDARD LVCMOS33 } [get_ports {seg_7[7]}]
set_property -dict { PACKAGE_PIN W6 IOSTANDARD LVCMOS33 } [get_ports {seg_7[6]}]
set_property -dict { PACKAGE_PIN U8 IOSTANDARD LVCMOS33 } [get_ports {seg_7[5]}]
set_property -dict { PACKAGE_PIN V8 IOSTANDARD LVCMOS33 } [get_ports {seg_7[4]}]
set_property -dict { PACKAGE_PIN U5 IOSTANDARD LVCMOS33 } [get_ports {seg_7[3]}]
set_property -dict { PACKAGE_PIN V5 IOSTANDARD LVCMOS33 } [get_ports {seg_7[2]}]
set_property -dict { PACKAGE_PIN U7 IOSTANDARD LVCMOS33 } [get_ports {seg_7[1]}]
set_property -dict { PACKAGE_PIN V7 IOSTANDARD LVCMOS33 } [get_ports {seg_7[0]}]
set_property -dict { PACKAGE_PIN U2 IOSTANDARD LVCMOS33 } [get_ports {com[0]}]
set_property -dict { PACKAGE_PIN U4 IOSTANDARD LVCMOS33 } [get_ports {com[1]}]
set_property -dict { PACKAGE_PIN V4 IOSTANDARD LVCMOS33 } [get_ports {com[2]}]
set_property -dict { PACKAGE_PIN W4 IOSTANDARD LVCMOS33 } [get_ports {com[3]}]
## Buttons
set_property -dict { PACKAGE_PIN U18 IOSTANDARD LVCMOS33 } [get_ports btn[0]] # Center
set_property -dict { PACKAGE_PIN T18 IOSTANDARD LVCMOS33 } [get_ports btn[1]] # Up
set_property -dict { PACKAGE_PIN W19 IOSTANDARD LVCMOS33 } [get_ports btn[3]] # Left
set_property -dict { PACKAGE_PIN T17 IOSTANDARD LVCMOS33 } [get_ports btn[2]] # Right
set_property -dict { PACKAGE_PIN U17 IOSTANDARD LVCMOS33 } [get_ports btn[4]] # Down
## Pmod Header JA - 초음파, 서보, I2C
set_property -dict { PACKAGE_PIN J1 IOSTANDARD LVCMOS33 } [get_ports {trig_1}]
set_property -dict { PACKAGE_PIN L2 IOSTANDARD LVCMOS33 } [get_ports {echo_1}]
set_property -dict { PACKAGE_PIN J2 IOSTANDARD LVCMOS33 } [get_ports {trig_2}]
set_property -dict { PACKAGE_PIN G2 IOSTANDARD LVCMOS33 } [get_ports {echo_2}]
set_property -dict { PACKAGE_PIN H1 IOSTANDARD LVCMOS33 } [get_ports {servo}]
set_property -dict { PACKAGE_PIN K2 IOSTANDARD LVCMOS33 } [get_ports {scl}]
set_property -dict { PACKAGE_PIN H2 IOSTANDARD LVCMOS33 } [get_ports {sda}]
## USB-RS232 Interface (UART TX)
set_property -dict { PACKAGE_PIN A18 IOSTANDARD LVCMOS33 } [get_ports tx_uart]
## Basys3 Power & Configuration
set_property CONFIG_VOLTAGE 3.3 [current_design]
set_property CFGBVS VCCO [current_design]
set_property BITSTREAM.GENERAL.COMPRESS TRUE [current_design]
set_property BITSTREAM.CONFIG.CONFIGRATE 33 [current_design]
set_property CONFIG_MODE SPIx4 [current_design]
동작 영상
초음파 레이더 시스템 실시간 동작 시연
360° 초음파 센서 데이터 실시간 시각화