AHT10读取温湿度
一.理论原理I2C 接口模块实现读写数据的流程将 done 信号读写一次完成信号作为输出。AHT10 控制模块例化 I2C 接口模块将 done 信号作为条件使用在对应的状态输入对应的命令最终得到一个传感器温度转换得来的 40 位位宽的数据。将 40 位位宽的数据作为输入传输给数据处理模块在此模块中将 40 位位宽的数据转换为温湿度分开的两个 20 位位宽的数据并将二进制转换为 BCD 码再将 BCD 码转换为 ASCII 码。将转换完成的 8bit 数据作为输入传输给串口 TX 模块最终输出到 PC 端上显示出温湿度情况。二.手册分析2.1命令及读取流程2.2器件地址2.3读写数据格式2.4数据转换2.5测量周期2.6考察校准三.设计3.1总体框图设计3.2状态转移图3.2.1 iic_interface3.2.2 aht10_ctrl3.3时序图3.3.1 iic_interface3.3.2 aht10_ctrl因为图片太长分两部分截图四.代码4.1 aht10_ctrl.v(iic_interface可直接用前文IIC读写EEPROM一文的接口模块)/**************************************功能介绍*********************************** Date : Author : Alegg xy. Version : Description: *********************************************************************************/ //---------模块及端口声名------------------------------------------------------ module aht10_ctrl ( input clk , input rst_n , input [6:0] device_id, output [39:0] data , output data_vld, output ready , output scl , inout sda ); //---------参数定义--------------------------------------------------------- //接口模块控制命令 define START_BIT 5b00001 define WRITE_BIT 5b00010 define READ_BIT 5b00100 define STOP_BIT 5b01000 define ACK_BIT 5b10000 //状态机参数定义 localparam IDLE b0000000001, INIT_REQ b0000000010, INIT b0000000100, WAIT b0000001000, RD_REQ b0000010000, RD b0000100000, DELAY b0001000000, READ_REQ b0010000000, READ b0100000000, DONE b1000000000; localparam AHT10_WRIGHT 8b0111_0000;// 写数据命令 localparam AHT10_READ 8b0111_0001;// 读数据命令 localparam AHT10_INIT_0 8hE1;// 初始化命令序列 localparam AHT10_INIT_1 8h08; localparam AHT10_INIT_2 8h00; localparam AHT10_MEAS_0 8hAC;// 触发测量命令序列 localparam AHT10_MEAS_1 8h33; localparam AHT10_MEAS_2 8h00; parameter MAX_40MS d200_000, MAX_80MS d400_000, MAX_2S d100_000_000; //---------内部信号定义----------------------------------------------------- reg [9:0] cstate ;//现态 reg [9:0] nstate ;//次态 wire IDLE_INIT_REQ ; wire INIT_REQ_INIT ; wire INIT_INIT_REQ ; wire INIT_WAIT ; wire WAIT_RD_REQ ; wire RD_REQ_RD ; wire RD_RD_REQ ; wire RD_DELAY ; wire DELAY_READ_REQ ; wire READ_REQ_READ ; wire READ_READ_REQ ; wire READ_DONE ; wire DONE_WAIT ; //例化接口模块信号 wire done ; reg [4:0] cmd ; reg cmd_vld ; reg [7:0] op_wr_data ; //延时计数器 reg [27:0] cnt_delay ; wire add_cnt_delay ; wire end_cnt_delay ; //字节计数器 reg [3:0] cnt_byte ; wire add_cnt_byte ; wire end_cnt_byte ; reg [27:0] MAX ;//计时最大值 reg [3:0] cmd_num ; //数据处理 wire [7:0] rd_data; reg [47:0] rd_data_r; wire rd_data_vld; //延时计数器 always (posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_delay d0; end else if(add_cnt_delay)begin if(end_cnt_delay)begin cnt_delay d0; end else begin cnt_delay cnt_delay 1d1; end end end assign add_cnt_delay (cstate IDLE) || (cstate DONE) || (cstate DELAY); assign end_cnt_delay add_cnt_delay cnt_delay MAX - 1d1; //考察MAX情况 always (posedge clk or negedge rst_n) begin if (!rst_n) begin MAX MAX_40MS; end else if (cstate IDLE) begin MAX MAX_40MS;//上电延时40ms end else if (cstate DELAY) begin MAX MAX_80MS;//测量延时80ms end else if (cstate DONE) begin MAX MAX_2S; end end //字节计数器 always (posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_byte d0; end else if(add_cnt_byte)begin if(end_cnt_byte)begin cnt_byte d0; end else begin cnt_byte cnt_byte 1d1; end end end assign add_cnt_byte done; assign end_cnt_byte add_cnt_byte cnt_byte cmd_num - 1; //考察cmd_num always (posedge clk or negedge rst_n) begin if (!rst_n) begin cmd_num 0; end else if (cstate INIT) begin cmd_num 4; end else if (cstate RD) begin cmd_num 4; end else if (cstate READ) begin cmd_num 7; end end //第一段时序逻辑描述状态转移 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 (IDLE_INIT_REQ) begin nstate INIT_REQ; end else begin nstate cstate; end end INIT_REQ :begin if (INIT_REQ_INIT) begin nstate INIT; end else begin nstate cstate; end end INIT :begin if (INIT_WAIT) begin nstate WAIT; end else if (INIT_INIT_REQ) begin nstate INIT_REQ; end else begin nstate cstate; end end WAIT :begin if (WAIT_RD_REQ) begin nstate RD_REQ; end else begin nstate cstate; end end RD_REQ :begin if (RD_REQ_RD) begin nstate RD; end else begin nstate cstate; end end RD :begin if (RD_DELAY) begin nstate DELAY; end else if (RD_RD_REQ) begin nstate RD_REQ; end else begin nstate cstate; end end DELAY :begin if (DELAY_READ_REQ) begin nstate READ_REQ; end else begin nstate cstate; end end READ_REQ :begin if (READ_REQ_READ) begin nstate READ; end else begin nstate cstate; end end READ :begin if (READ_DONE) begin nstate DONE; end else if (READ_READ_REQ) begin nstate READ_REQ; end else begin nstate cstate; end end DONE :begin if (DONE_WAIT) begin nstate WAIT; end else begin nstate cstate; end end default :; endcase end assign IDLE_INIT_REQ (cstate IDLE) end_cnt_delay; assign INIT_REQ_INIT (cstate INIT_REQ) 1b1 ; assign INIT_INIT_REQ (cstate INIT) done ; assign INIT_WAIT (cstate INIT) end_cnt_byte ; assign WAIT_RD_REQ (cstate WAIT) 1b1 ; assign RD_REQ_RD (cstate RD_REQ) 1b1 ; assign RD_RD_REQ (cstate RD) done ; assign RD_DELAY (cstate RD) end_cnt_byte ; assign DELAY_READ_REQ (cstate DELAY) end_cnt_delay; assign READ_REQ_READ (cstate READ_REQ) 1b1 ; assign READ_READ_REQ (cstate READ) done ; assign READ_DONE (cstate READ) end_cnt_byte ; assign DONE_WAIT (cstate DONE) end_cnt_delay; //发送指令 always (posedge clk or negedge rst_n) begin if (!rst_n) begin TX(0,0,0); end else begin case (cstate) INIT_REQ:begin//发送0xE1 case (cnt_byte) 0:TX(1,(START_BIT | WRITE_BIT),AHT10_WRIGHT); 1:TX(1,(WRITE_BIT),AHT10_INIT_0); 2:TX(1,(WRITE_BIT),AHT10_INIT_1); 3:TX(1,(WRITE_BIT | STOP_BIT),AHT10_INIT_2); default: TX(0,cmd,op_wr_data); endcase end RD_REQ:begin//发送0xAC case (cnt_byte) 0:TX(1,{WRITE_BIT | START_BIT},AHT10_WRIGHT); 1:TX(1,{WRITE_BIT},AHT10_MEAS_0); 2:TX(1,{WRITE_BIT},AHT10_MEAS_1); 3:TX(1,{WRITE_BIT | STOP_BIT},AHT10_MEAS_2); default: TX(0,cmd,op_wr_data); endcase end READ_REQ:begin//接受数据 case (cnt_byte) 0:TX(1,{WRITE_BIT | START_BIT},AHT10_READ); 1:TX(1,{READ_BIT},8h00); 2:TX(1,{READ_BIT},8h00); 3:TX(1,{READ_BIT},8h00); 4:TX(1,{READ_BIT},8h00); 5:TX(1,{READ_BIT},8h00); 6:TX(1,{READ_BIT | ACK_BIT | STOP_BIT},8h00); default: TX(0,cmd,op_wr_data); endcase end default: TX(0,cmd,op_wr_data); endcase end end //数据处理 always (posedge clk or negedge rst_n) begin if (!rst_n) begin rd_data_r d0; end else if (rd_data_vld) begin rd_data_r {rd_data_r[39:0],rd_data}; end end //接口模块例化 i2c_interface u_i2c_interface( .clk (clk), .rst_n (rst_n), .cmd (cmd), .cmd_vld (cmd_vld), .done (done), .wr_data (op_wr_data), .rd_data (rd_data), .rd_data_vld(rd_data_vld), .scl (scl), .sda (sda) ); task TX; input task_cmd_vld; input [4:0] task_cmd; input [7:0] task_wr_data; begin cmd_vld task_cmd_vld; cmd task_cmd; op_wr_data task_wr_data; end endtask assign data rd_data_r[39:0]; assign data_vld READ_DONE; assign ready cstate WAIT; endmodule4.2 data_process(数据处理模块)/**************************************功能介绍*********************************** Date : Author : Alegg xy. Version : Description: *********************************************************************************/ //---------模块及端口声名------------------------------------------------------ module data_process( input clk , input rst_n , input [39:0] data , input data_vld, input ready , output [7:0] tx_data , output tx_data_vld ); //---------参数定义--------------------------------------------------------- //状态机参数定义 localparam IDLE b01,// DATA b10;// reg [19:0] data_hum;//湿度数据 reg [19:0] data_temp;//温度数据 reg [40:0] data_hum_r; reg [40:0] data_temp_r; wire [7:0] data_hum_w0; wire [7:0] data_hum_w1; wire [7:0] data_hum_w2; wire [7:0] data_temp_w0; wire [7:0] data_temp_w1; wire [7:0] data_temp_w2; reg data_vld_0; reg data_vld_1; reg [1:0] cstate ;//现态 reg [1:0] nstate ;//次态 wire IDLE_DATA ; wire DATA_IDLE ; reg [4:0] cnt_byte ; wire add_cnt_byte ; wire end_cnt_byte ; reg [7:0] num ; //---------内部信号定义----------------------------------------------------- //数据有效信号打拍 always (posedge clk or negedge rst_n) begin if (!rst_n) begin data_vld_0 0; data_vld_1 0; end else begin data_vld_0 data_vld; data_vld_1 data_vld_0; end end //数据寄存 always (posedge clk or negedge rst_n) begin if (!rst_n) begin data_hum 0; data_temp 0; end else if (data_vld) begin data_hum data[39:20]; data_temp data[19:0]; end else begin data_hum data_hum; data_temp data_temp; end end //二进制转BCD always (posedge clk or negedge rst_n) begin if (!rst_n) begin data_hum_r 12d123; end else if (data_vld_1) begin data_hum_r ((data_hum*10000)20); end end always (posedge clk or negedge rst_n) begin if (!rst_n) begin data_temp_r 12d123; end else if (data_vld_1) begin data_temp_r (((data_temp*20000)20)-5000); end end //每一位数据 assign data_hum_w0 (data_hum_r/1000)%10; assign data_hum_w1 (data_hum_r/100)%10; assign data_hum_w2 (data_hum_r/10)%10; assign data_temp_w0 (data_temp_r/1000)%10; assign data_temp_w1 (data_temp_r/100)%10; assign data_temp_w2 (data_temp_r/10)%10; //byte计数器 always (posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_byte 4d0; end else if(add_cnt_byte)begin if(end_cnt_byte)begin cnt_byte 4d0; end else begin cnt_byte cnt_byte 1b1; end end end assign add_cnt_byte (cstate DATA) ready; assign end_cnt_byte add_cnt_byte cnt_byte 18; //第一段时序逻辑描述状态转移 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 (IDLE_DATA) begin nstate DATA; end else begin nstate cstate; end end DATA:begin if (DATA_IDLE) begin nstate IDLE; end else begin nstate cstate; end end default : nstate IDLE; endcase end assign IDLE_DATA (cstate IDLE) ready data_vld; assign DATA_IDLE (cstate DATA) end_cnt_byte; //BCD转ASCII码 always (*) begin if (cstate DATA) begin case (cnt_byte) 0: num 8hCE; 1: num 8hC2; 2: num 8hB6; 3: num 8hC8; 4: num :; 5: num data_temp_w0 0; 6: num data_temp_w1 0; 7: num .; 8: num data_temp_w2 0; 9: num 8hCA; 10: num 8hAA; 11: num 8hB6; 12: num 8hC8; 13: num :; 14: num data_hum_w0 0; 15: num data_hum_w1 0; 16: num .; 17: num data_hum_w2 0; 18: num 8h0a; default: num 0; endcase end end assign tx_data num; assign tx_data_vld add_cnt_byte; endmodule五.仿真5.1仿真代码timescale 1ns/1ns module tb_top(); //激励信号定义 reg tb_clk ; reg tb_rst_n ; //输出信号定义 wire tx ; wire scl ; wire sda ; pullup(sda); //时钟周期参数定义 parameter CLOCK_CYCLE 20; defparam u_top.u_aht10_ctrl.MAX_40MS 20, u_top.u_aht10_ctrl.MAX_80MS 40, u_top.u_aht10_ctrl.MAX_2S 1000; //模块例化 top u_top( .clk (tb_clk ), .rst_n (tb_rst_n ), .tx (tx), .scl (scl), .sda (sda) ); i2c_slave_model u_i2c_slave_model( .scl(scl), .sda(sda) ); //产生时钟 initial tb_clk 1b0; always #(CLOCK_CYCLE/2) tb_clk ~tb_clk; //产生激励 initial begin tb_rst_n 1b1; #(CLOCK_CYCLE*2); tb_rst_n 1b0; #(CLOCK_CYCLE*20); tb_rst_n 1b1; #5000000; $stop; end endmodule其中用到了仿真模型完整工程可以通过https://download.csdn.net/download/weixin_67803687/88384435获取5.2仿真效果5.2.1 scl sda关系5.2.2 不同状态计bit数不同读数据和写数据时 8bit起始位校验位停止位都是 1bit5.2.3 不同状态命令值不同由图可知我们不同状态的命令不同需要符合起始位/写数据/读数据/停止位/校验位对应的关系存在如下情况5.2.4 初始化指令 温度测量指令5.2.5 aht10_ctrl模块初始化命令状态循环温度测量命令同理读数据更改为 7 个字节也就是循环 7 次5.2.6 计数器复用六.效果