【FPGA】基于FPGA实现AHT10温湿度传感器数据采集

aht10温湿度传感器特点及使用介绍 aht10温湿度传感器特点及使用介绍前言一、ds18b20数字温度传感器外观二、原理图三、相关参数讲解1.引脚2.温度测量范围3.通讯方式(单总线)4.优点4.特点四、内部结构图总结 前言 本文着重介绍ds18b20数字温度传感器的原理、功能及使用方法 一、ds18b20数字温度传感器外观 二、原理图 三、相关参数讲解 1.引脚 3根引脚,名称与功能如下; VDD 为外接供电电源输入端 GND 地线 DQ 为数字信号输入/输出端 2.温度测量范围 温度范围为: 测量范围为 -55 ℃ ~ 阅读详情
AI摘要

本项目使用Cyclone IV E开发板控制AHT10温湿度传感器进行数据采集,将温湿度值打印到终端,还可设置报警值触发蜂鸣器。介绍了AHT10特性、指令及测量步骤,进行系统架构设计、模块划分,描述状态转移,给出代码实现,经仿真测试和板级验证。

写在前面:
相关参考文章:【FPGA】FPGA实现IIC协议读写EEPROM
在本项目中所使用的开发板型号:Cyclone IV E (EP4CE6F17C8),温湿度传感器型号:AHT10。

一、需求分析

  1. 使用C4开发板实现控制AHT10温湿度传感器进行数据采集。
  2. 温度值以十进制形式的摄氏温度打印到终端,保留一位小数,显示形式例如xx.x℃。
  3. 湿度值以百分数形式打印到终端,保留一位小数,显示形式例如:xx.x%。
  4. 使用按键设置温湿度报警值,当采集的温湿度值超过预设的报警值时,触发蜂鸣器报警。

二、AHT10简介

(一)AHT10特性

AHT10是一款标准I2C接口的温湿度传感器。供电范围为1.8-3.6V,推荐电压为3.3V。电源( VDD)和接地(GND)之间须连接一个 10uF的去耦电容,器件引脚接口图如下:

在这里插入图片描述
SDA引脚用于传感器的数据输入和输出。当向传感器发送命令时,SDA在串行时钟( SCL)的上升沿有效,且当SCL为高电平时,SDA 必须保持稳定。在 SCL下降沿之后,SDA值可被改变。

AHT10读写遵循I2C协议,可参考IIC协议工程,时序图如下:
在这里插入图片描述
在这里插入图片描述
本工程中使用时钟频率为200KHz。

(二)AHT10基本指令及测量步骤

1、AHT10基本指令集:
在这里插入图片描述

2、AHT10测量步骤

(1)上电后等待40ms ,读取温湿度值之前,首先看状态字的校准使能位Bit[3]是否为1(通过发送0x71可以获取一个字节的状态字),如果不为1,要发送0xEi命令(初始化),此命令参数有两个字节,第一个字节为0x08,第二个字节为0x00。状态位说明如下:
在这里插入图片描述
(2)直接发送0xAC命令(触发测量),此命令参数有两个字节,第一个字节为0x33,第二个字节为0x00。
在这里插入图片描述
(3)等待80ms测量数据完成,发送0x71读取6字节温湿度数据。
在这里插入图片描述

(三)数据转换

在这里插入图片描述

按照此公式进行转换数据不正确,所以在数据转换代码中做了修改。

三、系统架构设计

本工程系统框图如下:
在这里插入图片描述

四、模块划分及信号说明

(一)模块划分

本工程将系统功能划分为8个模块,各模块功能描述如下:

  1. top:顶层设计模块。
  2. aht10_ctrl:控制驱动AHT10命令的发送、驱动i2c_interface接口模块与AHT10传感器进行数据交互。
  3. i2c_interface:AHT10使用标准的I2C接口协议,该模块实现aht10_ctrl控制模块通过I2C协议时序读取温湿度数据。
  4. data_process:温湿度数据处理模块,将aht10_ctrl控制模块读回的温湿度数据根据转换公式进行转换,并将转换的数据再次转换成ASCII码通过串口进行发送。
  5. uart_tx:串口数据发送模块,将data_process模块转换后的ASCII格式数据通过串口发送给上位机,通过串口调试助手打印温湿度数据信息。
  6. key_filter:按键消抖模块,将按键输入的进行进行消抖处理。
  7. set_limit:温湿度报警值设置模块,通过按键设置温湿度报警值。
  8. seg_driver:数码管显示模块,显示温湿度设置模式及温湿度设置的报警值。

(二)端口信号说明

  1. top模块
    在这里插入图片描述
  2. aht10_ctrl模块
    在这里插入图片描述
  3. i2c_interface模块
    在这里插入图片描述
  4. data_process模块
    在这里插入图片描述
  5. uart_tx模块
    在这里插入图片描述
    6 key_filter模块
    在这里插入图片描述
  6. set_limit模块
    在这里插入图片描述
  7. seg_driver模块
    在这里插入图片描述

五、状态转移描述

  1. aht10_ctrl控制模块状态转移图
    在这里插入图片描述
    状态说明:
    WAIT:上电等待40ms,等待结束后进入INIT状态。
    INIT:初始化,发送初始化指令,进入WAIT_INIT状态。
    WAIT_INIT:等待初始化,检查校准使能位是否为1,不为1则继续进行初始化,初始化完成后进入IDLE状态。
    IDLE:空闲状态,等待读请求。
    RD_REQ:发送读取温湿度数据指令,发送完成后进入WAIT_MES状态。
    WAIT_MES:等待80ms测量温湿度数据完成,进入READ状态。
    READ:读取温度数据,读取完成后进入IDLE状态,等待下一次读请求。
  2. i2c_interface接口模块状态转移图
    在这里插入图片描述
    状态说明:
    IDLE:空闲状态,等待读写请求。
    START:发送起始位,当控制命令cmd[5:0]中含有起始命令时,进行该状态发送起始位。
    WR_DATA:写数据状态,在写数据状态期间,将wr_din[7:0]按照IIC协议时序写入AHT10。
    RD_DATA:读数据状态,在读数据状态期间,按照IIC协议时序从AHT10中读取数据。
    REC_ACK:接收从机发送的ACK应答信号。
    SEND_ACK:发送ACK或者NACK信号。
    STOP:发送停止位,当控制命令cmd[5:0]中含有停止命令时,进行该状态发送停止位。

六、代码实现

1. aht10读写顶层设计模块

//  **************************************************************
//  Author: Zhang JunYi
//  Create Date: 2022.11.15                        
//  Design Name: AHT10    
//  Module Name: top         
//  Target Device: Cyclone IV E (EP4CE6F17C8), 温湿度传感器(AHT10)             
//  Tool versions: Quartus Prime 18.1             
//  Description: aht10读写顶层设计模块
//  **************************************************************

module top (
    input           clk             ,
    input           rst_n           ,
    //  key
    input   [2:0]   key_in          ,
    //  AHT10
    inout           sda             ,
    output          scl             ,
    //  UART
    output          uart_txd        ,
    //  beep
    output          beep            ,
    //  数码管
    output  [7:0]   seg_dig         ,
    output  [5:0]   seg_sel         
);

    wire            sda_in          ;
    wire            sda_out         ;
    wire            sda_out_en      ;

    assign sda = sda_out_en ? sda_out : 1'bz ;
    assign sda_in = sda ;

    wire            req             ;
    wire    [7:0]   wrdata          ;
    wire    [3:0]   cmd             ;
    wire    [7:0]   rddata          ;
    wire            rddata_vld      ;
    wire            done            ;

    wire    [19:0]  hum_data        ; 
    wire    [19:0]  tem_data        ; 
    wire            data_vld        ; 

    wire            ready           ;  
    wire    [7:0]   tx_data         ;
    wire            tx_data_vld     ;

    wire            tem_add         ;
    wire            hum_add         ;
    wire            set             ;
    wire            modle           ;
    wire    [7:0]   tem_lim         ;
    wire    [7:0]   hum_lim         ;

    key_filter u_key_filter1 (
    /*input           */.clk         (clk           ),
    /*input           */.rst_n       (rst_n         ),
    /*input           */.key_in      (key_in[0]     ),
    /*output    reg   */.key_out     (set           )
    );

    key_filter u_key_filter2 (
    /*input           */.clk         (clk           ),
    /*input           */.rst_n       (rst_n         ),
    /*input           */.key_in      (key_in[1]     ),
    /*output    reg   */.key_out     (tem_add       )
    );
    key_filter u_key_filter3 (
    /*input           */.clk         (clk           ),
    /*input           */.rst_n       (rst_n         ),
    /*input           */.key_in      (key_in[2]     ),
    /*output    reg   */.key_out     (hum_add       )
    );

    //  模块例化
    aht10_ctrl u_aht10_ctrl (
    /*input               */.clk                 (clk       ),
    /*input               */.rst_n               (rst_n     ),
    /*//  i2c_interface*/
    /*output              */.req                 (req       ),       //  读写请求
    /*output  [7:0]       */.wr_dout             (wrdata    ),       //  发送指令数据
    /*output  [3:0]       */.cmd                 (cmd       ),       //  发送读写控制命令
    /*input   [7:0]       */.rdin                (rddata    ),       //  读回的数据
    /*input               */.rdin_vld            (rddata_vld),
    /*input               */.rw_done             (done      ),        //  读写一字节数据完成标志
    //  data_process
    /*output  [19:0]      */.hum_data            (hum_data  ),       //  湿度数据
    /*output  [19:0]      */.tem_data            (tem_data  ),       //  温度数据
    /*output              */.data_vld            (data_vld  )        //  温湿度数据有效标志
    );

    i2c_interface u_i2c_interface (
    /*input               */.clk                 (clk           ),
    /*input               */.rst_n               (rst_n         ),

    /*//  eeprom_ctrl*/
    /*input               */.req                 (req           ),       //  读写请求
    /*input   [7:0]       */.wr_din              (wrdata        ),       //  需要发送的一字节数据
    /*input   [3:0]       */.cmd                 (cmd           ),       //  控制命令组合
    /*output  [7:0]       */.rdout               (rddata        ),       //  读取的数据
    /*output              */.rdout_vld           (rddata_vld    ),       //  读取数据有效标志
    /*output              */.rw_done             (done          ),       //  读写一字节完成标志
    /*//  EEPROM*/
    /*input               */.sda_in              (sda_in        ),
    /*output              */.sda_out             (sda_out       ),
    /*output              */.sda_out_en          (sda_out_en    ),
                            .scl                 (scl           )
    );

    data_process u_data_process (
    /*input           */.clk             (clk           ),
    /*input           */.rst_n           (rst_n         ),
    /*//  aht10_ctrl*/
    /*input           */.din_vld         (data_vld      ),
    /*input   [19:0]  */.tem_data        (tem_data      ),
    /*input   [19:0]  */.hum_data        (hum_data      ),
    /*//  set_limit*/
    /*input   [7:0]   */.tem_lim         (tem_lim       ),
    /*input   [7:0]   */.hum_lim         (hum_lim       ),
    /*//  uart_tx*/
    /*input           */.ready           (ready         ),
    /*output  [7:0]   */.tx_data         (tx_data       ),
    /*output          */.tx_data_vld     (tx_data_vld   ),
    /*//  beep*/
    /*output          */.beep            (beep          )    
    );

    set_limit u_set_limit (
        /*input           */.clk             (clk       ),
        /*input           */.rst_n           (rst_n     ),
        /*//  key_filter*/
        /*input           */.tem_add         (tem_add   ),       //  设置温度报警值标志,每按一次+5摄氏度
        /*input           */.hum_add         (hum_add   ),       //  设置湿度报警值标志,每按一次+5%
        /*input           */.set             (set       ),       //  设置模式,每按一次在温度和湿度设置之间切换
        /*//  seg_driver*/
        /*output          */.modle           (modle     ),       //  当前设置模式  0:设置温度   1:设置湿度
        /*output  [7:0]   */.tem_lim         (tem_lim   ),       //  温度报警值
        /*output  [7:0]   */.hum_lim         (hum_lim   )        //  湿度报警值
    );

    seg_driver u_seg_driver(
    /*input                   */.clk          (clk      ),
    /*input                   */.rst_n        (rst_n    ),
    /*// set_limit*/
    /*input   [7:0]           */.tem_lim      (tem_lim  ),
    /*input   [7:0]           */.hum_lim      (hum_lim  ),
    /*input                   */.modle        (modle    ),

    /*output  reg   [7:0]     */.seg_dig      (seg_dig  ),      //  段选信号
    /*output  reg   [5:0]     */.seg_sel      (seg_sel  )      //  片选信号
    );

    uart_tx u_uart_tx (
        /*input               */.clk             (clk           ),
        /*input               */.rst_n           (rst_n         ),
        /*//  control*/ 
        /*input   [7:0]       */.tx_din          (tx_data       ),
        /*input               */.tx_din_vld      (tx_data_vld   ),
        /*output              */.ready           (ready         ),       //  给control模块的握手信号,表示可以接收数据进行发送 
        /*//  上位机*/
        /*output              */.uart_tx         (uart_txd      )
    );


endmodule

2. I2C接口驱动模块

//  **************************************************************
//  Author: Zhang JunYi
//  Create Date: 2022.11.15                        
//  Design Name: AHT10    
//  Module Name: i2c_interface         
//  Target Device: Cyclone IV E (EP4CE6F17C8), 温湿度传感器(AHT10)          
//  Tool versions: Quartus Prime 18.1             
//  Description: I2C接口驱动模块
//  **************************************************************
`include "param.v"

module i2c_interface (
    input               clk                 ,
    input               rst_n               ,
    //  eeprom_ctrl
    input               req                 ,       //  读写请求
    input   [7:0]       wr_din              ,       //  需要发送的一字节数据
    input   [3:0]       cmd                 ,       //  控制命令组合
    output  [7:0]       rdout               ,       //  读取的数据
    output              rdout_vld           ,       //  读取数据有效标志
    output              rw_done             ,       //  读写一字节完成标志
    //  EEPROM
    input               sda_in              ,
    output              sda_out             ,
    output              sda_out_en          ,
    output              scl
);
    //  参数定义
    localparam  IDLE    =   7'b000_0001 ,
                START   =   7'b000_0010 ,
                WR_DATA =   7'b000_0100 ,
                RD_DATA =   7'b000_1000 ,
                REC_ACK =   7'b001_0000 ,
                SEND_ACK=   7'b010_0000 ,
                STOP    =   7'b100_0000 ;

    //  信号定义
    reg     [6:0]       state_c         ;
    reg     [6:0]       state_n         ;

    reg     [7:0]       cnt_scl         ;       //  scl周期计数器
    wire                add_cnt_scl     ;
    wire                end_cnt_scl     ;

    reg     [3:0]       bit_num         ;       //  bit数
    reg     [3:0]       cnt_bit         ;       //  bit计数器
    wire                add_cnt_bit     ;
    wire                end_cnt_bit     ;

    reg     [7:0]       dout_data       ;       //  发送数据寄存
    reg     [3:0]       command         ;       //  控制命令寄存

    reg                 scl_dout         ;       //  SDA寄存     
    reg                 sda_dout        ;
    reg                 sda_dout_en     ;

    reg     [7:0]       rx_data         ;       //  接收读回的数据
    reg                 ack_flag        ;       //  ack响应标志


    //  状态转移条件
    wire                idle2start      ;
    wire                idle2wrdata     ;
    wire                idle2rddata     ;
    wire                start2wrdata    ;
    wire                start2rddata    ;
    wire                wrdata2recack   ;
    wire                rddata2sendack  ;
    wire                recack2idle     ;
    wire                recack2stop     ;
    wire                sendack2idle    ;
    wire                sendack2stop    ;
    wire                stop2idle       ;

    //  状态机
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            state_c <= IDLE ;
        end
        else begin
            state_c <= state_n ;
        end
    end

    always @(*)begin
        case (state_c)
            IDLE: begin
                if(idle2start)
                    state_n = START ;
                else if(idle2wrdata)
                    state_n = WR_DATA ;
                else if(idle2rddata)
                    state_n = RD_DATA ;
                else
                    state_n = state_c ;
            end
            START: begin
                if(start2wrdata)
                    state_n = WR_DATA ;
                else if(start2rddata)
                    state_n = RD_DATA ;
                else
                    state_n = state_c ;
            end
            WR_DATA: begin
                if(wrdata2recack)
                    state_n = REC_ACK ;
                else
                    state_n = state_c ;
            end
            RD_DATA: begin
                if(rddata2sendack)
                    state_n = SEND_ACK ;
                else
                    state_n = state_c ;
            end
            REC_ACK: begin
                if(recack2idle)
                    state_n = IDLE ;
                else if(recack2stop)
                    state_n = STOP ;
                else
                    state_n = state_c ;
            end
            SEND_ACK: begin
                if(sendack2idle)
                    state_n = IDLE ;
                else if(sendack2stop)
                    state_n = STOP ;
                else
                    state_n = state_c ;
            end
            STOP: begin
                if(stop2idle)
                    state_n = IDLE ;
                else
                    state_n = state_c ;
            end
            default: state_n = IDLE ;
        endcase
    end

    //  状态转移条件
    assign  idle2start      = state_c == IDLE       && req && (cmd & `STA)                      ;
    assign  idle2wrdata     = state_c == IDLE       && req && (cmd & `WRITE)                    ;
    assign  idle2rddata     = state_c == IDLE       && req && (cmd & `READ)                     ;
    assign  start2wrdata    = state_c == START      && end_cnt_bit && (command & `WRITE)        ;   
    assign  start2rddata    = state_c == START      && end_cnt_bit && (command & `READ)         ;   
    assign  wrdata2recack   = state_c == WR_DATA    && end_cnt_bit                              ;
    assign  rddata2sendack  = state_c == RD_DATA    && end_cnt_bit                              ;
    assign  recack2idle     = state_c == REC_ACK    && end_cnt_bit && (command & `STO) == 0     ;
    assign  recack2stop     = state_c == REC_ACK    && end_cnt_bit && (command & `STO)          ;
    assign  sendack2idle    = state_c == SEND_ACK   && end_cnt_bit && (command & `STO) == 0     ;
    assign  sendack2stop    = state_c == SEND_ACK   && end_cnt_bit && (command & `STO)          ;
    assign  stop2idle       = state_c == STOP       && end_cnt_bit                              ;

    //  cnt_scl  200KHz  一个SCL周期为250个系统时钟周期
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            cnt_scl <= 0 ;
        end
        else if(add_cnt_scl)begin
            if(end_cnt_scl)begin
                cnt_scl <= 0 ;
            end				
            else begin	    
                cnt_scl <= cnt_scl + 1 ;
            end 		    
        end
    end                 
    assign	add_cnt_scl	= state_c != IDLE ;
    assign	end_cnt_scl	= add_cnt_scl && (cnt_scl == `SCL_PERIOD - 1) ;

    //  bit_num
    always @(*)begin
        if(state_c == RD_DATA || state_c == WR_DATA)begin
            bit_num = 8 ;
        end
        else begin
            bit_num = 1 ;
        end
    end

    //  cnt_bit
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            cnt_bit <= 0 ;
        end
        else if(add_cnt_bit)begin
            if(end_cnt_bit)begin
                cnt_bit <= 0 ;
            end				
            else begin	    
                cnt_bit <= cnt_bit + 1 ;
            end 		    
        end
    end           
    assign	add_cnt_bit	= end_cnt_scl ;
    assign	end_cnt_bit	= add_cnt_bit && (cnt_bit == bit_num - 1) ;

    //  dout_data
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            dout_data <= 0 ;
        end
        else if(req)begin
            dout_data <= wr_din ;
        end
    end

    //  command
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            command <= 0 ;
        end
        else if(req)begin
            command <= cmd ;
        end
    end

    //  scl_dout
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            scl_dout <= 1'b1 ;
        end
        else if(idle2start | idle2wrdata | idle2rddata)begin
            scl_dout <= 1'b0 ;
        end
        else if(add_cnt_scl && cnt_scl == `SCL_HALF)begin
            scl_dout <= 1'b1 ;
        end
        else if(end_cnt_scl && ~stop2idle)begin
            scl_dout <= 1'b0 ;
        end
    end

    //  sda_dout_en
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            sda_dout_en <= 1'b0 ;
        end
        else if(idle2start || idle2wrdata || rddata2sendack || sendack2stop || recack2stop)begin
            sda_dout_en <= 1'b1 ;
        end
        else if(idle2rddata || start2rddata || wrdata2recack || stop2idle)begin
            sda_dout_en <= 1'b0 ;
        end
    end

    //  sda_dout
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            sda_dout <= 1'b1 ;
        end
        else if(state_c == START)begin
            if(cnt_scl == `HIGH_HALF)begin
                sda_dout <= 1'b0 ;
            end
            else if(cnt_scl == `LOW_HALF)begin
                sda_dout <= 1'b1 ;
            end
        end
        else if(state_c == WR_DATA && cnt_scl == `LOW_HALF)begin
            sda_dout <= dout_data[7 - cnt_bit] ;
        end
        else if(state_c == SEND_ACK && cnt_scl == `LOW_HALF)begin
            sda_dout <= (command & `STO) ? 1'b1 : 1'b0 ;
        end
        else if(state_c == STOP)begin
            if(cnt_scl == `LOW_HALF)begin       
                sda_dout <= 1'b0;
            end
            else if(cnt_scl == `HIGH_HALF)begin    
                sda_dout <= 1'b1;               
            end 
        end
        else if(wrdata2recack | rddata2sendack)begin
            sda_dout <= 1'b1;  
        end
    end
    //  rx_data
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            rx_data <= 0 ;
        end
        else if(state_c == RD_DATA && cnt_scl == `HIGH_HALF)begin
            rx_data[7 - cnt_bit] <= sda_in ;
        end
    end

    //  ack_flag
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            ack_flag <= 1'b0 ;
        end
        else if(state_c == REC_ACK && cnt_scl == `HIGH_HALF)begin
            ack_flag <= ~sda_in ;
        end
        else begin
            ack_flag <= 1'b0 ;
        end
    end

    //  输出
    assign rdout = rx_data ;   
    assign rdout_vld = rddata2sendack ;
    assign rw_done = stop2idle | sendack2idle | recack2idle ;
    assign sda_out = sda_dout ; 
    assign sda_out_en = sda_dout_en ;
    assign scl = scl_dout ;
    
endmodule     

3. aht10读写控制模块

//  **************************************************************
//  Author: Zhang JunYi
//  Create Date: 2022.11.15                        
//  Design Name: AHT10    
//  Module Name: aht10_ctrl         
//  Target Device: Cyclone IV E (EP4CE6F17C8), 温湿度传感器(AHT10)             
//  Tool versions: Quartus Prime 18.1             
//  Description: aht10读写控制模块
//  **************************************************************
`include "param.v"
module aht10_ctrl (
    input               clk                 ,
    input               rst_n               ,
    //  i2c_interface
    output              req                 ,       //  读写请求
    output  [7:0]       wr_dout             ,       //  发送指令数据
    output  [3:0]       cmd                 ,       //  发送读写控制命令
    input   [7:0]       rdin                ,       //  读回的数据
    input               rw_done             ,       //  读写一字节数据完成标志
    input               rdin_vld            ,
    //  data_process
    output  [19:0]      hum_data            ,       //  湿度数据
    output  [19:0]      tem_data            ,       //  温度数据
    output              data_vld                    //  温湿度数据有效标志
);

    //  参数定义
    localparam  WAIT      =   8'b0000_0001 ,     //  上电等待40ms
                INIT      =   8'b0000_0010 ,     //  初始化
                WAIT_INIT =   8'b0000_0100 ,     //  等待初始化完成
                IDLE      =   8'b0000_1000 ,     //  空闲
                RD_REQ    =   8'b0001_0000 ,     //  读数据请求
                WAIT_MES  =   8'b0010_0000 ,     //  等待测量完成80ms
                READ      =   8'b0100_0000 ,     //  读数据
                DONE      =   8'b1000_0000 ;     //  读操作完成

    //  信号定义
    reg     [7:0]       state_c             ;
    reg     [7:0]       state_n             ;

    reg     [27:0]      cnt_delay           ;       //  延时计数器
    wire                add_cnt_delay       ;
    wire                end_cnt_delay       ;
    reg     [27:0]      delay               ;

    reg     [3:0]       cnt_byte            ;       //  字节计数器
    wire                add_cnt_byte        ;
    wire                end_cnt_byte        ;

    reg                 init_flag           ;       //  初始化完成标志

    reg                 tx_req              ;       //  task发送请求
    reg     [3:0]       tx_cmd              ;       //  task发送控制命令
    reg     [7:0]       tx_data             ;       //  task发送数据

    reg     [47:0]      rd_data             ;       //  读回的温湿度数据寄存


    //  状态转移条件
    wire                wait2init           ;
    wire                init2waitinit       ;
    wire                waitinit2idle       ;
    wire                waitinit2init       ;
    wire                idle2rdreq          ;
    wire                rdreq2waitmes       ;
    wire                waitmes2read        ;
    wire                read2done           ;
    wire                done2idle           ;
    //  状态机
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            state_c <= WAIT ;
        end
        else begin
            state_c <= state_n ;
        end
    end

    always @(*)begin
        case (state_c)
            WAIT: begin
                if(wait2init)
                    state_n = INIT ;
                else
                    state_n = state_c ;
            end
            INIT: begin
                if(init2waitinit)
                    state_n = WAIT_INIT ;
                else
                    state_n = state_c ;
            end
            WAIT_INIT: begin
                if(waitinit2idle)
                    state_n = IDLE ;
                else if(waitinit2init)
                    state_n = INIT ;
                else
                    state_n = state_c ;
            end
            IDLE: begin
                if(idle2rdreq)
                    state_n = RD_REQ ;
                else
                    state_n = state_c ;
            end
            RD_REQ: begin
                if(rdreq2waitmes)
                    state_n = WAIT_MES ;
                else
                    state_n = state_c ;
            end
            WAIT_MES: begin
                if(waitmes2read)
                    state_n = READ ;
                else
                    state_n = state_c ;
            end
            READ: begin
                if(read2done)
                    state_n = DONE ;
                else
                    state_n = state_c ;
            end
            DONE: begin
                if(done2idle)
                    state_n = IDLE ;
                else
                    state_n = state_c ;
            end
            default: state_n = IDLE ;
        endcase
    end

    //  状态转移描述
    assign  wait2init      = state_c == WAIT        && end_cnt_delay    ; 
    assign  init2waitinit  = state_c == INIT        && end_cnt_byte     ; 
    assign  waitinit2idle  = state_c == WAIT_INIT   && init_flag        ; 
    assign  waitinit2init  = state_c == WAIT_INIT   && ~init_flag && end_cnt_byte       ; 
    assign  idle2rdreq     = state_c == IDLE        && end_cnt_delay    ; 
    assign  rdreq2waitmes  = state_c == RD_REQ      && end_cnt_byte     ; 
    assign  waitmes2read   = state_c == WAIT_MES    && end_cnt_delay    ; 
    assign  read2done      = state_c == READ        && end_cnt_byte     ; 
    assign  done2idle      = state_c == DONE        && (1'b1)           ; 

    //  delay
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            delay <= `DELAY_40ms ;
        end
        else if(state_c == WAIT)begin
            delay <= `DELAY_40ms ;
        end
        else if(state_c == WAIT_MES)begin
            delay <= `DELAY_80ms ;
        end
        else if(state_c == IDLE)begin
            delay <= `DELAY_500ms ;
        end
    end

    //  cnt_delay
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            cnt_delay <= 0 ;
        end
        else if(add_cnt_delay)begin
            if(end_cnt_delay)begin
                cnt_delay <= 0 ;
            end				
            else begin	    
                cnt_delay <= cnt_delay + 1 ;
            end 		    
        end
    end             
    assign	add_cnt_delay = (state_c == WAIT) || (state_c == WAIT_MES) || (state_c == IDLE) ;
    assign	end_cnt_delay = add_cnt_delay && (cnt_delay == delay - 1) ;

    //  cnt_byte
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            cnt_byte <= 0 ;
        end
        else if(add_cnt_byte)begin
            if(end_cnt_byte)begin
                cnt_byte <= 0 ;
            end				
            else begin	    
                cnt_byte <= cnt_byte + 1 ;
            end 		    
        end
    end             
    assign	add_cnt_byte = rw_done ;
    assign	end_cnt_byte = add_cnt_byte && (cnt_byte == ((state_c == READ) ? 7:4) - 1) ;

    //  使用task任务发送数据
    always  @(*)begin
        case (state_c)
            INIT : 
                case(cnt_byte)
                    0           :TX(1'b1,{`STA | `WRITE},{`AHT10_ADDR,1'b0}) ;       //  发起始位、写控制字
                    1           :TX(1'b1,`WRITE,`GET_STATE) ;                        
                    2           :TX(1'b1,`WRITE,`AHT10_INIT_1) ;  
                    3           :TX(1'b1,{`WRITE | `STO} ,`AHT10_INIT_2) ;  
                    default     :TX(1'b0,tx_cmd,tx_data) ;
                endcase 
            WAIT_INIT:
                case(cnt_byte)
                    0           :TX(1'b1,{`STA | `WRITE},{`AHT10_ADDR,1'b0}) ;       //  发起始位、写控制字
                    1           :TX(1'b1,`WRITE,`GET_STATE) ;                        //  发读取状态字命令
                    2           :TX(1'b1,{`STA | `WRITE},{`AHT10_ADDR,1'b1}) ;       //  发读控制字
                    3           :TX(1'b1,{`READ | `STO},0) ;  
                    default     :TX(1'b0,tx_cmd,tx_data) ;
                endcase
            RD_REQ: 
                case(cnt_byte)
                    0           :TX(1'b1,{`STA | `WRITE},{`AHT10_ADDR,1'b0}) ;       //  发起始位、写控制字
                    1           :TX(1'b1,`WRITE,`AHT10_MEAS_0) ;  
                    2           :TX(1'b1,`WRITE,`AHT10_MEAS_1) ;  
                    3           :TX(1'b1,{`WRITE | `STO},`AHT10_MEAS_2) ;  
                    default     :TX(1'b0,tx_cmd,tx_data) ;
                endcase    
            READ :            
                case(cnt_byte)
                    0           :TX(1'b1,{`STA | `WRITE},{`AHT10_ADDR,1'b1}) ;       //  发起始位、写控制字
                    1           :TX(1'b1,`READ,0) ;  
                    2           :TX(1'b1,`READ,0) ;  
                    3           :TX(1'b1,`READ,0) ;  
                    4           :TX(1'b1,`READ,0) ;  
                    5           :TX(1'b1,`READ,0) ;  
                    6           :TX(1'b1,{`READ | `STO},0) ;
                    default     :TX(1'b0,tx_cmd,tx_data) ;
                endcase
            default: TX(1'b0,0,0) ;
        endcase
    end

    //  init_flag
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            init_flag <= 1'b0 ;
        end
        else if(state_c == WAIT_INIT && rw_done && rdin[3])begin
            init_flag <= 1'b1 ;
        end
    end

    //  rd_data
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            rd_data <= 0 ;
        end
        else if(state_c == READ && rw_done && cnt_byte > 0)begin
            rd_data <= {rd_data[39:0],rdin} ;
        end
    end

    //  task
    task TX;   
        input                   req     ;
        input       [3:0]       command ;
        input       [7:0]       data    ;
        begin 
            tx_req  = req ;
            tx_cmd  = command ;
            tx_data = data ;
        end 
    endtask  

    //  输出
    assign req     = tx_req ; 
    assign cmd     = tx_cmd ; 
    assign wr_dout = tx_data ; 
    assign hum_data  = rd_data[39:20] ;
    assign tem_data  = rd_data[19:0] ;
    assign data_vld  = read2done ;

endmodule

4. aht10温湿度数据处理模块

//  **************************************************************
//  Author: Zhang JunYi
//  Create Date: 2022.11.15                        
//  Design Name: AHT10    
//  Module Name: data_process         
//  Target Device: Cyclone IV E (EP4CE6F17C8), 温湿度传感器(AHT10)             
//  Tool versions: Quartus Prime 18.1             
//  Description: aht10温湿度数据处理模块
//  **************************************************************
`include "param.v"

module data_process (
    input           clk             ,
    input           rst_n           ,
    //  aht10_ctrl
    input           din_vld         ,
    input   [19:0]  tem_data        ,
    input   [19:0]  hum_data        ,
    //  set_limit
    input   [7:0]   tem_lim         ,
    input   [7:0]   hum_lim         ,
    //  uart_tx
    input           ready           ,
    output  [7:0]   tx_data         ,
    output          tx_data_vld     ,
    //  beep
    output          beep                
);

    //  信号定义
    reg     [19:0]      tem_data_r          ;       //  温湿度数据寄存
    reg     [19:0]      hum_data_r          ;

    reg     [5:0]       cnt_byte            ;       //  字节计数器
    wire                add_cnt_byte        ;
    wire                end_cnt_byte        ;

    reg                 process_flag        ;       //  数据处理标志

    reg     [7:0]       data                ;       //  串口显示数据

    reg                 flag                ;       //  蜂鸣器标志
    reg                 tem_alarm           ;
    reg                 hum_alarm           ;

    wire    [7:0]       tem_ten             ;       //  温度数据十位
    wire    [7:0]       tem_bit             ;       //  温度数据个位
    wire    [7:0]       tem_dot1            ;       //  温度数据小数位1
    wire    [7:0]       tem_dot2            ;       //  温度数据小数位2

    wire    [7:0]       hum_ten             ;       //  湿度数据十位
    wire    [7:0]       hum_bit             ;       //  湿度数据个位
    wire    [7:0]       hum_dot1            ;       //  湿度数据小数位1
    wire    [7:0]       hum_dot2            ;       //  湿度数据小数位2

    //  fifo
    wire                wrreq               ;
    wire                rdreq               ;
    wire                empty               ;
    wire                full                ;
    wire    [7:0]       q                   ;
    wire    [7:0]       usedw               ;

    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            tem_data_r <= 0 ;
            hum_data_r <= 0 ;
        end
        else if(din_vld)begin
            // tem_data_r <= ((tem_data * 200) >> 20) - 50 ;   
            // hum_data_r <= (hum_data * 100) >> 20 ;
            tem_data_r <= (((tem_data * 2000) >> 12) - (500)); //扩大10倍
            hum_data_r <= ((hum_data * 1000) >> 12);
            // tem_data_r = ((((tem_data << 10)
            //              + (tem_data << 9)
            //              + (tem_data << 8)
            //              + (tem_data << 7)
            //              + (tem_data << 6)
            //              + (tem_data << 4)) >> 20 ) - 500) * 10 ;
            // hum_data_r = (((hum_data << 9)
            //             + (hum_data << 8)
            //             + (hum_data << 7)
            //             + (hum_data << 6)
            //             + (hum_data << 5)
            //             + (hum_data << 3)) >> 20) * 10 ;
        end
    end

    //  process_flag
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            process_flag <= 1'b0 ;
        end
        else if(din_vld)begin
            process_flag <= 1'b1 ;
        end
        else if(end_cnt_byte)begin
            process_flag <= 1'b0 ;
        end
    end

    //  cnt_byte
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            cnt_byte <= 0 ;
        end
        else if(add_cnt_byte)begin
            if(end_cnt_byte)begin
                cnt_byte <= 0 ;
            end				
            else begin	    
                cnt_byte <= cnt_byte + 1 ;
            end 		    
        end
    end             
    assign	add_cnt_byte =  process_flag;
    assign	end_cnt_byte = add_cnt_byte && (cnt_byte == 24) ;

    //  flag
    // always @(*)begin
    //     if(!rst_n)begin
    //         flag <= 1'b0 ;
    //     end
    //     else if(add_cnt_byte && (cnt_byte == 6 && tem_ten >= (tem_lim / 10)) || (cnt_byte == 18 && hum_ten >= (hum_lim / 10)))begin
    //         flag <= 1'b1 ;
    //     end
    //     else if(add_cnt_byte && (cnt_byte == 6 && tem_ten < (tem_lim / 10)) || (cnt_byte == 18 && hum_ten < (hum_lim / 10)))begin
    //         flag <= 1'b0 ;
    //     end
    // end

    //  tem_alarm
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            tem_alarm <= 1'b0 ;
        end
        else if(add_cnt_byte && tem_ten >= (tem_lim / 10))begin
            tem_alarm <= 1'b1 ;
        end
        else if(add_cnt_byte && tem_ten < (tem_lim / 10))begin
            tem_alarm <= 1'b0 ;
        end
    end

    //  hum_alarm
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            hum_alarm <= 1'b0 ;
        end
        else if(add_cnt_byte && hum_ten >= (hum_lim / 10))begin
            hum_alarm <= 1'b1 ;
        end
        else if(add_cnt_byte && hum_ten < (hum_lim / 10))begin
            hum_alarm <= 1'b0 ;
        end
    end

    //  flag
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            flag <= 1'b0 ;
        end
        else if(tem_alarm | hum_alarm)begin
            flag <= 1'b1 ;
        end
        else if(~tem_alarm & ~hum_alarm)begin
            flag <= 1'b0 ;
        end
    end

    assign tem_ten = (tem_data_r / 100 % 10 ) ;
    assign tem_bit = (tem_data_r % 100 / 10  ) ;
    assign tem_dot1 = (tem_data_r % 10  ) ;
    assign tem_dot2 = 0 ;

    assign hum_ten = (hum_data_r / 100 % 10 ) ;
    assign hum_bit = (hum_data_r % 100 / 10  ) ;
    assign hum_dot1 = (hum_data_r % 10 ) ;
    assign hum_dot2 = 0 ;

    //  data
    always @(*)begin
        case (cnt_byte)
            1 : data <= 8'hce;      //  温度ASCII码
            2 : data <= 8'hc2;
            3 : data <= 8'hb6;
            4 : data <= 8'hc8;
            5 : data <= 8'h3a;      //   :ASCII码
            6 : data <= tem_ten + 48;       //  十位
            7 : data <= tem_bit + 48;       //  个位
            8 : data <= 8'h2e;      //   .ASCII码
            9 : data <= tem_dot1 + 48;            //  小数位1
            10: data <= tem_dot2 + 48;            //  小数位2
            11: data <= 8'ha1;      //   ℃ASCII码
            12: data <= 8'he6;
            13: data <= 9;          //   tab
            14: data <= 8'hca;      //   湿度ASCII码
            15: data <= 8'haa;
            16: data <= 8'hb6;
            17: data <= 8'hc8;
            18: data <= 8'h3a;      //   :ASCII码
            19: data <= hum_ten + 48;      //  十位
            20: data <= hum_bit + 48;       //  个位
            21: data <= 8'h2e;      //   .ASCII码
            22: data <= hum_dot1 + 48;           //  小数位1
            23: data <= hum_dot2 + 48;           //  小数位2
            24: data <= 8'h25;      //   %ASCII码
            default: data <= 0 ;
        endcase
    end

    //  fifo例化
    fifo	fifo_inst (
	    .aclr   ( ~rst_n        ),
	    .clock  ( clk           ),
	    .data   ( data          ),
	    .rdreq  ( rdreq         ),
	    .wrreq  ( wrreq         ),

	    .empty  ( empty         ),
	    .full   ( full          ),
	    .q      ( q             ),
	    .usedw  ( usedw         )
	);
    assign  wrreq = ~full && process_flag && cnt_byte > 0;
    assign  rdreq = ~empty && ready ;

    //  输出
    assign tx_data = q ;
    assign tx_data_vld = rdreq ;
    assign beep = ~flag ;
    
endmodule

5. aht10设置温湿度报警值模块

//  **************************************************************
//  Author: Zhang JunYi
//  Create Date: 2022.11.15                        
//  Design Name: AHT10    
//  Module Name: set_limit         
//  Target Device: Cyclone IV E (EP4CE6F17C8), 温湿度传感器(AHT10)             
//  Tool versions: Quartus Prime 18.1             
//  Description: aht10设置温湿度报警值模块
//  **************************************************************

module set_limit (
    input           clk             ,
    input           rst_n           ,
    //  key_filter
    input           tem_add         ,       //  设置温度报警值标志,每按一次+5摄氏度
    input           hum_add         ,       //  设置湿度报警值标志,每按一次+5%
    input           set             ,       //  设置模式,每按一次在温度和湿度设置之间切换
    //  seg_driver
    output          modle           ,       //  当前设置模式  0:设置温度   1:设置湿度
    output  [7:0]   tem_lim         ,       //  温度报警值
    output  [7:0]   hum_lim                 //  湿度报警值
);

    //  信号定义

    reg     [7:0]   cnt_tem         ;
    wire            add_cnt_tem     ;
    wire            end_cnt_tem     ;

    reg     [7:0]   cnt_hum         ;
    wire            add_cnt_hum     ;
    wire            end_cnt_hum     ;

    reg             flag            ;       //  设置模式

    //  cnt_tem
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            cnt_tem <= 0 ;
        end
        else if(add_cnt_tem)begin
            if(end_cnt_tem)begin
                cnt_tem <= 0 ;
            end				
            else begin	    
                cnt_tem <= cnt_tem + 10 ;
            end 		    
        end
    end             
    assign	add_cnt_tem = tem_add ;
    assign	end_cnt_tem = add_cnt_tem && (cnt_tem == 100) ;

    //  cnt_hum
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            cnt_hum <= 0 ;
        end
        else if(add_cnt_hum)begin
            if(end_cnt_hum)begin
                cnt_hum <= 0 ;
            end				
            else begin	    
                cnt_hum <= cnt_hum + 10 ;
            end 		    
        end
    end             
    assign	add_cnt_hum = hum_add ;
    assign	end_cnt_hum = add_cnt_hum && (cnt_hum == 100) ;

    //  flag
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            flag = 1'b0 ;
        end
        else if(set)begin
            flag = ~flag ;
        end
    end

    //  输出
    assign tem_lim = cnt_tem ;
    assign hum_lim = cnt_hum ;
    assign modle = flag ;
    
endmodule

6. 参数文件

//  IIC时钟参数
`define  SCL_PERIOD  250
`define  SCL_HALF    125
`define  LOW_HALF    65 
`define  HIGH_HALF   190

//  控制命令
`define  WRITE    4'b1000     //  写
`define  READ     4'b0100     //  读
`define  STA      4'b0010     //  起始位
`define  STO      4'b0001     //  停止位

//  AHT10命令参数
`define AHT10_ADDR 7'b0111_000      //  设备地址

`define GET_STATE    8'b1110_0001     //  获取状态字

`define AHT10_INIT_0 8'b1110_0001     //  初始化命令序列
`define AHT10_INIT_1 8'b0000_1000
`define AHT10_INIT_2 8'b0000_0000

`define AHT10_MEAS_0 8'b1010_1100       //  触发测量命令序列    
`define AHT10_MEAS_1 8'b0011_0011
`define AHT10_MEAS_2 8'b0000_0000

`define AHT10_MEAS_4 8'b0111_0001     //  读数据命令


`define DELAY_40ms  2_000_000        //  上电等待40ms
`define DELAY_80ms  4_000_000        //  测量数据80ms
`define DELAY_500ms 5000_0000       //  0.5s采集一次数据

//  UART参数配置文件
`define BAUD_RATE_115200

`define CLK_FREQ 50_000_000

`ifdef BAUD_RATE_9600
    `define BAUD `CLK_FREQ / 9600
`elsif BAUD_RATE_19200
    `define BAUD `CLK_FREQ / 19200
`elsif BAUD_RATE_38400
    `define BAUD `CLK_FREQ / 38400
`elsif BAUD_RATE_57600
    `define BAUD `CLK_FREQ / 57600
`elsif BAUD_RATE_115200
    `define BAUD `CLK_FREQ / 115200
`endif 

7. 其他模块
按键消抖模块、数码管驱动模块、串口发送模块比较简单,这里不过多赘述。

七、仿真测试

由于没有AHT10的仿真模型,仿真模拟AHT10返回数据,下面只对比较重要的几个模块进行仿真测试。
仿真代码如下:

`timescale 1ns/1ps

module test_tb ();

    reg             clk         ;
    reg             rst_n       ;

    wire			sda			;
    wire			scl			;
    reg				sda_i	    ;
    top u_top(
        .clk        ( clk        ),
        .rst_n      ( rst_n      ),
        .sda        ( sda        ),
        .scl        ( scl        ),
        .uart_txd   ( uart_txd   )
    );
    assign sda = u_top.sda_out_en ? 1'bz:sda_i;

    localparam CYCLE = 20;
    always #(CYCLE/2) clk=~clk;

    reg			[ 10:0 ]			i			;
    reg			[ 10:0 ]			j			;

    initial begin
        rst_n = 1'b1;
        clk = 1'b1;
        #(CYCLE * 2);
        rst_n = 1'b0;
        #(CYCLE * 2);
        #2;
        rst_n = 1'b1;

        @(posedge u_top.u_aht10_ctrl.init2waitinit); //初始化

        for (i = 0; i<4 ; i = i+1 ) begin
            @(posedge u_top.u_aht10_ctrl.add_cnt_byte);
        end

        for (i = 0; i<9 ; i = i+1 ) begin //模拟初始化完成
            @(posedge u_top.u_i2c_interface.add_cnt_bit)
            if(i == 3)
                sda_i = 1;
            else if(i == 8)
                sda_i = 0;
        end

        repeat(5) begin
            @(posedge u_top.u_aht10_ctrl.waitmes2read);//等待控制模块到达读取状态
            @(posedge u_top.u_aht10_ctrl.add_cnt_byte);
            for (i = 0; i<6 ; i = i+1 ) begin//发送6个数据
                @(posedge u_top.u_aht10_ctrl.add_cnt_byte);
                for (j = 0; j<9 ; j = j+1 ) begin//模拟从机回数据
                    @(posedge u_top.u_i2c_interface.end_cnt_scl)
                    if(j == 8)
                        sda_i = 0;
                    else
                        sda_i = {$random};
                end
            end
        end

    $stop;
end

endmodule

仿真结果:
(1)aht10_ctrl模块
在这里插入图片描述
(2)i2c_interface模块
在这里插入图片描述
(3)data_process模块
在这里插入图片描述
(4)uart_tx模块
在这里插入图片描述

八、板级验证

终端信息打印:
在这里插入图片描述
上板之后,温湿度报警值默认是0℃和0%,需要手动设置报警界限,所以一开始上板蜂鸣器就会开始工作。通过按键设置好温湿度报警值之后就会正常工作,当温度或者湿度超过预设报警值时蜂鸣器开始工作,当温度或湿度同时低于预设报警值时,蜂鸣器停止工作。

按键操作说明:

key1:设置温湿度报警值模式,初始状态为设置温度报警值模式(数码管显示“TE 温度值”),按下key1切换为设置湿度报警值模式(数码管显示“HU 湿度值”),在两种设置模式之间切换。
key2:当处于设置温度报警值模式时(数码管显示“TE 温度值”),按下key2,温度报警值+10%,最高设置不超过90%。
key3:当处于设置湿度报警值模式时(数码管显示“HU 湿度值”),按下key3:湿度报警值+10℃,最高设置不超过90℃。
key4:复位按键。

IIC协议实现AHT10 AHT10的供电电压在1.8v~3.6v,其中推荐3.3v。 阅读详情

相关推荐

I2C应用——AHT10温湿度传感器

I2C读取AHT10温湿度数据需要结合传感器的数据手册来编写代码。 //aht10.c #include "aht10.h" #include "delay.h" #include "iic.h" /** * @brief 向ATH10写入数据 * * @param cmd 命令 * @param data 要写入的数据 * @param len 写入数据大小 * * @return u8 0,正常,其他,错误代码 */ u8 AHT10_Write_Data(u8

qq_42878057的博客 5804

【模块系列】STM32&&AHT10温湿度模块

以下是AHT10模块官网介绍原话。还有就是官网已经显示停产了,不过淘宝还是有小模块玩玩的。AHT10是一款高精度,完全校准,贴片封装的温湿度传感器,MEMS的制作工艺,确保产品具有极高的可靠性与卓越的长期稳定性。传感器包括一个电容式感湿元件和一个高性能CMOS微处理器相连接。该产品具有品质卓越、超快响应、抗干扰能力强、性价比极高等优点。AHT10 通信方式采用标准I²C通信方式,超小的体积、极低的功耗,使其成为各类应用甚至最为苛刻的应用场合的最佳选择。

m0_60313295的博客 2522

FPGA实验记录五:I2C读取AHT10温湿度传感器

VDD、GND电源引脚:AHT10的供电范围为1.8-3.6V,推荐电压为3.3V。SCL串行时钟:用于微处理器(FPGA)与AHT10之间的通讯同步。由于接口包含了完全静态逻辑,因而不存在最小SCL频率。SDA串行数据:用于传感器的数据输入和输出。当向传感器发送命令时,SDA在串行时钟SCL的上升沿有效,且当SCL为高电平之后,SDA必须保持稳定。在SCL下降沿之后,SDA值可被改变。SDA的有效时间在SCL上升沿之前的TSU和下降沿之后的TH0。......

ChenJ_1012的博客 6098

STM32 F103C8T6学习笔记13:IIC通信—AHT10温湿度传感器模块

今日学习一下这款AHT10 温湿度传感器模块,给我的OLED手环添加上测温湿度的功能。 文章提供源码、测试工程下载、测试效果图。

NULL指向我的博客 7438

Apache Doris集群IP变更急救指南:用Docker容器+priority_networks快速恢复FE/BE节点

本文详细介绍了Apache Doris集群在IP变更情况下的应急处理方案,通过Docker容器和priority_networks配置快速恢复FE/BE节点。文章提供了从容器化环境构建、元数据迁移到生产环境切换的全流程指南,帮助运维团队在30分钟内完成集群恢复,显著减少停机时间。

pink7的博客 114

quartus 13.1常见报错解决方法

在使用quartus中会遇到很多由于安装或设置不规范造成的错误。我就目前我遇到的一些错误以及我的解决方法分享给大家,这个文章将会持续更新,如果读者有遇到软件中错误无法解决的问题,也欢迎在评论区留言。 一、编译出现lience错误 在对设计的电路编译时,系统在程序运行3秒内即结束并报错,大概意思为现有的证书不支持编译。这个常见问题源自破解不成功,这里读者很有可能犯的错误是在使用破解器的时候没有区分x86(即32-bit)和x64软件破解器对应的文件夹。 如图所示有两种破解器,分别对应32位和64位的软件,大部

肥宅的博客 3万+

基于FPGA实现AHT10温湿度传感器数据采集

AHT10是一款标准I2C接口的温湿度传感器。供电范围为1.8-3.6V,推荐电压为3.3V。电源( VDD)和接地(GND)之间须连接一个 10uF的去耦电容,器件引脚接口图如下:SDA引脚用于传感器的数据输入和输出。当向传感器发送命令时,SDA在串行时钟( SCL)的上升沿有效,且当SCL为高电平时,SDA 必须保持稳定。在 SCL下降沿之后,SDA值可被改变。开发板硬件管脚配置表:DirectionNode NameLocationInputclkPIN E1Inputrst n。

2301_76461741的博客 2079

嵌入式八股文-ARM

嵌入式八股文总结(ARM篇)-优快云博客现象:I2C死锁就是时钟线SCL一直处于高电平,数据线SDA一直处于低电平。从机拉低数据线SDA时(发送应答信号给主机时或发送数据0时)主机意外复位,主机复位后时钟线SCL就为高电平了,此时,SCL为高电平而SDA为低电平,主机就以为有其他设备占有了总线,而SCL为高电平时 数据位SDA不允许有变化,意思是:主机就一直等待时钟线SDA拉高,而从机就一直等待时钟线SCL拉高 就造成了死锁的现象。解决方法:1.选择带有复位功能的从设备,复位后SDA被拉高。

m0_63127436的博客 1259

FPGA实战 -- IIC+UART --- 温湿度传感器AHT10

本文就是根据ATH10手册对传感器进行编码,让温湿度传感器通过IIC接口将采集的数据发送到FPGA芯片,并且通过串口助手接收芯片发送过来的数据,实现实时检测环境的温湿度。

2201_75683149的博客 1909

CST-Python(Pycharm如何与CST联合仿真,获取S参数)

我们想使用Python与CST联合仿真,其实是不需要自己下载Python的,因为CST在下载的时候就自带了Python3.6,我们只需要找到并将软件的环境设置到相应位置,即可联合仿真。(我的保存路径为D:\Program Files (x86)\CST Studio Suite 2020,在寻找时可以将前面切换成自己的保存路径,后面不需要修改)在CST帮助文档(打开CST软件,按F11即可直接访问帮助文档)里面,进行如下操作,便可以看到CST适配的Python版本为Python3.6!

weixin_52696285的博客 5648

Ubuntu20.04下运行LOAM系列:A-LOAM、LeGO-LOAM、SC-LeGO-LOAM、LIO-SAM 和 LVI-SAM

在我第一篇博文Ubuntu 20.04配置ORB-SLAM2和ORB-SLAM3运行环境+ROS实时运行ORB-SLAM2+Gazebo仿真运行ORB-SLAM2+各种相关库的安装的基础环境下跑通A-LOAM首先已经按照上一篇文章已经安装好了ROS noetic、Eigen3.4.0、OpenCV4.2.0和PCL1.10,A-LOAM在Github的开源地址:https://github.com/HKUST-Aerial-Robotics/A-LOAM。接下来根据代码要求,需要安装Ceres,另外环境的变

zardforever123的博客 3万+

基于FPGA温湿度采集(AHT10)

C4MB开发板、AHT10。

伊木子曦的博客 2206

22、计算智能在自闭症检测与管理中的应用

本文探讨了计算智能在自闭症谱系障碍(ASD)检测与管理中的应用。在检测方面,结合可穿戴设备、传感技术与多模态数据(如眼动追踪、问卷、神经成像等),利用机器学习和深度学习算法提升诊断准确性,并介绍了多种公开数据集及研究方法。在管理方面,通过生理指标(HRV、GSR、呼吸频率)监测情绪状态,结合智能可穿戴设备与支持性应用平台(如LetMeTalk、MITA、Rethink Ed等),实现对ASD患者的实时干预与个性化支持。文章还展示了多模态筛查与管理流程的系统架构,强调未来技术整合与个性化服务的发展方向。

star的博客 91

基于FPGA的IIC控制AHT20读取温湿度

AHT20温湿度采集模块,本文介绍了在FPGA中用IIC驱动AHT20读取温湿度数据,并将结果显示在数码管上,也能通过UART串口发送数据至PC上实时显示。

Turing_kun的博客 1448

超临界二氧化碳发电技术深度解析

超临界二氧化碳发电技术正在突破传统热电转换的物理边界。作为新一代发

硬核科技 602

52、切换线性动态系统:原理、挑战与高斯和滤波解决方案

本文介绍了切换线性动态系统(SLDS)的基本原理及其在复杂时间序列建模中的应用。SLDS结合了隐马尔可夫模型的离散状态切换与线性动态系统的连续状态演化,适用于系统动态发生跳跃的场景,如化工过程监测和金融市场分析。由于精确推理在计算上不可行,文章重点阐述了高斯和滤波这一近似方法,通过有限高斯混合来逼近后验分布,并详细描述了其递归更新、权重计算与组件合并流程。同时讨论了性能评估、优化策略及常见问题的解决方案,并展望了SLDS与深度学习、在线学习和多模态融合的未来发展方向。

algae的博客 161

FPGA驱动AHT20温湿度传感器:IIC协议实现与调试经验分享

本文详细介绍了使用FPGA驱动AHT20温湿度传感器的完整实现过程,重点解析了IIC协议的Verilog状态机设计、传感器初始化校准及数据采集计算。分享了基于逻辑分析仪的调试经验和常见问题解决方案,为嵌入式开发提供实用参考。

efc123456的博客 910

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

AHT10读取温湿度工程

AHT10读取温湿度工程 【下载地址】AHT10读取温湿度工程 本项目基于FPGA与AHT10温湿度传感器模块,构建了一套高效稳定的温湿度读取系统。通过IIC协议实现FPGA与传感器间的可靠通信,模块化设计包括IIC接口、AHT10控制、数据处理及串口收发等核心功能。系统能够实时读取并处理温湿度数据,支持串口输出,便于用...

gitblog_06772的博客 570

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

AHT10读取温湿度

由图可知我们不同状态的命令不同,需要符合起始位/写数据/读数据/停止位/校验位,对应的关系存在如下情况。(iic_interface可直接用前文IIC读写EEPROM一文的接口模块)读数据和写数据时 8bit,起始位,校验位,停止位都是 1bit。温度测量命令同理,读数据更改为 7 个字节,也就是循环 7 次。其中用到了仿真模型,完整工程可以通过。因为图片太长,分两部分截图。

weixin_67803687的博客 1211

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

使用STM32F103完成基于I2C协议的AHT20温湿度传感器的数据采集

使用STM32F103完成基于I2C协议的AHT20温湿度传感器的数据采集一、关于I2C1.什么是I2C2.I2C信号3.软件I2C与硬件I2C二、主要代码1.main.c2.AHT20芯片使用过程3.AHT20读取数据过程运行结果全部代码参考文章 一、关于I2C 1.什么是I2C 在消费电子,工业电子等领域,会使用各种类型的芯片,如微控制器,电源管理,显示驱动,传感器,存储器,转换器等,他们有着不同的功能,有时需要快速的进行数据的交互,为了使用最简单的方式使这些芯片互联互通,于是I2C诞生了,I2C(I

JMFLFZYF的博客 309

AHT10读取温湿度工程:实时监测环境变化

AHT10读取温湿度工程:实时监测环境变化 【下载地址】AHT10读取温湿度工程 本项目基于FPGA与AHT10温湿度传感器模块,构建了一套高效稳定的温湿度读取系统。通过IIC协议实现FPGA与传感器间的可靠通信,模块化设计包括IIC接口、AHT10控制、数据处理及串口收发等核心功能。系统能够实时读取并处理温湿度数据,支...

gitblog_06748的博客 568

【工程源码】基于FPGA的AHT10温湿度传感器实验

功能描述: 左边部分的数码管显示的是当前相对湿度:46.2% 右边部分的数码管显示的是当前的温度:28.6℃ AHT10模块是3.3V供电,所以接线的时候就近接在GPIO0的3.3V供电附近 具体接线方式: SCL接PIN_D3 SDA接PIN_E5 ...

zgmxs的专栏 1253

AHT10温湿度传感器I2C驱动与数据解析全流程设计

本文详细解析了AHT10温湿度传感器的I2C驱动与数据解析全流程设计,包括硬件连接、初始化流程、测量触发与数据读取、数据处理与串口输出设计等关键步骤。通过实际案例和代码示例,帮助开发者快速掌握AHT10的应用技巧,提升物联网设备的温湿度监测能力。

dechen6073的博客 397

使用Vitis iic模块在FPGA上进行DHT20/AHT20温湿度传感器数据读取

目前网上大部分DHT20/AHT20温湿度传感器的读取都是基于stm32等单片机的,本篇文章讲一讲如何借助vivado和vitis在FPGA上进行DHT20温湿度传感器数据的读取。

qq_62868689的博客 2076

从时序调试到数据稳定:FPGA与AHT20的IIC通信可靠性设计实战

本文详细探讨了FPGA与AHT20温湿度模块通过IIC协议实现高可靠性通信的设计实战。重点分析了IIC协议底层时序调试、AHT20传感器初始化异常处理及状态机优化策略,提供了基于Verilog的可靠驱动方案,有效解决工业应用中数据稳定性问题。

mac99的博客 987

基于verilog驱动ATH10温湿度传感器

基于verilog驱动AHT10温湿度传感器

qq_59532413的博客 901
上一篇: 【FPGA】FPGA实现SPI协议读写FLASH(一)----- M25P16操作概述
下一篇: 【FPGA】FPGA实现SPI协议读写FLASH(二)----- SPI接口驱动模块设计
白码王子小张
博客等级 码龄7年 6665粉丝 121原创
评论 15
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值