当前位置: 首页 > news >正文

专门做汽车配件保养的网站株洲的网站建设

专门做汽车配件保养的网站,株洲的网站建设,安平县哪里做网站,企业网站的建立与维护论文一.阅读官方手册 手册在下方网址下载#xff0c;该模块在各个网店平台均有销售 百度网盘 请输入提取码 手册重点关注IIC地址#xff08;读地址0x71#xff0c;写地址0x70#xff09;、IIC命令和读写数据逻辑#xff0c;手册写的比较简单#xff08;感觉很多细节没到位…一.阅读官方手册 手册在下方网址下载该模块在各个网店平台均有销售 百度网盘 请输入提取码 手册重点关注IIC地址读地址0x71写地址0x70、IIC命令和读写数据逻辑手册写的比较简单感觉很多细节没到位可以自己去看看 二.设计模块思路分层次设计 1.上层模块控制aht20_control.v 我在一开始的时候模块分为3个功能IDLE(复位和刚上电时状态)、初始化、读取数据实际上后面发现这样划分存在一些问题 我一开始根据手册是这样划分功能的 IDLE上电和复位时各个引脚和寄存器应该配的值 延时40ms手册上提到该模块上电后要等待20ms才会进入空闲态我们这里等待40ms更加稳定 初始化发送初始化命令查看使能校准位是否为1为1后我们再进入读取状态 读取此时发送读取数据指令和读数据在这里循环 在实际实现中我发现了几个问题 1.首先是使能校验位的问题在没有正确初始化的时候使能校验位仍然显示正常即Bit[3]1; 发现这个问题的原因在下表中的记录的状态寄存器值 0001_1000刚上电时读取值可以看到此时Bit[3]1虽然说明已校准但我在发送读取指令的时候是发送不过去的读取到的数据全为0 1101_0111发送初始化命令后马上读状态寄存器 Bit[3]0 推测是初始化进行中需等待 0001_1000发送初始化命令后隔一会读状态寄存器Bit[3]1说明已校准 通过上面的记录我们可以发现查看状态寄存器如果显示校准但不一定能读取指令 那我们如何判断初始化是否正常呢 我发现初始化失败的通信往往主机在发送iic时在发送数据结束时收到的ack为1即iic发送消息从机未应答未拉低sda我们可以通过判断在iic的一次发送中ack是否恒为低电平如果ack采集到高电平那么证明发送失败那我们需要重新发送初始化命令 2.每次发送完采集数据指令后需重新初始化 在初始化后我发现我指令只能发送一次完整的采集指令重复发送采集指令ack会被置1即iic通信失败经过尝试我选择了重复初始化采集的步骤PS后面做实验的时候又可以重复发送采集指令了怀疑是当时时间没配好 最后实现的时序框图如下 2.底层IIC通信的实现iic.v  、cmd.v 设计思路对于IIC通信我们外部需要配置和得到的有指令和地址读取的数据个数写数据个数 可以将其写成这两种情况 1.写发送写地址传入写数据 2.读发送写地址发送要读的寄存器地址发送读地址读数据 我们分两层模块实现cmd模块查看IIC进行到哪一步然后切换指令和读数据iic模块将指令转化为SDA的高低电平或者读取SDA高低电平存放在一个字节中改变SCL判断从机是否响应 下图实现了一个简单的iic控制逻辑start置1后启动一次iicstart使用完后记得置0iic发送的内容是根据此时select选择的功能实现例如我设置select0时初始化AHT20select1时查看状态寄存器select2时发送指令采集温湿度select3时获取温湿度数据 实际上层不止start、select两个信号图中省略了例如cmd模块需要在读取完成时传回读取到的数据也可以添加iic是否通信失败的信号通信失败传一个error信号上层就可以根据error信号来进行重传操作等 3.串口通信将数据发送至电脑端 分为了串口发送模块和串口控制模块串口发送模块的代码在网上很多自己实现也比较简单串口控制是数据按照我指定的格式发送例如WET:63.5%TEM:34.0/n实现起来也比较简单可以查看我的代码部分学习 三.Verilog代码设计 1.模块控制aht20_control.v 功能代码采用了三段式状态机同时在状态机里面加了一些时序的处理iic启动的逻辑串口发送启动的逻辑同时对接收到的原始数据进行了处理得到处理后的温湿度数据 //负责控制时序 module aht20_control (input sys_clk ,input rst_n ,input [7:0] read_data,input iic_done ,input done_recv,input ack,output reg iic_start,output reg [1:0] select ,output reg [15:0] temper ,output reg [15:0] wet ,output reg start_send ,output [3:0] led ); parameter CNT_TIMER49_999_999;//1s测一次温湿度parameter CNT_40MS 1_999_999;//40msparameter CNT_10MS 499_999;//10MSreg [27:0] cnt_time;//1s计时器reg [24:0] cnt_40ms;//40ms计时器reg [22:0] cnt_10ms;//40ms计时器reg ack_reg;reg ack_reg1;reg [4:0] cnt_recv;//查看接收到第几位reg [19:0] temper_reg;//温度值reg [19:0] wet_reg;//湿度值reg done_recv_reg;always (posedge sys_clk) begindone_recv_regdone_recv;endreg [3:0] cur_state,next_state;assign ledcur_state[3:0];parameter IDLE 4b0000,WAIT_40MS 4b0001,//等待40msINIT 4b0011,//初始化WAIT_10MS 4b0010,//初始化后等待10MS同时查看INIT命令ACK是否常为0CAPTURE 4b0110,//发送采集命令WAIT_500MS 4b0111,//等待500msGET_DATA 4b0101,//得到数据WAIT_1S 4b0100;//等到1s重复上面步骤always (posedge sys_clk) beginif(!rst_n)cur_stateIDLE;elsecur_statenext_state;end//状态跳转逻辑always (*) beginif (!rst_n)next_stateIDLE;elsecase (cur_state)IDLE : next_stateWAIT_40MS;WAIT_40MS : if(cnt_40msCNT_40MS) next_stateINIT;elsenext_stateWAIT_40MS;INIT : if(iic_done) next_stateWAIT_10MS;elsenext_stateINIT;WAIT_10MS : if(ack_reg1)next_stateWAIT_40MS;else if(cnt_10msCNT_10MS)next_stateCAPTURE;elsenext_stateWAIT_10MS;CAPTURE : if(iic_done) next_stateWAIT_500MS;elsenext_stateCAPTURE;WAIT_500MS : if(cnt_timeCNT_TIMER/2) next_stateGET_DATA;elsenext_stateWAIT_500MS;GET_DATA : if(iic_done) next_stateWAIT_1S;elsenext_stateGET_DATA;WAIT_1S : if(cnt_timeCNT_TIMER) next_stateWAIT_40MS;elsenext_stateWAIT_1S;default: next_stateIDLE;endcaseendalways (posedge sys_clk) beginif(!rst_n)beginiic_start 0 ;//启动iicselect 0 ;//选择调用的命令temper 0 ;//输出的温度wet 0 ;//输出的湿度start_send 0 ;//输出传输标志用于触发串口传输temper_reg 0 ;//温度值wet_reg 0 ;//湿度值cnt_time 0 ;//1s计时器cnt_40ms 0 ;//40ms计时器cnt_10ms 0 ;//10ms计时器ack_reg 0 ;ack_reg1 0 ;cnt_recv 0 ;endelse beginif(cur_stateIDLE)beginiic_start 0 ;//启动iicselect 0 ;//选择调用的命令temper 0 ;//输出的温度wet 0 ;//输出的湿度start_send 0 ;//输出传输标志用于触发串口传输temper_reg 0 ;//温度值wet_reg 0 ;//湿度值cnt_time 0 ;//1s计时器cnt_40ms 0 ;//40ms计时器cnt_10ms 0 ;//10ms计时器ack_reg 0 ;ack_reg1 0 ;cnt_recv 0 ;endelse if(cur_stateWAIT_40MS)beginiic_start 0 ;//启动iicselect 0 ;//选择调用的命令tempertemper;//输出的温度wetwet;//输出的湿度start_send 0 ;//输出传输标志用于触发串口传输temper_reg temper_reg ;//温度值wet_reg wet_reg ;//湿度值if(cnt_timeCNT_TIMER)cnt_time0;elsecnt_timecnt_time1;//1s计时器if(cnt_40msCNT_40MS)cnt_40mscnt_40ms1; //40ms计时器else if(cnt_40msCNT_40MS)cnt_40mscnt_40ms;elsecnt_40ms0;cnt_10ms 0 ;//10ms计时器ack_reg 0 ;ack_reg1 0 ;cnt_recv 0 ;endelse if(cur_stateINIT)beginiic_start1;//启动iicselect 0 ;//选择调用的命令tempertemper;//输出的温度wetwet;//输出的湿度start_send 0 ;//输出传输标志用于触发串口传输temper_reg temper_reg ;//温度值wet_reg wet_reg ;//湿度值if(cnt_timeCNT_TIMER)cnt_time0;elsecnt_timecnt_time1;//1s计时器cnt_40ms 0 ;//40ms计时器cnt_10ms 0 ;//10ms计时器if(ack1)ack_reg1;elseack_regack_reg;ack_reg1ack_reg;cnt_recv 0 ;endelse if(cur_stateWAIT_10MS)beginiic_start 0 ;//启动iicselect 0 ;//选择调用的命令temper temper ;//输出的温度wet wet ;//输出的湿度start_send 0 ;//输出传输标志用于触发串口传输temper_reg temper_reg ;//温度值wet_reg wet_reg ;//湿度值if(cnt_timeCNT_TIMER)cnt_time0;elsecnt_timecnt_time1;//1s计时器cnt_40ms 0 ;//40ms计时器if(cnt_10msCNT_10MS)cnt_10mscnt_10ms1;else if(cnt_10msCNT_10MS)cnt_10mscnt_10ms;elsecnt_10ms0;ack_reg0 ;ack_reg1ack_reg1 ;//reg1记录了上一状态的ack值如果ack至少有1个时钟为1那么重发命令cnt_recv 0 ;endelse if(cur_stateCAPTURE)beginiic_start 1 ;//启动iicselect 2 ;//选择调用的命令tempertemper;//输出的温度wetwet;//输出的湿度start_send 0 ;//输出传输标志用于触发串口传输temper_reg temper_reg ;//温度值wet_reg wet_reg ;//湿度值if(cnt_timeCNT_TIMER)cnt_time0;elsecnt_timecnt_time1;//1s计时器cnt_40ms 0 ;//40ms计时器cnt_10ms 0 ;//10ms计时器ack_reg 0 ;ack_reg1 0 ;cnt_recv 0 ;endelse if(cur_stateWAIT_500MS)beginiic_start 0 ;//启动iicselect 0 ;//选择调用的命令tempertemper;//输出的温度wetwet;//输出的湿度start_send 0 ;//输出传输标志用于触发串口传输temper_reg temper_reg ;//温度值wet_reg wet_reg ;//湿度值cnt_timecnt_time1;//1s计时器cnt_40ms 0 ;//40ms计时器cnt_10ms 0 ;//10ms计时器ack_reg 0 ;ack_reg1 0 ;cnt_recv 0 ;endelse if(cur_stateGET_DATA)beginiic_start 1 ;//启动iicselect 3 ;//选择调用的命令tempertemper;//输出的温度wetwet;//输出的湿度start_send 0 ;//输出传输标志用于触发串口传输if(done_recv)beginif(cnt_recv1)wet_reg[19:12]read_data;else if(cnt_recv2)wet_reg[11:4]read_data;else if(cnt_recv3)beginwet_reg[3:0]read_data[7:4];temper_reg[19:16]read_data[3:0];endelse if(cnt_recv4)temper_reg[15:8]read_data;else if(cnt_recv5)temper_reg[7:0]read_data;endcnt_timecnt_time1;//1s计时器cnt_40ms 0 ;//40ms计时器cnt_10ms 0 ;//10ms计时器ack_reg 0 ;ack_reg1 0 ;if(done_recv_reg)cnt_recvcnt_recv1;endelse if(cur_stateWAIT_1S)beginiic_start 0 ;//启动iicselect 0 ;//选择调用的命令tempertemper_tem[15:0];//输出的温度wetwet_tem[15:0];//输出的湿度if(cnt_timeCNT_TIMER-3)start_send 1 ;//输出传输标志用于触发串口传输elsestart_send 0 ;temper_reg temper_reg ;//温度值wet_reg wet_reg ;//湿度值cnt_timecnt_time1;//1s计时器cnt_40ms 0 ;//40ms计时器cnt_10ms 0 ;//10ms计时器ack_reg 0 ;ack_reg1 0 ;endendendwire [26:0] temper_tem;assign temper_temtemper_reg*2000/1024/1024-500;wire [26:0] wet_tem;assign wet_temwet_reg*1000/1024/1024;); endmodule 2.IIC模块iic.v 功能实现了iic模块的通信通过启动信号能够启动iic传、收数据这里需要注意的是sda和scl需配置为inout类型同时添加en信号使其为输出的值和切换高阻态1bz接收值 //iic协议 module iic(input sysclk ,input rst_n ,input start ,//开始信号input worr ,//读写使能--表示读写方向的 worr0---只有写 worr1---只有读 worr先是0再是1---读写都有多字节处理input [7:0] sendnum ,//写的数据个数 --控制循环--看到底写几个数据input [7:0] recvnum ,//读的数据个数 --控制循环--看到底读几个数据input [7:0] data_in ,//需要写的数据output reg [7:0] data_out ,//读数据--通过iic读出的数据output done_recv ,//读数据结束信号output done_send ,//写数据的结束信号output done_iic ,//iic的工作结束信号inout sda ,//iic的数据总线inout scl ,//iic的时钟总线output ack ,output [3:0] led );parameter clk 50_000_000 ;//1s内部时钟周期数parameter iicclk 100_000 ;//iic工作时钟 --100Khzparameter delay clk/iicclk ;//iic的工作周期parameter MID delay/2 ;//iic周期的中点位置parameter Q_MID delay/4 ;//iic周期的 1/4parameter TQ_MID MID Q_MID ;//iic周期的 3/4//--------parameter IDW 8h70 ;//从机设备写地址parameter IDR 8h71 ;//从机设备读地址reg [7:0] cnt_send ;//写数据的计数器--看写状态写了多少个数据reg [7:0] cnt_recv ;//读数据的计数器--看读状态读了多少个数据reg [7:0] data_in_reg ;//写数据的寄存器--为了防止数据出问题reg worr_reg ;//读写方向寄存器reg [1:0] start_reg ;//开始信号寄存器reg ack_flag ;//应答寄存器reg [8:0] cnt ;//iic的工作周期计数器reg [3:0] cnt_bit ;//数据位计数器--表示具体传输到了哪一个bit了assign ack ack_flag;//三态门reg sda_en ;//工作使能reg sda_out ; wire sda_in ;assign sda_in sda;assign sda sda_en?sda_out:1bz;reg scl_en ;//工作使能reg scl_out ; wire scl_in ;assign scl_in scl;assign scl scl_en?scl_out:1bz;//开始信号说明--》用于检测沿和电平always(posedge sysclk)if(!rst_n)start_reg0;else start_reg{start_reg[0],start};// 01 11 10 00//状态声明parameter IDLE 4d0 ,//空闲态START 4d1 ,//开始状态ID 4d2 ,//0010ACK1 4d3 ,SENDDATA 4d4 ,//0100ACK2 4d5 ,//0101STOP 4d6 ,RECVDATA 4d7 ,ACK3 4d8 ,START1 4d9 ,ID1 4d10 ,ACK4 4d11 ;reg [3:0] cur_state,next_state;//三段式状态机第一段always(posedge sysclk)if(!rst_n) cur_stateIDLE;elsecur_statenext_state;//三段式状态机第二段always(*)if(!rst_n)next_stateIDLE;elsecase(cur_state)IDLE :beginif(start_reg2b11(sendnum!0||recvnum!0))//检测到高电平next_stateSTART;elsenext_statecur_state;endSTART :beginif(cntdelay-1)//一个iic的工作周期就跳转next_stateID;elsenext_statecur_state;endID :beginif(cnt_bit7 cntdelay-1)//传完一个寻址地址从机地址读写方向位next_stateACK1;elsenext_statecur_state; endACK1 :beginif(ack_flag1)//应答无效next_stateIDLE;//回到IDLE--重新等待else if(ack_flag0 worr_reg1 cntdelay-1)//应答有效 主机读 一个iic周期结束next_stateRECVDATA;else if(ack_flag0 worr_reg0 cntdelay-1)//应答有效 主机写 一个iic周期结束next_stateSENDDATA;else//除了以上条件next_statecur_state; endSENDDATA :beginif(cnt_bit7 cntdelay-1)//写完一次数据next_stateACK2;elsenext_statecur_state; endACK2 :begin//if(ack_flag1)//应答无效// next_stateIDLE;//回到IDLE--重新等待/*else if(ack_flag0 cntdelay-1 sendnum0 recvnum0)//应答有效 一个iic周期结束 写完 没有读next_stateIDLE;*/if(cntdelay-1 cnt_sendsendnum recvnum0)//应答有效 一个iic周期结束 写完 没有读next_stateSTOP;else if(cntdelay-1 cnt_sendsendnum recvnum!0)//应答有效 一个iic周期结束 写完 有读next_stateSTART1;else if(cntdelay-1 cnt_sendsendnum)//应答有效 一个iic周期结束 没有写完next_stateSENDDATA;else//除了以上条件next_statecur_state; endSTOP :beginif(cntdelay-1)next_stateIDLE;elsenext_statecur_state;endRECVDATA :beginif(cnt_bit7 cntdelay-1)//读完一次数据next_stateACK3;elsenext_statecur_state; endACK3 :beginif(cntdelay-1 cnt_recvrecvnum)//iic一个工作周期 读完next_stateSTOP;else if(cntdelay-1 cnt_recvrecvnum)//iic一个工作周期 没有读完next_stateRECVDATA;else next_statecur_state; endSTART1 :beginif(cntdelay-1)//一个iic的工作周期就跳转next_stateID1;elsenext_statecur_state;endID1 :beginif(cnt_bit7 cntdelay-1)//传完一个寻址地址从机地址next_stateACK4;elsenext_statecur_state; endACK4 :beginif(ack_flag1)//应答无效next_stateIDLE;else if(ack_flag0 cntdelay-1 )//iic一个工作周期 应答有效next_stateRECVDATA;else next_statecur_state; end default :next_stateIDLE;endcase//三段式状态机第三段always(posedge sysclk)if(!rst_n)begincnt_send 0;//写数据的计数器cnt_recv 0;//读数据的计数器data_in_reg 0;//写数据的寄存器worr_reg 0;//读写方向的寄存器ack_flag 0;//应答信号的寄存器cnt 0;//iic的工作周期计数器cnt_bit 0;//bit位计数器data_out 0;//读出去的数据sda_en 0;//数据使能sda_out 0;//数据输出scl_en 0;//时钟使能scl_out 0;//时钟输出endelsecase(cur_state)IDLE :begincnt_send 0;//写数据的计数器cnt_recv 0;//读数据的计数器data_in_reg data_in;//写数据的寄存器 寄存数据worr_reg worr;//读写方向的寄存器ack_flag 0;//应答信号的寄存器cnt 0;//iic的工作周期计数器cnt_bit 0;//bit位计数器data_out 0;//读出去的数据sda_en 1;//数据使能sda_out 1;//数据输出scl_en 1;//时钟使能scl_out 1;//时钟输出endSTART :begincnt_send 0;//写数据的计数器cnt_recv 0;//读数据的计数器//data_in_reg data_in;//写数据的寄存器 寄存数据 ------保持worr_reg worr;//读写方向的寄存器 -------保持ack_flag 0;//应答信号的寄存器if(cntdelay-1)//iic的工作周期计数器cnt 0;elsecnt cnt1;cnt_bit 0;//bit位计数器data_out 0;//读出去的数据sda_en 1;//数据使能--》开关打开if(cntQ_MID)//前1/4个周期sda_out 1;//数据输出elsesda_out 0;scl_en 1;//时钟使能if(cntTQ_MID)//1/4~3/4处置为高电平scl_out 1;//时钟输出elsescl_out 0;endID :begincnt_send 0;//写数据的计数器cnt_recv 0;//读数据的计数器//data_in_reg data_in;//写数据的寄存器 寄存数据 ------保持worr_reg worr;//读写方向的寄存器 -------保持ack_flag 0;//应答信号的寄存器if(cntdelay-1)//iic的工作周期计数器cnt 0;elsecnt cnt1;if(cntdelay-1)cnt_bit cnt_bit1;//bit位计数器data_out 0;//读出去的数据sda_en 1;//数据使能--》开关打开if(worr_reg0 cnt1)//如果是写方向sda_out IDW[7-cnt_bit];//数据输出else if(worr_reg1 cnt1) //如果是读方向sda_out IDR[7-cnt_bit];elsesda_out sda_out;scl_en 1;//时钟使能if(cntQ_MID cntTQ_MID)//1/4~3/4处置为高电平scl_out 1;//时钟输出elsescl_out 0;endACK1 :begincnt_send 0;//写数据的计数器cnt_recv 0;//读数据的计数器//data_in_reg data_in;//写数据的寄存器 寄存数据 ------保持worr_reg worr;//读写方向的寄存器 -------保持if(cntMID)ack_flag sda_in;//应答信号的寄存器if(cntdelay-1)//iic的工作周期计数器cnt 0;elsecnt cnt1;cnt_bit 0;//bit位计数器data_out 0;//读出去的数据sda_en 0;sda_out 1;scl_en 1;//时钟使能if(cntQ_MID cntTQ_MID)//1/4~3/4处置为高电平scl_out 1;//时钟输出elsescl_out 0;endSENDDATA :begin//cnt_send cnt_send;//写数据的计数器--保持cnt_recv 0;//读数据的计数器//data_in_reg data_in;//写数据的寄存器 寄存数据 ------保持worr_reg worr;//读写方向的寄存器 -------保持ack_flag 0;//应答信号的寄存器if(cntdelay-1)//iic的工作周期计数器cnt 0;elsecnt cnt1;if(cntdelay-1)cnt_bit cnt_bit1;//bit位计数器data_out 0;//读出去的数据sda_en 1;if(cnt1)sda_out data_in_reg[7-cnt_bit];scl_en 1;//时钟使能if(cntQ_MID cntTQ_MID)//1/4~3/4处置为高电平scl_out 1;//时钟输出elsescl_out 0;endACK2 :beginif(cntMID)cnt_send cnt_send1;//写数据的计数器cnt_recv 0;//读数据的计数器data_in_reg data_in;//写数据的寄存器 寄存数据 ------保持worr_reg worr;//读写方向的寄存器 ------保持if(cntMID)ack_flag sda_in;//应答信号的寄存器if(cntdelay-1)//iic的工作周期计数器cnt 0;elsecnt cnt1;cnt_bit 0;//bit位计数器data_out 0;//读出去的数据sda_en 0;sda_out 1;scl_en 1;//时钟使能if(cntQ_MID cntTQ_MID)//1/4~3/4处置为高电平scl_out 1;//时钟输出elsescl_out 0;endSTOP :begincnt_send 0;//写数据的计数器cnt_recv 0;//读数据的计数器data_in_reg 0;//写数据的寄存器 寄存数据 ------保持worr_reg 0;//读写方向的寄存器 -------保持ack_flag 0;//应答信号的寄存器if(cntdelay-1)//iic的工作周期计数器cnt 0;elsecnt cnt1;cnt_bit 0;//bit位计数器data_out 0;//读出去的数据sda_en 1;if(cntTQ_MID)// 3/4sda_out 0;elsesda_out 1;scl_en 1;//时钟使能if(cntQ_MID)//1/4scl_out 0;//时钟输出elsescl_out 1;endRECVDATA :begin//cnt_send 0;//写数据的计数器--保持//cnt_recv cnt_recv;//读数据的计数器//data_in_reg data_in;//写数据的寄存器 寄存数据 ------保持worr_reg worr;//读写方向的寄存器 -------保持ack_flag 0;//应答信号的寄存器if(cntdelay-1)//iic的工作周期计数器cnt 0;elsecnt cnt1;if(cntdelay-1)cnt_bit cnt_bit1;//bit位计数器if(cntMID)data_out[7-cnt_bit] sda_in;//读出去的数据sda_en 0;sda_out 1;scl_en 1;//时钟使能if(cntQ_MID cntTQ_MID)//1/4~3/4处置为高电平scl_out 1;//时钟输出elsescl_out 0;endACK3 :begin//cnt_send cnt_send1;//写数据的计数器if(cntMID)cnt_recv cnt_recv1;//读数据的计数器//data_in_reg data_in;//写数据的寄存器 寄存数据 ------保持worr_reg worr;//读写方向的寄存器 -------保持ack_flag 0;//应答信号的寄存器if(cntdelay-1)//iic的工作周期计数器cnt 0;elsecnt cnt1;cnt_bit 0;//bit位计数器data_out data_out;//读出去的数据sda_en 1;sda_out 0;scl_en 1;//时钟使能if(cntQ_MID cntTQ_MID)//1/4~3/4处置为高电平scl_out 1;//时钟输出elsescl_out 0;endSTART1 :begincnt_send 0;//写数据的计数器cnt_recv 0;//读数据的计数器//data_in_reg data_in;//写数据的寄存器 寄存数据 ------保持worr_reg worr;//读写方向的寄存器 -------保持ack_flag 0;//应答信号的寄存器if(cntdelay-1)//iic的工作周期计数器cnt 0;elsecnt cnt1;cnt_bit 0;//bit位计数器data_out 0;//读出去的数据sda_en 1;//数据使能--》开关打开if(cntQ_MID)//前1/4个周期sda_out 1;//数据输出elsesda_out 0;scl_en 1;//时钟使能if(cntTQ_MID)//1/4~3/4处置为高电平scl_out 1;//时钟输出elsescl_out 0;endID1 :begincnt_send 0;//写数据的计数器cnt_recv 0;//读数据的计数器//data_in_reg data_in;//写数据的寄存器 寄存数据 ------保持worr_reg worr;//读写方向的寄存器 -------保持ack_flag 0;//应答信号的寄存器if(cntdelay-1)//iic的工作周期计数器cnt 0;elsecnt cnt1;if(cntdelay-1)cnt_bit cnt_bit1;//bit位计数器data_out 0;//读出去的数据sda_en 1;//数据使能--》开关打开if(cnt1) //如果是读方向sda_out IDR[7-cnt_bit];elsesda_out sda_out;scl_en 1;//时钟使能if(cntQ_MID cntTQ_MID)//1/4~3/4处置为高电平scl_out 1;//时钟输出elsescl_out 0;endACK4 :begincnt_send 0;//写数据的计数器cnt_recv 0;//读数据的计数器//data_in_reg data_in;//写数据的寄存器 寄存数据 ------保持worr_reg worr;//读写方向的寄存器 -------保持if(cntMID)ack_flag sda_in;//应答信号的寄存器if(cntdelay-1)//iic的工作周期计数器cnt 0;elsecnt cnt1;cnt_bit 0;//bit位计数器data_out 0;//读出去的数据sda_en 0;sda_out 1;scl_en 1;//时钟使能if(cntQ_MID cntTQ_MID)//1/4~3/4处置为高电平scl_out 1;//时钟输出elsescl_out 0;enddefault :begincnt_send 0;//写数据的计数器cnt_recv 0;//读数据的计数器data_in_reg data_in;//写数据的寄存器 寄存数据worr_reg worr;//读写方向的寄存器ack_flag 0;//应答信号的寄存器cnt 0;//iic的工作周期计数器cnt_bit 0;//bit位计数器data_out 0;//读出去的数据sda_en 0;//数据使能sda_out 1;//数据输出scl_en 0;//时钟使能scl_out 1;//时钟输出endendcase assign done_recv (cur_stateACK3 cntMID)?1:0;assign done_send (cur_stateACK2 cntMID)?1:0;assign done_iic (cur_stateSTOP cntdelay-30)?1:0;endmodule 3.指令控制模块cmd.v 功能用于切换指令以及确定每条指令需要收发多少条数据 //负责切换命令、控制发送接收数据数量 module cmd(input sys_clk ,input rst_n ,input [7:0] data_iic ,//iic数据input done_recv ,//iic接收完一个字节input done_send ,//iic发送完一个字节input done_iic ,//iic结束input [1:0] select ,output reg worr ,//读写位控制output reg [7:0] sendnum ,//发送几个数据output reg [7:0] recvnum ,//接收几个数据output reg [7:0] data_cmd ,//数据命令output reg cmd_flag ,input [3:0] led );parameter IDLE 4b0000,INIT 4b0001,//初始化AHT20CAT 4b0011,//查看状态寄存器CAP 4b0010,//采集命令GET 4b0110;//获取数据reg [3:0] cur_state,next_state;reg [3:0] cnt_cmd;always (posedge sys_clk) beginif(!rst_n)cur_stateIDLE;elsecur_statenext_state;endalways (*) beginif(!rst_n)next_stateIDLE;elsecase (select)0 : next_stateINIT;1 : next_stateCAT;2 : next_stateCAP;3 : next_stateGET;default: next_stateIDLE;endcaseendalways (posedge sys_clk) beginif(!rst_n)beginworr 0;//worr1读0写sendnum 0;recvnum 0;data_cmd 8hFF;cnt_cmd 0;endelse if(cur_stateINIT)begin//初始化发送0xBEworr0;sendnum 3;recvnum 0;if(done_send1)cnt_cmd cnt_cmd1;else if(done_iic)cnt_cmd 0;elsecnt_cmd cnt_cmd;if(cnt_cmd0)data_cmd8hBE;else if(cnt_cmd1)data_cmd8h08;else if(cnt_cmd2)data_cmd8h00; endelse if(cur_stateCAT)begin//查看状态寄存器读地址第一位worr1;sendnum 0;recvnum 1;data_cmd8h71;cnt_cmd 0;endelse if(cur_stateCAP)begin//发送采集命令发送0xAC 0x33 0x00worr0;sendnum 3;recvnum 0;if(done_send1)cnt_cmd cnt_cmd1;else if(done_iic)cnt_cmd 0;elsecnt_cmd cnt_cmd;if(cnt_cmd0)data_cmd8hAC;else if(cnt_cmd1)data_cmd8h33;else if(cnt_cmd2)data_cmd8h00;endelse if(cur_stateGET)begin//查看6个字节的数据 状态寄存器 湿度 湿度 湿度温度各一半 温度 温度worr1;sendnum 0;recvnum 6;data_cmd8hFF;cnt_cmd 0;endend endmodule4.串口模块uart_tx.v、uart_tx_control.v 功能实现串口发送指定格式的数据 module uart_tx (input clk,input [7:0]data,input en_flag,input rst_n,output reg tx,output reg tx_done,output reg en );reg [4:0] cntw;//0-9帧0起始位1-8数据位9停止位reg [22:0] cnt;//数据时钟同步reg [7:0]data_reg;always (posedge clk) beginif(!rst_n)data_reg0;else if(en_flag1en0)data_regdata;elsedata_regdata_reg;end//使能信号开启 always (posedge clk) beginif(!rst_n)en0;else beginif(en_flag1)en1;else if(cntw9cnt5207)//5207en0;elseenen;endend//数据位和每帧时间计数always(posedge clk)beginif(!rst_n)cntw0;else beginif(en1cnt5207)cntwcntw1;else if(en0)cntw0;elsecntwcntw;end endalways(posedge clk)beginif(!rst_n)cnt0;else beginif(en1)beginif(cnt5207)cnt0;elsecntcnt1;endelsecnt0;end end//给tx输出赋值always (posedge clk) beginif(!rst_n)tx1;else beginif(en1)beginif(cntw0)tx0;else if(cntw9)tx1;elsetxdata_reg[cntw-1];endelsetx1; endend//给txdone赋值always (posedge clk) beginif(!rst_n)tx_done0;else beginif(cntw9cnt5207)tx_done1;elsetx_done0;endend endmodule module uart_tx_control (input sys_clk,input rst_n,input [15:0]wet,input [15:0]temper,input start_send,//发送一次串口数据input tx_done,input tx_en,output reg start_flag,output reg [7:0] data );reg [7:0] cnt;always (posedge sys_clk) beginif(!rst_n)cnt0;else if(tx_done)cntcnt1;else if(start_send)cnt0;elsecntcnt;endalways (posedge sys_clk) beginif(!rst_n)start_flag0;else beginif (start_send)start_flag1;else if(tx_donecnt17)start_flag1;elsestart_flag0;endendalways (*) beginif(!rst_n)data0;elsecase (cnt)0 :data8h57;//W1 :data8h45;//E2 :data8h54;//T3 :data8h3A;//:4 :datawet/100%1048;5 :datawet/10%1048;6 :data8h2E;//.7 :datawet%1048;//8 :data8h25;//%9 :data8h54;//T10 :data8h45;//E11 :data8h4D;//M12 :data8h3A;//:13 :datatemper/100%1048;14 :datatemper/10%1048;15 :data8h2E;//.16 :datatemper%1048;17 :data8h0A;//换行\ndefault: data0;endcaseend endmodule 5.顶层模块top.v 功能实现各模块的连接与例化 module top(input sys_clk,input rst_n,inout sda,inout scl,output uart_txd,output [3:0] led );wire [7:0] read_data,sendnum,recvnum,data_cmd;wire [15:0] temper,wet;wire [1:0] select;aht20_control aht20_control(.sys_clk (sys_clk),.rst_n (rst_n),.read_data (read_data),.iic_done (done_iic),.done_recv (done_recv),.ack (ack),.iic_start (start_iic),.select (select),.temper (temper),.wet (wet),.start_send (start_send),.led (led));cmd cmd(.sys_clk (sys_clk),.rst_n (rst_n),.data_iic (read_data),//iic数据.done_recv (done_recv),//iic接收完一个字节.done_send (done_send),//iic发送完一个字节.done_iic (done_iic) ,//iic结束.select (select) ,.worr (worr) ,//读写位控制.sendnum (sendnum) ,//发送几个数据.recvnum (recvnum) ,//接收几个数据.data_cmd (data_cmd) ,//数据命令.cmd_flag () ,.led ());iic iic(.sysclk (sys_clk),.rst_n (rst_n),.start (start_iic),//开始信号.worr (worr), //读写使能--表示读写方向的 worr0---只有写 worr1---只有读 worr先是0再是1---读写都有多字节处理.sendnum (sendnum), //写的数据个数 --控制循环--看到底写几个数据.recvnum (recvnum), //读的数据个数 --控制循环--看到底读几个数据.data_in (data_cmd), //需要写的数据.data_out (read_data),//读数据--通过iic读出的数据.done_recv (done_recv),//读数据结束信号.done_send (done_send),//写数据的结束信号.done_iic (done_iic), //iic的工作结束信号.sda (sda), //iic的数据总线.scl (scl), //iic的时钟总线.ack (ack),.led () ); wire [7:0]uart_tx_data; uart_tx uart_tx(.clk (sys_clk), .rst_n (rst_n), .en_flag (uart_tx_en), .data (uart_tx_data),.tx (uart_txd), .tx_done (tx_done), .en ()); uart_tx_control uart_tx_control(.sys_clk (sys_clk),.rst_n (rst_n),.wet (wet),.temper(temper),.start_send(start_send),//发送一次串口数据.tx_done(tx_done),.tx_en(),.start_flag(uart_tx_en),.data(uart_tx_data) ); endmodule四.效果展示 可以看到数据显示正常1s发送一次此外还要啰嗦两句重庆夏天是真的热啊室内30多°可惜家里有人吹不了空调我快热飞了
http://www.pierceye.com/news/469286/

相关文章:

  • 温州网站运营微信公众号服务号网站开发流程
  • 网站宣传的好处山西房地产网站建设
  • 网站seo工作内容大学做视频网站
  • 台州网站建设企业网站 微信开发
  • 安徽省水利厅网站 基本建设营销策划公司名称
  • 网页设计师培训学院开封做网站优化
  • 山西电力建设三公司网站影院禁止18岁以下观众观影
  • 防伪网站模板网站开发怎么赚钱
  • 医院网站建设意义推广咨询
  • 广东省54个市win10最强优化软件
  • 交换链接网站asp.net企业网站框架
  • 惠州网站建设制作推广医疗设备响应式网站
  • 有哪些做ppt的网站cms网站开发涉及的知识
  • 软件开发成本估算表苏州百度seo代理
  • 网站内部链接有什么作用临安做企业网站的公司
  • 整合营销网站网站建设销售话术开场白
  • 永久免费wap自助建站北京家装设计师排名
  • 西安学校网站建设报价做淘宝客没有网站怎么做
  • 网站建设运营思路网站已在别处备案怎么转入阿里云
  • 网站开发前端如何开发秦皇岛做网站
  • sns网站建设最好看免费观看高清大全宫崎骏
  • 手机网站开发下载app开发长沙
  • 重庆南川网站制作价格西宁网站建设优化
  • 电子商务网站建设与管理试卷6平面设计接单兼职
  • 建设手机网站大概要多少钱云南建投二公司官网
  • 公司如何建设网站首页网页设计与网站开发试题答案
  • 中企动力合作网站网站app下载平台怎么做
  • 网站开发专业成功人士重庆邮电大学官网网站
  • 官方网站后台图片下载怎么做网站开发与支付宝端口连接
  • 浏览器怎么打开网站服务器下载在线音乐网站开发摘要