uart를 통한 bluetooth통신(미완)

정유석·2024년 11월 6일

교육 - 베릴로그

목록 보기
28/28
module bluetooth_tx(
    input clk, reset_p,
    input data_valid,
    input [3:0] btn,
    output reg [15:0] led,
    output reg tx);

    parameter baud_rate = 9600;
    parameter system_clk = 100_000_000;
    parameter clk_per_bit = system_clk / baud_rate;
    parameter half_clk_per_bit = clk_per_bit / 2;
    
    parameter idle = 2'b00;
    parameter start = 2'b01;
    parameter data = 2'b10;
    parameter stop = 2'b11;
    
    wire btn_nedge;
    button_cntr tx_btn(.clk(clk), .reset_p(reset_p), .btn(btn[0]), .btn_nedge(btn_nedge));
    
    wire clk_div_100_nedge;
    clock_div_100 clk_100(.clk(clk), .reset_p(reset_p), .clk_div_100_nedge(clk_div_100_nedge));
    
    wire clk_div_1000_nedge;
    clock_div_1000 clk_1000(.clk(clk), .reset_p(reset_p), .clk_source(clk_div_100_nedge), .clk_div_1000_nedge(clk_div_1000_nedge));
    
    wire second_clk;
    clock_div_1000 clk_1000_2(.clk(clk), .reset_p(reset_p), .clk_source(clk_div_1000_nedge), .clk_div_1000_nedge(second_clk));      
    
    reg [9:0] s_count;
    always @(negedge clk or posedge reset_p)begin
        if(reset_p)begin
            s_count = 0;
        end
        else begin
            if(clk_div_1000_nedge)begin
                s_count = s_count + 1;
                if(s_count > 1000)begin
                    s_count = 0;
                end
            end
        end
    end
               
    reg [31:0] count;
    always @(negedge clk or posedge reset_p)begin
        if(reset_p)begin
            count = 0;
        end
        else if(clk)begin
            if(count > 32'hffff_ffff)begin
                count = 0;
            end
            count = count + 1;
        end
    end
    
    reg [1:0] state, next_state;
    always @(negedge clk or posedge reset_p)begin
        if(reset_p)begin
            state = idle;
        end
        else begin
            state = next_state;
        end
    end
    
    reg [9:0] send_data;
    reg [7:0] tx_data;
    reg [15:0] clk_count;
    reg [2:0] bit_index;
    reg busy, start_flag;
        
    always @(posedge clk or posedge reset_p)begin
        if(reset_p)begin
            next_state = idle;
            tx = 1;
            tx_data = 0;
            bit_index = 7;
            clk_count = 0;
            busy = 1;
            send_data = 0;
            led = 0;
            start_flag = 0;
        end
        else begin
            case(state)
                idle : begin
                    if(btn_nedge)begin //수동 조작을 위해 data_valid을 btn[0]로 대체
                        led[4] = 1;
                        led[5] = 0;
                        led[6] = 0;
                        led[7] = 0; 
                        tx_data = 1;
                        bit_index = 7;
                        clk_count = 0;
                        start_flag = 1;                
                    end
                    if(start_flag && second_clk)begin
                        start_flag = 0;
                        next_state = start;  
                    end
                end
                start : begin
                    led[4] = 0;
                    led[5] = 1;
                    led[6] = 0;
                    led[7] = 0;
                    busy = 1;
//                    tx = send_data[9];
                    tx = 0;
                    if(clk_count > half_clk_per_bit)begin
                        if(second_clk)begin
                            next_state = data;
                            clk_count = 0;
                        end
                    end 
                    else begin
                        clk_count = clk_count + 1;
                    end
                end
                data : begin
                        led[4] = 0;
                        led[5] = 0;
                        led[6] = 1;
                        led[7] = 0;
                    tx = tx_data[bit_index];
                    
                    if(clk_count < clk_per_bit - 1)begin
                        clk_count = clk_count + 1;
                    end   
                    else begin
                        if(!start_flag && bit_index > 0)begin
                            bit_index = bit_index - 1;
                            clk_count = 0;
                        end
                        else begin
                            bit_index = 7;
                            start_flag = 1;
                         end
                    
                        if(start_flag && second_clk)begin
                            next_state = stop;
                            clk_count = 0;
                            start_flag = 0;
                       end
                    end                 
                        
                end
                stop : begin
                        led[4] = 0;
                        led[5] = 0;
                        led[6] = 0;
                        led[7] = 1;
//                    tx = send_data[0];
                    tx = 1;
                    busy = 0;
                    if(second_clk)begin
                        tx_data = {tx_data[6:0], 1'b0};
                        if(tx_data > 9)begin
                            tx_data = 0;
                        end                  
                        next_state = idle;
                        tx = 0;
                    end
                end                        
            endcase        
        end
    end
       
endmodule

module bluetooth_rx(
    input clk, reset_p,
    input rx,
    output reg data_valid,
    output reg [15:0] led);
    
    parameter baud_rate = 9600;
    parameter system_clk = 100_000_000;
    parameter clk_per_bit = system_clk / baud_rate;
    parameter half_clk_per_bit = clk_per_bit / 2;
    
    parameter idle = 2'b00;
    parameter start = 2'b01;
    parameter data = 2'b10;
    parameter stop = 2'b11;
    
    reg [2:0] state, next_state;
    always @(negedge clk or posedge reset_p)begin
        if(reset_p)begin
            state = idle;
        end
        else begin
            state = next_state;
        end
    end

    reg [15:0] clk_count; 
    reg [7:0] rx_data; 
    reg [2:0] bit_index;  
    always @(negedge clk or posedge reset_p)begin
        if(reset_p)begin
            next_state = idle;
            clk_count = 0;
            data_valid = 0;
        end
        else begin
            led = 0;
            case(state)
                idle : begin
                    led[0] = 1;
                    data_valid = 0;
                    if(~rx)begin
                        clk_count = 0;
                        next_state = start;
                    end
                end
                start : begin
                    led[1] = 1;
                    if(clk_count == half_clk_per_bit)begin
                        if(~rx)begin
                            clk_count = 0;
                            next_state = data;
                        end
                    end
                    else begin
                        clk_count = clk_count + 1;
                    end
                end
                data : begin
                    led[2] = 1;
                    if(clk_count < clk_per_bit - 1)begin
                        clk_count = clk_count + 1;
                    end
                    else begin
                        clk_count = 0;
                        rx_data[bit_index] = rx;
                        if(bit_index < 7)begin
                            bit_index = bit_index + 1;
                        end
                        else begin
                            bit_index = 0;
                            next_state = stop;
                        end                       
                    end
                end
                stop : begin
                    led[3] = 1;
                    if(clk_count < clk_per_bit - 1)begin
                        clk_count = clk_count + 1;
                    end
                    else begin
                        data_valid = 1;
                        next_state = idle;
                    end
                end 
            endcase
        end
    end
    
endmodule


//gpt---------------------------------------------------------------------------



module bluetooth_uart(
    input wire clk,            // 시스템 클럭
    input wire reset,          // 리셋 신호
    input wire rx,             // UART 수신 핀
    output reg tx,             // UART 송신 핀
    output reg [7:0] data_out, // 수신된 데이터
    output reg data_valid      // 데이터 유효 신호
);
    // UART 파라미터
    parameter BAUD_RATE = 9600;          // UART 통신 속도
    parameter CLK_FREQ = 50000000;       // 클럭 주파수 (50 MHz)
    localparam CLOCKS_PER_BIT = CLK_FREQ / BAUD_RATE; // 비트당 클럭 수

    // 상태 머신 정의
    reg [3:0] state;
    reg [3:0] bit_index;
    reg [7:0] tx_buffer;
    reg [15:0] clk_counter;

    // 수신 상태
    localparam IDLE = 4'd0;
    localparam START_BIT = 4'd1;
    localparam RECEIVE = 4'd2;
    localparam STOP_BIT = 4'd3;

    // 송신 상태
    localparam TX_IDLE = 4'd0;
    localparam TX_START_BIT = 4'd1;
    localparam TX_SEND = 4'd2;
    localparam TX_STOP_BIT = 4'd3;

    // 수신
    always @(posedge clk or posedge reset) begin
        if (reset) begin
            state <= IDLE;
            clk_counter <= 0;
            bit_index <= 0;
            data_valid <= 0;
        end else begin
            case (state)
                IDLE: begin
                    data_valid <= 0;
                    if (~rx) begin // 스타트 비트 감지
                        state <= START_BIT;
                        clk_counter <= 0;
                    end
                end

                START_BIT: begin
                    if (clk_counter < CLOCKS_PER_BIT - 1) begin
                        clk_counter <= clk_counter + 1;
                    end else begin
                        clk_counter <= 0;
                        state <= RECEIVE;
                        bit_index <= 0;
                    end
                end

                RECEIVE: begin
                    if (clk_counter < CLOCKS_PER_BIT - 1) begin
                        clk_counter <= clk_counter + 1;
                    end else begin
                        clk_counter <= 0;
                        data_out[bit_index] <= rx; // 비트 수신
                        if (bit_index < 7) begin
                            bit_index <= bit_index + 1;
                        end else begin
                            state <= STOP_BIT;
                        end
                    end
                end

                STOP_BIT: begin
                    if (clk_counter < CLOCKS_PER_BIT - 1) begin
                        clk_counter <= clk_counter + 1;
                    end else begin
                        clk_counter <= 0;
                        data_valid <= 1; // 데이터 유효
                        state <= IDLE;   // 상태 초기화
                    end
                end
            endcase
        end
    end

    // 송신
    always @(posedge clk or posedge reset) begin
        if (reset) begin
            tx <= 1; // 기본적으로 HIGH 상태
            state <= TX_IDLE;
            clk_counter <= 0;
            bit_index <= 0;
        end else begin
            case (state)
                TX_IDLE: begin
                    if (data_valid) begin
                        tx_buffer <= data_out; // 송신할 데이터 설정
                        state <= TX_START_BIT;
                        clk_counter <= 0;
                    end
                end

                TX_START_BIT: begin
                    if (clk_counter < CLOCKS_PER_BIT - 1) begin
                        clk_counter <= clk_counter + 1;
                    end else begin
                        clk_counter <= 0;
                        tx <= 0; // 스타트 비트 전송
                        state <= TX_SEND;
                    end
                end

                TX_SEND: begin
                    if (clk_counter < CLOCKS_PER_BIT - 1) begin
                        clk_counter <= clk_counter + 1;
                    end else begin
                        clk_counter <= 0;
                        tx <= tx_buffer[bit_index]; // 비트 전송
                        if (bit_index < 7) begin
                            bit_index <= bit_index + 1;
                        end else begin
                            state <= TX_STOP_BIT;
                        end
                    end
                end

                TX_STOP_BIT: begin
                    if (clk_counter < CLOCKS_PER_BIT - 1) begin
                        clk_counter <= clk_counter + 1;
                    end else begin
                        clk_counter <= 0;
                        tx <= 1; // 스톱 비트 전송
                        state <= TX_IDLE;
                    end
                end
            endcase
        end
    end
endmodule

//도월===============================================
`timescale 1ns / 1ps

// UART 송신기
module uart_tx(
    input clk,             // FPGA 클럭
    input reset,           // 리셋 신호
    input [7:0] data_in,   // 전송할 데이터
    input send,            // 전송 트리거
    output reg tx,         // UART 전송 핀
    output reg busy        // 전송 중 상태
);
    parameter CLK_FREQ = 100_000_000; // 클럭 주파수 (100MHz)
    parameter BAUD_RATE = 9600;       // UART 전송 속도
    parameter BIT_PERIOD = CLK_FREQ / BAUD_RATE; // 각 비트의 전송 주기

    reg [3:0] bit_index;    // 현재 전송 중인 비트의 인덱스
    reg [15:0] baud_count;  // 비트 전송을 위한 카운터
    reg [9:0] tx_shift_reg; // 데이터와 스타트, 스톱 비트를 포함한 10비트 레지스터

    always @(posedge clk or posedge reset) begin
        if (reset) begin
            tx <= 1;         // 기본 상태
            busy <= 0;       // 현재 전송 중이 아님
            baud_count <= 0;
            bit_index <= 0;
            tx_shift_reg <= 10'b1111111111; // 기본 상태
        end else if (send && !busy) begin
            tx_shift_reg <= {1'b1, data_in, 1'b0}; // 데이터와 스타트 비트, 스톱 비트
            busy <= 1;
            bit_index <= 0; // 비트 인덱스 초기화
        end else if (busy) begin
            if (baud_count < BIT_PERIOD - 1) begin
                baud_count <= baud_count + 1;
            end else begin
                baud_count <= 0;
                tx <= tx_shift_reg[0];
                tx_shift_reg <= {1'b1, tx_shift_reg[9:1]}; // 비트 시프트
                if (bit_index < 9) begin
                    bit_index <= bit_index + 1;
                end else begin
                    busy <= 0; // 전송 완료
                    bit_index <= 0;
                end
            end
        end
    end
endmodule

//----------------------------------------------------------------------------------------------------------------------------------------

module uart_rx (
    input clk, reset_p,
    input rx,                 // UART 수신 핀 (HC-06의 TX 핀에 연결)
    output reg [7:0] data_out, // 수신된 데이터
    output reg received       // 데이터 수신 완료 신호
);

    parameter CLKS_PER_BIT = 10417; // 100MHz / 9600 baud rate
    parameter CLKS_PER_HALF_BIT = CLKS_PER_BIT / 2;

    reg [3:0] state;
    reg [15:0] clock_count;
    reg [2:0] bit_index;
    reg [7:0] rx_data;

    parameter IDLE = 4'b0000;
    parameter START_BIT = 4'b0001;
    parameter DATA_BITS = 4'b0010;
    parameter STOP_BIT = 4'b0011;
    parameter CLEANUP = 4'b0100;

    always @(posedge clk or posedge reset_p) begin
        if (reset_p) begin
            state <= IDLE;
            received <= 1'b0;
            data_out <= 8'h00;
            clock_count <= 0;
            bit_index <= 0;
        end
            else begin
                case (state)
                    IDLE: begin
                        received <= 1'b0;
                        clock_count <= 0;
                        bit_index <= 0;
                        
                        if (rx == 1'b0) begin
                            state <= START_BIT;
                        end
                    end
                    START_BIT: begin
                        if (clock_count == CLKS_PER_HALF_BIT) begin
                            if (rx == 1'b0) begin
                                clock_count <= 0;
                                state <= DATA_BITS;
                            end
                                else begin
                                    state <= IDLE;
                                end
                        end
                            else begin
                                clock_count <= clock_count + 1;
                            end
                    end
                    DATA_BITS: begin
                        if (clock_count < CLKS_PER_BIT - 1) begin
                            clock_count <= clock_count + 1;
                        end
                            else begin
                                clock_count <= 0;
                                rx_data[bit_index] <= rx;
                                if (bit_index < 7) begin
                                    bit_index <= bit_index + 1;
                                end
                                    else begin
                                        bit_index <= 0;
                                        state <= STOP_BIT;
                                    end
                            end
                    end
                    STOP_BIT: begin
                        if (clock_count < CLKS_PER_BIT - 1) begin
                            clock_count <= clock_count + 1;
                        end
                            else begin
                                received <= 1'b1;
                                data_out <= rx_data;
                                state <= CLEANUP;
                            end
                    end
                    CLEANUP: begin
                        state <= IDLE;
                        received <= 1'b0;
                    end
                    default: state <= IDLE;
                endcase
            end
    end
endmodule

// 최상위 TOP Module-----------------------------------------------------------------------------------------------------------------------
module SOC_check_top(
    input clk,              // 100 MHz 클럭
    input reset_p,        // switch 리셋 신호
    input [4:0] btn,        // 4개의 버튼 입력
    output tx,              // UART 송신 핀
    input rx,               // UART 수신 핀
    output [3:0] com,       // 7-세그먼트 공통 캐소드 선택
    output [7:0] seg_7,     // 7-세그먼트 세그먼트 제어
    output reg [15:0] led   // LED 출력
);

    // 버튼 엣지 검출 신호
    wire btn_up, btn_left, btn_right, btn_down;     // 버튼 엣지 검출 신호
    wire [15:0] value;                              // 표시할 16비트 값
    reg [3:0] digit [0:3];                          // 4개의 4비트 자릿수 배열
    reg [1:0] sel_digit;                            // 현재 선택된 자릿수
    // FND 값을 저장할 레지스터
    reg [15:0] save_fnd_value;

    // 버튼 엣지 검출 모듈 인스턴스화
    button_cntr btn0_counter(.clk(clk), .reset_p(reset_p), .btn(btn[0]), .btn_pedge(btn_set));
    button_cntr btn1_counter(.clk(clk), .reset_p(reset_p), .btn(btn[1]), .btn_pedge(btn_up));
    button_cntr btn2_counter(.clk(clk), .reset_p(reset_p), .btn(btn[2]), .btn_pedge(btn_left));
    button_cntr btn3_counter(.clk(clk), .reset_p(reset_p), .btn(btn[3]), .btn_pedge(btn_right));
    button_cntr btn4_counter(.clk(clk), .reset_p(reset_p), .btn(btn[4]), .btn_pedge(btn_down));

    // 버튼을 눌러서 숫자를 조작하는 로직
    always @(posedge clk or posedge reset_p) begin
        if (reset_p) begin
            digit[0] <= 4'd0;
            digit[1] <= 4'd0;
            digit[2] <= 4'd0;
            digit[3] <= 4'd0;
            sel_digit <= 2'b00;
        end
            else begin
                // 자릿수 선택 및 값 변경 로직
                if (btn_right) sel_digit <= (sel_digit == 2'b00) ? 2'b11 : sel_digit - 1;
                if (btn_left) sel_digit <= (sel_digit == 2'b11) ? 2'b00 : sel_digit + 1;
    
                if (btn_up && digit[sel_digit] < 4'd9) digit[sel_digit] <= digit[sel_digit] + 1;
                if (btn_down && digit[sel_digit] > 4'd0) digit[sel_digit] <= digit[sel_digit] - 1;
            end
    end

    // 7-세그먼트 표시를 위한 값 설정
    assign value = {digit[3], digit[2], digit[1], digit[0]};

    // 7-세그먼트 컨트롤러 인스턴스화
    fnd_cntr fnd_controller(
        .clk(clk),
        .reset_p(reset_p),
        .value(value),
        .com(com),
        .seg_7(seg_7)
    );

    // 통신 관련 파라미터 및 신호 정의
    parameter CLK_FREQ = 100_000_000;      // 클럭 주파수 (100MHz)
    parameter BAUD_RATE = 9600;            // UART의 전송 속도 (9600bps)
    parameter CLKS_PER_BIT = CLK_FREQ / BAUD_RATE;

    // 송신 신호
    reg [7:0] data_to_send;   // 전송할 데이터
    reg send;                 // 데이터 전송 트리거
    wire busy;                // 전송 중 상태

    // 수신 신호
    wire [7:0] received_data;  // 수신 데이터
    wire received_flag;        // 데이터 수신 완료 신호
    reg send_flag;
    wire busy_flag;

    // 상태 정의
    localparam IDLE = 3'b000;          // 대기 상태
    localparam SEND_DIGIT = 3'b001;    // 숫자 송신 상태
    localparam WAIT_BUSY = 3'b010;     // 송신 완료 대기 상태

    // 상태 머신 및 UART 송신 로직
    reg [2:0] state;                    // 상태 머신 상태
    reg [1:0] digit_index;              // 현재 자릿수 인덱스
    reg btn_set_prev;                   // 이전 btn_set 상태

    // 송신 모듈 인스턴스화
    uart_tx #(
        .CLK_FREQ(CLK_FREQ),
        .BAUD_RATE(BAUD_RATE)
    ) uart_tx_inst (
        .clk(clk),
        .reset(reset_p),
        .data_in(data_to_send),
        .send(send),
        .tx(tx),
        .busy(busy)
    );

    // 수신 모듈 인스턴스화
    uart_rx uart_receiver (
        .clk(clk),
        .reset_p(reset_p),
        .rx(rx),
        .data_out(received_data),
        .received(received_flag)
    );
    
    // 송신 로직
    always @(posedge clk or posedge reset_p) begin
        if (reset_p) begin
            save_fnd_value <= 16'h0000;   // FND 값 초기화
            data_to_send <= 8'h00;
            send <= 1'b0;
            state <= IDLE;
            digit_index <= 2'd3; // 역순으로 시작하기 위해 3으로 초기화
            btn_set_prev <= 1'b0;
        end
            else begin
                btn_set_prev <= btn_set;
                case (state)
                    IDLE: begin
                        if (btn_set && !btn_set_prev) begin  // btn_set의 상승 엣지 감지
                            save_fnd_value <= value;        // 현재 FND 값을 저장
                        end
                        if (received_flag && received_data == "Q") begin
                            digit_index <= 2'd3;            // 전송할 자릿수를 초기화
                            state <= SEND_DIGIT;            // 송신 시작
                        end
                    end
                    SEND_DIGIT: begin
                        if (!busy) begin
                            case (digit_index)
                                2'd3: data_to_send <= save_fnd_value[15:12] + 8'h30; // 가장 상위 자릿수
                                2'd2: data_to_send <= save_fnd_value[11:8] + 8'h30;
                                2'd1: data_to_send <= save_fnd_value[7:4] + 8'h30;
                                2'd0: data_to_send <= save_fnd_value[3:0] + 8'h30; // 가장 하위 자릿수
                            endcase
                            send <= 1'b1;
                            state <= WAIT_BUSY;
                        end
                    end
                    WAIT_BUSY: begin
                        if (!busy) begin
                            send <= 1'b0;
                            if (digit_index == 2'd0) begin  // 모든 자릿수 전송 완료
                                state <= IDLE;
                            end
                                else begin
                                    digit_index <= digit_index - 1'b1; // 다음 자릿수로 이동
                                    state <= SEND_DIGIT;
                                end
                        end
                    end
                    default: state <= IDLE;
                endcase
            end
    end

    // 수신 및 LED 제어 로직 (수정하지 않음)
    always @(posedge clk or posedge reset_p) begin
        if (reset_p) begin
            led <= 16'h0000;
            send_flag <= 1'b0;
        end
            else begin
                if (received_flag) begin
                    case (received_data)
                //필요한 부분만 주석을 풀어서 사용하세요.
                //학생--------------------------------------------------------------
                      8'h30: led <= 16'h0000;  // ASCII '0'이면 모든 LED를 끔
                      8'h31: led <= 16'hFFFF;  // ASCII '1'이면 모든 LED를 켬
                //------------------------------------------------------------------

                //선생님-------------------------------------------------------------
//                    8'h30: led <= 16'h0000;  // ASCII '0'이면 모든 LED를 끔
//                    8'h31: led[0] <= 1'b1;   // ASCII '1'이면 LED 1번만 켬
//                    8'h32: led[1] <= 1'b1;   // ASCII '2'이면 LED 2번만 켬
//                    8'h33: led[2] <= 1'b1;   // ASCII '3'이면 LED 2번만 켬
//                    8'h34: led[3] <= 1'b1;   // ASCII '4'이면 LED 2번만 켬
//                    8'h35: led[4] <= 1'b1;   // ASCII '5'이면 LED 2번만 켬
//                    8'h36: led[5] <= 1'b1;   // ASCII '6'이면 LED 2번만 켬
//                    8'h37: led[6] <= 1'b1;   // ASCII '7'이면 LED 2번만 켬
//                    8'h38: led[7] <= 1'b1;   // ASCII '8'이면 LED 2번만 켬
//                    8'h39: led[8] <= 1'b1;   // ASCII '9'이면 LED 2번만 켬

//                    8'h41: led[0] <= 1'b0;   // ASCII 'A'이면 LED 1번만 끔 
//                    8'h42: led[1] <= 1'b0;   // ASCII 'B'이면 LED 2번만 끔
//                    8'h43: led[2] <= 1'b0;   // ASCII 'C'이면 LED 3번만 끔
//                    8'h44: led[3] <= 1'b0;   // ASCII 'D'이면 LED 4번만 끔
//                    8'h45: led[4] <= 1'b0;   // ASCII 'E'이면 LED 5번만 끔
//                    8'h46: led[5] <= 1'b0;   // ASCII 'F'이면 LED 6번만 끔
//                    8'h47: led[6] <= 1'b0;   // ASCII 'G'이면 LED 7번만 끔
//                    8'h48: led[7] <= 1'b0;   // ASCII 'H'이면 LED 8번만 끔
//                    8'h49: led[8] <= 1'b0;   // ASCII 'I'이면 LED 9번만 끔
                //-------------------------------------------------------------------
                            default: led <= led;     // 다른 값이면 LED 상태 유지
                    endcase
                    if (!busy) begin
                        send_flag <= 1'b1;
                    end
                end
                    else begin
                        send_flag <= 1'b0;
                    end
            end
    end

endmodule
profile
개인 기록공간

0개의 댓글