
STM8Lxxx I2C 程序第二次数据通信失败的问题分析 . ~. J8 o M+ ]# X" s7 m2 v前言 本篇文章主要是对STM8Lxxxx 在I2C 通信调试中遇到的第一次通信正常,但第二次通信失败问题的分析和处理。- ~% z- G5 p; z' C0 E 1. I2C 协议总体分析。5 C6 H# Y2 S* Y3 ] STM8Lxxx I2C 硬件逻辑使用时非常灵活,因此也造成对各个状态处理的复杂性,稍不注意,I2C 调试就不能通过。- w3 T) P- n) z) a @$ u 下面是I2C 开始(START)和结束(STOP)波形,STM8Lxxx 也是遵守这个协议的。6 y1 G2 w" R- T* {4 B. p/ [ SCL 信号由主控提供。$ W/ _9 f7 R M& l6 f% Y STM8Lxxx 总线端口为开漏输出,外部需要上拉电阻。; e% F% g# E1 R) E% Y3 [ 下面协议为简单的单主控单从机收发协议。' a6 A) U( _9 n$ m Z5 D ![]() 0 a e. M& G: M2 q( W: o5 T7 s 2. 下面对一个简单的单主机发送,单从机接收协议进行说明6 f/ O( a* ^, O/ s( E4 s! H 下面为主发送的一个协议图: 主控给从机发送数据,等到从机应答信号后再发送下byte 数据,直到数据发送完成后,主机发送一个stop 信号释放总线。& N1 X: ?, @. H) Q; I ![]() ' @7 h: f5 z- Q3 ?* q9 Q/ A& r3 U 下面是从机接收协议图,从机接收主机发过来的数据并存储,每byte 传输完成后发送一个应答信号给主机(从机在每byte 传输完的第九个Clock 把SDA 信号线拉低到低电平)。 ![]() 3. 程序中的出错现象9 N8 r) @& _4 s" j4 |$ d# e 客户的程序调时发现相同的数据连续从主控发给从机,只有第一次的通信波形是好的,第二次通信时设备地址可正常发送,从机也有应答,但当第一byte 数据发送完成后,主机收不到从机的应答信号。 ! S( o9 i- d- e; z$ U# z& o 4. 问题产生原因9 m7 n, D: m( {4 R) B8 b* n 客户使用的是E:\Download\STM8L\STSW-STM8016\STM8L15x-16x-05x-AL31-L_StdPeriph_Lib\Project\STM8L15x_StdPeriph_Examples\I2C\I2C_TwoBoards\I2C_DataExchange 中的程序。 ![]() ![]() 客户在程序编写时看到下图中用橙色标出的文字,就错误理解成从机每次收到I2C 的STOP 信号后,从机都要给I2C_CR2 的STOP 置位来释放SCL 和SDA 信号线。2 o! y0 z# |/ |3 O, W ![]() ![]() 客户对I2C 中断处理程序进行了修改,对应的代码如下,黄色部分标出了客户修改的代码: ![]() 8 f( @. A0 f7 h1 w3 U) \ 跟踪程序发现I2C 主机在发送第二次数据时,从第一个byte 数据传输完成时信号波形开始不正常,从机一直没有ACK 发出来。SCL 线一直保持在低电平。8 g6 S! {. D$ G7 T! @1 J0 X 跟踪从机程序,发现第二次传输时ADDR 中断能正常进入,从机也有应答,但之后RXNE 位一直不会被置位,被置位的是I2C_SR1 的bit7, TXE 位一直为“1”,而中断处理中并没对这一状态进行处理和清空,所以一直会不断进入中断处理程序,不做处理又跳出中断,程序通信就死在了这里。7 B+ ?; } D) }! o9 F" _ ![]() 把程序恢复成示例程序,通信正常。2 T5 f2 ^' d# I {: }$ g" l1 s - j: b# C3 E f- |% v 5.代码设计中应注意的地方。 建议客户在修改示例代码时谨慎一些,特别要注意重要寄存器的操作;弄明白后再进行更改;如果需要测试,最好标注清楚, 不要测试完成后又忘了修改回来。1 ?# ]+ Q! {9 f2 W 4 ]- }. O* Z0 \0 z 文档下载' q6 B o6 x j& Q$ t . v% d n" S5 q: @+ k+ K3 I 更多实战经验 |
STM8自学笔记(推荐STM8很好的入门电子书)
基于STM8的DALI (数字可寻址调光协议)
分享STM8 风驰光盘的资料,是完整的(包括原理图+例程+PDF注释)
《无刷直流电机控制应用 基于STM8S系列单片机》
STM8S库函数中文参考 小软件
【资料分享】STM8L的智能手持血糖监测设备的源码
基于STM8S207工程模板
【培训资料】STM8系列PPT培训资料
STM8S 直流电机例程及相关资料
无刷直流电机控制应用+基于STM8S系列单片机---电子书
在这几天的努力下主要发现两个问题1.在传输过程中,特别当速度快的时候,当从机处于接收状态时, 有些时候,SR1寄存器中RXNE和STOPF两个状态位同时被置1,不知道这种情况是不是被允许的,然而官方给的示例代码里没有对这种状态进行处理,导致I2C传输失败;当从机处于发送状态时,SR1寄存器中BTF和TXE两个状态位同时被置1,相同的,官方给的示例代码里没有对这种状态进行处理,导致I2C传输失败。 7 E# l1 J8 F; y' ]
下面是官方给的中断中的示例代码,其中default中的内容为我修改的内容,主要是对传输过程中,SR1寄存器中有两个状态位同时被置的处理。经修改后,能正常通信。但是不知道是不是真的是这个问题,希望大虾们拍砖。 C# L* U1 F. E3 {" Z& C4 E5 w: l. g
void bsp_i2c_slave_received_for_isr(void){6 {4 h r' O4 b5 J) q* Y6 Q; k
//static uint8_t a=0;
/* Read SR2 register to get I2C error */
if ((I2C->SR2) != 0)9 o$ b1 W0 b8 k2 \
{6 k6 b3 t/ k* G0 l- w* w
/* Clears SR2 register */
I2C->SR2 = 0;; m( ^, f+ d* b' h. K, T9 ?$ `
" U, U' H: u+ w7 H
}
i2c_slave.Event = I2C_GetLastEvent();
switch (i2c_slave.Event)
{
/******* Slave transmitter ******/% V& W! e. {5 k0 ] e8 a
/* check on EV1 */0 G# ]' l+ u' G
case I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED:3 v6 w+ v1 w K
i2c_slave.Tx_Idx = 0;- H, u9 u5 F- ?3 j ?2 T4 Z" D b
break;+ }4 e, d/ O3 ]* b+ r* J7 ]
, I. ?2 y% O0 W5 n; {7 m
/* check on EV3 */. Z0 U- _& G, c: r
case I2C_EVENT_SLAVE_BYTE_TRANSMITTING:
/* Transmit data */0 S: q: R5 c; y' f$ `
I2C_SendData(i2c_slave.Slave_Buffer_Rx[i2c_slave.Tx_Idx++]);' M0 J5 L+ t) I% B4 i( Q- c: m
break;
/******* Slave receiver **********/
/* check on EV1*/
case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED:0 r! k2 J# B f$ g+ c
break;
/* Check on EV2*/" ^/ y) T$ }5 G0 R( y& n
case I2C_EVENT_SLAVE_BYTE_RECEIVED:* G) |9 J0 p: f4 f
i2c_slave.Slave_Buffer_Rx[i2c_slave.Rx_Idx++] = I2C_ReceiveData();
! k- h6 u: Q i' H4 s5 h( q
break;. G S0 v/ R) S
/* Check on EV4 */
case (I2C_EVENT_SLAVE_STOP_DETECTED):+ L5 |0 Z L6 T3 e
/* write to CR2 to clear STOPF flag */2 Q# e, q( _. R. ]
I2C->CR2 |= I2C_CR2_ACK;' N$ a9 h4 c! p4 b* m# t
1 u2 u1 a. I6 G+ e3 w+ } N
break;
default:5 R( T- I# P# M- H3 l' c8 a: I4 Q
if ((I2C->SR1&0x40) != 0)6 c; I- i1 B, q5 Z8 }
{ h& I# m1 ^; K! q
/* Clears SR2 register */
i2c_slave.Slave_Buffer_Rx[i2c_slave.Rx_Idx++] = I2C_ReceiveData();: q( R* n; N7 i, H
1 r- k6 R" {9 U3 S2 K) c* T
}' l1 x6 z/ L: f9 G5 z1 L, ~
if ((I2C->SR1&0x04) != 0)% r6 j) r6 S% ?. V% p Q' v& b
{
/* Clears SR2 register */( K& v' ^2 e! w# |$ i) k) I
I2C_SendData(i2c_slave.Slave_Buffer_Rx[i2c_slave.Tx_Idx++]);3 |' [! X" E$ F& ]% n" t& E- [
}; }+ i' n& F/ g
break;
}
}
2 f, H$ U/ h9 E0 m ~
昨天调试STM8L还发现了一个硬件问题, IIC通信线的上拉电阻太小,导致通信没有识别“低”状态。建议将I2C两个脚初始化成标准IO,一秒钟翻转一次,发现IO口能输出方波,但是没有低状态。