FPGA:三大协议(IIC、UART、SPI)之IIC

这篇具有很好参考价值的文章主要介绍了FPGA:三大协议(IIC、UART、SPI)之IIC。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

摘要:1、本文讲述IIC的物理层面的结构(使用iic工作的物理层面的连接);2、本文讲解协议层面的通信交流格式(IIC时序);3、提供一个主机和从机的一个verilog代码;4、本文的主从机指的是:板子一号作为主机,发送数据给作为从机的板子二号;注意:在实际应用中,一般器件作为从机,我们写的程序作为主机通过数据线控制器件进行工作。

一、IIC物理结构

fpgaiic,fpga开发

fpgaiic,fpga开发

 

 二、IIC时序

1、前言:当两个器件要通过IIC协议来交流,已经在物理层面做好了准备,连接好了SDA和SCL两根线,也就是建立了一个交流通道。(比如已经拨通了电话,接下来就开始讲话了)。

2、常态:当建立好了联系,有了一个沟通的通道之后(就像拨通了电话),但是双方都没有交流(打了电话但是都不说话)。这个时候SDA和SCL的状态是高阻态,此时的高阻态不是人为设定的,是在硬件上有一个上拉电阻,让空闲时刻的SDA和SCL两根数据线为高阻态。

3、通信状态1(主机发送,从机接收):通道已经建立好了,开始交流(电话拨通开始说话了)。

(1)起始位(1bit):开始交流的时候发送一个起始位(相当于打电话说:喂,您好):

起始位构成:当SCL保持高电平期间(高阻态,主机不控制即可),SDA线拉低(主机控制SDA拉低),称为IIC的起始信号。

(2)数据位(8bit):起始位发送完毕之后开始发送数据: 数据的发送参照的是SCL时钟线(相当于给器件一个时钟),是由主机产生的(SCL产生可以是记录一段时间,SCL数据线高低电平翻转)。

数据位:变化是在SCL为低的时候SDA变化,SDA在SCL为高的时候保持不变;因为器件(从机)在SCL为高电平的时候读取SDA的数据(电平高低),来表示传输的数据。

数据线控制:SCL根据传输速率周期变化(主机控制),SDA在SCL为低的时候发送数据(比如数据是0001 1100,第一位发送0,则第一个SCL为低的时候拉低SDA,且在SCL为高的时候SDA保持不变,表示发送0),主机控制SDA。

(3)应答位(1bit):应答表示从机应答主机,给主机说一声,收到数据了。主机收到之后就知道发送的数据成功被接收到了。

数据位:SCL还是根据传输速率正常周期性变化(主机控制),SDA这个时候主机不能控制,SDA控制权交给从机;主机在SCL为高的时候接收SDA传来的数据,如果这一bit是低,那么表示正确应答(ACK,正确应答),从机正确收到数据了,如果为SDA高(NACK,错误应答)那么表示,从机收到数据错误了。

注:对于(2)、(3),可以多次进行,要发送多个Byte数据,那么可以先(1)—(2)—(3)—(2)—(3)、、、、

*(4)停止位:当发送完数据之后并且应答收到之后,主机发送一个停止位表示本次交流结束(就像打电话说拜拜)。

数据位:在SCL位高的时候,拉高SDA,表示停止位。

数据线控制:本来在SCL为高的时候SDA要保持不变表示数据发送,因此:把SDA由低拉高表示停止信号。

注:当有多Byte数据要发送的时候,那么可以先(1)—(2)—(3)—(2)—(3)、、、—(4)。

注:有一种情况:当主机收到的(3)---应答位是高电平(SDA是高,NACK),表示错位应答,那么这个时候不管发完数据没有都要发送一个停止信号来结束这次通话。(就像两个特工交流,暗号没对上,那么就要终止交易)。

时序图:

fpgaiic,fpga开发

 流程图:

fpgaiic,fpga开发

 4、通信状态2(从机发送,主机接收)

(1)起始位(1bit):主机发起通信,告诉可以开始了

起始位构成:当SCL保持高电平期间(高阻态,主机不控制即可),SDA线拉低(主机控制SDA拉低),称为IIC的起始信号。

(2)数据位(8bit):起始位发送完毕之后开始接收数据: 数据的接收参照的是SCL时钟线(相当于给器件一个时钟),是由主机产生的(SCL产生可以是记录一段时间,SCL数据线高低电平翻转)。

数据位:主机在SCL为高的时候识别SDA,SDA的高低认定是数据这一bit的高低,最后接收8位表示这一Byte数据。

数据线控制:SCL根据传输速率周期变化(主机是控制SCL线的),主机放开SDA线给从机操作,并且主机在SCL线为高的时候识别SDA。

(3)应答位(1bit):应答表示主机应答从机,给从机说一声,表示主机接受到从机的数据了。

数据线控制:SCL照旧周期变化(主机控制),在SCL为低的时候SDA变化,应答从机。这个时候有2种情况的应答:第一种:数据接收正确,且后面主机还要接收数据,回复正确应答:SDA拉低(ACK),从机接收到之后继续发送数据;第二种:数据接收正确,但是后面主机不再接收数据了,回复错误应答,SDA拉高(NACK)。表示从机不再发送数据了。这个时候主机再发送停止位表示交流结束。

*(4)停止位当发送完数据之后并且应答收到之后,主机发送一个停止位表示本次交流结束(就像打电话说拜拜)。

数据位:在SCL位高的时候,拉高SDA,表示停止位。

数据线控制:本来在SCL为高的时候SDA要保持不变表示数据发送,因此:把SDA由低拉高表示停止信号。

时序图:

fpgaiic,fpga开发

流程图:

fpgaiic,fpga开发

思路总结:

(1)我们可以使用一个计数器来控制输出SCL,计满一定数额就让SCL实现翻转,这样就产生了SCL时钟。

(2)可以用一个计数器来记录发送或者接收的数据位数,来确定我们接收或者发送的数据位数是否正确。

 主机verilog代码:

module iic_master(
    input		clk,
    input		rst_n,

    input		start,           //发起数据请求
/*     input[7:0]	data_tx,         //要发送的数据 ,同TX_DATA*/

    output	reg	iic_scl,          //发送的时钟总线scl,根据选择的传输速率实现不同的scl的输出。

    //inout     iic_sda,          
    // assign iic_sda = sda_oe ? sda_out : 1'bz;
    //assign sda_in = iic_sda;                              
    input		sda_in,          //发送的总线sda
    output reg  sda_oe,          //
    output reg  sda_out
);

//parameter declarations
parameter SCL_MAX = 9'd500; // 50M/10k
localparam TX_DATA = 24'h112345;//发送三个字节

//状态
localparam 
    IDEL  = 4'b0001,
    START = 4'b0010,
    SEND_DA = 4'b0100,
    STOP = 4'b1000;

reg             work_en;        //数据开始传输使能位

reg [7:0]       data_tmp;
reg             ack;


reg     [8:0]   cnt_scl;        //生成scl,250次翻转一下
wire			add_cnt_scl ;       //Counter Enable
wire			end_cnt_scl ;       //Counter Reset 

reg     [3:0]   cnt_bit;        //表明哪一个位发送
wire			add_cnt_bit ;       //Counter Enable
wire			end_cnt_bit ;       //Counter Reset 

reg		[1:00]	cnt_byte		; //Counter   
wire			add_cnt_byte ; //Counter Enable
wire			end_cnt_byte ; //Counter Reset 

reg     [3:0]   state_c,state_n;//状态
reg    [8:0]    max_scl_cnt;

//状态跳转条件定义
wire        idle2start;
wire        start2send_da;
wire        send_da2stop;
wire        stop2idle;

//使能位赋值操作
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin  
            work_en <= 1'b0; 
        end  
        else if(start)begin
            work_en <= 1'b1;
        end
        else if(stop2idle)begin
            work_en <= 1'b0;
        end
        else begin
            work_en <= work_en;
        end
    end

//计数器1  cnt_scl
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin  
            cnt_scl <= 9'd0; 
        end  
        else if(add_cnt_scl)begin  
            if(end_cnt_scl)begin  
                cnt_scl <= 9'd0; 
            end  
            else begin  
                cnt_scl <= cnt_scl + 1; 
            end  
        end  
        else begin  
            cnt_scl <= cnt_scl;  
        end  
    end 

assign add_cnt_scl = work_en;                                  //随时开始计数
assign end_cnt_scl = add_cnt_scl && cnt_scl >= max_scl_cnt;     //一个周期结束一次计数,当进入发送停止位的时候也要清零

always@(*)begin//变换是组合逻辑,方便试试更新,不会出现说延时错误
    case(state_c)
        IDEL,START,STOP :   max_scl_cnt = SCL_MAX >> 1;
        SEND_DA         :   max_scl_cnt = SCL_MAX;
        default         :   max_scl_cnt = SCL_MAX;
    endcase
end
//计数器2,cnt_bit      
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin  
            cnt_bit <= 4'd0; 
        end  
        else if(add_cnt_bit)begin  
            if(end_cnt_bit)begin  
                cnt_bit <= 4'd0; 
            end  
            else begin  
                cnt_bit <= cnt_bit + 1'b1; 
            end  
        end  
        else begin  
            cnt_bit <= cnt_bit;  
        end  
    end 
            
    assign add_cnt_bit = (state_c == SEND_DA) && end_cnt_scl; //开始位计数是在进入数据发送的时候,并且是在结束计数一个周期的时候进行计数位加一
    assign end_cnt_bit = add_cnt_bit && cnt_bit >= 4'd8 ; 

//状态机第一段,描述状态输出
    always @(posedge clk or negedge rst_n)begin//要和第三段相同,不然的话flag_cak不能归零,cnt_us也不能
        if(!rst_n)begin
            state_c <= IDEL;
        end
        else begin
            state_c <= state_n;
        end
    end
//状态机第二段,描述状态转换,对n_state操作
    always @(*)begin
        case(state_c)
            IDEL: begin
                if(idle2start)begin
                    state_n = START;
                end
                else begin
                    state_n = IDEL;
                end
            end
            START :begin
                if(start2send_da)begin
                    state_n = SEND_DA;
                end
                else begin
                    state_n = START;
                end
            end
            SEND_DA :begin
                if(send_da2stop)begin
                    state_n = STOP;
                end
                else begin
                    state_n = SEND_DA;
                end
            end
            STOP :begin
                if(stop2idle)begin
                    state_n = IDEL;
                end
                else begin
                    state_n = STOP;
                end
            end
            default :state_n = IDEL;
        endcase
    end

    assign idle2start       =       state_c == IDEL     &&   start; //跳出IDLE状态条件:在start来临
    assign start2send_da    =       state_c == START    &&   end_cnt_scl;//跳出START状态条件:起始位发送完成
    assign send_da2stop     =       state_c == SEND_DA  &&   (end_cnt_byte || (ack && end_cnt_bit));//跳出发数据状态的条件:发送完三个字节之后,或者是异常之后,回复一个高电平
    assign stop2idle        =       state_c == STOP     &&   end_cnt_scl;
    
//第三段,定义状态机输出情况,可以时序逻辑,也可以组合逻辑
	always @(posedge clk or negedge rst_n)begin  
		if(!rst_n)begin  
            data_tmp <= 8'd0;
            iic_scl <= 1'b1;
			sda_oe <= 1'b0;
            sda_out <= 1'b1;
            ack <= 1'b0;
		end 
		else begin  
			case(state_c)
                IDEL : begin
                    iic_scl <= 1'b1;
                    sda_oe <= 1'b1;//空闲状态                 //在等待状态要释放总线,但是此时时钟总线是一直跑的
                    sda_out <= 1'b1;
                    ack <= 1'b0;
                end 

                START :begin//半个周期
                    sda_oe <= 1'b1;
                    sda_out <= 1'b0;//进来就拉低
                    if(cnt_scl >= (max_scl_cnt >> 1))begin
                        iic_scl <= 1'b0;
                    end
                    else begin
                        iic_scl <= 1'b1;
                    end
                end

                SEND_DA : begin
                    case(cnt_byte)
                        0:data_tmp <= TX_DATA[7:0];
                        1:data_tmp <= TX_DATA[15:8];
                        2:data_tmp <= TX_DATA[23:16];
                        default: data_tmp <= 8'd0;
                    endcase
                    
                    if(cnt_scl > (max_scl_cnt >> 2 ) && (cnt_scl < ((max_scl_cnt >>2 ) + (max_scl_cnt >>1 ))))begin//高电平持续时间
                            iic_scl <= 1'b1;
                    end
                    else begin
                            iic_scl <= 1'b0;
                    end

                    if(cnt_bit != 4'd8)begin
                        sda_oe <= 1'b1;
                        sda_out <= data_tmp[cnt_bit];
                    end
                    else begin//接收应答位
                        sda_oe <= 1'b0;
                        if(cnt_bit == 4'd8 && cnt_scl == max_scl_cnt >> 1)begin
                            if(sda_in)begin//当异常的时候ack保存当前输入的值
                                ack <= sda_in;
                            end
                            else begin
                                ack <= ack;
                            end
                        end
                        else ;
                    end

                end
                STOP : begin
                    sda_oe <= 1'b1;//进入就是总线控制
                    if(end_cnt_scl)begin//结束可以修改结束时间
                        sda_out <= 1'b1;
                    end
                    else begin
                        sda_out <= 1'b0;
                    end

                    if(cnt_scl >= (max_scl_cnt >> 1))begin
                        iic_scl <= 1'b1;
                    end
                    else begin
                        iic_scl <= 1'b0;
                    end
                end
                default :;
            endcase

		end  
	end //always end

//字节计数器
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin  
            cnt_byte <= 2'd0; 
        end  
        else if(add_cnt_byte)begin  
            if(end_cnt_byte)begin  
                cnt_byte <= 2'd0; 
            end  
            else begin  
                cnt_byte <= cnt_byte + 1'b1; 
            end  
        end  
        else begin  
            cnt_byte <= cnt_byte;  
        end  
    end    

    assign add_cnt_byte = end_cnt_bit; //开始计数是在发送数据状态,实现加一是位记完9位
    assign end_cnt_byte = add_cnt_byte && (cnt_byte >= 2'd2 || send_da2stop) ; //当异常输入的时候也要对计数位清零


endmodule

从机verilog代码:文章来源地址https://www.toymoban.com/news/detail-736975.html

module iic_slave(
    input		clk,
    input		rst_n,
    input		iic_scl,

    input		sda_in,         //sda总线信号输入
    output  reg  sda_oe,
    output  reg  sda_out,		    //sda接收端发送
    output  reg [23:0]   data_out        //接收到的数据全部整合
);

parameter SCL_MAX = 9'd500; // 50M/10k
localparam	IDLE	=	4'b0001, 
            SLAVE	=	4'b0010,
            ACK		=	4'b0100,
            JUDG	=	4'b1000;
            
reg		[3:00]	state_c, state_n; //
reg             flag_judg2idle;

//表示最大计数
reg    [8:0]    max_scl_cnt;
reg             work_en;//开始使能

//接收到的信号
reg [7:0]       data_tmp;

/* //计数器
reg     [8:0]   cnt_scl;        //生成scl,250次翻转一下
wire			add_cnt_scl ;       //Counter Enable
wire			end_cnt_scl ;       //Counter Reset  */

reg     [3:0]   cnt_bit;        //表明哪一个位发送
wire			add_cnt_bit ;       //Counter Enable
wire			end_cnt_bit ;       //Counter Reset 

reg		[1:00]	cnt_byte		; //Counter   
wire			add_cnt_byte ; //Counter Enable
wire			end_cnt_byte ; //Counter Reset 
        
//跳转条件定义
wire			idle2slave;
wire			slave2ack;
wire			ack2judg;
wire			judj2idle;
wire            judj2slave;

//检测开始标志
//对信号打拍
reg             sda_start_r1;
reg             sda_start_r2;
wire            flag_start;

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        sda_start_r1 <= 1'b0;
        sda_start_r2 <= 1'b0;
    end
    else begin
        sda_start_r1 <= sda_in;
        sda_start_r2 <= sda_start_r1;
    end
end
assign flag_start = ((~sda_start_r1 && sda_start_r2) && iic_scl) ? 1'b1 : 1'b0;//检测开始信号,检测下降沿

//检测结束标志
reg             sda_stop_r1;
reg             sda_stop_r2;
wire            flag_stop;
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        sda_stop_r1 <= 1'b0;
        sda_stop_r2 <= 1'b0;
    end
    else begin
        sda_stop_r1 <= sda_in;
        sda_stop_r2 <= sda_stop_r1;
    end
end
assign flag_stop = ((sda_stop_r1 && ~sda_stop_r2) && iic_scl) ? 1'b1 : 1'b0;//检测停止信号,检测上升沿

//检测iic_scl的上升沿
reg             scl_r1;
reg             scl_r2;
wire            flag_scl_pos;
wire            flag_scl_neg;
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        scl_r1 <= 1'b0;
        scl_r2 <= 1'b0;
    end
    else begin
        scl_r1 <= iic_scl;
        scl_r2 <= scl_r1;
    end
end
assign flag_scl_pos = ((scl_r1 && ~scl_r2) && iic_scl) ? 1'b1 : 1'b0;//检测停止信号,检测上升沿
assign flag_scl_neg = ((~scl_r1 && scl_r2) && (iic_scl == 1'b0)) ? 1'b1 : 1'b0;//检测停止信号,检测下降沿


//使能赋值
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin  
        work_en <= 1'b0; 
    end  
    else if(flag_start)begin
        work_en <= 1'b1;
    end
    else if(judj2idle)begin//当判断是结束之后回到idle状态,表示使能结束
        work_en <= 1'b0;
    end
    else begin
        work_en <= work_en;
    end
end

//计数器
always@(*)begin//变换是组合逻辑,方便试试更新,不会出现说延时错误
    case(state_c)
        IDLE                 :   max_scl_cnt = SCL_MAX >> 1;
        SLAVE,ACK,JUDG      :   max_scl_cnt = SCL_MAX;
        default             :   max_scl_cnt = SCL_MAX;
    endcase
end
/* //计数器1  cnt_scl
always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin  
            cnt_scl <= 9'd0; 
        end  
        else if(add_cnt_scl)begin  
            if(end_cnt_scl)begin  
                cnt_scl <= 9'd0; 
            end  
            else begin  
                cnt_scl <= cnt_scl + 1; 
            end  
        end  
        else begin  
            cnt_scl <= 9'd0;  //回到idle自动归零
        end  
    end 
assign add_cnt_scl = work_en;                                  //当开始位来临的时候开始计数
assign end_cnt_scl = (add_cnt_scl && cnt_scl >= max_scl_cnt) || judj2idle;     //一个周期结束一次计数,当进入发送停止位的时候也要清零 */

//计数器2,cnt_bit      
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin  
            cnt_bit <= 4'd0; 
        end  
        else if(add_cnt_bit)begin  
            if(end_cnt_bit)begin  
                cnt_bit <= 4'd0; 
            end  
            else begin  
                cnt_bit <= cnt_bit + 1'b1; 
            end  
        end  
        else begin  
            cnt_bit <= cnt_bit;  
        end  
    end 
            
    assign add_cnt_bit = (state_c == SLAVE || state_c == ACK || state_c == JUDG) && flag_scl_neg; //开始位计数是在进入数据
    assign end_cnt_bit = (add_cnt_bit && cnt_bit >= 4'd8) || judj2idle  ; //停止位来领直接归零

//第一段设置状态转移空间
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        state_c <= IDLE;
    end
    else begin
        state_c <= state_n;
    end
end //always end

//第二段、组合逻辑定义状态转移
always@(*)begin
    case(state_c)
        IDLE:begin
            if(idle2slave)begin
                state_n = SLAVE;
            end
            else begin
                state_n = state_c;
            end
        end
        SLAVE:begin
            if(slave2ack)begin
                state_n = ACK;
            end 
            else begin
                state_n = state_c;	
            end 
        end
        ACK:begin
            if(ack2judg)begin
                state_n = JUDG;
            end 	
            else begin
                state_n = state_c;	
            end 
        end 
        JUDG:begin
            if(judj2idle)begin
                state_n = IDLE;
            end 
            else if(judj2slave)begin
                state_n = SLAVE;
            end
            else begin
                state_n = state_c;	
            end 
        end 
        default: begin
            state_n = IDLE;
        end
    endcase
end //always end
        
assign	idle2slave	=	state_c ==  IDLE	&& 	(flag_scl_neg && iic_scl == 1'b0);
assign	slave2ack   =	state_c	==	SLAVE	&&	(cnt_bit == 4'd7 && flag_scl_neg);//8位数据位接收完毕,但是还是要留一位给应答位
assign	ack2judg	=	state_c	==	ACK 	&&	(cnt_bit == 4'd8 && flag_scl_neg);
assign	judj2idle	=	state_c	==	JUDG	&&	flag_judg2idle;
assign	judj2slave	=	state_c	==	JUDG	&&	(cnt_bit == 4'd0 && flag_scl_neg) ;//接收完一个字节数据回到salve状态
        
//第三段,定义状态机输出情况,可以时序逻辑,也可以组合逻辑
always @(posedge clk or negedge rst_n)begin  
    if(!rst_n)begin  
        sda_out <= 1'b0;
        sda_oe <= 1'd0;
        data_tmp <= 8'd0;
        data_out <= 24'd0;
        flag_judg2idle <= 1'b0;
    end  
    else begin  
        case (state_c)
            IDLE:begin
                flag_judg2idle <= 1'b0;
            end
            SLAVE :begin
                sda_oe <= 1'd0;
                if(flag_scl_pos && iic_scl)begin
                    data_tmp[cnt_bit] <= sda_in;
                end
                else ;
            end
            ACK :begin//持续一个bit的低电平输出应答
                case(cnt_byte)
                    2'b00:begin
                            data_out[7 : 0]   <= data_tmp;
                            sda_out <= 1'd0;
                            sda_oe <= 1'd1;
                        end
                    2'b01:begin
                            data_out[15:8]    <= data_tmp;
                            sda_out <= 1'd0;
                            sda_oe <= 1'd1;
                        end
                    2'b10:begin
                            data_out[23:16]   <= data_tmp;
                            sda_out <= 1'd1;
                            sda_oe <= 1'd1;
                        end
                    default :data_tmp <= 24'd0;
                endcase
            end
            JUDG:begin//检测下一个位是不是停止位
                sda_oe <= 1'd0;
                if(iic_scl == 1'b1 && flag_stop)begin//如果是停止位就结束,回到idle状态
                    flag_judg2idle <= 1'b1;
                end
                else if(flag_scl_pos && iic_scl)begin//在下一个iic_scl周期进行检测,看是否是停止位,先保存当前数据
                    data_tmp[cnt_bit] <= sda_in;
                end
                else ;
            end
            default :begin
                sda_out <= 1'd1;
                sda_oe <= 1'd0;
            end
        endcase
    end
end //always end

//字节计数器
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin  
            cnt_byte <= 2'd0; 
        end  
        else if(add_cnt_byte)begin  
            if(end_cnt_byte)begin  
                cnt_byte <= 2'd0; 
            end  
            else begin  
                cnt_byte <= cnt_byte + 1'b1; 
            end  
        end  
        else begin  
            cnt_byte <= cnt_byte;  
        end  
    end    

    assign add_cnt_byte = end_cnt_bit; //开始计数是在发送数据状态,实现加一是位记完9位
    assign end_cnt_byte = (add_cnt_byte && cnt_byte >= 2'd2) ||  judj2idle ; //停止位来领直接归零


endmodule

到了这里,关于FPGA:三大协议(IIC、UART、SPI)之IIC的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 常用通讯协议(UART、RS232、RS485、IIC、SPI)简单介绍

    目录 常用通讯协议随笔 通讯基础 UART UART存在的问题: RS232 接口 信号 电平转换 RS232存在的问题 RS485 信号 接口 电平转换 RS485的优势 IIC IIC总线通讯过程 IIC总线寻址方式 起始信号和停止信号 字节传输于应答 同步信号 典型IIC时序 SPI SPI寻址方式 SPI总线通讯过程 极性和相位

    2024年02月02日
    浏览(42)
  • SPI、UART、RS232、RS485、IIC 5种嵌入式经典通信总线协议

      UART即通用异步收发器,是一种通用的串行、异步通信总线。该总线有两条数据线,可以实现全双工的发送和接收。在嵌入式系统种常用于主机与辅助设备之间的通信。UART就是串口,也是一种通信协议/总线协议。 电脑上已经逐步没有了,换成了usb,但是在嵌入式领域是最

    2024年01月16日
    浏览(55)
  • FPGA——实现三线SPI和UART

    目录 逻辑框图(原理图) 端口约束和ILA  ILA waveform  实测波形 串口调试工具 源代码 顶层  FPGA和芯片之间通过三线SPI接口通信(DATA复用一个IO端口),FPGA和PC之间通过UART串口通信。 原理图包含4个模块,分别为:内建模块IBUFDS(用于将外部差分时钟转换为内部单端时钟)、

    2024年02月09日
    浏览(33)
  • 嵌入式Linux裸机开发(七)UART串口、IIC、SPI通信

    大概学完这三种通信后,之后就先去学系统移植,其他的先暂时放下 串口全称叫做串行接口,通常也叫做 COM 接口。 UART:(Universal Asynchronous Receiver/Trasmitter)通用异步串行收发器。 USART:(Universal Synchronous/Asynchronous Receiver/Transmitter)通用同步/异步串行收发器,相比 UART多了

    2024年02月07日
    浏览(72)
  • 【FPGA协议篇】UART通信及其verilog实现(代码采用传参实现模块通用性,适用于快速开发)

    ​ 即通用异步收发器(Universal Asynchronous Receiver/Transmitter),是一种 串行、异步、全双工 的通信协议。特点是通信线路简单,适用于远距离通信,但传输速度慢。 数据传输速率:波特率(单位:baud,波特) 常见波特率有:1200、2400、4800、19200、38400、57600等,最常用的是9600和11520

    2024年02月05日
    浏览(45)
  • UART协议——FPGA代码篇

            UART 串口通信有几个重要的参数,分别是波特率、起始位、数据位、停止位和奇偶检验位,对于两个使用UART 串口通信的端口,这些参数必须匹配,否则通 起始位:表示数据传输的开始,电平逻辑为“0” 。 数据位:可能值有5、6、7、8、9,表示传输这几个bit 位数

    2024年01月18日
    浏览(36)
  • 详解UART通信协议以及FPGA实现

      从《浅谈UART,TTL,RS-232,RS-485的区别》这篇文章,我们知道了UART是一种串行、异步、全双工的通信协议,属于协议层;传输过程一般采用RS-232,RS-485电平标准,将所需传输的数据一位接一位地传输;整体传输框架如下:   串口通信由发送端和接收端构成,两根信号线

    2024年04月28日
    浏览(36)
  • FPGA-结合协议时序实现UART收发器(一):UART协议、架构规划、框图

    记录FPGA的UART学习笔记,以及一些细节处理,主要参考奇哥fpga学习资料。 本次UART主要采用计数器方法实现,实现uart的稳定性发送和接收功能,最后实现串口数据回环进行功能测试。 UART协议如图。 包含:空闲位、起始位、数据位、校验位、停止位、空闲位(一般没有) 对于

    2024年02月08日
    浏览(63)
  • 【FPGA】SPI协议

    SPI(Serial Perripheral Interface, 串行外围设备接口)是 Motorola 公司推出的一种同步串行接口技术。SPI 总线在物理上是通过接在外围设备微控制器(PICmicro) 上面的微处理控制单元 (MCU) 上叫作同步串行端口(Synchronous Serial Port) 的模块(Module)来实现的, 它允许 MCU 以全双工的同步串行方式

    2024年02月09日
    浏览(34)
  • 【LabVIEW FPGA入门】LabVIEW FPGA 实现SPI通信协议

            该实现由两个组件组成:在 LabVIEW FPGA 中实现的 SPI 协议以及用于从主机 PC 或实时控制器与 FPGA 进行通信的 LabVIEW 主机接口。该架构允许从单个主机程序控制多个 SPI 端口,同时仍然允许定制 FPGA VI 以进行其他数据采集和处理。该实现不使用任何DMA(直接内存访问

    2024年01月17日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包