通信协议篇——I2C通信

通信协议篇——I2C通信

1.简介

I2C(Inter-Integrated Circuit)是一种串行通信总线,总线上可以挂多个设备,可实现同步半双工通信。

2.原理

通信方式

I2C通信属于串行通信,使用串行数据线SDA和串行时钟线SCL两线实现同步半双工通信。

同步接收端时钟频率和发送端时钟频率一致
异步接收端时钟频率和发送端时钟频率不一致

同步通信和异步通信的区别:

  • 异步通信中的接收方并不知道数据什么时候会到达,收发双方可以有各自自己的时钟。发送方发送的时间间隔可以不均,接收方是在数据的起始位和停止位的帮助下实现信息同步的。这种传输通常是很小的分组,比如一个字符为一组,为这个组配备起始位和结束位。所以这种传输方式的效率是比较低的,毕竟额外加入了很多的辅助位作为负载,常用在低速的传输中。
  • 同步通信中双方使用频率一致的时钟 ,它的分组相比异步通信则大得多,称为一个数据帧,通过独特的bit串作为启停标识。发送方要以固定的节奏去发送数据,而接收方要时刻做好接收数据的准备,识别到前导码后马上要开始接收数据了。同步这种方式中因为分组很大,很长一段数据才会有额外的辅助位负载,所以效率更高,更加适合对速度要求高的传输,当然这种通信对时序的要求也更高。
单工在任何时间,数据只能单向传输
半双工能够双向通信,但通信双方不能同时进行数据收发,在同一时刻只有一方发送另一方接收
全双工能够双向通信,且通信双方能够同时进行数据收发,两者同步进行

I2C通信中,主机通过时钟线SCL发送时钟信号,通过数据线SDA发送数据(包括从机地址、指令、数据包等),在发送完一帧数据后,需要等待从机的响应,才能继续发送下一帧数据,因此I2C属于同步通信。

I2C通信中,数据在一根数据线SDA上传输,同一时刻数据传输的方向只能是单向的,从A到B或者从B到A;通过切换传输方向从而实现双向通信,因此I2C属于半双工通信。

数据格式

I2C通信的数据包大小为8bit,主要有三类——指令、字节地址、数据。数据传输时,按照高位在前,低位在后的顺序(即MSB First,LSB Last)。

类型格式
指令7位从机地址+1位读写命令(写0,读1)
字节地址8位字节地址,从这个地址开始读写数据
数据8位数据

I2C通信通过时钟线SCL和数据线SDA确定几种通信状态——空闲状态、启动信号、停止信号、数据位传输、应答信号。

空闲状态

当I2C总线的SDA和SCL两条信号线同时处于高电平时,规定为总线的空闲状态。此时各个器件的输出级场效应管均处在截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高。

启动信号

在时钟线SCL保持高电平期间,数据线SDA上的下降沿,定义为I2C总线的启动信号,它标志着一次数据传输的开始。启动信号是由主机建立的,在建立该信号之前,I2C总线必须处于空闲状态。

停止信号

在时钟线SCL保持高电平期间,数据线SDA上的上升沿,定义为I2C总线的停止信号,它标志着一次数据传输的终止。停止信号是由主机建立的,建立该信号之后,I2C总线将返回空闲状态。

在这里插入图片描述

数据位传输

在I2C通信中,时钟线SCL上的每一个时钟,同步对应着数据线SDA上的一位数据。即在SCL串行时钟的配合下,在SDA上逐位地串行传送每一位数据。进行数据传送时,在SCL是高电平期间,SDA上的电平必须保持稳定,低电平为数据0,高电平为数据1。只有在SCL为低电平期间,才允许SDA上的电平改变状态。

应答信号

I2C总线上的所有数据都是以8bit字节传输的,发送器每发送一个字节,就在第9个时钟开始时释放数据线,由接收器反馈一个应答信号。应答信号为低电平时,规定为有效应答位(ACK),表示接收器已经成功地接收了该字节;应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。对于反馈有效应答位ACK的要求是,接收器在第9个时钟脉冲之前的低电平期间将SDA线拉低,并且确保在该时钟的高电平期间为稳定的低电平。
如果接收器是主控器,则在它收到最后一个字节后,发送一个NACK信号,以通知被控发送器结束数据发送,并释放SDA线,以便主控接收器发送一个停止信号。
在这里插入图片描述

操作时序

I2C设备的操作时序有四种,分别为写单个存储字节,写多个存储字节,读单个存储字节和读多个存储字节。操作时序如下图:

在这里插入图片描述

具体通信过程

以写单个存储字节这一操作为例,介绍I2C通信的具体流程:

​ 初始状态:SCL、SDA都为高电平,总线处于空闲状态;

→启动信号:在SCL为高电平时,SDA由高变低,产生下降沿,此时I2C通信开始启动;

→发送7位从机地址和1位读写指令:按位传输,按照高位在前、低位在后的顺序,且遵循SCL高电平时SDA上的数据保持不变,SCL低电平时SDA上的数据发生改变的原则,每个时钟脉冲发送一位地址数据;

→接收响应:I2C通信中,每发送完8bit数据,会接收1bit响应;此时,主机先把数据线SDA释放,然后在第9个时钟脉冲的高电平期间读取SDA上的应答信号,0代表ACK信号,1代表NACK信号;只有接收到ACK信号,才继续之后的操作,否则重新开始通信过程;

→发送8位字节地址:同上;

→接收响应:同上;

→写入8位数据:同上;

→接收响应:同上;

→停止信号:在SCL为高电平时,SDA由低变高,产生上升沿,此时I2C通信结束。

其他三种操作的具体流程是类似的。

标准接口
namedescriptiondirectionlength
clk系统时钟input1
rst复位信号input1
sclI2C串行时钟线output1
sdaI2C串行数据线inout1
rd_sigI2C读命令input1
wr_sigI2C写命令input1
rd_dataI2C读取的数据output8
wr_dataI2C写入的数据input8
addrI2C读/写的开始字节地址input8
done_sigI2C读/写操作完成信号output1

3.程序实现

通过EEPROM的读写操作,验证I2C通信的程序实现。

RTL视图

在这里插入图片描述

I2C控制模块
`timescale 1ns/1ps

//Module Name	:	iic_control
//Description	:	read and write eeprom using iic bus
//Editor		:	Yongxiang
//Time			:	2019-11-25

module iic_control
	(
		input wire	clk_50M,
		input wire	rst_n,
		output reg	wr_sig,
		output reg	rd_sig,
		output reg[7:0]	addr_sig,
		output reg[7:0]	wr_data,
		input wire	done_sig
	);

reg[1:0] state;

//eeprom先写后读
always @(posedge clk_50M)
begin
	if(!rst_n)begin
		state <= 2'd0;
		addr_sig <= 8'd0;
		wr_data <= 8'd0;
		rd_sig <= 1'b0;
		wr_sig <= 1'b0;
	end
	else begin
		case(state)
			2'd0:begin
				if(done_sig)begin
					wr_sig <= 1'b0;
					rd_sig <= 1'b0;
					state <= 2'd1;
				end
				else begin
					wr_sig <= 1'b1;
					rd_sig <= 1'b0;
					wr_data <= 8'hff;	//写入数据0Xff
					addr_sig <= 8'd0;	//在eeprom的0X00地址写入数据
				end
			end
			2'd1:begin
				if(done_sig)begin
					wr_sig <= 1'b0;
					rd_sig <= 1'b0;
					state <= 2'd2;
				end
				else begin
					wr_sig <= 1'b0;
					rd_sig <= 1'b1;
					addr_sig <= 8'd0;	//在eeprom的0X00地址写入数据
				end
			end
			2'd2:begin
				state <= 2'd2;
			end
		endcase
	end
end

endmodule

I2C通信模块
`timescale 1ns/1ps

//module name	:	iic
//description	:	iic communication module
//Editor		:	Yongxiang
//Time			:	2019-11-25

module iic
	(
		input wire clk_50M,
		input wire rst_n,
		input wire wr_sig,	//写命令,1有效
		input wire rd_sig,	//读命令,1有效
		input wire[7:0] addr_sig,	//数据地址
		input wire[7:0] wr_data,	//写数据
		output reg[7:0] rd_data,	//读数据
		output reg done_sig,	//读写完成标志,1有效
		output reg scl,
		inout wire sda
	);
	
reg[4:0] state;
reg[4:0] state_save;
reg[8:0] cnt;
reg[7:0] data_reg;
reg is_out;
reg sda_reg;
reg is_ask_n;	//应答信号,0有效

assign sda = is_out ? sda_reg : 1'bz;	//SDA输入输出方向控制

//IIC读写数据
always @(posedge clk_50M)
begin
	if(!rst_n)begin		//系统复位
		state <= 5'd0;
		cnt <= 9'd0;
		sda_reg <= 1'b1;	//SDA置高
		scl <= 1'b1;		//SCL置高
		is_out <= 1'b1;
		is_ask_n <= 1'b1;	
		rd_data <= 8'd0;
		done_sig <= 1'b0;
	end
	else if(wr_sig)begin		//iic数据写
		case(state)
			5'd0:begin	//iic启动
				is_out <= 1'b1;		//SDA输出
				if(cnt == 9'd0)begin
					scl <= 1'b1;
					sda_reg <= 1'b1;
					cnt <= cnt + 9'd1;
				end
				else if(cnt == 9'd100)begin
					sda_reg <= 1'b0;	//启动信号:在SCL为1时,SDA的下降沿
					cnt <= cnt + 9'd1;
				end
				else if(cnt == 9'd200)begin
					scl <= 1'b0;
					cnt <= cnt + 9'd1;
				end
				else if(cnt == 9'd249)begin
					cnt <= 9'd0;
					state <= 5'd1;
				end
				else begin
					cnt <= cnt + 9'd1;
				end
			end
			5'd1:begin	//发送7位从机地址、1位写命令
				data_reg <= 8'hA0;
				state <= 5'd7;
				state_save <= 5'd2;
			end
			5'd2:begin	//发送数据写入地址
				data_reg <= addr_sig;
				state <= 5'd7;
				state_save <= 5'd3;
			end
			5'd3:begin	//写入数据
				data_reg <= wr_data;
				state <= 5'd7;
				state_save <= 5'd4;
			end
			5'd4:begin	//iic停止
				is_out <= 1'b1;		//SDA输出
				if(cnt == 9'd0)begin
					scl <= 1'b0;
					sda_reg <= 1'b0;
					cnt <= cnt + 9'd1;
				end
				else if(cnt == 9'd50)begin
					scl <= 1'b1;		
					cnt <= cnt + 9'd1;
				end
				else if(cnt == 9'd150)begin
					sda_reg <= 1'b1;	//停止信号:在SCL为1时,SDA的上升沿
					cnt <= cnt + 9'd1;
				end
				else if(cnt == 9'd249)begin
					cnt <= 9'd0;
					state <= 5'd5;
				end
				else begin
					cnt <= cnt + 9'd1;
				end
			end
			5'd5:begin	//写iic结束
				done_sig <= 1'b1;
				state <= 5'd6;
			end
			5'd6:begin
				done_sig <= 1'b0;
				state <= 5'd0;
			end
			
			5'd7,5'd8,5'd9,5'd10,5'd11,5'd12,5'd13,5'd14:begin	//发送一个字节
				is_out <= 1'b1;
				sda_reg <= data_reg[14-state];		//高位先发送
				if(cnt == 9'd0)begin
					scl <= 1'b0;
					cnt <= cnt + 9'd1;
				end
				else if(cnt == 9'd50)begin
					scl <= 1'b1;
					cnt <= cnt + 9'd1;
				end
				else if(cnt == 9'd150)begin
					scl <= 1'b0;
					cnt <= cnt + 9'd1;
				end
				else if(cnt == 9'd199)begin
					cnt <= 9'd0;
					state <= state + 5'd1;
				end
				else begin
					cnt <= cnt + 9'd1;
				end
			end
			5'd15:begin	//等待应答
				is_out <= 1'b0;	//SDA输入
				if(cnt == 9'd0)begin
					scl <= 1'b0;
					cnt <= cnt + 9'd1;
				end
				else if(cnt == 9'd50)begin
					scl <= 1'b1;
					cnt <= cnt + 9'd1;
				end
				else if(cnt == 9'd100)begin
					is_ask_n <= sda;
					cnt <= cnt + 9'd1;
				end
				else if(cnt == 9'd150)begin
					scl <= 1'b0;
					cnt <= cnt + 9'd1;
				end
				else if(cnt == 9'd199)begin
					cnt <= 9'd0;
					state <= state + 5'd1;
				end
				else begin
					cnt <= cnt + 9'd1;
				end
			end
			5'd16:begin
				if(!is_ask_n)begin	//接收到应答信号
					state <= state_save;
				end
				else begin
					state <= 5'd0;
				end
			end
		endcase
	end
	else if(rd_sig)begin		//iic数据读
		case(state)
			5'd0:begin	//iic启动
				is_out <= 1'b1;		//SDA输出
				if(cnt == 9'd0)begin
					scl <= 1'b1;
					sda_reg <= 1'b1;
					cnt <= cnt + 9'd1;
				end
				else if(cnt == 9'd100)begin
					sda_reg <= 1'b0;	//启动信号:在SCL为1时,SDA的下降沿
					cnt <= cnt + 9'd1;
				end
				else if(cnt == 9'd200)begin
					scl <= 1'b0;
					cnt <= cnt + 9'd1;
				end
				else if(cnt == 9'd249)begin
					cnt <= 9'd0;
					state <= 5'd1;
				end
				else begin
					cnt <= cnt + 9'd1;
				end
			end
			5'd1:begin	//发送7位从机地址、1位写命令
				data_reg <= 8'hA0;
				state <= 5'd9;
				state_save <= 5'd2;
			end
			5'd2:begin	//发送读取数据地址
				data_reg <= addr_sig;
				state <= 5'd9;
				state_save <= 5'd3;
			end
			5'd3:begin	//iic再次启动
				is_out <= 1'b1;		//SDA输出
				if(cnt == 9'd0)begin
					scl <= 1'b1;
					sda_reg <= 1'b1;
					cnt <= cnt + 9'd1;
				end
				else if(cnt == 9'd100)begin
					sda_reg <= 1'b0;	//启动信号:在SCL为1时,SDA的下降沿
					cnt <= cnt + 9'd1;
				end
				else if(cnt == 9'd200)begin
					scl <= 1'b0;
					cnt <= cnt + 9'd1;
				end
				else if(cnt == 9'd249)begin
					cnt <= 9'd0;
					state <= 5'd4;
				end
				else begin
					cnt <= cnt + 9'd1;
				end
			end
			5'd4:begin	//发送7位从机地址、1位读命令
				data_reg <= 8'hA1;
				state <= 5'd9;
				state_save <= 5'd5;
			end
			5'd5:begin	//读数据
				data_reg <= 8'd0;
				state <= 5'd19;
				state_save <= 5'd6;
			end
			5'd6:begin	//iic停止
				is_out <= 1'b1;		//SDA输出
				if(cnt == 9'd0)begin
					scl <= 1'b0;
					sda_reg <= 1'b0;
					cnt <= cnt + 9'd1;
				end
				else if(cnt == 9'd50)begin
					scl <= 1'b1;		
					cnt <= cnt + 9'd1;
				end
				else if(cnt == 9'd150)begin
					sda_reg <= 1'b1;	//停止信号:在SCL为1时,SDA的上升沿
					cnt <= cnt + 9'd1;
				end
				else if(cnt == 9'd249)begin
					cnt <= 9'd0;
					state <= 5'd7;
				end
				else begin
					cnt <= cnt + 9'd1;
				end
			end
			5'd7:begin	//读iic结束
				done_sig <= 1'b1;
				state <= 5'd8;
			end
			5'd8:begin
				done_sig <= 1'b0;
				state <= 5'd0;
			end
			
			5'd9,5'd10,5'd11,5'd12,5'd13,5'd14,5'd15,5'd16:begin	//发送一个字节
				is_out <= 1'b1;
				sda_reg <= data_reg[16-state];		//高位先发送
				if(cnt == 9'd0)begin
					scl <= 1'b0;
					cnt <= cnt + 9'd1;
				end
				else if(cnt == 9'd50)begin
					scl <= 1'b1;
					cnt <= cnt + 9'd1;
				end
				else if(cnt == 9'd150)begin
					scl <= 1'b0;
					cnt <= cnt + 9'd1;
				end
				else if(cnt == 9'd199)begin
					cnt <= 9'd0;
					state <= state + 5'd1;
				end
				else begin
					cnt <= cnt + 9'd1;
				end
			end
			5'd17:begin	//等待应答
				is_out <= 1'b0;	//SDA输入
				if(cnt == 9'd0)begin
					scl <= 1'b0;
					cnt <= cnt + 9'd1;
				end
				else if(cnt == 9'd50)begin
					scl <= 1'b1;
					cnt <= cnt + 9'd1;
				end
				else if(cnt == 9'd100)begin
					is_ask_n <= sda;
					cnt <= cnt + 9'd1;
				end
				else if(cnt == 9'd150)begin
					scl <= 1'b0;
					cnt <= cnt + 9'd1;
				end
				else if(cnt == 9'd199)begin
					cnt <= 9'd0;
					state <= state + 5'd1;
				end
				else begin
					cnt <= cnt + 9'd1;
				end
			end
			5'd18:begin
				if(!is_ask_n)begin	//接收到应答信号
					state <= state_save;
				end
				else begin
					state <= 5'd0;
				end
			end
			
			5'd19,5'd20,5'd21,5'd22,5'd23,5'd24,5'd25,5'd26:begin	//接收一个字节
				is_out <= 1'b0;
				if(cnt == 9'd0)begin
					scl <= 1'b0;
					cnt <= cnt + 9'd1;
				end
				else if(cnt == 9'd50)begin
					scl <= 1'b1;
					cnt <= cnt + 9'd1;
				end
				else if(cnt == 9'd100)begin
					data_reg[26-state] <= sda;	//高位先接收
					cnt <= cnt + 9'd1;
				end
				else if(cnt == 9'd150)begin
					scl <= 1'b0;
					cnt <= cnt + 9'd1;
				end
				else if(cnt == 9'd199)begin
					cnt <= 9'd0;
					state <= state + 5'd1;
				end
				else begin
					cnt <= cnt + 9'd1;
				end
			end
			5'd27:begin	//无应答信号
				is_out <= 1'b1;	//SDA输入
				rd_data <= data_reg;	//接收完一个字节数据
				if(cnt == 9'd0)begin
					scl <= 1'b0;
					cnt <= cnt + 9'd1;
				end
				else if(cnt == 9'd50)begin
					scl <= 1'b1;
					cnt <= cnt + 9'd1;
				end
				else if(cnt == 9'd150)begin
					scl <= 1'b0;
					cnt <= cnt + 9'd1;
				end
				else if(cnt == 9'd199)begin
					cnt <= 9'd0;
					state <= state_save;
				end
				else begin
					cnt <= cnt + 9'd1;
				end
			end
		endcase
	end
end

endmodule

数码管显示模块

——部分具体实现代码省略(比较简单)

`timescale 1ns/1ps

//module name: smg_demo


module smg_demo
	(
		input clk_50MHz,
		input rst,
		input[7:0] data,
		output[5:0] smg_sig,
		output[7:0] smg_data
		//output rdsig_nextdata
	);

wire clk_1khz, clk_1hz;
	
//clkdiv
smg_clkdiv smg_clkdiv_inst
	(
		.clk_50MHz(clk_50MHz),
		.rst(rst),
		.clk_1khz(clk_1khz),
		.clk_1hz(clk_1hz)
		//.rdsig_nextdata(rdsig_nextdata)
	);
	
//display
smg_display smg_display_inst
	(
		.clk_1khz(clk_1khz),
		.clk_1hz(clk_1hz),
		.rst(rst),
		.data(data),
		.smg_sig(smg_sig),
		.smg_data(smg_data)
	);
	
endmodule

顶层模块
`timescale 1ns/1ps

//Module Name	:	eeprom
//Description	:	top_file
//Editor		:	Yongxiang
//Time			:	2019-11-25

module eeprom
	(
		input wire	clk_50M,
		input wire	rst_n,
		output wire	scl,
		inout wire	sda,
		output wire[5:0] smg_sig,
		output wire[7:0] smg_data
	);
	
wire wr_sig;
wire rd_sig;
wire[7:0] addr_sig;
wire[7:0] wr_data;
wire[7:0] rd_data;
wire done_sig;

//iic_control
iic_control iic_control_inst
	(
		.clk_50M(clk_50M),
		.rst_n(rst_n),
		.wr_sig(wr_sig),
		.rd_sig(rd_sig),
		.addr_sig(addr_sig),
		.wr_data(wr_data),
		.done_sig(done_sig)
	);

//iic
iic iic_inst
	(
		.clk_50M(clk_50M),
		.rst_n(rst_n),
		.wr_sig(wr_sig),		//写命令,1有效
		.rd_sig(rd_sig),		//读命令,1有效
		.addr_sig(addr_sig),	//数据地址
		.wr_data(wr_data),	//写数据
		.rd_data(rd_data),	//读数据
		.done_sig(done_sig),	//读写完成标志,1有效
		.scl(scl),
		.sda(sda)
	);

//smg
smg_demo smg_demo_inst
	(
		.clk_50MHz(clk_50M),
		.rst(rst_n),
		.data(rd_data),
		.smg_sig(smg_sig),
		.smg_data(smg_data)
	);

endmodule
	
  • 5
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
书名:《Visual C++/Turbo C串口通信编程实践》(电子工业出版社.龚建伟.熊光明)。 内容简介 本书从编程实践的角度详细介绍了Windows环境下和DOS环境下的串口通信的基本方法,并根据当前串口与网络结合发展的趋势,介绍了串口与网络TCP/IP、远程控制与监测相结合的一些解决方案和编程要点。由于编程步骤详尽,初学Visual C++/C(甚至是以前完全没有接触过Visual C++)的读者也能很快编写出Visual C++的串口通信程序。本书配光盘,书中实例源程序和相关资料可在对应章节的文件夹中找到。 本书是从事串口及网络通信的技术人员和学习者的极佳参考资料,也可以作为数据通信课程的辅助教材。 作者简介 龚建伟,工学博士,目前在北京理工大学从事科研究与教学工作。主要从事计算机控制技术、顺人和智慧能车辆技术、数据通信技术的研究。 目录 第1章 轻松体验串口通信编程与调试 1 1.1 使用串口调试助手来体验串口通信 1 1.2 体验Windows环境下的Visual C++串口通信编程 4 1.3 体验DOS环境下Turbo C串口通信编程 12 第2章 多线程串口编程工具CSerialPort类 16 2.1 CSerialPort类的功能及成员函数介绍 16 2.2 应用CSerialPort类编制基于对话框的应用程序 30 2.3 应用CSerialPort类编制基于单文档的应用程序 35 2.4 对CSerialPort类的改进 40 2.4.1 改进一:ASCII文本和二进制数据发送方式兼容 40 2.4.2 改进二:也许能解决内存泄漏 43 2.4.3 改进三:彻底关闭串口,释放串口资源 44 第3章 控件MSComm串口编程 46 3.1 MSComm控件介绍 46 3.1.1 VC中应用MSComm控件编程步骤 46 3.1.2 MSComm控件串行通信处理方式 47 3.1.3 MSComm 控件的属性说明 48 3.1.4 MSComm控件错误信息 55 3.2 使用MSComm控件的几个疑难问题 56 3.2.1 使用VARIANT 和SAFEARRAY 数据类型从串口读写数据 56 3.2.2 MSComm控件能离开对话框独立存在吗 59 3.2.3 如何发送接收ASCII值为0和大于128的字符 60 3.2.4 在同一程序中用MSComm控件控制多个串口的具体操作方法 62 3.2.5 解决使用控件编程时程序占用的内存会不断增大的问题 62 3.2.6 在MSComm控件串口编程时遇到的其他问题 63 3.3 在基于单文档(SDI)程序中应用MSComm控件 63 3.4 应用MSComm控件控制多个串口实例 69 3.5 串口与MODEM拨号应用简例 76 3.5.1 创建工程 76 3.5.2 代码分析 78 3.5.3 应用 85 第4章 Windows API串口编程 87 4.1 Windows API串口编程概述 87 4.2 API串口编程中用到的结构及相关概念说明 89 4.2.1 DCB(Device Control Block)结构 89 4.2.2 超时设置COMMTIMEOUTS结构 92 4.2.3 OVERLAPPED异步I/O重叠结构 94 4.2.4 通信错误与通信设备状态 95 4.2.5 串行通信事件 96 4.3 Windows API串行通信函数 97 4.4 Win32 API串口通信编程的一般流程和特殊实例 116 4.4.1 Win32 API串口通信编程的一般流程 116 4.4.2 用查询方式读串口 116 4.4.3 同步I/O读写数据 117 4.4.4 关于流控制的设置问题 118 4.5 CSerialPort类中的API函数编程应用剖析 119 4.6 Win32 API串口编程TTY(虚拟终端)实例 128 4.6.1 建立程序工程 128 4.6.2 建立串口设置对话框 129 4.6.3 编写CTermDoc类的相关代码 132 4.6.4 小结 141 4.6.5 在CTermView类中字添加符键入处理代码与串口接收处理代码 142 第5章 串口调试助手V2.2编程 147 5.1 建立SCOMM程序工程实现界面功能 147 5.2 串口的初始化及关闭 150 5.3 串口数据的发送与接收及十六进制数据的处理 151 5.3.1 十六进数据发送处理 152 5.3.2 手动发送处理 152 5.3.3 自动发送处理 153 5.3.4 接收处理及十六进制显示 154 5.4 其他辅助功能的实现 156 5.4.1 接收数据的文件保存 156 5.4.2 实现小文件发送 158 5.4.3 图钉按钮功能使程序能浮在最上层 161 5.4.4 对话框动画图标的实现 162 5.4.5 超链接功能的实现 164 5.4.6 如何打开帮助网页文件 164 第6章 DOS环境下的Turbo C串口编程及通用实例GSerial类 168 6.1 PC机异步通信适配器8250及其编程操作 169 6.1.1 INS8250内部寄存器及其选择方式 169 6.1.2 波特率设置 169 6.1.3 数据位、奇偶校验、停止位等数据格式设置 170 6.1.4 查询I/O方式相关设置 171 6.1.5 中断I/O通信方式相关设置 171 6.1.6 MODEM寄存器 172 6.2 COMRXTX程序实例 173 6.3 通用实例程序GSerial类 175 6.4 用GSerial类控制多串口 186 6.5 多串口编程PC机高号中断8259A可编程中断控制器的控制 195 第7章 串口通信用户层协议的编制与数据处理方法 197 7.1 通信协议的编制 197 7.1.1 为什么要编制用户通信协议 197 7.1.2 串口通信中用户层协议编制原则 199 7.1.3 在串口通信中几种常用的用户层协议 200 7.2 串口通信数据包处理方法编程实例 202 7.2.1 编程任务 203 7.2.2 编程步骤 203 7.2.3 程序测试 216 第8章 单片机串口通信 218 8.1 单片机串口硬件系统及C51程序开发 218 8.1.1 较典型的单片机硬件系统实例 218 8.1.2 C51语言及程序简介 220 8.1.3 开发C51程序的利器Keil C51 uVision2及串口程序仿真 221 8.2 C51单片机串口通信程序实例 226 8.2.1 实例一 226 8.2.2 实例二 227 第9章 串口与网络结合的解决方案及编程 230 9.1 串口与网络结合的硬件解决方案 230 9.2典型串口与联网的设备 231 9.2.1 NPort5400系列产品的特点 231 9.2.2 NPort 5400系列产品的典型应用介绍 233 9.2.3 NPort5400系列产品的设置与编程测试 235 9.3 与Access数据库结合的串口通信实例 237 9.3.1 微机网络检测系统说明 237 9.3.2 创建ODBC数据源 238 9.3.3 创建工程 239 9.3.4 程序简介 244 9.4 与WinSock结合的串口通信实例 246 9.4.1 客户端应用程序 247 9.4.2 服务器应用程序 252 9.5 在已经编好的串口通信程序中加入网络通信功能 260 9.5.1参照MFC AppWizard创建WinSockets程序 261 9.5.2 利用Windows Sockets API和第三方提供的类进行编程 262 9.6 串口通信用于遥控操作简例 262 第10章 计算机串口与其他设备通信编程实例 266 10.1通过串口收发短消息 266 10.1.1 SMS编码规范及编码与解码例程 266 10.1.2 AT命令收发短消息实例 273 10.1.3 “实时”接收短消息的方法 281 10.1.4 用串口收发SMS短信编程的一些讨论 283 10.2 计算机与Rabbit 2000嵌入式系统通信编程实例 286 10.2.1 Rabbit 2000微处理器介绍 286 10.2.2 动态C(Dynamic C)语言介绍 287 10.2.3 某车载无线调度系统实例介绍 288 10.3 计算机与PLC通信程序实例 294 10.4 MATLAB环境串口编程通信实例 295 10.4.1 MATLAB串口类Serial应用 295 10.4.2 通过串口使MATLAB Simulink与下位机通讯进行控制 299 10.4.3 xPC目标环境下串口通信实现 299 第11章 串口通信基本概念及标准 302 11.1 串口通信基本概念 302 11.1.1 串行通信概述 302 11.1.2 单工、半双工和全双工的定义 305 11.1.3 同步传送与异步传送 306 11.1.4 串行通信协议 306 11.2 RS-232-C串口标准 309 11.2.1 RS-232-C标准 309 11.2.2 RS-232-C串行通信接线实例 312 11.3 RS-422/485串口标准 314 11.3.1 概述 314 11.3.2 RS-422与RS-485串行接口标准 315 11.3.3 RS-422与RS-485的网络安装注意要点 317 11.3.4 RS-232、RS422、RS485电气参数对比 318 11.4 串口调试注意事项 318 11.5 常用数据校验法 318 11.5.1 奇偶校验 318 11.5.2 循环冗余码校验 319 11.6 串口连接和TCP/IP连接对比 320 11.7 现场总线与RS-232、RS-485的本质区别 320 11.8 MODEM通信技术 320 11.8.1 MODEM的基本工作原理 320 11.8.2 MODEM的功能 322 11.8.3 MODEM的分类 322 11.8.4 MODEM的安装 324 11.8.5 MODEM V.92标准介绍 326 11.8.6 MODEM的速度 327 11.8.7 MODEM优化方法 328 11.8.8 MODEM命令/AT命令 329 第12章 不占用串口的串口数据捕捉 338 12.1 驱动程序的基本概念:VxD与WDM 338 12.1.1 虚拟设备驱动程序VxD 338 12.1.2 Win32驱动程序模型WDM 340 12.1.3 在不同操作系统下选用哪种驱动程序模式 341 12.2 VxD示例程序介绍——VToolsD中的CommHook 341 12.3 串口数据捕捉实例程序 351 12.3.1 编程任务 351 12.3.2 编程步骤 351 12.4 虚拟串口简介 364 附录A Turbo C说明 366 附录B ASCII码表 376 源码链接:http://download.csdn.net/download/nihuichao/10244970
第1章 串行通信原理与设计 1 1.1 串行通信基本概念 1 1.1.1 串行通信特点 1 1.1.2 串行通信传输方式 2 1.1.3 数据纠错与检错 2 1.1.4 传输速率与距离 3 1.2 串行传输协议 4 1.2.1 异步传输协议 4 1.2.2 面向字符的同步传输协议 5 1.2.3 面向比特的同步传输协议 7 1.3 串行接口标准 9 1.3.1 EIA RS-232C标准 9 1.3.2 RS-423A、RS-422A和RS-485标准 12 1.3.3 USB接口标准 14 1.4 串口硬件设计 15 1.4.1 串口应用设计流程 15 1.4.2 Windows下的串口资源 15 1.4.3 DCE与DTE设备的识别方法 16 1.4.4 握手处理 16 1.4.5 RS-232C与RS-485接口转换 17 1.4.6 接地及隔离技术 17 1.5 小结 20 第2章 使用MSComm控件编程 21 2.1 MSComm控件属性及事件 21 2.1.1 MSComm最常用的属性 21 2.1.2 与输入操作有关的属性 23 2.1.3 与输出操作有关的属性 24 2.1.4 与传输控制有关的属性 25 2.1.5 MSComm控件的事件 26 2.2 对不同类型数据的处理方法 26 2.2.1 使用MSComm控件发送与接收字符串 27 2.2.2 使用MSComm控件发送与接收二进制数据 27 2.3 MSComm错误处理方法 28 2.3.1 关于发送缓冲区 28 2.3.2 关于接收缓冲区 29 2.3.3 接收数据的实际处理方法 29 2.4 控件编程 30 2.4.1 加载及使用控件 31 2.4.2 初始化及打开串口 36 2.4.3 串口事件处理 37 2.4.4 关闭串口 38 2.4.5 关于协议的问题 38 2.5 通信编程实例 38 2.5.1 程序功能 38 2.5.2 界面设计 38 2.5.3 变量声明 40 2.5.4 创建串口 41 2.5.5 设置串口 42 2.5.6 打开串口 43 2.5.7 关闭串口 43 2.5.8 接收数据处理 44 2.5.9 实际传输文件截图 45 2.6 程序发布问题 45 2.7 小结 45 第3章 使用WinAPI串口编程 47 3.1 API串口编程概述 47 3.2 采用同步查询方式的编程方法 47 3.2.1 创建串口 48 3.2.2 关闭串口 53 3.2.3 发送数据 53 3.2.4 接收数据 53 3.2.5 定时接收数据的方法 54 3.3 采用重叠I/O方式的编程方法 55 3.3.1 定义全局变量 55 3.3.2 创建串口 55 3.3.3 发出读写操作 56 3.3.4 读写线程函数的建立 57 3.3.5 关闭串口 61 3.4 采用事件驱动方式的编程方法 61 3.4.1 定义全局变量 61 3.4.2 打开串口及开启事件线程 62 3.4.3 发送数据 64 3.4.4 自定义消息函数读取数据 65 3.4.5 关闭串口及关闭事件线程 67 3.5 编程实例 67 3.5.1 程序功能 67 3.5.2 界面设计 68 3.5.3 变量声明 69 3.5.4 设置串口 70 3.5.5 打开串口 72 3.5.6 关闭串口 73 3.5.7 发送字符 73 3.5.8 命令的有效性处理 74 3.5.9 实际字符传送截图 75 3.6 小结 76 第4章 多线程编程 77 4.1 多线程基本概述 77 4.1.1 线程与进程 77 4.1.2 何时使用多线程 78 4.1.3 多线程串口的应用 78 4.2 线程的操作 78 4.2.1 创建线程 78 4.2.2 终止线程 80 4.2.3 关于内存泄漏 81 4.3 线程间通信 81 4.3.1 使用全局变量 81 4.3.2 使用自定义消息 81 4.4 线程同步 82 4.4.1 使用临界区(Critical Section) 82 4.4.2 使用互斥对象(Mutex) 83 4.4.3 使用信号量(Semaphore) 84 4.4.4 使用事件(Event) 84 4.4.5 各种方法的比较 85 4.5 多线程串口程序设计 85 4.5.1 多线程的应用框架 85 4.5.2 相关的声明 86 4.5.3 创建线程 87 4.5.4 编写线程函数 87 4.5.5 编写消息响应函数 88 4.5.6 线程的结束 88 4.6 小结 89 第5章 TAPI编程 91 5.1 关于TAPI 91 5.1.1 什么是TAPI 91 5.1.2 Windows中的TAPI系统架构 91 5.1.3 Windows中的TAPI电话服务类型 92 5.2 TAPI 2.X介绍 93 5.2.1 基本概念 93 5.2.2 TAPI应用程序结构 93 5.2.3 常用函数介绍 94 5.3 CTapi14类介绍 98 5.3.1 变量/函数声明 98 5.3.2 初始化操作 100 5.3.3 创建函数 100 5.3.4 呼叫函数 101 5.3.5 回调函数处理方式 103 5.3.6 与回调相关的函数 103 5.3.7 处理呼叫状态的函数 105 5.3.8 处理连接状态的函数 108 5.3.9 挂机函数 109 5.3.10 通信状态显示函数 110 5.3.11 延时函数 111 5.4 使用CTapi14类的编程实例 111 5.4.1 程序功能 111 5.4.2 界面设计 111 5.4.3 CTapi14类的使用方法 112 5.4.4 变量/函数声明 113 5.4.5 电话操作函数 114 5.4.6 消息处理函数 115 5.4.7 显示信息函数 117 5.4.8 实际使用截图 117 5.5 小结 118 第6章 计算机与单片机通信 119 6.1 单片机的串口原理 119 6.1.1 串口结构 119 6.1.2 串口寄存器及中断 120 6.2 串行通信硬件设计 121 6.2.1 常用接口芯片介绍 121 6.2.2 接口电路 121 6.3 串行口通信参数设置 122 6.3.1 波特率的设置 122 6.3.2 奇偶校验位的使用方法 123 6.3.3 通信协议约定 123 6.4 单片机的串口编程方法 124 6.4.1 功能描述 124 6.4.2 通信协议 124 6.4.3 初始化串口及寄存器 124 6.4.4 编写中断服务程序 125 6.5 计算机界面设计 128 6.5.1 功能描述 128 6.5.2 界面设计 128 6.6 计算机端程序设计 129 6.6.1 头文件引用及变量声明 129 6.6.2 初始化控件 131 6.6.3 向单片机发出请求 132 6.6.4 在控件事件中接收数据 133 6.6.5 超时定时器的编程 140 6.6.6 关闭串口 141 6.7 小结 142 第7章 计算机与PLC通信 143 7.1 PLC的串口通信 143 7.1.1 PLC的通信方式 143 7.1.2 计算机与PLC通信流程 144 7.1.3 与通信相关的寄存器 144 7.1.4 与通信相关的指令 148 7.1.5 通信中断事件 149 7.1.6 通信中断指令 150 7.1.7 硬件连线及设置 151 7.1.8 PC/PPI电缆切换时间的影响 151 7.2 PLC通信编程 152 7.2.1 功能描述 152 7.2.2 通信协议 152 7.2.3 程序结构及变量说明 153 7.2.4 主程序 154 7.2.5 初始化 154 7.2.6 发送与接收处理 155 7.3 计算机界面设计 158 7.3.1 主界面设计 158 7.3.2 设置对话框设计 159 7.4 计算机程序设计 160 7.4.1 功能描述 160 7.4.2 变量/函数声明 160 7.4.3 初始化代码 161 7.4.4 参数配置 162 7.4.5 读串口操作 166 7.4.6 写串口操作 169 7.4.7 接收数据处理 172 7.4.8 命令有效性处理 178 7.4.9 实际传输数据截图 179 7.5 小结 180 第8章 计算机与Modem的通信 181 8.1 Modem的工作原理 181 8.1.1 Modem的基本工作原理 181 8.1.2 Modem的功能介绍 182 8.1.3 内置Modem与外置Modem 182 8.2 Modem的通信标准 183 8.2.1 调制协议 183 8.2.2 差错控制协议 184 8.2.3 数据压缩协议 184 8.2.4 文件传输协议 184 8.3 Modem的AT命令 185 8.3.1 Modem工作状态切换 185 8.3.2 AT命令串简介 187 8.3.3 常用基本AT命令分类 187 8.3.4 呼叫与应答相关命令 187 8.3.5 状态切换命令 190 8.3.6 握手相关命令 191 8.3.7 基本AT命令的简单测试方法 192 8.3.8 常用寄存器命令及寄存器含义 194 8.3.9 使用PSTN进行串行通信的工作流程 195 8.4 使用Modem远程传输文件程序设计 196 8.4.1 功能描述 196 8.4.2 通信流程 197 8.4.3 XModem通信协议 198 8.4.4 界面设计 199 8.4.5 变量声明 200 8.4.6 初始化 201 8.4.7 串口配置与操作 202 8.4.8 发送文件 204 8.4.9 接收文件 205 8.4.10 OnComm事件函数 206 8.4.11 建立超时定时器 228 8.5 小结 230 第9章 两台计算机间通信 231 9.1 通信方式介绍 231 9.2 通信协议 232 9.2.1 通信流程 233 9.2.2 数据包格式 233 9.3 通信实现思路 234 9.3.1 功能描述 234 9.3.2 通信事件的处理方法 235 9.3.3 各种操作状态的含义 235 9.4 界面设计 237 9.4.1 主界面设计 237 9.4.2 设置对话框设计 238 9.5 程序设计 239 9.5.1 变量/函数声明 239 9.5.2 初始化代码 241 9.5.3 参数配置 242 9.5.4 发送文件 246 9.5.5 事件消息响应函数 248 9.5.6 命令的有效性处理 267 9.5.7 自定义功能函数 269 9.5.8 程序测试 274 9.6 小结 274 第10章 软件传真机 275 10.1 传真的基本知识 275 10.1.1 工作原理 275 10.1.2 传真机的分类 276 10.1.3 传真机通信规程 277 10.2 关于传真精灵SmartFax 278 10.2.1 主要功能 278 10.2.2 发送传真函数 278 10.2.3 接收传真函数 281 10.2.4 其他功能函数 283 10.2.5 如何使用传真精灵 284 10.3 软件传真机程序设计 285 10.3.1 功能介绍 285 10.3.2 界面设计 286 10.3.3 关于头文件的引用 289 10.3.4 变量/函数声明 289 10.3.5 初始化操作 291 10.3.6 程序流程分析 293 10.3.7 关于TAPI操作的函数 296 10.3.8 发送传真相关函数 304 10.3.9 接收传真相关函数 306 10.3.10 传真消息响应函数OnSmartFax() 309 10.3.11 传真参数相关操作函数 317 10.3.12 其他功能函数 322 10.4 小结 324 第11章 计算机与射频卡通信 325 11.1 射频卡简介 325 11.1.1 射频卡工作原理 325 11.1.2 射频卡的分类 326 11.1.3 射频卡的优点 327 11.1.4 射频卡的应用 327 11.2 射频卡的应用框架 327 11.3 MIFARE卡介绍 328 11.3.1 TYPE A 与TYPE B 328 11.3.2 TYPE A 卡的初始化与防冲突 329 11.3.3 MIFARE 1型卡的存储结构 333 11.3.4 MIFARE 1型卡存取控制与数据区的关系 334 11.4 射频卡模块介绍 336 11.4.1 MCM200/MCM500概述 336 11.4.2 MCM200/MCM500接口简介 337 11.4.3 MCM200/MCM500读写操作过程 338 11.4.4 ZLG500A读写模块介绍 339 11.5 射频卡应用的设计 340 11.5.1 读写器成品的设计方法 340 11.5.2 使用射频卡模块的设计方法 340 11.6 小结 340 第12章 组态王的应用 341 12.1 组态王参数设置 341 12.1.1 RS-485板卡的使用方法 341 12.1.2 串口通信方式 342 12.1.3 串口参数设置 346 12.2 组态王通信协议 346 12.2.1 寄存器定义 346 12.2.2 读命令格式 347 12.2.3 写命令格式 347 12.2.4 命令格式中的符号说明 348 12.2.5 命令举例说明 349 12.3 组态王端的程序设计 350 12.3.1 程序功能 350 12.3.2 界面设计 350 12.3.3 KingComClient设备的设置 352 12.3.4 变量定义 352 12.3.5 命令语言 353 12.4 计算机端的程序设计 353 12.4.1 功能描述 353 12.4.2 界面设计 354 12.4.3 变量/函数声明 355 12.4.4 初始化代码 356 12.4.5 串口配置与操作 357 12.4.6 串口事件响应函数 361 12.4.7 自定义功能函数 368 12.4.8 模拟数值的产生 372 12.4.9 实际通信截图 372 12.5 小结 374 第13章 云台及镜头控制系统 375 13.1 云台及镜头的应用概况 375 13.1.1 数字监控系统概述 375 13.1.2 监控系统组成 375 13.2 如何控制云台与镜头 376 13.2.1 云台及镜头的设备简介 376 13.2.2 云台及镜头的控制原理 377 13.2.3 解码器概述 377 13.2.4 常用通信协议 377 13.3 串口控制云台和镜头程序设计 378 13.3.1 硬件接线说明 378 13.3.2 通信协议介绍 379 13.3.3 程序功能 380 13.3.4 界面设计 380 13.3.5 变量/函数声明 383 13.3.6 初始化操作 386 13.3.7 按下与弹起控制的实现方法 388 13.3.8 串口操作 407 13.3.9 发送数据 408 13.3.10 程序测试截图 417 13.4 小结 417 附录 串口调试 419
Arduino的I2C通信是一种串行通信协议,用于在多个设备之间进行数据传输。在Arduino板上,I2C总线的两个引脚是SDA和SCL。根据不同的Arduino电路板,这些引脚的编号可能会有所不同。例如,在Arduino UNO中,引脚A4对应SDA,引脚A5对应SCL;在Arduino Mega2560中,引脚20对应SDA,引脚21对应SCL。\[2\]\[3\] 在I2C通信中,可以有一个主设备和多个从设备。主设备负责协调总线上的其他设备之间的信息传输。通常情况下,Arduino作为主设备,控制连接到它的其他I2C通信模块。为了建立I2C连接,需要将主Arduino的SDA引脚和SCL引脚连接到从设备Arduino的对应引脚上,并通过共享接地来建立连接。在连接建立后,可以将主站和从站的代码上传到Arduino板上,实现I2C通信。\[1\] 需要注意的是,大多数Arduino相关的I2C模块已经添加了上拉电阻,因此只需要将I2C从设备连接到Arduino的I2C接口上即可。\[2\] #### 引用[.reference_title] - *1* *3* [arduino——I2C通讯](https://blog.csdn.net/m0_46152804/article/details/125130186)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Arduino成长日记7 - I2C通讯](https://blog.csdn.net/qq_36955622/article/details/106898840)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值