首页 > 代码库 > 数字电路期末课程设计总结(三)IIC总线调用
数字电路期末课程设计总结(三)IIC总线调用
首先介绍一下IIC总线。高速设备为了抗干扰,大多数都用低压差分信号(LVDS)。差分线路由于传递差模信号,可以有效抑制共模噪声和串扰。IIC总线虽然由于速度限制不能驱动高速设备,多用于KHz级别的信号传递,不过依然有着比较广泛的用途。
IIC网上资料繁多,我就不再赘述。
写数据分三步:
1.主机发送地址位(写),从机应答。
2.主机发送控制字,从机应答。
3.主机发送数据。
读数据分四步:
1.主机发送地址位(写),从机应答。
2.主机发送控制字,从机应答。
3.主机发送地址位(读),从机应答。
3.主机接收数据。
这次主要实现的功能:
根据工作状态控制字决定AOUT端输出波形(波形控制字控制波形),
或是AIN0,AIN1,AIN3端读入不同传感器的数据。
顶层模块图:
IIC模块读(写)完毕后Done_Sig产生1个高脉冲,驱动RomAddressCtrl模块和StateToCtrlByte模块改变工作状态,
外部的State控制信号由StateToCtrlByte模块处理后产生对应的IIC控制字,
Done_Sig信号与State控制信号通过控制Start_Sig信号决定IIC模块读写状态。
顶层代码如下:
1 module I2C4In1 2 ( 3 input clock, // 时钟线 4 input reset, // 复位线 5 input[4:0] State, // 工作状态控制字 6 7 8 9 inout SDA, // IIC数据线10 input[2:0] WaveChoose, // 波形控制字11 input[7:0] FreqChoose, // 相位控制字12 13 output SCL, // IIC时钟线14 output[7:0] ReadDataOut // 读数据输出15 ); 16 17 /***************************/ 18 RomAddressCtrl U1( // ROM地址控制模块19 .Done_Sig(Done_Sig), // IIC结束信号20 .clock(clock), // 时钟线21 .reset(reset), // 复位线22 .FreqChoose(FreqChoose), // 相位控制字23 .isStart(isStart), // ROM输出IIC使能24 .RomAddress(RomAddress) // ROM地址25 );26 27 WaveRomChoose U4( // ROM选择模块,选择输出波形对应的ROM28 .WaveChoose(WaveChoose), // 波形控制字29 .address(RomAddress), // ROM地址30 .clock(clock), // 时钟线31 .q(RomData) // ROM数据输出32 );33 wire[7:0] RomData; // 模块间连线34 wire[10:0] RomAddress; // 模块间连线35 wire[1:0] isStart; // 模块间连线36 wire[1:0] Start_Sig; // 模块间连线37 // IIC控制字输出模块38 StateToCtrlByte U3(clock,reset,State,IICCtrlByte,isStart,Start_Sig,Done_Sig,RdData,ReadDataOut);39 /***************************/40 wire[7:0] IICCtrlByte; // 模块间连线41 wire[7:0] RdData; // 模块间连线42 wire Done_Sig; // 模块间连线43 44 iic_func_module U2 // IIC模块45 (46 .clock( clock ),47 .reset( reset ),48 .Start_Sig(Start_Sig ),49 .Addr_Sig( IICCtrlByte ),50 .WrData( RomData ),51 .RdData( RdData ),52 .Done_Sig( Done_Sig ),53 .SCL( SCL ),54 .SDA( SDA )55 );56 57 58 endmodule
地址:1001000(0/1)
A2A1A0见下图,都连了地,所以都是0.
IIC代码如下(源于黑金FPGA社区):
1 module iic_func_module 2 ( 3 input clock, 4 input reset, 5 6 input [1:0]Start_Sig, // IIC使能信号,10为读,01为写 7 input [7:0]Addr_Sig, // 控制字 8 input [7:0]WrData, // 写数据 9 output [7:0]RdData, // 读数据 10 output Done_Sig, // 转换完成信号,一个高脉冲 11 12 output SCL, // IIC时钟线 13 inout SDA // IIC数据线 14 15 16 ); 17 18 /*************************/ 19 20 parameter FREQ14 = 11‘d85; 21 parameter FREQ24 = 11‘d170; 22 parameter FREQ34 = 11‘d255; 23 parameter FREQ = 11‘d341; // 时间参量,对应50MHz时钟 24 25 /*************************/ 26 27 reg [4:0]i; 28 reg [4:0]Go; 29 reg [10:0]C1; 30 reg [7:0]rData; 31 reg rSCL; 32 reg rSDA; 33 reg isAck; 34 reg isDone; 35 reg isOut; 36 37 always @ ( posedge clock or negedge reset ) 38 if( !reset ) 39 begin 40 i <= 5‘d0; 41 Go <= 5‘d0; 42 C1 <= 11‘d0; 43 rData <= 8‘d0; 44 rSCL <= 1‘b1; 45 rSDA <= 1‘b1; 46 isAck <= 1‘b1; 47 isDone <= 1‘b0; 48 isOut <= 1‘b1; 49 end 50 else if( Start_Sig[0] ) 51 case( i ) 52 53 0: // Start 54 begin 55 isOut = 1; 56 57 rSCL <= 1‘b1; 58 59 if( C1 == 0 ) rSDA <= 1‘b1; 60 else if( C1 == FREQ24 ) rSDA <= 1‘b0; 61 62 if( C1 == FREQ -1) begin C1 <= 11‘d0; i <= i + 1‘b1; end 63 else C1 <= C1 + 1‘b1; 64 end 65 66 1: // Write Device Addr 67 begin rData <= {4‘b1001, 3‘b000, 1‘b0}; i <= 5‘d7; Go <= i + 1‘b1; end 68 69 2: // Wirte Word Addr 70 begin rData <= Addr_Sig; i <= 5‘d7; Go <= i + 1‘b1; end 71 72 3: // Write Data 73 begin rData <= WrData; i <= 5‘d7; Go <= i + 1‘b1; end 74 75 /*************************/ 76 77 4: // Stop 78 begin 79 isOut = 1‘b1; 80 81 if( C1 == 0 ) rSCL <= 1‘b0; 82 else if( C1 == FREQ14 ) rSCL <= 1‘b1; 83 84 if( C1 == 0 ) rSDA <= 1‘b0; 85 else if( C1 == FREQ34 ) rSDA <= 1‘b1; 86 87 if( C1 == FREQ14 + FREQ -1 ) begin C1 <= 11‘d0; i <= i + 1‘b1; end 88 else C1 <= C1 + 1‘b1; 89 end 90 91 5: 92 begin isDone <= 1‘b1; i <= i + 1‘b1; end 93 94 6: 95 begin isDone <= 1‘b0; i <= 5‘d0; end 96 97 /*******************************/ //function 98 99 7,8,9,10,11,12,13,14:100 begin101 isOut = 1‘b1;102 rSDA <= rData[14-i];103 104 if( C1 == 0 ) rSCL <= 1‘b0;105 else if( C1 == FREQ24 ) rSCL <= 1‘b1; 106 107 if( C1 == FREQ -1 ) begin C1 <= 11‘d0; i <= i + 1‘b1; end108 else C1 <= C1 + 1‘b1;109 end110 111 15: // waiting for acknowledge112 begin113 isOut = 1‘b0;114 if( C1 == FREQ34 ) isAck <= SDA;115 116 if( C1 == 0 ) rSCL <= 1‘b0;117 else if( C1 == FREQ24 ) rSCL <= 1‘b1;118 119 if( C1 == FREQ -1 ) begin C1 <= 11‘d0; i <= i + 1‘b1; end120 else C1 <= C1 + 1‘b1; 121 end122 123 16:124 if( isAck != 0 ) i <= 5‘d0;125 else i <= Go; 126 127 /*******************************/ // end function128 129 endcase130 131 else if( Start_Sig[1] ) 132 case( i )133 134 0: // Start135 begin136 isOut = 1;137 138 rSCL <= 1‘b1;139 140 if( C1 == 0 ) rSDA <= 1‘b1; 141 else if( C1 == FREQ24 ) rSDA <= 1‘b0; 142 143 if( C1 == FREQ -1 ) begin C1 <= 11‘d0; i <= i + 1‘b1; end144 else C1 <= C1 + 1‘b1;145 end146 147 1: // Write Device Addr148 begin rData <= {4‘b1001, 3‘b000, 1‘b0}; i <= 5‘d9; Go <= i + 1‘b1; end149 150 2: // Wirte Word Addr151 begin rData <= Addr_Sig; i <= 5‘d9; Go <= i + 1‘b1; end152 153 3: // Start again154 begin155 isOut = 1‘b1;156 157 if( C1 == 0 ) rSCL <= 1‘b0;158 else if( C1 == FREQ14 ) rSCL <= 1‘b1;159 else if( C1 == FREQ14 + FREQ ) rSCL <= 1‘b0;160 161 if( C1 == 0 ) rSDA <= 1‘b0; 162 else if( C1 == FREQ14 ) rSDA <= 1‘b1;163 else if( C1 == FREQ34 ) rSDA <= 1‘b0; 164 165 if( C1 == FREQ + FREQ24 -1 ) begin C1 <= 11‘d0; i <= i + 1‘b1; end166 else C1 <= C1 + 1‘b1;167 end168 169 4: // Write Device Addr ( Read )170 begin rData <= {4‘b1001, 3‘b000, 1‘b1}; i <= 5‘d9; Go <= i + 1‘b1; end171 172 5: // Read Data173 begin rData <= 8‘d0; i <= 5‘d19; Go <= i + 1‘b1; end174 175 6: // Stop176 begin177 isOut = 1‘b1;178 179 if( C1 == 0 ) rSCL <= 1‘b0;180 else if( C1 == FREQ14 ) rSCL <= 1‘b1; 181 182 if( C1 == 0 ) rSDA <= 1‘b0;183 else if( C1 == FREQ34 ) rSDA <= 1‘b1; 184 185 if( C1 == 50 + FREQ -1 ) begin C1 <= 11‘d0; i <= i + 1‘b1; end186 else C1 <= C1 + 1‘b1; 187 end188 189 7:190 begin isDone <= 1‘b1; i <= i + 1‘b1; end191 192 8: 193 begin isDone <= 1‘b0; i <= 5‘d0; end194 195 /*******************************/ //function196 197 9,10,11,12,13,14,15,16:198 begin199 isOut = 1‘b1;200 201 rSDA <= rData[16-i];202 203 if( C1 == 0 ) rSCL <= 1‘b0;204 else if( C1 == FREQ24 ) rSCL <= 1‘b1; 205 206 if( C1 == FREQ -1 ) begin C1 <= 11‘d0; i <= i + 1‘b1; end207 else C1 <= C1 + 1‘b1;208 end209 210 17: // waiting for acknowledge211 begin212 isOut = 1‘b0;213 214 if( C1 == FREQ34 ) isAck <= SDA;215 216 if( C1 == 0 ) rSCL <= 1‘b0;217 else if( C1 == FREQ24 ) rSCL <= 1‘b1;218 219 if( C1 == FREQ -1 ) begin C1 <= 11‘d0; i <= i + 1‘b1; end220 else C1 <= C1 + 1‘b1; 221 end222 223 18:224 if( isAck != 0 ) i <= 5‘d0;225 else i <= Go;226 227 /*****************************/228 229 19,20,21,22,23,24,25,26: // Read230 begin231 isOut = 1‘b0;232 if( C1 == FREQ34 ) rData[26-i] <= SDA;233 234 if( C1 == 0 ) rSCL <= 1‘b0;235 else if( C1 == FREQ24 ) rSCL <= 1‘b1; 236 237 if( C1 == FREQ -1 ) begin C1 <= 11‘d0; i <= i + 1‘b1; end238 else C1 <= C1 + 1‘b1;239 end 240 241 27: // no acknowledge242 begin243 isOut = 1‘b1;244 //if( C1 == 100 ) isAck <= SDA;245 246 if( C1 == 0 ) rSCL <= 1‘b0;247 else if( C1 == FREQ24 ) rSCL <= 1‘b1;248 249 if( C1 == FREQ -1 ) begin C1 <= 11‘d0; i <= Go; end250 else C1 <= C1 + 1‘b1; 251 end252 253 /*************************************/ // end fucntion254 255 endcase256 257 /***************************************/258 259 assign Done_Sig = isDon;260 assign RdData =http://www.mamicode.com/ rData;261 assign SCL = rSCL;262 assign SDA = isOut ? rSDA : 1‘bz; 263 264 /***************************************/ 265 266 267 endmodule268
StateToCtrlByte模块:
State决定IICCtrlByte(IIC控制字)。针对27-41行的写法,我做了一些思考。最初用的是锁存器写法。
1 always@(State) 2 case(State)3 5‘b00001: RegIICCtrlByte <= 8‘b00000000;4 5‘b00010: RegIICCtrlByte <= 8‘b00000001;5 5‘b00100: RegIICCtrlByte <= 8‘b01000000;6 5‘b01000: RegIICCtrlByte <= 8‘b00000011;7 endcase
后来发现存在bug,信号有时会过不去。于是改成了组合逻辑式写法
1 assign IICCtrlByte = State[0]==1?8‘d0:(State[1]==1?8‘d1:(State[2]==1?8‘d64:8‘d3));
StateToCtrlByte:
1 module StateToCtrlByte(clock,reset,State,IICCtrlByte,isStart,Start_Sig,Done_Sig,RdData,ReadDataOut); 2 input[4:0] State; 3 input[1:0] isStart; 4 input Done_Sig; 5 input clock,reset; 6 input[7:0] RdData; //IIC模块读操作数据输入 7 8 output[1:0] Start_Sig; 9 output[7:0] IICCtrlByte;10 output[7:0] ReadDataOut; // IIC模块读操作数据输出11 12 reg[1:0] RegStart;13 reg[7:0] RegReadDataOut;14 // reg[7:0] RegIICCtrlByte;15 16 always @ ( posedge clock or negedge reset ) 17 if( !reset ) 18 begin19 RegStart <= 2‘b00;20 end21 else22 case( Done_Sig ) 23 0: if(State==5‘b00100)RegStart <= 2‘b01;else RegStart <= 2‘b10; 24 1: begin RegStart <= 2‘b00; RegReadDataOut <= RdData;end25 endcase 26 27 // always@(State) 28 // case(State)29 // 5‘b00001: RegIICCtrlByte <= 8‘b00000000;30 // 5‘b00010: RegIICCtrlByte <= 8‘b00000001;31 // 5‘b00100: RegIICCtrlByte <= 8‘b01000000;32 // 5‘b01000: RegIICCtrlByte <= 8‘b00000011;33 // endcase34 35 assign IICCtrlByte = State[0]==1?8‘d0:(State[1]==1?8‘d1:(State[2]==1?8‘d64:8‘d3));36 assign ReadDataOut = RegReadDataOut;37 assign Start_Sig = RegStart;38 //光照 AIN0 8‘b00000000; 0000139 //温度 AIN1 8‘b00000001; 0001040 //频率输出 8‘b01000000; 0010041 //内部电阻分压 AIN3 8‘b00000011; 0100042 endmodule
1 // 相位累加模块 2 module RomAddressCtrl(Done_Sig,clock,reset,FreqChoose,isStart,RomAddress); 3 4 input Done_Sig; 5 input clock; 6 input reset; 7 input[7:0] FreqChoose; 8 9 output[1:0] isStart; // 输出使能。01写操作,00中止10 output[10:0] RomAddress; // ROM地址11 12 reg [3:0] i; // 状态变量 i13 reg [1:0] RegisStart; // 输出使能寄存器14 reg[10:0] RegRomAddress; // ROM地址寄存器15 16 // 相位累加模块17 // 收到IIC结束信号Done_Sig后 18 always @ ( posedge clock or negedge reset ) 19 if( !reset )20 begin21 i <= 4‘d0;22 RegisStart <= 2‘b00;23 end24 else25 case( Done_Sig )26 27 0: RegisStart <= 2‘b01; 28 29 1: begin RegisStart <= 2‘b00; i <= 4‘d0; RegRomAddress <= RegRomAddress + FreqChoose;end30 31 endcase32 33 assign isStart = RegisStart;34 assign RomAddress = RegRomAddress;35 36 endmodule
1 module WaveRomChoose(WaveChoose,address,clock,q); 2 3 input clock; 4 input[2:0] WaveChoose; 5 input[10:0] address; 6 7 output[7:0] q; 8 9 wire[7:0] SinData;10 wire[7:0] SquData;11 wire[7:0] TriData;12 13 rom_sin U1(14 .address(address),15 .clock(clock),16 .q(SinData)17 );18 19 rom_squ U2(20 .address(address),21 .clock(clock),22 .q(SquData)23 );24 25 rom_tri U3(26 .address(address),27 .clock(clock),28 .q(TriData)29 );30 31 assign q = WaveChoose[0]?SinData:(WaveChoose[1]?SquData:TriData);32 endmodule
数字电路期末课程设计总结(三)IIC总线调用