본문 바로가기
# Semiconductor/- Semicon Academy

[Harman 세미콘 아카데미] 59~61일차 - Verilog(PWM 활용, 다기능 시계 구현 프로젝트)

by Graffitio 2023. 9. 18.
[Harman 세미콘 아카데미] 59~61일차 - Verilog(PWM 활용, 다기능 시계 구현 프로젝트)
728x90
반응형
[PWM 활용]

 

📌 LED 밝기 제어

 

PWM 주기를 조절하여 LED 점멸 속도를 제어하고,

Duty cycle을 조절하여 LED 밝기를 제어하는 코드를 작성해보도록 하자,

 


 

📌 Code

 

Code 설명을 위한 PWM 파형

clk_freqx100 신호에 따라서 nedge가 발생하고,

nedge에 맞춰서 cnt_duty가 증가한다.

 

module PWM_100(
    input clk, rstp,
    input [6:0] duty, // 듀티비 설정 변수 
    input [13:0] pwm_freq, // parameter 대신 여기에 선언해도 된다. 10,000Hz 쓸 거니까 14bit
    output reg pwm_100pc // pc : % -> 하나당 센티(1/100)이라는 뜻
    );
    
    parameter sys_clk_freq = 125_000_000; // cora boadr의 시스템 클락
//    parameter pwm_freq = 1000; // 1000Hz짜리 pwm을 만들기 위한 define
    
    reg [26:0] cnt;
    reg clk_freqX100; // 100배된 클럭 주기 생성을 위한 변수 
    always @(posedge clk, posedge rstp) begin
        if(rstp) begin
            cnt = 0;
            clk_freqX100 = 0;
        end
        else begin
            // 125000까지 카운트하고 클럭 주기 생성
//            if(cnt >= 124_999) begin  // 1000Hz짜리를 만들 것이기 때문에 sys clk를 1000으로 나눔
//            if(cnt >= (sys_clk_freq / pwm_freq / 2)) begin // 토글시켜서 사용할 것이니까 2로 나눔
//            if(cnt >= (sys_clk_freq / pwm_freq / 2 / 100)) begin // 듀티비를 계산하기 위해 100 나눠주고 clk_freqX100을 카운트하여 0과 1을 부여한다.
            if(cnt >= (sys_clk_freq / pwm_freq / 200)) begin // always문 들어 올때마다 나누기 연산하게 되므로, Negative Slack 발생 가능성 높아짐. 간단하게 바꿔주자
                cnt = 0;
                clk_freqX100 = ~clk_freqX100; // pwm 한 주기를 만들기 위한 문장
            end
            else begin
                cnt = cnt + 1; // 클락을 세는 카운터
            end
//            // Duty cycle : 50%
//            if(cnt < 62500) begin
//                pwm_100pc = 0;
//            end
//            else begin
//                pwm_100pc = 1;
//            end
        end
    end 
    
    wire clk_freqX100_n;
    edge_detector_p edg(.clk(clk), .cp_in(clk_freqX100), .rst(rst), .n_edge(clk_freqX100_n)); // Edge Detector
    // 이전 always문에서 clk_freqX100 동작하고 4ns 후에나 edge 잡을 것이다.
    // Timing 문제로 인해 posedge clk를 사용하는 edge detector를 사용하는 것이 좋다.
    // 지금 상황에서는 nedge clk보다 pedge clk가 약 2배정도 더 여유가 있다.
    
    reg [6:0] cnt_duty; // 듀티사이클의 카운터 변수 
    always @(posedge clk, posedge rstp) begin
        if(rstp) begin
            cnt_duty = 0;
            pwm_100pc = 0;
        end
        else if(clk_freqX100_n) begin
            if(cnt_duty >= 99) begin
                cnt_duty = 0;    
            end
            else begin
                cnt_duty = cnt_duty + 1;
            end
            if(cnt_duty < duty) pwm_100pc = 1; // 예를 들어 50을 duty로 받으면, 50까지는 1, 나머지는 0
            else pwm_100pc = 0;
        end
    end 
endmodule

 

 

module led_pwm_top(
        input clk, rstp,
        output led_r,led_g,led_y
);
    reg [27:0] clk_div;
    always@(posedge clk) clk_div = clk_div +1;
    
    PWM_100 pwm_r(.clk(clk), .rstp(rstp), .duty({2'b00,clk_div[27:23]}), .pwm_freq(10000), .pwm_100pc(led_r));
    PWM_100 pwm_g(.clk(clk), .rstp(rstp), .duty({2'b00,clk_div[26:22]}), .pwm_freq(10000), .pwm_100pc(led_g));
    PWM_100 pwm_y(.clk(clk), .rstp(rstp), .duty({2'b00,clk_div[25:21]}), .pwm_freq(10000), .pwm_100pc(led_y));

endmodule

 

위와 같이 Duty cycle에 분주된 시간을 넣으면 해당 시간만큼 LED 밝기와 출력이 결정된다.

 


 

📌 Result

 

 

위 : Yellow LED, 아래 : Red LED

 

1bit씩 밀었기 때문에 Red가 1번 깜빡이는동안 Green은 2번, Yellow는 4번 깜빡인다.

 


📌 PWM 모터 칼리브레이션

 

만약 제조사가 다른 모터를 사용하거나, 초기 칼리브레이션이 잘 안 된 모터를 사용 하여

자동차를 굴릴 경우, 직진임에도 불구하고 한 쪽으로 치우칠 수 있다.

 

이와 같은 경우에는 SW적으로 칼리브레이션을 해주어야 하는데,

아래 코드와 같이 duty cycle를 조금씩 조정해가면서 맞추면 된다.

 

PWM_100 pwm_r(.clk(clk), .reset_p(reset_p), .duty({2'b00,clk_div[27:23] + 6}), .pwm_freq(10000), .pwm_100pc(led_r));

 


 

[Team Project]

 

📌 Project Summary

 

Project name

   : 다기능 시계 구현

 

Mission

  i) 시간, 분을 출력하는 시계 기능

  ii) 10ms 단위의 StopWatch 기능

  iii) Cook Timer 기능(99분 59초까지, 알람 기능 추가)

 

프로젝트 기간 및 팀원

    기간 : 2 Days 

    팀원 : 3명

 


 

2023.09.18 ~ 2023.09.20까지
프로젝트 진행 및 발표 예정

 


 

728x90
반응형