# 오늘도 젓갈의 날 ~
로베이 컵에 참여하는 것은 로봇이되는 것이기 때문에 로봇의 구체적인 기계 방식에 대해 이야기하지 말고 외부 세계와 통신하는 센서는 필수 불가결합니다. 외부 환경 데이터를 수집하고 처리하여 수행 할 수 있습니다. 다양한 기능.
간단한 모듈, 온도 및 습도 센서 DHT11에 대해 이야기하겠습니다.
DHT11 소개
DHT11은 온도 및 습도 측정을위한 저렴하고 사용하기 쉬운 투 인원 센서입니다. 그것은 초소형 크기와 극히 낮은 전력 소비의 특성을 가지고 있습니다. 단일 버스를 사용하여 단일 칩 컴퓨터로 양방향 직렬 데이터 전송을 수행하며 신호 전송 거리는 20m 이상에 달할 수 있습니다. 높은 정확도와 실시간이 필요하지 않은 온도 및 습도 측정 상황에 매우 적합합니다.
이 기사에서는 DFRobot 오픈 소스 하드웨어 플랫폼의 DHT11 모듈과 DFRduino 개발 보드를 보여주고 DHT11의 드라이버와 사용을 설명합니다.
DHT11 전기 매개 변수
전원 공급 장치 전압 : 3 ~ 5.5V (일반 값 : 5V);
온도 범위 : 0 ~ 50 ℃, 오류 ± 2 ℃;
습도 범위 : 20 ~ 90 % RH, 오류 ± 5 % RH;
샘플링 기간 : 더 큼 1 초 / 회 이상.
이 센서에는 VCC, GND 및 DATA라는 세 개의 핀이 있습니다. 이것은 단일 데이터 포트가있는 센서입니다. 데이터 포트는 양방향 전송에 사용됩니다.이 핀은 FPGA에서로 설정되어야합니다 inout
.
작동 원리
DHT11은 통신을 위해 단일 버스를 사용하는데, 이는 DATA 핀과 마이크로 컨트롤러를 연결하는 라인입니다. 버스는 항상 유휴 상태 와 통신 상태 사이에 있습니다.
단일 칩 마이크로 컴퓨터가 DHT11과 상호 작용하지 않을 때 버스는 유휴 상태에 있고 풀업 저항의 작동하에 높은 수준의 상태에 있습니다.
MCU와 DHT11이 통신 중일 때 버스는 통신 상태이며 완전한 통신 과정은 다음과 같습니다.
① MCU는 버스를 구동하는 IO를 출력 모드로 구성합니다. DHT11로 데이터를 보낼 준비가되었습니다.
② 마이크로 컨트롤러는 시작 신호를 보내기 위해 최소 18ms 동안 버스를 아래로 당깁니다. 그런 다음 버스를 하이로 당기고 20 ~ 40us를 지연시켜 시작 신호의 끝을 나타냅니다.
③ 단일 칩 마이크로 컴퓨터는 DHT11에서 반환 된 데이터를 수신 할 준비가 된 입력 모드로 드라이브 버스의 IO를 구성합니다.
④ DHT11은 마이크로 컨트롤러에서 보낸 초기 신호를 감지하면 응답을 시작하고 수집 된 센서 데이터를 반환합니다. DHT11은 먼저 마이크로 컨트롤러에 대한 승인 (ACK)으로 버스를 80us 낮게 가져온 다음 수집 된 온도 및 습도 데이터를 반환 할 준비가 된 버스를 80us만큼 높입니다. 온도 및 습도 데이터는 고정 프레임 형식으로 전송됩니다.
프레임은 40 비트이고 각 비트의 전송 타이밍 로직은 다음과 같습니다. 각 비트는 50us의 로우 레벨 (DHT11이 버스를 로우로 끌어 옴)에 의해 주도되고 DHT11은 버스를 하이로 끌어옵니다. 26 ~ 28us는 로직 0을 나타내고, 70us 지속되면 로직 1을 나타냅니다.
이 신호 다이어그램을 보면 모듈과 마스터 간의 통신 모드를 알 수 있습니다.
- 전원을 켠 후 1 초 동안 불안정한 상태를 지나갈 때까지 기다리십시오.
- IO는 신호 출력 모드이며 로우 레벨은 18ms 이상 지속됩니다. (20ms 권장)
- IO 레벨은 20 ~ 40us 동안 높게 설정됩니다. (30us 권장)
- IO는 신호 입력 모드이며 DHT 응답 시간으로 들어갑니다. (즉, 모듈은 마스터 컨트롤의 정보를 수신하고 데이터 전송 전 신호를 반환합니다.)
- 낮은 레벨은 80us를 지연시키고 레벨은 80us를 끌어 올려 DHT 응답을 완료합니다.
- 전송할 데이터 로직 0/1을 입력하고 40 비트 지속됩니다.
- 로직 0, 레벨은 50us 동안 풀다운되고 레벨은 25us 동안 풀업됩니다.
- 로직 1, 레벨은 50us에 대해 풀다운되고 레벨은 80us에 대해 풀업됩니다.
- 데이터 전송이 끝나면 버스가 하이로 당겨집니다. (여기에서 1 초 이상 지연된 후 다음 데이터 수집을 수행 할 수 있습니다.)
Verilog 드라이버 코드 :
// dht11
// made by 00
//time 2020.4.28
module dht11(
input clk,
input rst_n,
inout dht11,
output reg [31:0] data_valid
);
/**************parameter********************/
parameter POWER_ON_NUM = 1000_000;
parameter S_POWER_ON = 3'd0;
parameter S_LOW_20MS = 3'd1;
parameter S_HIGH_13US = 3'd2;
parameter S_LOW_83US = 3'd3;
parameter S_HIGH_87US = 3'd4;
parameter S_SEND_DATA = 3'd5;
parameter S_DEALY = 3'd6;
//reg define
reg[2:0] cur_state;
reg[2:0] next_state;
reg[20:0] count_1us;
reg[5:0] data_count;
reg[39:0] data_temp;
reg[4:0] clk_cnt;
reg clk_1M;
reg us_clear;
reg state;
reg dht_buffer;
reg dht_d0;
reg dht_d1;
wire dht_podge; //data posedge
wire dht_nedge; //data negedge
/*********************main codes*********************/
assign dht11 = dht_buffer;
assign dht_podge = ~dht_d1 & dht_d0; // catch posedge
assign dht_nedge = dht_d1 & (~dht_d0); // catch negedge
/*********************counters*****************************/
//clock with 1MHz
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
clk_cnt <= 5'd0;
clk_1M <= 1'b0;
end
else if (clk_cnt < 5'd24)
clk_cnt <= clk_cnt + 1'b1;
else begin
clk_cnt <= 5'd0;
clk_1M <= ~ clk_1M;
end
end
//counter 1 us
always @ (posedge clk_1M or negedge rst_n) begin
if (!rst_n)
count_1us <= 21'd0;
else if (us_clear)
count_1us <= 21'd0;
else
count_1us <= count_1us + 1'b1;
end
//change state
always @ (posedge clk_1M or negedge rst_n) begin
if (!rst_n)
cur_state <= S_POWER_ON;
else
cur_state <= next_state;
end
// state machine
always @ (posedge clk_1M or negedge rst_n) begin
if(!rst_n)
begin
next_state <= S_POWER_ON;
dht_buffer <= 1'bz;
state <= 1'b0;
us_clear <= 1'b0;
data_temp <= 40'd0;
data_count <= 6'd0;
end
else
begin
case (cur_state)
S_POWER_ON : //wait
begin
if(count_1us < POWER_ON_NUM)
begin
dht_buffer <= 1'bz;
us_clear <= 1'b0;
end
else
begin
next_state <= S_LOW_20MS;
us_clear <= 1'b1;
end
end
S_LOW_20MS: // send 20 ms
begin
if(count_1us < 20000)
begin
dht_buffer <= 1'b0;
us_clear <= 1'b0;
end
else
begin
next_state <= S_HIGH_13US;
dht_buffer <= 1'bz;
us_clear <= 1'b1;
end
end
S_HIGH_13US: // Hign 13 us
begin
if (count_1us < 20)
begin
us_clear <= 1'b0;
if(dht_nedge)
begin
next_state <= S_LOW_83US;
us_clear <= 1'b1;
end
end
else
next_state <= st_delay;
end
S_LOW_83US:
begin
if(dht_podge)
next_state <= S_HIGH_87US;
end
S_HIGH_87US: // ready to receive data signal
begin
if(dht_nedge)
begin
next_state <= S_SEND_DATA;
us_clear <= 1'b1;
end
else
begin
data_count <= 6'd0;
data_temp <= 40'd0;
state <= 1'b0;
end
end
S_SEND_DATA: // have 40 bit
begin
case(state)
0: begin
if(dht_podge)
begin
state <= 1'b1;
us_clear <= 1'b1;
end
else
us_clear <= 1'b0;
end
1: begin
if(dht_nedge)
begin
data_count <= data_count + 1'b1;
state <= 1'b0;
us_clear <= 1'b1;
if(count_1us < 60)
data_temp <= {
data_temp[38:0],1'b0}; //0
else
data_temp <= {
data_temp[38:0],1'b1}; //1
end
else //wait for high end
us_clear <= 1'b0;
end
endcase
if(data_cnt == 40) //check data bit
begin
next_state <= st_delay;
if(data_temp[7:0] == data_temp[39:32] + data_temp[31:24] + data_temp[23:16] + data_temp[15:8])
data_valid <= data_temp[39:8];
end
end
S_DELAY: // after data received delay 2s
begin
if(count_1us < 2000_000)
us_cnt_clr <= 1'b0;
else
begin
next_state <= S_LOW_20MS; // send signal again
us_cnt_clr <= 1'b1;
end
end
default :
cur_state <= cur_state;
endcase
end
end
//edge
always @ (posedge clk_1M or negedge rst_n) begin
if (!rst_n) begin
dht_d0 <= 1'b1;
dht_d1 <= 1'b1;
end
else begin
dht_d0 <= dht11;
dht_d1 <= dht_d0;
end
end
endmodule
Pro-test 가능합니다. 댓글이 모두 영어로되어있는 이유는 코드를 작성할 때 영문 키보드를 열고 중국어를 쓸 수 없어 중국어 기호의 실수를 피할 수 있기 때문입니다.
물리적 테스트
이것은 Robei Cup 대회에서 사용될 예정이지만, RISC-V 아키텍처를 사용하려면 Xilinx를 사용하여 하드 코어를 조정해야하기 때문에 Xilinx 또는 Altera의 보드를 사용할지 여전히 얽혀 있습니다. 아직 할 수없는 것 같아서 먼저 구조를 구축 한 다음 RISC-V로 구현할 수 있는지 확인하려고합니다.