2019年6月11日 星期二

[Verilog] DHT22







純記錄

module IOT_Bridge(
                output [7:0] seg,
                output [3:0] dig,
                output reg [3:0] led,
                input clock,
                input [3:0] sw,
                inout dht22_sda
        );
               
        // variables of clocks
        wire ck1Mhz;
        wire ck1KHz;   
        wire ck1Hz;     
        CLK_1MHZ  clk_1MHz(clock, ck1Mhz);
        CLK_1KHZ  clk_1KHz(clock, ck1Khz);
        CLK_1HZ   clk_1Hz(clock, ck1Hz);
       
        // variables of 7-seg LED
   wire [3:0] D3;
   wire [3:0] D2;
   wire [3:0] D1;
   wire [3:0] D0;
   wire [15:0] number;  // number to display
       
   BIN2BCD bin2bcd(number, D3, D2, D1, D0);
   Seg7    seg7(seg, dig, ck1Khz, D3, D2, D1, D0);   
               
        //DHT22 variables
        reg dht22_reset;
        reg dht22_get;
        reg dht22_select; //1=humidity, 0=temperature
        wire  [39:0] dht22_data;
        DHT22 dht22(ck1Mhz, dht22_reset, dht22_get, dht22_sda, dht22_data);
       
        assign number[15:0] = dht22_select ? dht22_data[39:24]:dht22_data[23:8];
       
        // clock
        reg [9:0] clock_counter;
       
        // initial
        initial
        begin
                dht22_reset = 0;
                dht22_get = 1;
                dht22_select = 1;
                clock_counter = 0;
                led[3:0]= 4'b1111; //LED off
        end         
       
        // select to show humidity or temperture
        always @ (posedge sw[0])
        begin      
                dht22_select = ~dht22_select;               
        end
               
        always @ (posedge ck1Khz)
        begin                              
                if (dht22_reset==0)
                        begin
                                dht22_reset = 1;
                                dht22_get = 0; //start to read DHT22
                        end
               
                led[3] = dht22_get;
                clock_counter = clock_counter + 1'b1;
                if(clock_counter==10'd1000)
                        begin
                                clock_counter = 0; 
                                dht22_reset = 0;
                        end
                if(clock_counter==10'd10) 
                        begin                      
                                dht22_get = 1; //stop read DHT22
                        end                 
        end                 
       
endmodule

/*
        DHT22.v : read DHT22 data
       
       
        source: https://github.com/evrinoma/AM2302
        Modify: Ghosty Guo
          Date: 2019/06/10
*/
module DHT22(
        input wire clk,
        input wire reset,
        input wire get,
        inout sda,
        output reg [39:0] outdata
);

reg lastSda       = 0;
reg wdata       = 0;
reg rw              = 1;

reg [39:0] data;
reg [9:0] address;

reg [3:0] state;
reg [9:0] count;

reg [3:0] trace;
reg [9:0] countTrace;

localparam STATE_IDLE                          = 0;
localparam STATE_START                        = 1;
localparam STATE_RELEASE                   = 2;
localparam STATE_RESPONSE_LOW      = 3;
localparam STATE_RESPONSE_HIGH     = 4;
localparam STATE_DATA_LOW                        = 5;
localparam STATE_DATA_HIGH                       = 6;
localparam STATE_STOP                                = 7;
localparam STATE_HALT                                 = 8;

localparam DELAY_HALT                                = 2;

assign sda = (rw)? 1'bz : wdata;

initial
begin
        outdata[39:0] = 40'd0;
end
       
always@(posedge clk)
begin
        if (!reset)
                begin
                        state <= STATE_IDLE;
                        rw            <= 1;
                        count <= 10'd0;
                        address <= 10'd39;
                        data <= 40'd0;
                        lastSda     <= 0;
                end
        else
                begin
                        case (state)
                                STATE_IDLE : begin //0
                                        if (!get)
                                                state <= STATE_START;
                                        else
                                                state <= STATE_IDLE;
                                        rw            <= 1;
                                        count       <= 10'd0;
                                        address <= 10'd39;
                                end
                                STATE_START : begin //1        
                                        if (count == 1000) //1ms
                                                begin
                                                        state <= STATE_RELEASE;
                                                        count <= 10'd0;
                                                end
                                        else
                                                begin
                                                        state <= STATE_START;
                                                        count <= count + 10'd1;
                                                end
                                        wdata <= 0;
                                        rw            <= 0;                       
                                end
                                STATE_RELEASE : begin //2
                                        if (count == 30) //30us
                                                begin
                                                        state <= STATE_RESPONSE_LOW;
                                                        count <= 10'd0;
                                                        rw            <= 1;
                                                end
                                        else
                                                begin
                                                        state <= STATE_RELEASE;
                                                        count <= count + 10'd1;
                                                        rw            <= 0;
                                                end
                                        wdata <= 1;
                                end
                                STATE_RESPONSE_LOW : begin //3
                                        if (trace != STATE_HALT )
                                                begin
                                                        if (count == 40)        //80us/2
                                                                begin
                                                                        if (sda && !lastSda)
                                                                                begin
                                                                                        state <= STATE_RESPONSE_HIGH;
                                                                                        count <= 10'd0;
                                                                                end                                                         
                                                                        else
                                                                                begin
                                                                                        state <= STATE_RESPONSE_LOW;                                                   
                                                                                end
                                                                end
                                                        else
                                                                begin
                                                                        count <= count + 10'd1;
                                                                end 
                                                        rw                    <= 1;       
                                                        lastSda     <= sda;
                                                end
                                        else
                                                begin
                                                        state <= STATE_IDLE;
                                                end
                                end
                                STATE_RESPONSE_HIGH : begin //4
                                        if (trace != STATE_HALT )
                                                begin
                                                        if (count == 40)        //80us/2
                                                                begin
                                                                        if (!sda && lastSda)
                                                                                begin
                                                                                        state <= STATE_DATA_LOW;
                                                                                        count <= 10'd0;
                                                                                end                                                         
                                                                        else
                                                                                begin
                                                                                        state <= STATE_RESPONSE_HIGH;                                                 
                                                                                end
                                                                end
                                                        else
                                                                begin
                                                                        count <= count + 10'd1;
                                                                end 
                                                        rw                    <= 1;       
                                                        lastSda     <= sda;
                                                end
                                        else
                                                begin
                                                        state <= STATE_IDLE;
                                                end
                                end
                                STATE_DATA_LOW : begin //5
                                        if (trace != STATE_HALT )
                                                begin
                                                        if (sda)
                                                                begin
                                                                        state <= STATE_DATA_HIGH;
                                                                end
                                                        else
                                                                begin
                                                                        state <= STATE_DATA_LOW;
                                                                end
                                                        rw            <= 1;       
                                                end
                                        else
                                                begin
                                                        state <= STATE_IDLE;
                                                end 
                                end
                                STATE_DATA_HIGH : begin //6
                                        if (trace != STATE_HALT )
                                                begin
                                                        if (sda)
                                                                begin
                                                                        count <= count + 10'd1;
                                                                        state <= STATE_DATA_HIGH;
                                                                end
                                                        else
                                                                begin
                                                                        if (count < 30)
                                                                                begin
                                                                                        data[address] = 1'b0;
                                                                                end
                                                                        else
                                                                                begin
                                                                                        data[address] = 1'b1;
                                                                                end
                                                                        if (address)
                                                                                begin
                                                                                        address = address - 10'd1;
                                                                                        state <= STATE_DATA_LOW;
                                                                                        count <= 10'd0;
                                                                                end
                                                                        else
                                                                                begin
                                                                                        // get all 40 bits
                                                                                        address <= 10'd39;
                                                                                        state <= STATE_STOP;
                                                                                        outdata[39:0] <= data[39:0];
                                                                                end
                                                                end
                                                        rw            <= 1;       
                                                end
                                        else
                                                begin
                                                        state <= STATE_IDLE;
                                                end
                                end
                                STATE_STOP : begin //7
                                        if (trace != STATE_HALT )
                                        begin
                                                if (sda)
                                                        begin
                                                                state <= STATE_IDLE;
                                                        end
                                                else
                                                        begin
                                                                state <= STATE_STOP;
                                                        end
                                                rw            <= 1;       
                                                end
                                        else
                                         begin
                                                state <= STATE_IDLE;              
                                         end
                                end
                        endcase
                end
end


always@(posedge clk)
begin
        if (!reset)
                begin
                        trace <= STATE_IDLE;
                        countTrace      <= 10'd0;
                end
        else
                begin              
                        case (trace)
                                STATE_IDLE, STATE_START,STATE_RELEASE : begin //0, 1, 2
                                                trace <= state;
                                                countTrace      <= 10'd0;                                
                                end                         
                                STATE_RESPONSE_LOW,STATE_RESPONSE_HIGH,STATE_DATA_LOW,STATE_DATA_HIGH,STATE_STOP : begin //3, 4, 5, 6, 7
                                        if (state == trace)
                                                if (countTrace > 85 ) //85us - max time for Responce period
                                                        begin
                                                                trace <= STATE_HALT;
                                                                countTrace      <= 10'd0;
                                                        end
                                                else
                                                        begin                              
                                                                countTrace <= countTrace + 10'd1;
                                                        end
                                        else
                                                begin
                                                        trace <= state;
                                                        countTrace      <= 10'd0;
                                                end
                                end
                                STATE_HALT : begin //8
                                        if (countTrace == DELAY_HALT)
                                                begin
                                                        trace <= STATE_IDLE;
                                                        countTrace      <= 10'd0;                                
                                                end
                                        else
                                                begin
                                                        countTrace <= countTrace + 10'd1;
                                                end
                                end
                        endcase
                end         
end


endmodule


module CLK_1KHZ(
                input clk_in,
                output reg clk_out
        );
       
       
        reg [14:0] clk_count;
       
       
        // initial
        initial
        begin
                clk_count = 0;
                clk_out = 0;
        end 

       
        // clock counts
        always @ (posedge clk_in)
        begin
                clk_count = clk_count + 1'b1;
                if(clk_count==25000) //50Mhz
                begin
                        clk_count = 0; 
                        clk_out = ~clk_out;
                end
        end
endmodule


module CLK_1MHZ(
                input clk_in,
                output reg clk_out
        );
       
       
        reg [4:0] clk_count;
       
       
        // initial
        initial
        begin
                clk_count = 0;
                clk_out = 0;
        end 

       
        // clock counts
        always @ (posedge clk_in)
        begin
                clk_count = clk_count + 1'b1;
                if(clk_count==25) //50Mhz
                begin
                        clk_count = 0; 
                        clk_out = ~clk_out;
                end
        end
endmodule

module CLK_1MHZ(
                input clk_in,
                output reg clk_out
        );
       
       
        reg [4:0] clk_count;
       
       
        // initial
        initial
        begin
                clk_count = 0;
                clk_out = 0;
        end 

       
        // clock counts
        always @ (posedge clk_in)
        begin
                clk_count = clk_count + 1'b1;
                if(clk_count==25) //50Mhz
                begin
                        clk_count = 0; 
                        clk_out = ~clk_out;
                end
        end
endmodule


/*
        Bin2BCD: Convert binary to 4 BCDs       
        ref: http://alex9ufoexploer.blogspot.com/2013/12/binary-to-bcd-conversion-algorithm.html
*/

module BIN2BCD(
        input [15:0] binary,
        output reg [3:0] BCD3,
        output reg [3:0] BCD2,
        output reg [3:0] BCD1,
        output reg [3:0] BCD0
        );
       
        integer i;
        always@(binary)
        begin
                BCD3 = 4'd0;
                BCD2 = 4'd0;
                BCD1 = 4'd0;
                BCD0 = 4'd0;
                for (i=14; i>=0; i=i-1)
                begin
                        if (BCD3>=4'd5)
                                BCD3 = BCD3 + 4'd3;
                        if (BCD2>=4'd5)
                                BCD2 = BCD2 + 4'd3;
                        if (BCD1>=4'd5)
                                BCD1 = BCD1 + 4'd3;
                        if (BCD0>=4'd5)
                                BCD0 = BCD0 + 4'd3;
                               
                        BCD3 = BCD3 << 1;
                        BCD3[0] = BCD2[3];
                        BCD2 = BCD2 << 1;
                        BCD2[0] = BCD1[3];
                        BCD1 = BCD1 << 1;
                        BCD1[0] = BCD0[3];
                        BCD0 = BCD0 << 1;
                        BCD0[0] = binary[i];
                end
        end

endmodule



沒有留言:

張貼留言