IIC协议实现AHT10

一.芯片介绍

1.物理层

接口
在这里插入图片描述
AHT10的供电电压在1.8v~3.6v,其中推荐3.3v

2.协议层

AHT10是一个标准的IIC协议,其具体的时序如下:
在这里插入图片描述
在SCL为高电平时,SDA由高电平跳变到低电平,标志着一次数据的传输开始,SDA传输数据时必须在SCL低电平才可以跳变,SCL在高电平时SDA必须保持稳定,当1byte数据传输完成后,会有一个响应位。在SCL高电平时,如果SDA为低电平则表示响应有效,否则则是无响应,最后在SCL高电平时SDA从低电平跳转到高电平标志一次数据发送完成。
在这里插入图片描述
适配的时钟频率为:100KHZ 和400KHZ

二.AHT10测量步骤

1.命令集

在这里插入图片描述

2.读取流程(手册给出最好2s测量一次)

状态位说明
在这里插入图片描述
1.启动传感器:给传感器上电,上电后需要传感器最多需要20ms(此时SCL为高电平)来达到空闲状态
2.启动和停止时序满足IIC协议,开始SCL在高电平时检测到SDA下降沿表示数据发送开始,结束SCL高电平时检测到SDA上升沿表示结束
3.发送命令:通过发送8bit数据来传输命令读取数据:0X71
4.传感器读取流程(在此做了简化,省略了一些步骤)
首先上电后要等待40ms,然后发送0XE1来初始化(此命令有两个字节:0x08和0x00),之后直接发送0xAC命令(此命令有两个字节:0x33,0x00)来触发测量,等待75ms(我这里等待了80ms)等待测量完成,之后发送0x71读取温湿度
在这里插入图片描述
在这里插入图片描述
读取后传输的数据一共有6byte,其中第一个字节为传感器的状态,后2.5个字节为湿度数据,最后2.5个字节为温度数据

3.数据处理

在这里插入图片描述
但是由于FPGA芯片不能处理小数,所以可以将RH和T都先扩大10000倍在处理来达到最后得到整数和小数数据。

三.代码设计

1.端口列表

AHT10(IIC)控制模块

module aht20_iic_control( 
    input   wire                clk         ,
    input   wire                rst_n       ,
    //数据接口
    output  wire    [39:0]      temp_data     ,//得到的40位数据(温度数据,湿度数据)
    output  wire                temp_data_vld ,//数据有效信号
    output  wire                ready       ,

    //iic接口
    output  wire                iic_scl     ,//IIC时钟线
    inout   wire                iic_sda      //IIC数据总线
);

AHT10(IIC)驱动模块

module iic_dirver#
(
    parameter T = "100k",
              SYSTEM_CLOCK = 50_000_000
)
( 
    input   wire                clk     ,
    input   wire                rst_n   ,

    //控制接口
    input   wire    [4:0]       cmd     ,//命令指令
    input   wire                cmd_vld ,//命令有效信号
    output  wire                done    ,//命令传输完成

    //数据接口
    input   wire    [7:0]       wr_data ,//写入的数据
    output  wire    [7:0]       rd_data ,//读取的数据
    output  wire                rd_data_vld,//读取数据有效信号

    output  wire                iic_scl ,//iic时钟
    inout   wire                iic_sda  //iic数据总线
);

其中:
cmd:命令信号用来控制iic驱动模块向从机发送指令的流程
Done:用来表示这一次指令发送完毕

module tx_ctrl( 
    input   wire                clk     ,
    input   wire                rst_n   ,
    input   wire    [39:0]      temp_data,//读取到的40位数据包括温度和湿度
    input   wire                temp_data_vld,//数据有效信号
    input   wire                ready   ,//tx空闲信号
    output  wire    [7:0]       tx_data ,//发送数据
    output  wire                tx_data_vld//发送数据有效信号
);

其中:
temp_data:为从AHT10中读取的除第一个字节以外的剩下的五个字节数据
Ready:为tx模块发送的,表示自己在空闲状态可以发送数据的信号
TX模块

module uart_tx#
(
    parameter   BPS = 115200,
    parameter   CLK_FRE = 50_000_000,
    parameter   CHECK_BIT = "NONE"//NONE 不校验 DDO奇数 EVEN偶数

)
( 
    input   wire                        clk     ,
    input   wire                        rst_n   ,
    input   wire                        tx_data_vld,//数据发送标志
    input   wire    [7:0]               tx_data  ,//发送数据
    output  reg                         tx       , 
    output  wire                        ready       //准备好发送
);

2.状态转移图

控制模块:
在这里插入图片描述

IDLE:这是一个上电等待状态,上电后等待40ms跳转
RST_REQ:这是一个复位请求发送状态
RST_WAIT_DONE:这是一个等待复位命令发送完成的状态,当4byte数据发送完成后跳转到WAIT状态,否则跳转到RST_REQ
WAIT:这是一个等待的空闲状态,什么也不用做
SUR_REQ:这是一个温度测量请求发送状态
SUR_WAIT_DONE:这是一个温度测量请求发送等待完成状态,当4byte数据发送完成后,跳转到DELAY状态,否则跳转到SUR_REQ状态
DEALY:这是一个等待延时状态,再此状态等待80ms
READ_REQ:这是一个读取温度请求状态
READ_WAIT_DONE:这是一个读取温度请求等待发送完成状态,当7byte数据发送完成后跳转到DONE状态否则跳转到READ_REQ状态
DONE:这是一个完成状态,表示一个测量循环完成,再此状态延迟2s后跳转到WAIT状态

驱动模块:
在这里插入图片描述

IDEL:空闲状态,等待指令
START:开始状态,表示开始数据写/读
WRITE: 向从机写状态
R_ACK:等待接收从状态机响应(这里等待1bit时间)
READ:从从状态机读数据状态
S_ACK:向从状态机发送响应信号状态
STOP:发送停止信号状态

3.代码实现

控制模块

/**************************************功能介绍***********************************
Date	: 
Author	: WZY.
Version	: 
Description: 
器件流程:首先上电后需要40ms的时间启动(在这20s内scl必须保持高电平),之后主机向从机发送初始化指令,发送结束后
发送检测温度指令,之后等待80ms的时间等待温度测量完成,紧接着发送温度读取指令,之后等待2s(推荐2s检测一次温度)返
回发送温度检测指令,以此循环往复。
*********************************************************************************/
    
//---------<模块及端口声名>------------------------------------------------------
module aht20_iic_control( 
    input 	wire				clk		    ,
    input 	wire				rst_n	    ,
    //数据接口
    output  wire    [39:0]      temp_data     ,//得到的40位数据(温度数据,湿度数据)
    output  wire                temp_data_vld ,//数据有效信号
    output  wire                ready       ,

    //iic接口
    output  wire                iic_scl     ,//IIC时钟线
    inout   wire                iic_sda      //IIC数据总线
);								 
//---------<参数定义>--------------------------------------------------------- 
//状态机参数定义
localparam  IDLE            = 10'b0000000001,//
            RST_REQ         = 10'b0000000010,//
            RST_WAIT_DONE   = 10'b0000000100,//
            WAIT            = 10'b0000001000,//
            SUR_REQ         = 10'b0000010000,//
            SUR_WAIT_DONE   = 10'b0000100000,//
            READ_REQ        = 10'b0001000000,//
            READ_WAIT_DONE  = 10'b0010000000,//
            DELAY           = 10'b0100000000,
            DONE            = 10'b1000000000;//

parameter   MAX_80MS        = 22'd3_999_999,
            MAX_40MS        = 21'd1_999_999,
            MAX_2S          = 28'd99_999_999;

parameter   WR_CTRL_BIT     = 8'b01110000,
            RD_CTRL_BIT     = 8'b01110001;

`define     START_BIT  5'b00001
`define     WRITE_BIT  5'b00010
`define     READ_BIT   5'b00100
`define     STOP_BIT   5'b01000
`define     ACK_BIT    5'b10000
//---------<内部信号定义>-----------------------------------------------------
reg 	[9:0]	cstate     ;//现态
reg	    [9:0]	nstate     ;//次态

wire            idle2rst_req            ;
wire            rst_req2rst_wait_done   ;
wire            rst_wait_done2wait      ;
wire            rst_wait_done2rst_req   ;
wire            wait2sur_req            ;
wire            wait2read_req           ;
wire            sur_req2sur_wait_done   ;
wire            sur_wait_done2delay     ;
wire            sur_wait_done2sur_req   ;
wire            read_req2read_wait_done ;
wire            read_wait_done2done     ;
wire            read_wait_done2read_req ;
wire            delay2read_req          ;
wire            done2wait               ;    

//模块例化
wire            done        ;
reg    [4:0]    cmd         ;
reg             cmd_vld     ;
reg    [7:0]    op_wr_data  ;

//命令计数器参数
reg         [3:0]    cmd_num        ;

reg			[3:0]	cnt_cmd	   	;
wire				add_cnt_cmd	;
wire				end_cnt_cmd	;

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

reg			[20:0]	cnt_delay_40ms	   	;
wire				add_cnt_delay_40ms	;
wire				end_cnt_delay_40ms	;

reg			[27:0]	cnt_delay_2s	   	;
wire				add_cnt_delay_2s	;
wire				end_cnt_delay_2s	;

//****************************************************************
//                      状态机
//****************************************************************

//第一段:时序逻辑描述状态转移
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        cstate <= IDLE;
    end 
    else begin 
        cstate <= nstate;
    end 
end

//第二段:组合逻辑描述状态转移规律和状态转移条件
always @(*) begin
    case(cstate)
        IDLE           : begin
                            if (idle2rst_req) begin
                                nstate = RST_REQ;
                            end
                            else begin
                                nstate = cstate;
                            end
                        end
        RST_REQ        : begin
                            if (rst_req2rst_wait_done) begin
                                nstate = RST_WAIT_DONE;
                            end
                            else begin
                                nstate = cstate;
                            end
                        end
        RST_WAIT_DONE  : begin
                            if (rst_wait_done2wait) begin
                                nstate = WAIT;
                            end
                            else if (rst_wait_done2rst_req) begin
                                nstate = RST_REQ;
                            end
                            else begin
                                nstate = cstate;
                            end
                        end
        WAIT           : begin
                            if (wait2sur_req) begin
                                nstate = SUR_REQ;
                            end
                            else begin
                                nstate = cstate;
                            end
                        end
        SUR_REQ        : begin
                            if (sur_req2sur_wait_done) begin
                                nstate = SUR_WAIT_DONE;
                            end
                            else begin
                                nstate = cstate;
                            end
                        end
        SUR_WAIT_DONE  : begin
                            if (sur_wait_done2delay) begin
                                nstate = DELAY;
                            end
                            else if (sur_wait_done2sur_req) begin
                                nstate = SUR_REQ;
                            end
                            else begin
                                nstate = cstate;
                            end
                        end
        READ_REQ       : begin
                            if (read_req2read_wait_done) begin
                                nstate = READ_WAIT_DONE;
                            end
                            else begin
                                nstate = cstate;
                            end
                        end
        READ_WAIT_DONE : begin
                            if (read_wait_done2done) begin
                                nstate = DONE;
                            end
                            else if (read_wait_done2read_req) begin
                                nstate = READ_REQ;
                            end
                            else begin
                                nstate = cstate;
                            end
                        end
        DELAY          : begin
                            if (delay2read_req) begin
                                nstate = READ_REQ;
                            end
                            else begin
                                nstate = cstate;
                            end
                        end
        DONE           : begin
                            if (done2wait) begin
                                nstate = WAIT;
                            end
                            else begin
                                nstate = cstate;
                            end
                        end
        default : ;
    endcase
end
            
//第三段:描述输出,时序逻辑或组合逻辑皆可
assign  idle2rst_req             = cstate == IDLE           && end_cnt_delay_40ms;//上电后延迟40ms     
assign  rst_req2rst_wait_done    = cstate == RST_REQ        && 1; 
assign  rst_wait_done2wait       = cstate == RST_WAIT_DONE  && end_cnt_cmd;//指令发送完成            
assign  rst_wait_done2rst_req    = cstate == RST_WAIT_DONE  && done;//子模块1byte命令发送完成
assign  wait2sur_req             = cstate == WAIT           && 1; 
assign  sur_req2sur_wait_done    = cstate == SUR_REQ        && 1; 
assign  sur_wait_done2delay      = cstate == SUR_WAIT_DONE  && end_cnt_cmd;//指令发送完成
assign  sur_wait_done2sur_req    = cstate == SUR_WAIT_DONE  && done;//子模块1byte命令发送完成
assign  read_req2read_wait_done  = cstate == READ_REQ       && 1; 
assign  read_wait_done2done      = cstate == READ_WAIT_DONE && end_cnt_cmd;//指令发送完成
assign  read_wait_done2read_req  = cstate == READ_WAIT_DONE && done ;//子模块1byte命令发送完成
assign  delay2read_req           = cstate == DELAY          && end_cnt_delay;//等待80ms
assign  done2wait                = cstate == DONE           && end_cnt_delay_2s; //等待2s

//****************************************************************
//                      指令计数器
//****************************************************************
always @(posedge clk or negedge rst_n)begin 
   if(!rst_n)begin
        cnt_cmd <= 3'd0;
    end 
    else if(add_cnt_cmd)begin 
        if(end_cnt_cmd)begin 
            cnt_cmd <= 3'd0;
        end
        else begin 
            cnt_cmd <= cnt_cmd + 1'b1;
        end 
    end
end 

assign add_cnt_cmd = done;
assign end_cnt_cmd = add_cnt_cmd && cnt_cmd == cmd_num - 1;

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        cmd_num <= 0;
    end
    else if (idle2rst_req) begin
        cmd_num <= 4;
    end
    else if (wait2sur_req) begin
        cmd_num <= 4;
    end
    else if (delay2read_req) begin
        cmd_num <= 7;
    end
end

//****************************************************************
//                  延时计数器
//****************************************************************
always @(posedge clk or negedge rst_n)begin 
   if(!rst_n)begin
        cnt_delay <= 22'd0;
    end 
    else if(add_cnt_delay)begin 
        if(end_cnt_delay)begin 
            cnt_delay <= 22'd0;
        end
        else begin 
            cnt_delay <= cnt_delay + 1'b1;
        end 
    end
end 

assign add_cnt_delay = cstate == DELAY;
assign end_cnt_delay = add_cnt_delay && cnt_delay == MAX_80MS;

//****************************************************************
//                  延时计数器
//****************************************************************
always @(posedge clk or negedge rst_n)begin 
   if(!rst_n)begin
        cnt_delay_40ms <= 22'd0;
    end 
    else if(add_cnt_delay_40ms)begin 
        if(end_cnt_delay_40ms)begin 
            cnt_delay_40ms <= 22'd0;
        end
        else begin 
            cnt_delay_40ms <= cnt_delay_40ms + 1'b1;
        end 
    end
end 

assign add_cnt_delay_40ms = cstate == IDLE;
assign end_cnt_delay_40ms = add_cnt_delay_40ms && cnt_delay_40ms == MAX_40MS;

//****************************************************************
//                  延时计数器
//****************************************************************
always @(posedge clk or negedge rst_n)begin 
   if(!rst_n)begin
        cnt_delay_2s <= 22'd0;
    end 
    else if(add_cnt_delay_2s)begin 
        if(end_cnt_delay_2s)begin 
            cnt_delay_2s <= 22'd0;
        end
        else begin 
            cnt_delay_2s <= cnt_delay_2s + 1'b1;
        end 
    end
end 

assign add_cnt_delay_2s = cstate == DONE;
assign end_cnt_delay_2s = add_cnt_delay_2s && cnt_delay_2s == MAX_2S;

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值