-아날로그 신호를 디지털 데이터로 변환시킴
표본화(sampling)=아날로그 신호를 일정한 시간 간격으로 쪼갬
양자화(Quantization)= 각 시점의 신호 크기를 반올림함
부호화(Encoding)=0과1의 이진 코드로 변환
표본화-양자화-부호화 순서대로 진행
-디지털 환경에서, 1이 켜져 있는 시간의 비율(폭)을 조절하여 아날로그적인 효과를 내는 제어 방식
신호가 켜져 있는 시간의 비율=Duty Cycle
%가 높을 수록 HIGH값이 늘어남
`timescale1ns /1ps
module top(
inputclk,
inputreset,
inputincrease_duty_btn,
inputdecrease_duty_btn,
input[1:0] motor_direction,
outputPWM_OUT,
outputPWM_OUT_LED,
output[1:0] in1_in2,
output[3:0] an,
output[7:0] seg
wirew_clean_inc_btn;
wirew_clean_dec_btn;
wire[3:0] w_DUTY_CYCLE;
wirew_tick;
tick_generator u_tick_generator(
.clk(clk),
.reset(reset),
.tick(w_tick)
);
debouncer u_increase_duty_btn(
.clk(clk),
.reset(reset),
.noisy_btn(increase_duty_btn),
.clean_btn(w_clean_inc_btn)
);
debouncer u_decrease_duty_btn(
.clk(clk),
.reset(reset),
.noisy_btn(decrease_duty_btn),
.clean_btn(w_clean_dec_btn)
);
pwm_duty_control u_pwm_duty_control(
.clk(clk),
.reset(reset),
.duty_inc(w_clean_inc_btn),
.duty_dec(w_clean_dec_btn),
.DUTY_CYCLE(w_DUTY_CYCLE), //FND에 출력 0~9
.PWM_OUT(PWM_OUT),
.PWM_OUT_LED(PWM_OUT_LED)
fnd_contorller u_fnd_contorller(
.clk(clk),
.reset(reset),
.tick(w_tick),
.in_data(w_DUTY_CYCLE),
.motor_dir(motor_direction),
.an(an),
.seg(seg)
);
assignin1_in2=motor_direction;
endmodule
btn_debouncer
`timescale1ns /1ps
module btn_debouncer(
inputclk,
inputreset,
input[2:0] btn, // 3개의 버튼 입력: btn[2:0] → 각각 btnL, btnC, btnR
output[2:0] debounced_btn
);
debouncer U_debouncer_btnL(
.clk(clk),
.reset(reset),
.noisy_btn(btn[0]),
.clean_btn(debounced_btn[0])
debouncer U_debouncer_btnC(
.clk(clk),
.reset(reset),
.noisy_btn(btn[1]),
.clean_btn(debounced_btn[1])
debouncer U_debouncer_btnR(
.clk(clk),
.reset(reset),
.noisy_btn(btn[2]),
.clean_btn(debounced_btn[2])
// assign led = debounced_btn; // button을 누를때 마다 led가 동작 되도록 한다.
endmodule
// 아래에 있는 코드는 버튼 디바운서 이다.
// 이는 버튼 3개(btn[2:0])의 입력에서 발생할 수 있는
// 노이즈(채터링)을 제거해, 안정적인 버튼 입력(debounced_btn[2:0])으로 만들어준다.
// 파라미터는 보통 클럭 카운트 제한값으로 사용되어,
// 얼마나 오랫동안 입력이 안정적인지를 판단하기 위한 시간 지연 설정이다.
// 예: 100MHz 클럭이라면, 999,999는 약 10ms의 디바운싱 지연을 의미할 수 있다.
module debouncer#(parameterDEBOUNCE_LIMIT =20'd999_999) (
inputclk,
inputreset,
inputnoisy_btn, // raw noisy button input
output regclean_btn
);
reg[19:0] count;
regbtn_state=0;
always@(posedgeclk or posedgereset) begin
if(reset) begin // active-high reset
count <=0;
btn_state <=0;
clean_btn <=0;
end else if(noisy_btn ==btn_state) begin // 버튼 상태가 이전과 동일할 경우 (안정됨)
count <=0;
end else begin
if(count <DEBOUNCE_LIMIT) // 버튼 상태가 바뀌었지만 아직 안정되지 않은 경우
count <=count +1;
else begin // 상태가 충분히 오랫동안 유지됨(10ms)
btn_state <=noisy_btn;
clean_btn <=noisy_btn;
count <=0; // 리셋하면 다음 변경을 다시 감지할 수 있음
end
end
end
endmodule
pwm_duty_control
`timescale1ns /1ps
// 100Mhz/10 -> 10Mhz의 주파수를 만듦.
// 100Mhz의 10% 조절 해상도를 가질 수 있는 최대 주파수
// 0~9까지 총 10번의 클럭을 세고
module pwm_duty_control(
inputclk,
inputreset,
inputduty_inc,
inputduty_dec,
output[3:0] DUTY_CYCLE, //FND에 출력 0~9
outputPWM_OUT,
outputPWM_OUT_LED
reg[3:0] r_DUTY_CYCLE=4'd5;
reg[3:0] r_counter_PWM;
// edge 검출 register
regr_prev_duty_inc,r_prev_duty_dec;
wirew_duty_inc=(duty_inc &&!r_prev_duty_inc); //rising edge 검출
wirew_duty_dec=(duty_dec&&!r_prev_duty_dec);
//duty cycle 제어 btnU,btnD
always@(posedgeclk, posedgereset) begin
if(reset) begin
r_DUTY_CYCLE<=4'd5; //50% duty cycle
end else begin
r_prev_duty_inc <=duty_inc; //이전 상태 저장
r_prev_duty_dec<=duty_dec;
if(w_duty_inc &&r_DUTY_CYCLE<4'd9)
r_DUTY_CYCLE<=r_DUTY_CYCLE+1;
if(w_duty_dec &&r_DUTY_CYCLE>4'd1)
r_DUTY_CYCLE<=r_DUTY_CYCLE-1;
end
end
// 10MHz PWM 신호 생성(0~9)
always@(posedgeclk, posedgereset) begin
if(reset) begin
r_counter_PWM <=0;
end else begin
if(r_counter_PWM >=4'd9)
r_counter_PWM<=0;
elser_counter_PWM<=r_counter_PWM+1;
end
end
assignPWM_OUT=(reset)? 1'b0: (r_counter_PWM<r_DUTY_CYCLE) ? 1'b1: 1'b0;
assignPWM_OUT_LED=PWM_OUT;
assignDUTY_CYCLE=r_DUTY_CYCLE;
endmodule
pwm_duty_control
`timescale1ns /1ps
// 100Mhz/10 -> 10Mhz의 주파수를 만듦.
// 100Mhz의 10% 조절 해상도를 가질 수 있는 최대 주파수
// 0~9까지 총 10번의 클럭을 세고
module pwm_duty_control(
inputclk,
inputreset,
inputduty_inc,
inputduty_dec,
output[3:0] DUTY_CYCLE, //FND에 출력 0~9
outputPWM_OUT,
outputPWM_OUT_LED
reg[3:0] r_DUTY_CYCLE=4'd5;
reg[3:0] r_counter_PWM;
// edge 검출 register
regr_prev_duty_inc,r_prev_duty_dec;
wirew_duty_inc=(duty_inc &&!r_prev_duty_inc); //rising edge 검출
wirew_duty_dec=(duty_dec&&!r_prev_duty_dec);
//duty cycle 제어 btnU,btnD
always@(posedgeclk, posedgereset) begin
if(reset) begin
r_DUTY_CYCLE<=4'd5; //50% duty cycle
end else begin
r_prev_duty_inc <=duty_inc; //이전 상태 저장
r_prev_duty_dec<=duty_dec;
if(w_duty_inc &&r_DUTY_CYCLE<4'd9)
r_DUTY_CYCLE<=r_DUTY_CYCLE+1;
if(w_duty_dec &&r_DUTY_CYCLE>4'd1)
r_DUTY_CYCLE<=r_DUTY_CYCLE-1;
end
end
// 10MHz PWM 신호 생성(0~9)
always@(posedgeclk, posedgereset) begin
if(reset) begin
r_counter_PWM <=0;
end else begin
if(r_counter_PWM >=4'd9)
r_counter_PWM<=0;
elser_counter_PWM<=r_counter_PWM+1;
end
end
assignPWM_OUT=(reset)? 1'b0: (r_counter_PWM<r_DUTY_CYCLE) ? 1'b1: 1'b0;
assignPWM_OUT_LED=PWM_OUT;
assignDUTY_CYCLE=r_DUTY_CYCLE;
endmodule
tick_generator
module tick_generator(
inputclk,
inputreset,
output regtick
);
parameterINPUT_FREQUENCY =100_000_000; // 100MHz
parameterTICK_Hz =1000; // 1kHz
parameterTICK_COUNT =INPUT_FREQUENCY /TICK_Hz; // 100,000
reg[$clog2(TICK_COUNT)-1:0] r_tick_counter =0;
always@(posedgeclk or posedgereset) begin
// 초기화
if(reset) begin
tick <=0;
r_tick_counter <=0;
end
// 카운팅 완료
else if(r_tick_counter ==TICK_COUNT-1) begin
r_tick_counter <=0;
tick <=1'b1; // 1클럭 폭 펄스
end
// r_counter 증가
else begin
r_tick_counter <=r_tick_counter +1;
tick <=1'b0;
end
end
endmodule
btnU를 누르면 DUTY CYCLE이 커지고, btnD를 누르면 DUTY CYCLE이 작아진다.