7/31 PWM

정유석·2024년 7월 31일

교육 - 베릴로그

목록 보기
18/28

PWM 출력


1s 주기면 깜빡 깜빡
1ms 이면 다이나믹 구동
주기가 더 짧아지면.....

led도 다이오드, 커패시터 성질있음, 주기가 짧으면 충전되다 방전되다 반복

밝기가 어둡게 켜진것처럼 보인다

펄스폭이 커지면 초록색 밝기로 켜짐

펄스폭이 작아지면, 파란색 펄스는 노란색으로 반응, 더 어두워짐

듀티비에 따라 밝기가 달라짐

pwm을 100단계로 나누어 조절

module pwm_100step(
    input clk, reset_p,
    input [6:0] duty, //100단계 //듀티값은 시뮬레이션에서 정해주었다
    output pwm);
    
    reg [6:0] cnt_sysclk;   //100까지 세는 카운터, 7비트 필요
    
    always @(negedge clk or posedge reset_p)begin //100분주, 10ns->1us
        if(reset_p)cnt_sysclk = 0;
        else begin
                if(cnt_sysclk >= 99) cnt_sysclk = 0;
                else cnt_sysclk = cnt_sysclk + 1;
        end
    end
    
    assign clk_div_100 = (cnt_sysclk < 50) ? 1 : 0; //펄스폭이 반반인 1us짜리 펄스
    
    edge_detector_n ed(
        .clk(clk), .reset_p(reset_p), .cp(clk_div_100),
        .n_edge(clk_div_100_nedge));
    
    reg [6:0] cnt;   //100까지 세는 카운터, 7비트 필요
    
    always @(negedge clk or posedge reset_p)begin //100분주, 1us->100us
        if(reset_p)cnt = 0;
        else if(clk_div_100_nedge)begin
                if(cnt >= 99) cnt = 0; //cnt가 99를넘어 다시 0되면 100us
                else cnt = cnt + 1;
        end
    end
    
    assign pwm = (cnt < duty) ? 1 : 0; //duty값은 시뮬레이션에서 넣어줌

endmodule   

duty에 10을 넣었을 때의 pwm

duty에 90을 넣었을 때의 pwm

7비트 cnt의 오버플로우를 이용한 0~127단계 조절

always @(negedge clk or posedge reset_p)begin
        if(reset_p)cnt = 0;
        else if(clk_div_100_nedge)begin
//                if(cnt >= 99) cnt = 0;
//                else 
                    cnt = cnt + 1; //7비트 cnt의 오버플로우를 이용한 0~127단계 조절
        end
    end

주파수 10000Hz

펄스폭이 작을때 주파수가 최소한 10000Hz는 되어야 led가 깜빡임 없이 켜지는것처럼 보일수있다고 한다

module pwm_100step(
    input clk, reset_p,
    input [6:0] duty, //100단계
    output pwm);
    
    parameter sys_clk_freq = 100_000_000;
    parameter pwm_freq = 10_000;
    parameter duty_step = 128;
    parameter temp = sys_clk_freq / duty_step / pwm_freq;  
    parameter temp_half = temp / 2;
    
    integer cnt_sysclk;   //100까지 세는 카운터,7비트 필요
    
    always @(negedge clk or posedge reset_p)begin
        if(reset_p)cnt_sysclk = 0;
        else begin
                if(cnt_sysclk >= temp-1) cnt_sysclk = 0; //지금까지 했던 주기에 맞는 분주를 하는 것이 아닌
                else cnt_sysclk = cnt_sysclk + 1; //주파수를 10000Hz에 맞춰놨고 주파수에 맞추기 위한 분주를 하는 것
        end                                      
    end
    
    assign clk_div_100 = (cnt_sysclk < temp_half) ? 1 : 0;
    
    edge_detector_n ed(
        .clk(clk), .reset_p(reset_p), .cp(clk_div_100),
        .n_edge(clk_div_100_nedge));
    
    reg [6:0] cnt;   //100까지 세는 카운터,7비트 필요
    
    always @(negedge clk or posedge reset_p)begin
        if(reset_p)cnt = 0;
        else if(clk_div_100_nedge)begin
                //if(cnt >= 99) cnt = 0;
                //else 
                    cnt = cnt + 1; //오버플로우를 이용한 127단계 조절
        end
    end
    
    assign pwm = (cnt < duty) ? 1 : 0;

endmodule 

스위치로 조절하기 위한 탑모듈

module led_pwm_top(
    input clk, reset_p,
    input [6:0] duty,
    output pwm);

    pwm_100step pwm_inst(.clk(clk), .reset_p(reset_p), .duty(duty), .pwm(pwm));
    
endmodule 

xdc 변경

# LEDs
set_property -dict { PACKAGE_PIN U16   IOSTANDARD LVCMOS33 } [get_ports {pwm}]

-----------------------------------------------
# Switches
set_property -dict { PACKAGE_PIN V17   IOSTANDARD LVCMOS33 } [get_ports {duty[0]}]
set_property -dict { PACKAGE_PIN V16   IOSTANDARD LVCMOS33 } [get_ports {duty[1]}]
set_property -dict { PACKAGE_PIN W16   IOSTANDARD LVCMOS33 } [get_ports {duty[2]}]
set_property -dict { PACKAGE_PIN W17   IOSTANDARD LVCMOS33 } [get_ports {duty[3]}]
set_property -dict { PACKAGE_PIN W15   IOSTANDARD LVCMOS33 } [get_ports {duty[4]}]
set_property -dict { PACKAGE_PIN V15   IOSTANDARD LVCMOS33 } [get_ports {duty[5]}]
set_property -dict { PACKAGE_PIN W14   IOSTANDARD LVCMOS33 } [get_ports {duty[6]}]

클락에의한 자동 밝기 조절을 위한 탑모듈

module led_pwm_top_2(
    input clk, reset_p,
    output pwm);
    
    reg [31:0] clk_div;
    always @(posedge clk)clk_div = clk_div + 1;
    
    pwm_100step pwm_inst(.clk(clk), .reset_p(reset_p), .duty(clk_div[27:21]), .pwm(pwm));

endmodule 

임시

module pwm_100step (
    input clk, reset_p,
    input [6:0] duty,
    output pwm);

    //  Prescaler 100
    parameter sys_clk = 100_000_000;  // System Clock Pulse 주파수
    parameter pwm_freq = 10_000;     //  LED가 연속적으로 보여지기 위한 주파수
    parameter duty_step = 128;          // Duty ratio의 단계

    parameter temp = sys_clk / duty_step / pwm_freq;
    parameter temp_half = temp / 2;

    integer cnt_sysclk;
    wire clk_div100_nedge;

     always @(negedge clk or posedge reset_p)begin
        if(reset_p)cnt_sysclk = 0;
        else begin
                if(cnt_sysclk >= temp - 1) cnt_sysclk = 0;
                else cnt_sysclk = cnt_sysclk + 1;
        end
    end

    assign clk_div_100 = (cnt_sysclk < temp_half) ? 0 : 1;
    edge_detector_n edge_detector_0 (.clk(clk), .reset_p(reset_p), .cp(clk_div_100), .n_edge(clk_div100_nedge));


    // Prescaler 128
    reg [6:0] cnt;

    always @(negedge clk or posedge reset_p)begin
        if(reset_p)cnt = 0;
        else if(clk_div100_nedge)begin
               cnt = cnt + 1; 
        end
    end

    assign pwm = (cnt < duty) ? 1 : 0;

endmodule
profile
개인 기록공간

0개의 댓글