카테고리 없음

[Project] Radar_System_사용 코드

juniha 2025. 7. 27. 18:44

사용 코드 _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° 초음파 센서 데이터 실시간 시각화