Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- structural modeling
- prescaling
- LED
- D Flip Flop
- KEYPAD
- java
- Algorithm
- half adder
- pwm
- uart 통신
- stop watch
- Linked List
- Pspice
- vivado
- i2c 통신
- soc 설계
- gpio
- atmega 128a
- DHT11
- ring counter
- BASYS3
- verilog
- test bench
- ATMEGA128A
- FND
- dataflow modeling
- Recursion
- behavioral modeling
- Edge Detector
- hc-sr04
Archives
- Today
- Total
거북이처럼 천천히
DHT11 - 1 본문
1. DHT11 온도, 습도 센서
- 이번 구현은 DHT11로부터 온도, 습도 데이터를 받아 Basys3의 FND로 출력하도록 구현하겠다.
- 'DHT11 - 2' 게시글과의 차이점은 "DHT11과 Basys3 간 통신 과정에서 문제 발생했을 경우에 대한 예외 처리 했는지 여부" 차이를 갖는다.
- DHT11 구현 소스 코드에 대한 자세한 설명은 아래 게시글을 참고하길 바란다.
https://jbhdeve.tistory.com/296
2. DHT11 구현 소스 코드
< Source, Convert from binary to bcd code >
- 이진수를 BCD 코드로 변환하기 위해 Double dabble 알고리즘을 사용했다.
// Convert from Binary to BCD Code
module bin_to_dec(
input [11:0] bin,
output reg [15:0] bcd
);
reg [3:0] i;
always @(bin) begin
bcd = 0;
for (i=0;i<12;i=i+1)begin
bcd = {bcd[14:0], bin[11-i]};
if(i < 11 && bcd[3:0] > 4) bcd[3:0] = bcd[3:0] + 3;
if(i < 11 && bcd[7:4] > 4) bcd[7:4] = bcd[7:4] + 3;
if(i < 11 && bcd[11:8] > 4) bcd[11:8] = bcd[11:8] + 3;
if(i < 11 && bcd[15:12] > 4) bcd[15:12] = bcd[15:12] + 3;
end
end
endmodule
< Source, Edge detector >
// Edge detector
module edge_detector (
input clk, reset_p,
input cp,
output n_edge, p_edge );
reg flip_flop_current, flip_flop_old;
always @(posedge clk or posedge reset_p) begin
if(reset_p) begin flip_flop_current <= 0; flip_flop_old <= 0; end
else begin
flip_flop_current <= cp;
flip_flop_old <= flip_flop_current;
end
end
assign p_edge = ({flip_flop_current, flip_flop_old} == 2'b10)? 1 : 0;
assign n_edge = ({flip_flop_current, flip_flop_old} == 2'b01)? 1 : 0;
endmodule
< Source, Clock divider N, N 분주화 >
// Clock Divider N
module clk_div_n #(parameter n = 100) (
input clk, reset_p,
input clk_source,
output clk_div_n,
output clk_div_n_nedge, clk_div_n_pedge );
wire clk_source_nedge;
edge_detector edge_detector_0 (.clk(clk), .reset_p(reset_p), .cp(clk_source), .n_edge(clk_source_nedge));
integer counter;
always @(posedge clk or posedge reset_p) begin
if(reset_p) counter = 0;
else if(clk_source_nedge) begin
if(counter >= n - 1) counter = 0;
else counter = counter + 1;
end
end
assign clk_div_n = (counter < n/2) ? 0 : 1;
edge_detector edge_detector_1 (.clk(clk), .reset_p(reset_p), .cp(clk_div_n), .n_edge(clk_div_n_nedge), .p_edge(clk_div_n_pedge));
endmodule
< Source, Clock divider 100, 100 분주화 >
// Clock Divider 100
module clk_div_100 (
input clk, reset_p,
output clk_div_100,
output clk_div_100_nedge, clk_div_100_pedge );
reg [6:0] counter;
always @(posedge clk or posedge reset_p) begin
if(reset_p) counter = 0;
else begin
if(counter >= 99) counter = 0;
else counter = counter + 1;
end
end
assign clk_div_100 = (counter < 50)? 0 : 1;
edge_detector edge_detector_0 (.clk(clk), .reset_p(reset_p), .cp(clk_div_100), .n_edge(clk_div_100_nedge), .p_edge(clk_div_100_pedge));
endmodule
< Source, Decoder of 7-segment >
// Decoder of 7-segment.
module decoder_seg7 (
input [3:0] hex_value,
output reg [7:0] seg_7);
always @(hex_value) begin
case(hex_value)
0 : seg_7 = 8'b0000_0011; //common anode, 0이 켜지는거임
1 : seg_7 = 8'b1001_1111; // 1
2 : seg_7 = 8'b0010_0101; // 2
3 : seg_7 = 8'b0000_1101; // 3
4 : seg_7 = 8'b1001_1001; // 4
5 : seg_7 = 8'b0100_1001; // 5
6 : seg_7 = 8'b0100_0001; // 6
7 : seg_7 = 8'b0001_1111; // 7
8 : seg_7 = 8'b0000_0001; // 8
9 : seg_7 = 8'b0000_1001; // 9
10 : seg_7 = 8'b0001_0001; // A
11 : seg_7 = 8'b1100_0001; // b
12 : seg_7 = 8'b0110_0011; // C
13 : seg_7 = 8'b1000_0101; // d
14 : seg_7 = 8'b0110_0001; // E
15 : seg_7 = 8'b0111_0001; // F
endcase
end
endmodule
< Source, Ring Counter of com >
// Ring Counter of com
module ring_counter (
input clk, reset_p,
output reg [3:0] com );
wire clk_1usec, clk_1msec;
clk_div_100 clk_div_1usec(.clk(clk), .reset_p(reset_p), .clk_div_100(clk_1usec));
clk_div_n #(.n(1000)) clk_div_1msec (.clk(clk), .reset_p(reset_p), .clk_source(clk_1usec), .clk_div_n_nedge(clk_1msec));
always @(posedge clk or posedge reset_p) begin
if(reset_p) com = 4'b1110;
else if(clk_1msec) com = {com[2:0], com[3]};
end
endmodule
< Source, Control FND >
// FND Control
module fnd_cntr (
input clk, reset_p,
input [15:0] hex_value,
output [3:0] com,
output [7:0] seg_7 );
// Ring Counter of com
ring_counter ring_counter_com (.clk(clk), .reset_p(reset_p), .com(com));
// Select value
reg [3:0] value;
always @(com) begin
case(com)
4'b1110 : value = hex_value[3:0];
4'b1101 : value = hex_value[7:4];
4'b1011 : value = hex_value[11:8];
4'b0111 : value = hex_value[15:12];
default : value = value;
endcase
end
// Show value to FND
decoder_seg7 decoder_7_segment (.hex_value(value), .seg_7(seg_7));
endmodule
< Source, Control DHT11 >
// Control DHT11
module dht11_cntr(
input clk, reset_p,
inout dht11_data,
output reg [7:0] temperature,
output reg [7:0] humidity,
output [5:0] led_state );
// State LED
assign led_state = state;
// Declare State
parameter S_IDLE = 6'b00_0001;
parameter S_LOW_18MS = 6'b00_0010;
parameter S_HIGH_20US = 6'b00_0100;
parameter S_LOW_80US = 6'b00_1000;
parameter S_HIGH_80US = 6'b01_0000;
parameter S_READ_DATA = 6'b10_0000;
// Declare Sub-State.
parameter S_WAIT_PEDGE = 2'b01;
parameter S_WAIT_NEDGE = 2'b10;
// Declare state, next state variable
reg [5:0] state, next_state;
reg [1:0] sub_state;
// Get 1usec one cycle pulse
wire clk_1usec;
clk_div_100 clk_div_1usec(.clk(clk), .reset_p(reset_p), .clk_div_100_nedge(clk_1usec));
// Making usecond counter.
reg [21:0] counter;
reg enable_counter;
always @ (posedge clk or posedge reset_p) begin
if(reset_p) begin counter = 0; end
else if(clk_1usec && enable_counter) counter = counter + 1;
else if(!enable_counter) counter = 0;
end
// 언제 next_state로 넘어가는가?
always @(posedge clk or posedge reset_p) begin
if(reset_p) state = S_IDLE;
else state = next_state;
end
// inout 키워드는 register가 아닌 wire형이기 때문에
// reg형으로 자료형 변환 불가.
// 따라서 임시 레지스터를 선언한 뒤, 임시 레지스터를 통한 dht11_data wire로
// 데이터를 MCU에서 dht11로 전송한다.
reg temp_dht11;
assign dht11_data = temp_dht11;
// Get positive edge or negative edge of dht11_data wire.
wire dht11_data_nedge, dht11_data_pedge;
edge_detector edge_detector_0 (.clk(clk), .reset_p(reset_p), .cp(dht11_data), .n_edge(dht11_data_nedge), .p_edge(dht11_data_pedge));
// 온도, 습도 데이터를 받아서 임시 저장한다.
// 왜냐하면 40bit를 전부 받은 후, check sum과 비교하여 전송 간에 데이터 손실이 있었는지 여부 확인하기 위해서
// 만약 손실이 없음을 확인하면 FND로 출력하며, 손실이 있으면 출력하지 않고, 다음 데이터를 받는다.
reg [39:0] temp_data;
reg [5:0] count_data;
// 각 상태의 동작 및 다음 상태로 전이될 조건을 정의
always @(negedge clk or posedge reset_p) begin
if(reset_p) begin
next_state = S_IDLE;
sub_state = S_WAIT_PEDGE;
temperature = 4'b0;
humidity = 4'b0;
temp_dht11 = 0;
temp_data = 0;
count_data = 0;
enable_counter = 0;
end
else begin
case(state)
// 1단계 : S_IDLE
S_IDLE : begin
if(counter < 22'd3_000_000) begin
enable_counter = 1;
temp_dht11 = 'bz;
end
else begin
enable_counter = 0;
next_state = S_LOW_18MS;
end
end
// 2단계 : S_LOW_18MS
S_LOW_18MS : begin
if(counter < 22'd18_000) begin
enable_counter = 1;
temp_dht11 = 'b0;
end
else begin
enable_counter = 0;
next_state = S_HIGH_20US;
end
end
// 3단계 : S_HIGH_20US
S_HIGH_20US : begin
if(counter < 22'd20) begin
enable_counter = 1;
temp_dht11 = 'bz;
end
else begin
enable_counter = 0;
next_state = S_LOW_80US;
end
end
// 4단계 : S_LOW_80US
S_LOW_80US :
if(dht11_data_pedge) next_state = S_HIGH_80US;
// 5단계 : S_HIGH_80US
S_HIGH_80US :
if(dht11_data_nedge) next_state = S_READ_DATA;
// 6단계 : S_READ_DATA
S_READ_DATA : begin
case (sub_state)
S_WAIT_PEDGE : begin
if(dht11_data_pedge) begin
enable_counter = 1;
sub_state = S_WAIT_NEDGE;
end
end
S_WAIT_NEDGE : begin
if(dht11_data_nedge) begin
if(counter < 45) temp_data = {temp_data[38:0], 1'b0};
else temp_data = {temp_data[38:0], 1'b1};
enable_counter = 0;
sub_state = S_WAIT_PEDGE;
count_data = count_data + 1;
end
end
endcase
// 40bit 데이터를 받았는지 여부 확인
if(count_data >= 40) begin
// Check Sum과 비교하여 데이터 손실 없음을 확인하면 FND로 출력한다.
if(temp_data[39:32] + temp_data[31:24] + temp_data[23:16] + temp_data[15: 8] == temp_data[7:0]) begin
humidity = temp_data[39:32];
temperature = temp_data[23:16];
end
// count_data 변수 값을 0으로 초기화
count_data = 0;
enable_counter = 0;
// state, sub-state 초기화
next_state = S_IDLE;
sub_state = S_WAIT_PEDGE;
end
end
endcase
end
end
endmodule
< Source, Top module of Control DHT11 >
// Top module
module top_module_dht11 (
input clk, reset_p,
inout dht11_data,
output [3:0] com,
output [7:0] seg_7,
output [5:0] led_state );
wire [7:0] temperature, humidity;
dht11_cntr control_dht11 (.clk(clk), .reset_p(reset_p), .dht11_data(dht11_data), .temperature(temperature), .humidity(humidity), .led_state(led_state));
// Convert from binary to decimal
wire [15:0] temperature_bcd, humidity_bcd;
bin_to_dec convert_temperature(.bin({4'b0, temperature}), .bcd(temperature_bcd));
bin_to_dec convert_humidity(.bin({4'b0, humidity}), .bcd(humidity_bcd));
// FND Control
wire [15:0] hex_value;
assign hex_value = {temperature_bcd[7:0], humidity_bcd[7:0]};
fnd_cntr fnd_control (.clk(clk), .reset_p(reset_p), .hex_value(hex_value), .com(com), .seg_7(seg_7));
endmodule
3. DHT11 구현 영상
'RTL Design > Verilog 연습' 카테고리의 다른 글
10kHz인 PWM 설계 (Duty ratio stage 128단계) - (2) (0) | 2024.08.11 |
---|---|
10kHz인 PWM 설계 (Duty ratio stage 128단계) - (1) (0) | 2024.08.11 |
10kHz인 PWM 설계 (Duty ratio stage 100단계) - (1) (0) | 2024.08.11 |
4X4 Matrix KeyPad - 2 (0) | 2024.08.10 |
4X4 Matrix KeyPad - 1 (0) | 2024.08.09 |