基于SCCB协议的FPGA实现
SCCB协议
1、协议内容
SCCB协议常用于vo系列的摄像头的寄存器配置中,是有IIC协议演变而来。本来,本人接触这个协议也是想配置摄像头用于摄像模块。但是,由于配置寄存器实在是太多,而且需要找的资料也比较多,就放弃了,以后有时间再去完成吧。现在先将SCCB协议的设计过程记录下来,方便以后查找。
SCCB协议的内容和IIC协议的内容大致相似。有开始位、数据位和结束位。只不过开始位和结束位的形式还是有所不同的。当然,这里指的是双线的SCCB协议,至于三线的协议,只是了解过,感兴趣可以在网上查一下。

这里是一相数据的简图(图中应该有九个数据,由于前期理解不到位认为是八个)。可以看到除了开始位和结束位发生了“错位”,其他的类型和IIC基本一样。
在SCCB中,一次完整的传输不是以一相为单位的,而是两相或三相为单位的。两相是用于读取数据,而三相则是用于写入数据。
这是设计时画的状态机简图,还是比较简单的,七个状态单个循环就可以实现。具体的时间间隔在代码中有,可以从数据手册中可以找到最小值。这里不做过多的细节介绍。
同理,写操作还要比读简单,只需要一次三相操作即可。只需要将状态机的状态数减为4,将数据传输状态的有两相改为三相即可。这里在代码中会有具体的体现。
2、FPGA设计(verilog)
从前面的简介看还是比较简单的,但是细节还是比较多,下面给一张细节图供后续的设计。

前面提到了使用状态机实现,自然需要构建状态机。
module sccb_read (
input clk,
input rst_n,
input work,
output work_end, input sio_din,
output reg sio_dcr,
output reg sio_c,
output reg sio_dout,
output reg [7:0] data_get
);
localparam D3000=3000;
localparam D1500=D3000/2;
localparam Cnt_D1500=D1500/20;
localparam Cnt_D3000=D3000/20;
localparam T54000n=Cnt_D3000*19;
localparam T15000n=Cnt_D3000*10;
localparam S1=4'd0;
localparam S2=4'd1;
localparam S3=4'd2;
localparam S4=4'd3;
localparam S5=4'd4;
localparam S6=4'd5;
localparam S7=4'd6;
wire [8:0] id;
wire [8:0] ad;
wire [8:0] id2;
assign id={8'h42,1'b0};
assign ad={8'h03,1'b0};
assign id2={8'h43,1'b0}; reg [3:0] state_now;
reg [3:0] state_nxt;
reg [7:0] cnt_wait;
reg [7:0] cnt_start;
reg [11:0] cnt_data;
reg [11:0] cnt_stop;
reg [7:0] cnt_start2;
reg [11:0] cnt_data2;
reg [11:0] cnt_stop2; reg [4:0] cnt_site;
reg [7:0] cnt_clk;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
state_now<=S1;
end
else begin
case(state_now)
S1: if(work && cnt_wait==Cnt_D3000-1'b1)state_now<=state_nxt;
S2: if(cnt_start==Cnt_D3000-1'b1)state_now<=state_nxt;
S3: if(cnt_data==T54000n-1'b1)state_now<=state_nxt;
S4: if(cnt_stop==T15000n-1'b1)state_now<=state_nxt;
S5: if(cnt_start2==Cnt_D3000-1'b1)state_now<=state_nxt;
S6: if(cnt_data2==T54000n-1'b1)state_now<=state_nxt;
S7: if(cnt_stop2==T15000n-1'b1)state_now<=state_nxt;
endcase
end
end
always@(*)begin
case(state_now)
S1: state_nxt<=S2;
S2: state_nxt<=S3;
S3: state_nxt<=S4;
S4: state_nxt<=S5;
S5: state_nxt<=S6;
S6: state_nxt<=S7;
S7: state_nxt<=S1;
endcase
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_wait<=1'b0;
end
else if(cnt_wait==Cnt_D3000)begin
cnt_wait<=1'b0;
end
else if(state_now==S1 )begin
if(work)begin
cnt_wait<=cnt_wait+1'b1;
end
end
else begin
cnt_wait<=1'b0;
end end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_start<=1'b0;
end
else if(cnt_start==Cnt_D3000-1'b1) begin
cnt_start<=1'b0;
end
else if(state_now==S2)begin
cnt_start<=cnt_start+1'b1;
end
else begin
cnt_start<=1'b0;
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_data<=1'b0;
end
else if(cnt_data==T54000n -1'b1)begin
cnt_data<=1'b0;
end
else if(state_now==S3 ) begin
cnt_data<=cnt_data+1'b1;
end
else begin
cnt_data<=1'b0;
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_stop<=1'b0;
end
else if(cnt_stop==T15000n-1'b1) begin
cnt_stop<=1'b0;
end
else if(state_now==S4)begin
cnt_stop<=cnt_stop+1'b1;
end
else begin
cnt_stop<=1'b0;
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_start2<=1'b0;
end
else if(cnt_start2==Cnt_D3000-1'b1) begin
cnt_start2<=1'b0;
end
else if(state_now==S5)begin
cnt_start2<=cnt_start2+1'b1;
end
else begin
cnt_start2<=1'b0;
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_data2<=1'b0;
end
else if(cnt_data2==T54000n -1'b1)begin
cnt_data2<=1'b0;
end
else if(state_now==S6 ) begin
cnt_data2<=cnt_data2+1'b1;
end
else begin
cnt_data2<=1'b0;
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_stop2<=1'b0;
end
else if(cnt_stop2==T15000n-1'b1) begin
cnt_stop2<=1'b0;
end
else if(state_now==S7)begin
cnt_stop2<=cnt_stop2+1'b1;
end
else begin
cnt_stop2<=1'b0;
end
end
这里是状态机的主体部分和驱动部分。由于这个协议的时间是有具体的要求,所以这里所有的状态转化都是基于特定的时间长度来构建的,而不是采用控制方式。除了第一个状态是需要外部驱动,其他的状态都是可以基于时间自行运转的,这也简化了后续的仿真时的难度。那个部分的状态不对可以直接对应到时间上,而不是去判断多个判断信号。本人认为这段代码还是比较基础的,就没有加上注释。
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_clk<=1'b0;
end
else if(cnt_clk==Cnt_D1500-1'b1)begin
cnt_clk<=1'b0;
end
else if(state_now==S3 || state_now== S6) begin
cnt_clk<=cnt_clk+1'b1;
end
else begin
cnt_clk<=1'b0;
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
sio_c<=1'b1;
end
else begin
case(state_now)
S1:sio_c<=1'b1;
S2:sio_c<=1'b1;
S3:if(cnt_clk==Cnt_D1500-1'b1)sio_c=~sio_c;
S4:sio_c<=1'b1;
S5:sio_c<=1'b1;
S6:if(cnt_clk==Cnt_D1500-1'b1)sio_c=~sio_c;
S7:sio_c<=1'b1;
endcase
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_site<=1'b0;
end
else if(state_now==S3 || state_now==S6) begin
if(cnt_clk==Cnt_D1500/2-1'b1 && sio_c==1'b0 )begin
cnt_site<=cnt_site+1'b1;
end
else begin
cnt_site<=cnt_site;
end
end
else begin
cnt_site<=1'b0;
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
sio_dout<=1'b1;
end
else begin
case(state_now)
S1:sio_dout<=1'b1;
S2:if(cnt_start==Cnt_D1500-1'b1)sio_dout<=1'b0;
S3:begin
case(cnt_site)
5'd0:sio_dout<=sio_dout;
5'd1:sio_dout<=id[8];
5'd2:sio_dout<=id[7];
5'd3:sio_dout<=id[6];
5'd4:sio_dout<=id[5];
5'd5:sio_dout<=id[4];
5'd6:sio_dout<=id[3];
5'd7:sio_dout<=id[2];
5'd8:sio_dout<=id[1];
5'd9:sio_dout<=id[0];
5'd10:sio_dout<=ad[8];
5'd11:sio_dout<=ad[7];
5'd12:sio_dout<=ad[6];
5'd13:sio_dout<=ad[5];
5'd14:sio_dout<=ad[4];
5'd15:sio_dout<=ad[3];
5'd16:sio_dout<=ad[2];
5'd17:sio_dout<=ad[1];
5'd18:sio_dout<=ad[0];
5'd19:sio_dout<=1'b0;
default:sio_dout<=sio_dout;
endcase
end
S4:if(cnt_stop==Cnt_D1500-1'b1)sio_dout<=1'b1;
S5:if(cnt_start2==Cnt_D1500-1'b1)sio_dout<=1'b0;
S6:begin
case(cnt_site)
5'd0:sio_dout<=sio_dout;
5'd1:sio_dout<=id2[8];
5'd2:sio_dout<=id2[7];
5'd3:sio_dout<=id2[6];
5'd4:sio_dout<=id2[5];
5'd5:sio_dout<=id2[4];
5'd6:sio_dout<=id2[3];
5'd7:sio_dout<=id2[2];
5'd8:sio_dout<=id2[1];
5'd9:sio_dout<=id2[0];
5'd18:sio_dout<=1'b1;
5'd19:sio_dout<=1'b0;
default:sio_dout<=sio_dout;
endcase
end
S7:if(cnt_stop2==Cnt_D1500-1'b1)sio_dout<=1'b1;
endcase
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
sio_dcr<=1'b1;
end
else begin
case(state_now)
S1:sio_dcr<=1'b1;
S2,S3,S4,S5,S7:sio_dcr<=1'b1;
S6:if(5'd9<cnt_site && cnt_site<5'd18)sio_dcr<=1'b0;else sio_dcr<=1'b1;
endcase
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
data_get<=8'b1111_1111;
end
else if(state_now==S6 && cnt_clk==Cnt_D1500/2-1'b1 && sio_c==1'b1 ) begin
case(cnt_site)
5'd10: data_get[7]<=sio_din;
5'd11: data_get[6]<=sio_din;
5'd12: data_get[5]<=sio_din;
5'd13: data_get[4]<=sio_din;
5'd14: data_get[3]<=sio_din;
5'd15: data_get[2]<=sio_din;
5'd16: data_get[1]<=sio_din;
5'd17: data_get[0]<=sio_din;
endcase
end
end
assign work_end=(state_now==S7 && cnt_stop2==T15000n-1'b1);
endmodule
这段代码则是有了状态机的基础上,针对所需的输出,构建的输出模型。具体的比较复杂,我也记不大清楚细节。大致看一下,最好自己写。这是SCCB实现的关键逻辑。
至于写模块就是这个模块的删减和增加,直接上代码即可:
module sccb_write (
input clk,
input rst_n,
input work,
input [15:0] data_sum,
output work_end,
// input sio_din,
output reg sio_dcr,
output reg sio_c,
output reg sio_dout
);
localparam D3000=3000;
localparam D1500=D3000/2;
localparam Cnt_D1500=D1500/20;
localparam Cnt_D3000=D3000/20;
localparam T81000n=Cnt_D3000*28;
localparam T15000n=Cnt_D3000*10;
localparam S1=4'd0;
localparam S2=4'd1;
localparam S3=4'd2;
localparam S4=4'd3;
wire [8:0] id;
wire [8:0] ad;
wire [8:0] da;
assign id={8'h42,1'b0};
assign ad={data_sum[15:8],1'b0};
assign da={data_sum[7:0],1'b0};
reg [1:0] state_now;
reg [1:0] state_nxt;
reg [7:0] cnt_wait;
reg [7:0] cnt_start;
reg [14:0] cnt_data;
reg [11:0] cnt_stop; reg [4:0] cnt_site;
reg [7:0] cnt_clk;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
state_now<=S1;
end
else begin
case(state_now)
S1: if(work && cnt_wait==Cnt_D3000-1'b1)state_now<=state_nxt;
S2: if(cnt_start==Cnt_D3000-1'b1)state_now<=state_nxt;
S3: if(cnt_data==T81000n-1'b1)state_now<=state_nxt;
S4: if(cnt_stop==T15000n-1'b1)state_now<=state_nxt;
endcase
end
end
always@(*)begin
case(state_now)
S1: state_nxt<=S2;
S2: state_nxt<=S3;
S3: state_nxt<=S4;
S4: state_nxt<=S1;
endcase
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_wait<=1'b0;
end
else if(cnt_wait==Cnt_D3000)begin
cnt_wait<=1'b0;
end
else if(state_now==S1 )begin
if(work)begin
cnt_wait<=cnt_wait+1'b1;
end
end
else begin
cnt_wait<=1'b0;
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_start<=1'b0;
end
else if(cnt_start==Cnt_D3000-1'b1) begin
cnt_start<=1'b0;
end
else if(state_now==S2)begin
cnt_start<=cnt_start+1'b1;
end
else begin
cnt_start<=1'b0;
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_data<=1'b0;
end
else if(cnt_data==T81000n -1'b1)begin
cnt_data<=1'b0;
end
else if(state_now==S3 ) begin
cnt_data<=cnt_data+1'b1;
end
else begin
cnt_data<=1'b0;
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_stop<=1'b0;
end
else if(cnt_stop==T15000n-1'b1) begin
cnt_stop<=1'b0;
end
else if(state_now==S4)begin
cnt_stop<=cnt_stop+1'b1;
end
else begin
cnt_stop<=1'b0;
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_clk<=1'b0;
end
else if(cnt_clk==Cnt_D1500-1'b1)begin
cnt_clk<=1'b0;
end
else if(state_now==S3 ) begin
cnt_clk<=cnt_clk+1'b1;
end
else begin
cnt_clk<=1'b0;
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
sio_c<=1'b1;
end
else begin
case(state_now)
S1:sio_c<=1'b1;
S2:sio_c<=1'b1;
S3:if(cnt_clk==Cnt_D1500-1'b1)sio_c=~sio_c;
S4:sio_c<=1'b1;
endcase
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_site<=1'b0;
end
else if(state_now==S3 ) begin
if(cnt_clk==Cnt_D1500/2-1'b1 && sio_c==1'b0 )begin
cnt_site<=cnt_site+1'b1;
end
else begin
cnt_site<=cnt_site;
end
end
else begin
cnt_site<=1'b0;
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
sio_dout<=1'b1;
end
else begin
case(state_now)
S1:sio_dout<=1'b1;
S2:if(cnt_start==Cnt_D1500-1'b1)sio_dout<=1'b0;
S3:begin
case(cnt_site)
5'd0:sio_dout<=sio_dout;
5'd1:sio_dout<=id[8];
5'd2:sio_dout<=id[7];
5'd3:sio_dout<=id[6];
5'd4:sio_dout<=id[5];
5'd5:sio_dout<=id[4];
5'd6:sio_dout<=id[3];
5'd7:sio_dout<=id[2];
5'd8:sio_dout<=id[1];
5'd9:sio_dout<=id[0];
5'd10:sio_dout<=ad[8];
5'd11:sio_dout<=ad[7];
5'd12:sio_dout<=ad[6];
5'd13:sio_dout<=ad[5];
5'd14:sio_dout<=ad[4];
5'd15:sio_dout<=ad[3];
5'd16:sio_dout<=ad[2];
5'd17:sio_dout<=ad[1];
5'd18:sio_dout<=ad[0];
5'd19:sio_dout<=da[8];
5'd20:sio_dout<=da[7];
5'd21:sio_dout<=da[6];
5'd22:sio_dout<=da[7];
5'd23:sio_dout<=da[4];
5'd24:sio_dout<=da[3];
5'd25:sio_dout<=da[2];
5'd26:sio_dout<=da[1];
5'd27:sio_dout<=da[0];
5'd28:sio_dout<=1'b0;
default:sio_dout<=sio_dout;
endcase
end
S4:if(cnt_stop==Cnt_D1500-1'b1)sio_dout<=1'b1;
endcase
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
sio_dcr<=1'b0;
end
else if(work) begin
sio_dcr<=1'b1;
end
else begin
sio_dcr<=1'b1;
end
end
assign work_end=(state_now==S4 && cnt_stop==T15000n-1'b1);
endmodule
实现的功能就是一次数据写入。
然后是顶层的模块:
module vo(
input clk,
input rst_n, inout sio_d,
output sio_c,
output pwdn,
output reset,
output xclk, output [7:0] data_get
);
reg work_r;
reg work_w;
wire sio_din;
wire work_end_r;
wire work_end_w;
wire sio_dcr;
wire sio_dcr_r;
wire sio_dcr_w;
wire sio_dout;
wire sio_dout_r;
wire sio_dout_w;
wire sio_c_r;
wire sio_c_w;
reg [15:0] data_sum; wire locked;
assign sio_d = (sio_dcr) ? sio_dout : 1'bz;
assign sio_din = sio_d; assign sio_dout = sio_dout_r & sio_dout_w;
assign sio_c = sio_c_r & sio_c_w;
assign sio_dcr = sio_dcr_r & sio_dcr_w; assign pwdn=1'b0;
assign reset=1'b1;
reg [7:0] cnt_work; always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_work<=1'b0;
end
else if(cnt_work==8'd11)begin
cnt_work<=8'd11;
end
else if(cnt_work==8'd10 && work_end_r)begin
cnt_work<=8'd11;
end
else if(work_end_w)begin
cnt_work<=cnt_work+1'b1;
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
work_w<=1'b0;
end
else if(cnt_work<8'd10 && locked) begin
work_w<=1'b1;
end
else begin
work_w<=1'b0;
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
work_r<=1'b0;
end
else if(cnt_work==8'd10 && locked)begin
work_r<=1'b1;
end
else begin
work_r<=1'b0;
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
data_sum<=16'h1280;
end
else begin
case(cnt_work)
8'd0:data_sum<=16'h1280; // reset sccb reg
8'd1:data_sum<=16'h1101; // raw data half clk
8'd2:data_sum<=16'h3a04; //
8'd3:data_sum<=16'h1201; //
8'd4:data_sum<=16'h1716;
8'd5:data_sum<=16'h1804;
8'd6:data_sum<=16'h1902;
8'd7:data_sum<=16'h1a7b;
8'd8:data_sum<=16'h3280;
8'd9:data_sum<=16'h0306;
default:data_sum<=data_sum;
endcase
end
end
pll pll_1(
.areset(~rst_n),
.inclk0(clk),
.c0(xclk),
.locked(locked)
);
sccb_write m1(
.clk(clk),
.rst_n(rst_n),
.work(work_w),
.data_sum(data_sum),
.work_end(work_end_w),
// input sio_din,
.sio_dcr(sio_dcr_w),
.sio_c(sio_c_w),
.sio_dout(sio_dout_w)
);
sccb_read m2(
.clk(clk),
.rst_n(rst_n),
.work(work_r),
.work_end(work_end_r), .sio_din(sio_din),
.sio_dcr(sio_dcr_r),
.sio_c(sio_c_r),
.sio_dout(sio_dout_r),
.data_get(data_get) );
本来顶层模块最好不要写逻辑,但是由于只是个人尝试,前期为了省事就在顶层里写了执行循环的模块。这就直接导致后期就不想移动代码。最后就成了这个样子。将就着用吧,本来就是用于测试一下的。
这个顶层的执行模块就是执行十次写数据和一次读数据。值得注意的是关于双向口的编写。这也是在前面读数据模块中会有sio_din,sio_dout,sio_dcr三个输入输出。这是用于模仿三态门。
3、实际结果
由于篇幅有限,仿真文件就不附上了。关于inout的仿真这里简单的说一下。
要在激励文件中设计inout,就要明白对应关系。使用同样的方法将inout转化为一个input、一个output和一个控制位。在这里如果想要完全模拟SCCB的从机,需要使用复杂的逻辑来判断读取和写入的状态。但是,如果只是想要简单地了解自己的设计是否成功,只需要将其强制为接受状态就行。
结果的话就展示一下modelsim的仿真图。

这部分是读的时序逻辑。

这部分是写的逻辑,由于修改模块输入后没有修改激励的输出,所以地址位和数据位是没有值的。

这是顶层模块的结果图。
在实际的板级测试时,数据基本上写读一致。由于只是测试了几个寄存器,也不确定是不是所有的都可行,这里就到此为止了。以后有时间可以应用到摄像头上。
基于SCCB协议的FPGA实现的更多相关文章
- SATA主机协议的FPGA实现之准备工作
SATA主机协议的FPGA实现之准备工作 从2月中旬准备开始,经过3个月的奋战,我的又一个项目--基于FPGA的固态硬盘读写控制电路,已经基本实现.由于实用资料的匮乏,以及项目本身颇具挑战性,这个 ...
- 千兆以太网TCP协议的FPGA实现
转自https://blog.csdn.net/zhipao6108/article/details/82386355 千兆以太网TCP协议的FPGA实现 Lzx 2017/4/20 写在前面,这应该 ...
- OV7725学习之SCCB协议(一)
OV7725摄像头只能作为从机,通过SCCB协议配置内置的172个寄存器.因此首先要了解的就是SCCB总线 1.SCCB协议简述 SCCB协议有两线也有三线,两线为SIO_C与SIO_D,三线为SIO ...
- 集成基于OAuth协议的单点登陆
在之前的一篇文章中,我们已经介绍了如何为一个应用添加对CAS协议的支持,进而使得我们的应用可以与所有基于CAS协议的单点登陆服务通讯.但是现在的单点登陆服务实际上并不全是通过实现CAS协议来完成的.例 ...
- 集成基于CAS协议的单点登陆
相信大家对单点登陆(SSO,Single Sign On)这个名词并不感到陌生吧?简单地说,单点登陆允许多个应用使用同一个登陆服务.一旦一个用户登陆了一个支持单点登陆的应用,那么在进入其它使用同一单点 ...
- 基于Z-WAVE 协议的LED智能照明系统的研究笔记
LED调光基础: ☆:LED照明调光控制信号的方式有两种: 1. 通过PWM信号控制LED灯具开关电源的占空比从而实现调光: 2. 通过调光控制信号和交流电源供电线合用的两线式或三线式(例如LED相控 ...
- 基于UDP协议模拟的一个TCP协议传输系统
TCP协议以可靠性出名,这其中包括三次握手建立连接,流控制和拥塞控制等技术.详细介绍如下: 1. TCP协议将需要发送的数据分割成数据块.数据块大小是通过MSS(maximum segment siz ...
- 性能测试总结工作总结-基于WebService协议脚本 内置函数手动编写
LoadRunner基于WebService协议脚本 WebService协议脚本有三种生成方式,一种是直接通过LoadRunner导入URL自动解析生成:一种是使用LoadRunner内置函数手动编 ...
- 网络编程——基于TCP协议的Socket编程,基于UDP协议的Socket编程
Socket编程 目前较为流行的网络编程模型是客户机/服务器通信模式 客户进程向服务器进程发出要求某种服务的请求,服务器进程响应该请求.如图所示,通常,一个服务器进程会同时为多个客户端进程服务,图中服 ...
- 基于XMPP协议的Android即时通信系
以前做过一个基于XMPP协议的聊天社交软件,总结了一下.发出来. 设计基于开源的XMPP即时通信协议,采用C/S体系结构,通过GPRS无线网络用TCP协议连接到服务器,以架设开源的Openfn'e服务 ...
随机推荐
- Ubuntu下使用PlatformIO开发STC89/STC12/Arduino
安装VSCode 从 https://code.visualstudio.com/Download 下载最新的 deb 版, 通过命令行安装 sudo apt install ./code_1.59. ...
- STM32F401的PWM输出
PWM的说明 PWM有三个关键指标: PWM频率, 占空比, 区分度 对于同一个时钟频率下工作的单片机, 区分度是和PWM工作频率相关的, 因为总频率是固定的, PWM工作频率越高, 留下给区分度的部 ...
- 使用TensorFlow实现MNIST数据集分类
1 MNIST数据集 MNIST数据集由70000张28x28像素的黑白图片组成,每一张图片都写有0~9中的一个数字,每个像素点的灰度值在0 ~ 255(0是黑色,255是白色)之间. MINST数据 ...
- Vue+SpringBoot+ElementUI实战学生管理系统-3.表结构设计
1.章节介绍 前一篇介绍了如何搭建前端工程,这一篇讲一下表结构设计,需要的朋友可以拿去自己定制.:) 2.获取源码 源码是捐赠方式获取,详细请QQ联系我 :)! 3.项目截图 登录页 列表操作 动态图 ...
- C# readonly修饰符
readonly修饰符在作祟 强化官方解释: readonly是一个修饰字段的关键字:被它修饰的字段只有在初始化或者构造函数中才能够赋值. readonly修饰的引用类型字段必须始终引用同一对象: r ...
- win32 - QueryDisplayConfig的使用
QueryDisplayConfig函数检索关于所有显示设备的所有可能的显示路径,或视图,在当前设置的信息. C++样本: (开箱即用) 代码列出了所有显示器的名称和拓展模式 #include < ...
- 硬件开发笔记(七): 硬件开发基本流程,制作一个USB转RS232的模块(六):创建0603封装并关联原理图元器件
前言 有了原理图,可以设计硬件PCB,在设计PCB之间还有一个协同优先动作,就是映射封装,原理图库的元器件我们是自己设计的.为了更好的表述封装设计过程,本文描述了贴片电阻电容0603芯片封装,创建 ...
- 项目实战:Qt + 树莓派3B+ 智能笔筒系统
红胖子(红模仿)的博文大全:开发技术集合(包含Qt实用技术.树莓派.三维.OpenCV.OpenGL.ffmpeg.OSG.单片机.软硬结合等等)持续更新中-(点击传送门) 需求 1.基于树莓 ...
- 07-Redis系列之-双写一致性,缓存详解和优化点
双写一致性 双写一致性指的是当我们更新了数据库的数据之后redis中的数据也要同步去更新. redis和mysql数据同步方案 先更新缓存,再更新数据库(然并软...) 先更新数据库,再更新缓存(一般 ...
- MBD工具链的云部署
MBD工具链的云部署 "云技术永远不会用于汽车开发".说到云部署在汽车行业的应用,业界曾经认为云技术并不适合用在汽车行业的产品开发.知识产权保护.数据的安全.流程不够透明.迁移成本 ...