【无标题】IIC 调试问题--中间电平

本文讲述了在IIC调试中,由于SDA电平未能正确拉低到低电平,导致芯片误识别为异常并停止响应的问题,强调了配置OD模式和及时处理中间电平的重要性。
AI助手已提取文章相关产品:

IIC 调试-- 电平拉不低 导致芯片IIC 通讯失败,  直接划重点

1 IO 要配置OD模式, 如果配置不了OD模式, SDA 高低电平后, 记得第一时间拉低,设为输入

2 图示--> 产生了一个中间电平, 此前遇到过几次, 这次终于知晓, 模拟的IIC SDA还是高电平,而芯片已经响应了低电平, 短路了 BBQ了,  然后芯片认为IIC通讯异常.不响应了.   

 

您可能感兴趣的与本文相关内容

分类专栏: FPGA通信接 文章标签: fpga verilog uartFPGA通信接专栏收录该内容31 篇文章¥49.90¥99.00订阅专栏超级会员免费看文章目录一、基本概念二、串特性三、串通信协议四、逻辑开发4.1verilog代码4.2代码解读五、调试效果六 传送门一、基本概念1、并行通信:指数据的多个位用多条数据线同时传输,同时具备传输速度快的优点和占用引脚资源多的缺点。2、串行通信:将数据分成一位一位的形式在一条传输线上逐个传输,优缺点与并行通信相反。3、同步通信:带时钟同步信号的数据传输,发送方和接收方在同一时钟的控制下,同步传输数据。4、异步通信:不带时钟同步信号的数据传输。发送方与接收方使用各自的时钟控制数据的发送和接收过程。5、串行通信的传输方向单工:数据只能沿一个方向传输半双工:数据传输可以沿两个方向,但同一时刻只能传输一个方向双工:数据可以同时进行双向传输6、常见的串行通信接通信标准 引脚说明 通信方式 通信方向UART TXD:发送 RXD:接收 GND:公共地 异步 双工单总线 DQ: 发送/接收端 异步 半双工SPI SCK:同步时钟 MISO:主机输入,从机输出 MOSI:主机输出,从机输入 同步 双工IIC SCL:同步时钟 SDA:数据输入\输入端 同步 半双工二、串特性1、串基本概念:通用异步收发传输器(Universal Asynchronous Receiver/Transmitter,通常称作UART) 是一种串行异步收发协议。2、通信速率:串通信的速率用波特率表示,波特率是指从一设备发到另一设备的波特率,即每秒钟可以通信的数据比特个数。UART波特率受发送和接收线对距离(线长度)的影响。常用的波特率有9600、19200、38400、57600、115200等。3、适用场景:一般适用于 传输速度要求不高,距离短的场合,实践中用于芯片调试信息的输出。4、电平标准:TTL、RS-232、RS-485是适用串的三种电平标准(电信号),常见接形式如4针杜邦线(TTL),DB9(RS232)。PL2303、CP2102芯片是USB 转 TTL串 的芯片,用USB来扩展串(TTL电平)。MAX232芯片是TTL电平与RS232电平的专用双向转换芯片,可以TTL转RS-232,也可以RS-232转TTL。uart是一种异步通信协议。而rs232只是物理层的电气接要求。uart可以使用rs232物理层来进行通信。而rs232作为物理层也可以用其余不同于uart的协议来做通信。为什么串有这么多不同的电气标准?有了UART这个东西之后是不是就可以直接在设备之间用了呢?如果是在一块板子上这里没有太大问题。现在大多数芯片的输出电压都是TTL的,所以电平兼容,而且一块板子上干扰又不会太高。但要是用在设备与设备之间通信,那可能就会有问题了。比如说主控电脑和电机驱动器之间。这种情况下TTL的抗噪能力就比较单薄了。比较简单的做法就是增加逻辑1和逻辑0之间的电压差,比如像RS232这种接中定义的电平格式。还有用差分信号的方式,比如RS485。没错,RS232只是一种接,定义了接的外观、各个引脚的功能、信号0和1对应的电压等。三、串通信协议UART串通信需要两根信号线来实现,一根用于串发送,另外一根负责串接收,要求通信双方配置相同的通信参数。UART在发送或接收过程中的一帧数据由 4 部分组成,起始位、数据位、奇偶校验位和停止位。●空闲位:UART协议规定,当总线处于空闲状态时信号线的状态为‘1’即高电平.●起始位:开始进行数据传输时发送方要先发出一个低电平’0’来表示传输字符的开始。因为空闲位一直是高电平所以开始第一次通讯时先发送一个明显区别于空闲状态的信号即为低电平。●数据位:起始位之后就是要传输的数据,数据可以是5,6,7,8,9位,构成一个字符,一般都是8位。先发送最低位最后发送最高位。●奇偶校验位:数据位传送完成后,要进行奇偶校验,校验位其实是调整个数,串校验分几种方式:1.无校验2.奇校验:如果数据位中’1’的数目是偶数,则校验位为’1’,如果’1’的数目是奇数,校验位为’0’。3.偶校验:如果数据为中’1’的数目是偶数,则校验位为’0’,如果为奇数,校验位为’1’。●停止位:数据结束标志,可以是1位,1.5位,2位的高电平。四、逻辑开发4.1verilog代码Top模块:module uart_top( input clk,//50M input reset_n, input uart_rx, output uart_tx, output led );//确定baud周期parameter Baud = 3'd0;reg [15:0]bclk_cnt; //一个串位占据的时钟个数always@(posedge clk or negedge reset_n)if(~reset_n) bclk_cnt <= 16'd5207;//1s/9600/20ns=5208 9600Bauelse begin case(Baud) 0:bclk_cnt <= 16'd5207; //9600Bau 1:bclk_cnt <= 16'd2603; //19200Bau 2:bclk_cnt <= 16'd1301; //38400Bau 3:bclk_cnt <= 16'd867; //57600Bau 4:bclk_cnt <= 16'd433; //115200Bau default:bclk_cnt <= 16'd5207; endcaseend//获取数据接收起始位reg uart_rx_reg1; reg uart_rx_reg2; reg uart_rx_reg3; wire uart_rx_nedge;always@(posedge clk or negedge reset_n) if(~reset_n)begin uart_rx_reg1 <= 1'b0; uart_rx_reg2 <= 1'b0; uart_rx_reg3 <= 1'b0; end else begin uart_rx_reg1 <= uart_rx; uart_rx_reg2 <= uart_rx_reg1; uart_rx_reg3 <= uart_rx_reg2; end//下降沿检测assign uart_rx_nedge = !uart_rx_reg2 & uart_rx_reg3;//#####################################3.state machinereg [2:0] state;parameter IDLE = 3'd0;parameter START = 3'd1;parameter DATA = 3'd2;parameter STOP = 3'd3;always@(posedge clk or negedge reset_n) if(!reset_n) begin state<=IDLE; end else case(state) IDLE: begin state<=uart_rx_nedge? START:IDLE; end START:begin if(start_cnt==bclk_cnt)begin if(begin_flag<2) state<=DATA; else state<=IDLE; end else state<=START; end DATA:begin state <=(data_cnt==4'd8&&start_cnt==bclk_cnt)? STOP :DATA; end STOP:begin state<=IDLE; endendcase//baud周期计数,计满为一个波特周期(时钟分频)reg [15:0]start_cnt;always @(posedge clk or negedge reset_n) begin if(!reset_n) start_cnt<=0; else if(start_cnt==bclk_cnt)begin start_cnt<=0; end else if(state==START||state==DATA)begin start_cnt<=start_cnt+1; endend//起始信号干扰排除reg [2:0]begin_flag;always @(posedge clk or negedge reset_n) begin if(!reset_n) begin_flag<=3'd0; else if(state==START)begin if(start_cnt==16'd1950||start_cnt==16'd2275||start_cnt==16'd2600||start_cnt==16'd2925|| start_cnt==16'd3250||start_cnt==16'd3575)begin begin_flag<=begin_flag+uart_rx_reg2; end else begin_flag<=begin_flag; end else begin_flag<=0;end//接收数据排序reg [3:0]data_cnt;always @(posedge clk or negedge reset_n)begin if(!reset_n) data_cnt<=0; else if(state==DATA)begin if(start_cnt==16'd1)begin data_cnt<=data_cnt+1; end else data_cnt<=data_cnt; end else data_cnt<=0; end//寄存接收到的数据reg [7:0]cur_data;always @(posedge clk or negedge reset_n) begin if(!reset_n)begin cur_data[0]<=3'd0; cur_data[1]<=3'd0; cur_data[2]<=3'd0; cur_data[3]<=3'd0; cur_data[4]<=3'd0; cur_data[5]<=3'd0; cur_data[6]<=3'd0; cur_data[7]<=3'd0; end else if(state==DATA)begin if(start_cnt==bclk_cnt/2)begin case(data_cnt) 4'd1 : cur_data[0] <= uart_rx_reg2; //寄存数据位最低位 4'd2 : cur_data[1] <= uart_rx_reg2; 4'd3 : cur_data[2] <= uart_rx_reg2; 4'd4 : cur_data[3] <= uart_rx_reg2; 4'd5 : cur_data[4] <= uart_rx_reg2; 4'd6 : cur_data[5] <= uart_rx_reg2; 4'd7 : cur_data[6] <= uart_rx_reg2; 4'd8 : cur_data[7] <= uart_rx_reg2; default:; endcase end endend//接收结束,发出发送指令(数据同步信号,50M一个周期)wire rx_bit_done;assign rx_bit_done=(state==STOP)? 1'b1:1'b0;uart_my_tx u1_uart_tx( .clk(clk), .reset_n(reset_n), .data_byte(cur_data), .send_en(rx_bit_done), .baud_set(Baud), .uart_tx(uart_tx), .tx_flag(led) ); endmodule123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154子模块:module uart_my_tx( input clk, input reset_n, input [7:0]data_byte, input send_en, input baud_set, output reg uart_tx, output tx_flag );assign tx_flag=start_flag;//busy信号相当于//寄存发送数据reg [7:0]data_byte_reg;//data_byte寄存后数据always@(posedge clk or negedge reset_n) if(!reset_n) data_byte_reg <= 8'd0; else if(send_en) data_byte_reg <= data_byte; else data_byte_reg <= data_byte_reg;//确定baud周期reg [15:0]bclk_cnt; //一个串位占据的时钟个数always@(posedge clk or negedge reset_n)if(~reset_n) bclk_cnt <= 16'd5207;//1s/9600/20ns=5208 9600Bauelse begin case(baud_set) 0:bclk_cnt <= 16'd5207; //9600Bau 1:bclk_cnt <= 16'd2603; //19200Bau 2:bclk_cnt <= 16'd1301; //38400Bau 3:bclk_cnt <= 16'd867; //57600Bau 4:bclk_cnt <= 16'd433; //115200Bau default:bclk_cnt <= 16'd5207; endcaseend//do transferreg start_flag;//指示写过程正在进行,可以据此产生busy信号reg tx_done;//指示写结束always@(posedge clk or negedge reset_n) if(~reset_n) start_flag<=0; else if(send_en) start_flag<=1; else if(pluse_cnt == 4'd10) start_flag<=0; else start_flag<=start_flag; //波特计数 计满为一个波特周期reg [15:0]baud_cnt;always @(posedge clk or negedge reset_n) begin if(!reset_n) baud_cnt<=0; else if(start_flag)begin if(baud_cnt==bclk_cnt) baud_cnt<=0; else baud_cnt<=baud_cnt+1; end else baud_cnt<=0;end//产生发送数据脉冲reg tran_pluse;always @(posedge clk or negedge reset_n) begin if(!reset_n) tran_pluse<=0; else if(baud_cnt==16'd1)begin tran_pluse<=1; end else tran_pluse<=0;end//脉冲计数使数据顺序发送reg [3:0]pluse_cnt;always @(posedge clk or negedge reset_n) begin if(!reset_n) pluse_cnt<=0; else if(pluse_cnt==4'd10)begin pluse_cnt<=0; end else if(tran_pluse) pluse_cnt<=pluse_cnt+1; else pluse_cnt<=pluse_cnt;end//产生tx_done数据发送完毕指示 always@(posedge clk or negedge reset_n) if(!reset_n) tx_done <= 1'b0; else if(pluse_cnt == 4'd10) tx_done <= 1'b1; else tx_done <= 1'b0;localparam START_BIT = 1'b0;localparam STOP_BIT = 1'b1; always@(posedge clk or negedge reset_n) if(!reset_n) uart_tx <= 1'b1; else begin case(pluse_cnt) 0:uart_tx <= 1'b1; 1:uart_tx <= START_BIT; 2:uart_tx <= data_byte_reg[0]; 3:uart_tx <= data_byte_reg[1]; 4:uart_tx <= data_byte_reg[2]; 5:uart_tx <= data_byte_reg[3]; 6:uart_tx <= data_byte_reg[4]; 7:uart_tx <= data_byte_reg[5]; 8:uart_tx <= data_byte_reg[6]; 9:uart_tx <= data_byte_reg[7]; // 10:uart_tx <= STOP_BIT; default:uart_tx <= 1'b1; endcase end reg [3:0]tr_cnt;always @(posedge clk or negedge reset_n) begin if(!reset_n) tr_cnt <= 0; else if(tx_done) tr_cnt<=tr_cnt+1; else tr_cnt<=tr_cnt;endila_0 your_instance_name ( .clk(clk), // input wire clk .probe0({tran_pluse,tr_cnt,pluse_cnt,start_flag}), // input wire [0:0] probe0 .probe1(data_byte_reg), // input wire [7:0] probe1 .probe2(tx_done), // input wire [0:0] probe2 .probe3(uart_tx) // input wire [0:0] probe3);endmodule1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301314.2代码解读1.描述●该串驱动的基本配置为:9600Baud、1bit停止位,8Bit数据位,无奇偶校验位;●该驱动运行的效果为:接受一个8bit数据,便产生一个send_en指示脉冲,指示发送模块将这8bit数据发送出去。在接收完成之后继续接收,在发送完成之后继续等待发送。2.步骤解读(从Top开始)①结合系统时钟以及驱动配置,使用信号bclk_cnt计算出9600Baud情况下,一个“Baud”的时钟个数,并给出易于修改波特率的方法。②通过经典代码,捕获uart_rx管脚的下降沿(uart_rx_nedge)便于捕获起始信号。③通过begin_flag信号对起始信号的干扰做一个判断和甄别,在状态机中,将据此信号决定状态机的走向。④通过data_cnt信号与接收数据对齐,从而便于在start_cnt==bclk_cnt/2(某位数据传输的正中间最稳定的时候)寄存串数据。⑤start_cnt信号计满为一个波特周期,便于数据寄存。⑥最后在top中生成rx_bit_done脉冲信号,用于指示将接收到的数据传送回去。⑦步骤1-5在top中完成对数据的接收,并产生的指示发送信号,进入到子模块中,收到send_en后,将接收到的8bit数据寄存到data_byte_reg信号。⑧根据top指示,选择设置的Baud(bclk_cnt信号)用于发送数据。⑨根据send_en和发送过程未结束产生tx_flag,相当于busy信号,该信号通过top连接至led。⑩根据子模块中计满波特周期信号baud_cnt结合tran_pluse脉冲信号,生成数据同步信号pluse_cnt,便于数据的发送。通过给uart_tx赋值完成数据发送,并产生tx_done信号表示一次8bit发送结束。3.注意事项①波特率指每秒传输的数据位数,系统使用不同的用户时钟,采用不同的波特率可能会造成,传输每一位数据所需的时钟个数成为小数,但较小偏差的波特率在串通信是被允许的。②当数据寄存完成后,可以提前一点结束接收过程,也就提前开始了下一个数据的监听,为下一帧数据的起始位预留时间。③采样时刻选取在每一位数据(每一个波特周期)的中点,确保数据稳定。⑤为了防止在传输的过程中数据出现变化,需要将数据做寄存处理。⑥通信双方的波特率、停止位、数据位、校验位的设置必须一致才能正确通信。⑦若时钟频率为50Mhz,得到一位数据需要的时钟数,基本的分频计数单元(每一位数据或者起始位停止位)1000000000(1s)/115200=8680ns 。每一位的时间是8680ns 用计数器计数8680/20=434,则计数434-1次即可。五、调试效果如图所示,是与Qt写的上位机进行通信实验的结果,可以看到配置一致,串工作,将发送的数据全部返回。软件源代码链接见文末。六 传送门Qt项目(1)Qt实现串调试助手FPGA通信接专栏汇总导航我的主页FPGA实现串源码END🔈文章原创,首发于优快云论坛。🔈欢迎点赞❤❤收藏⭐⭐打赏💴💴!🔈欢迎评论区或私信指出错误❌,提出宝贵意见或疑问❓。
最新发布
09-05
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值