장영현 2023. 6. 30. 02:59
728x90

교통신호등 제어기 설계

timescale 1ns / 1ps

module TrafficLightController(
    input clk, reset, standby, test,
    output reg [6:0] FND,
    output reg G1en, Y1en, R1en, G2en, Y2en, R2en
);
    parameter YY=3'b000, RY=3'b001, GR=3'b010, YR=3'b011, RG=3'b100;  // 상태에 대한 매개 변수 정의
    reg [2:0] state=YY;  // 현재 상태 레지스터

    parameter RGTime=10, RYTime=3, GRTime=15, YRTime=3, TESTTime=2;  //  각 상태의 지속 시간을 정의하기 위한 매개 변수 정의

    integer TimeCnt, onTime;  // 시간 카운트 및 상태 전환에 사용되는 정수 변수 정의

    reg [6:0] G1=7'b0000000, Y1=7'b0000000, R1=7'b0000000;  // 신호등 1의 각 색상 상태를 나타내는 레지스터
    reg [6:0] G2=7'b0000000, Y2=7'b0000000, R2=7'b0000000;  // 신호등 2의 각 색상 상태를 나타내는 레지스터
    reg clk1hz, clk100hz;  // 1Hz 및 100Hz 클럭 신호 정의
    integer cnt1hz, cnt100hz;  // 1Hz 및 100Hz 클럭 분주에 사용되는 카운터 정의
    reg [3:0] clkcnt;  // FND 출력을 위한 클럭 카운터
    
    // 1Hz 및 100Hz 주기의 클럭 신호 생성
    always @ (posedge clk) begin
        if (cnt1hz >= 49_999_999) begin  // 1Hz로 분주
            cnt1hz <= 0;
            clk1hz <= ~clk1hz;
        end else
            cnt1hz <= cnt1hz+1;
        
        if (cnt100hz >= 499_999) begin  // 100Hz로 분주
            cnt100hz <= 0;
            clk100hz <= ~clk100hz;
        end else
            cnt100hz <= cnt100hz+1;
    end 

    // 상태 전환 및 출력 제어
    always @ (posedge clk1hz or posedge standby) begin
        if (standby) begin
            // 대기 상태일 때 초기화
            state <= YY;  // 상태 초기화
            TimeCnt <= 0;  // 시간 카운터 초기화
        end else begin
            case(state)
                YY: begin
                    state <= RY;  // YY 상태에서 RY 상태로 전환
                end
                
                RY: begin
                    if (!test) onTime <= RYTime;  // 일반 운영 모드일 때 RY 상태의 지속 시간 설정
                    else onTime <= TESTTime;  // 테스트 모드일 때 RY 상태의 지속 시간 설정
                    
                    TimeCnt <= TimeCnt + 1;  // 시간 카운터 증가
                    if (TimeCnt == onTime) begin
                        state <= GR;  // RY 상태에서 GR 상태로 전환
                        TimeCnt <= 0;  // 시간 카운터 초기화
                    end
                end   
                
                GR: begin
                    if (!test) onTime <= GRTime;  // 일반 운영 모드일 때 GR 상태의 지속 시간 설정
                    else onTime <= TESTTime;  // 테스트 모드일 때 GR 상태의 지속 시간 설정
                    
                    TimeCnt <= TimeCnt + 1;  // 시간 카운터 증가
                    if (TimeCnt == onTime) begin
                        state <= YR;  // GR 상태에서 YR 상태로 전환
                        TimeCnt <= 0;  // 시간 카운터 초기화
                    end
                end
                
                YR: begin
                    if (!test) onTime <= YRTime;  // 일반 운영 모드일 때 YR 상태의 지속 시간 설정
                    else onTime <= TESTTime;  // 테스트 모드일 때 YR 상태의 지속 시간 설정
                    
                    TimeCnt <= TimeCnt + 1;  // 시간 카운터 증가
                    if (TimeCnt == onTime) begin
                        state <= RG;  // YR 상태에서 RG 상태로 전환
                        TimeCnt <= 0;  // 시간 카운터 초기화
                    end
                end
                
                RG: begin
                    if (!test) onTime <= RGTime;  // 일반 운영 모드일 때 RG 상태의 지속 시간 설정
                    else onTime <= TESTTime;  // 테스트 모드일 때 RG 상태의 지속 시간 설정
                    
                    TimeCnt <= TimeCnt + 1;  // 시간 카운터 증가
                    if (TimeCnt == onTime) begin
                        state <= RY;  // RG 상태에서 RY 상태로 전환
                        TimeCnt <= 0;  // 시간 카운터 초기화
                    end
                end  
            endcase
        end
    end
   
   always @ (state) begin
    case (state)
        YY: begin
            // YY 상태일 때의 출력 제어
            R1 <= 7'b1111111; Y1 <= 7'b1000000; G1 <= 7'b1111111;
            R2 <= 7'b1111111; Y2 <= 7'b1000000; G2 <= 7'b1111111;
        end
        RY: begin
            // RY 상태일 때의 출력 제어
            R1 <= 7'b1111111; Y1 <= 7'b1000000; G1 <= 7'b1111111;
            R2 <= 7'b0001000; Y2 <= 7'b0111111; G2 <= 7'b1111111;
        end
        GR: begin
            // GR 상태일 때의 출력 제어
            R1 <= 7'b0001000; Y1 <= 7'b0111111; G1 <= 7'b1111111;
            R2 <= 7'b1111111; Y2 <= 7'b0111111; G2 <= 7'b1000010;
        end
        YR: begin
            // YR 상태일 때의 출력 제어
            R1 <= 7'b0001000; Y1 <= 7'b0111111; G1 <= 7'b1111111;
            R2 <= 7'b1111111; Y2 <= 7'b1000000; G2 <= 7'b1111111;
        end
        RG: begin
            // RG 상태일 때의 출력 제어
            R1 <= 7'b1111111; Y1 <= 7'b0111111; G1 <= 7'b1000010;
            R2 <= 7'b0001000; Y2 <= 7'b0111111; G2 <= 7'b1111111;
        end
        default:;  // 기본 상태인 경우 아무 작업도 수행하지 않음
    endcase
end

   
    // 신호등 상태에 따른 출력 제어
    always @ (clkcnt or G1, Y1, R1, G2, Y2, R2) begin
        if(clkcnt[0]) begin  // clkcnt[0]이 1인 경우
            G1en <= 1'b0;  // G1 출력 비활성화
            R1en <= 1'b1;  // R1 출력 활성화
            G2en <= 1'b1;  // G2 출력 활성화
            R2en <= 1'b1;  // R2 출력 활성화
            Y1en <= Y1[6];  // Y1 출력 활성화 비트 설정
            Y2en <= Y2[6];  // Y2 출력 활성화 비트 설정
            FND <= G1;  // FND 출력 설정
            
        end else if(clkcnt[1]) begin  // clkcnt[1]이 1인 경우
            G1en <= 1'b1;  // G1 출력 활성화
            R1en <= 1'b0;  // R1 출력 비활성화
            G2en <= 1'b1;  // G2 출력 활성화
            R2en <= 1'b1;  // R2 출력 활성화
            FND <= R1;  // FND 출력 설정
            
        end else if(clkcnt[2]) begin  // clkcnt[2]이 1인 경우
            G1en <= 1'b1;  // G1 출력 활성화
            R1en <= 1'b1;  // R1 출력 활성화
            G2en <= 1'b0;  // G2 출력 비활성화
            R2en <= 1'b1;  // R2 출력 활성화
            FND <= G2;  // FND 출력 설정
            
        end else if(clkcnt[3]) begin  // clkcnt[3]이 1인 경우
            G1en <= 1'b1;  // G1 출력 활성화
            R1en <= 1'b1;  // R1 출력 활성화
            G2en <= 1'b1;  // G2 출력 활성화
            R2en <= 1'b0;  // R2 출력 비활성화
            FND <= R2;  // FND 출력 설정
            
        end else begin
            G1en <= 1'b1;  // G1 출력 활성화
            R1en <= 1'b1;  // R1 출력 활성화
            G2en <= 1'b1;  // G2 출력 활성화
            R2en <= 1'b1;  // R2 출력 활성화
        end
    end
endmodule
## 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]

## Switches
set_property -dict { PACKAGE_PIN V17   IOSTANDARD LVCMOS33 } [get_ports {standby}]
set_property -dict { PACKAGE_PIN R2    IOSTANDARD LVCMOS33 } [get_ports {reset}]

##7 Segment Display
set_property -dict { PACKAGE_PIN W7   IOSTANDARD LVCMOS33 } [get_ports {FND[0]}]
set_property -dict { PACKAGE_PIN W6   IOSTANDARD LVCMOS33 } [get_ports {FND[1]}]
set_property -dict { PACKAGE_PIN U8   IOSTANDARD LVCMOS33 } [get_ports {FND[2]}]
set_property -dict { PACKAGE_PIN V8   IOSTANDARD LVCMOS33 } [get_ports {FND[3]}]
set_property -dict { PACKAGE_PIN U5   IOSTANDARD LVCMOS33 } [get_ports {FND[4]}]
set_property -dict { PACKAGE_PIN V5   IOSTANDARD LVCMOS33 } [get_ports {FND[5]}]
set_property -dict { PACKAGE_PIN U7   IOSTANDARD LVCMOS33 } [get_ports {FND[6]}]

set_property -dict { PACKAGE_PIN U2   IOSTANDARD LVCMOS33 } [get_ports {G1en}]
set_property -dict { PACKAGE_PIN U4   IOSTANDARD LVCMOS33 } [get_ports {R1en}]
set_property -dict { PACKAGE_PIN V4   IOSTANDARD LVCMOS33 } [get_ports {G2en}]
set_property -dict { PACKAGE_PIN W4   IOSTANDARD LVCMOS33 } [get_ports {R2en}]

##Buttons
set_property -dict { PACKAGE_PIN U18   IOSTANDARD LVCMOS33 } [get_ports test]

 

코드 해석

 

  • 모듈 인터페이스:

 

  1. clk, reset, standby, test: 입력 신호로서, 각각 클럭 신호, 리셋 신호, 대기 신호, 테스트 신호.
  2. FND: 7비트 출력 신호로서, 세그먼트 디스플레이에 표시될 값을 표시.
  3. G1en, Y1en, R1en, G2en, Y2en, R2en: 출력 신호로서, 각각 G1, Y1, R1, G2, Y2, R2의 활성화 여부를 나타낸다.

 

  • 내부 변수 및 상수:

 

  1. FND: 7비트 레지스터로서, 세그먼트 디스플레이에 표시될 값을 저장.
  2. G1en, Y1en, R1en, G2en, Y2en, R2en: 레지스터로서, 각각 G1, Y1, R1, G2, Y2, R2의 활성화 여부를 저장.
  3. state: 3비트 레지스터로서, 현재 상태를 나타낸다.
  4. TimeCnt, onTime: 정수형 변수로서, 상태 변화 및 출력 제어에 사용되는 시간 카운트를 관리.
  5. G1, Y1, R1, G2, Y2, R2: 7비트 레지스터로서, 각 신호등의 상태를 나타낸다.
  6. clk1hz, clk100hz: 1Hz, 100Hz 주기의 클럭 신호를 생성하기 위한 레지스터.
  7. cnt1hz, cnt100hz: 1Hz, 100Hz 클럭 카운트를 관리.
  8. clkcnt: 4비트 레지스터로서, 상태별 클럭 카운트를 관리.

 

  • 모듈 동작:

 

  1. 모듈은 주어진 클럭 신호 및 입력 신호에 따라 상태를 변경하고, 각 상태에 따른 출력을 제어한다.
  2. clk1hz 및 clk100hz 레지스터는 주어진 클럭 신호에 따라 1Hz 및 100Hz 주기의 클럭 신호를 생성한다.
  3. state 레지스터는 현재 상태를 나타내며, TimeCnt 변수는 각 상태에서의 시간 카운트를 관리한다.
  4. 입력 신호 standby에 따라 동작이 초기화되거나 대기 상태로 들어간다.
  5. 주어진 상태에 따라 각 신호등의 상태와 출력 신호를 설정한다.
  6. clkcnt 레지스터는 clk100hz 신호를 기반으로 클럭 카운트를 관리하며, 각 클럭 카운트에 따라 출력을 제어한다.