|
最近一直在研究STM32F0的IIC,因为项目要用到IIC,master/slave mode都需要,实现数据通信和IAP功能。 网上有关于这部分资料特别少,所以共享一下,只晒出初始化和中断部分的代码的框架。代码在附件 .c里面, 如果有不对的地方,欢迎指正,大家互相学习一下! ( G3 g* r+ f* Q3 ~ STM32F0相对于STM32F1和STM8S 有很大变化,支持时钟延长即I2C_CR1_NOSTRETCH,并且支持SMBUS。 1,初始化部分:配置时钟和引脚,不使用时钟延长的功能0 }( `4 ~4 ]" n5 ]* T6 q. j0 c r 2,I2C1_IRQHandler 主要处理中断事件5 X0 e, \7 S! R# y2 j 在I2C_ISR_ADDR事件时,如果设置了多个地址,要判断是那个地址,并且要清除中断标志位。& ]; C& c" q. _$ e% V 根据I2C1->ISR&I2C_ISR_DIR 的结果判断是发送数据还是接收数据。9 ^' ?5 F+ b) K (1)发送数据,流程如下 N3 K K: E) q, o- o
这里要区别一下I2C_ISR_TXIS,I2C_ISR_TXE,描述如下
(2) 接收数据,流程如下* ~! d' y9 G( E6 F
|
IIC SLAVE mode.zip
下载1.84 KB, 下载次数: 904
DMA 原理从 0 到 1:为什么它能解放 CPU?一文讲透 DMA 的工作流程
小白也能明白的STM32的低功耗与唤醒机制
STM32系统中2种数据掉电保护的方法
分享STM32F051中文参考手册(重制书签版)
AI工具训练营-用ChatGPT解决HID Keyboard实现的问题
STM32固件库分享,超全系列整理
STM32小白入门指南:从基础到OTA实现方案
STM32超详细学习笔记
新手必看!STM32单片机应该怎么学?
如果你解决了这些问题,就可以直接学STM32
微信公众号
手机版
2 R2 O6 K6 M- K @8 Z( x' z% w
我在网上找到你们的代码。我复制了一下。有些问题想了解一下8 ~2 {- m L1 c& E1 F0 |$ a
void I2C_GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* Enable GPIOA clock */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
/*!< sEE_I2C Periph clock enable */+ p3 U) G7 r+ ~& h, f( F
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1 , ENABLE);4 M7 e# _, M0 h
/*!< GPIO configuration */
/*!< Configure sEE_I2C pins: SCL */
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;* p8 u k0 J7 N$ [, [, z- c
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;//GPIO_Mode_IN
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_Level_3;+ k. D9 x2 j- }0 X$ Y) d
GPIO_InitStruct.GPIO_OType = GPIO_OType_OD;//open-drain S- V% F' C* k
GPIO_Init(GPIOA , &GPIO_InitStruct);: p1 `2 c1 ~! Y1 D! l4 y
/*!< Configure sEE_I2C pins: SDA */9 @1 L3 B# z4 w9 H6 E
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
GPIO_Init(GPIOA, &GPIO_InitStruct);
/* Connect PXx to I2C_SCL*/& Y8 |) D t! }( g) g
GPIO_PinAFConfig( GPIOA , GPIO_PinSource9, GPIO_AF_4);
/* Connect PXx to I2C_SDA*/
GPIO_PinAFConfig( GPIOA ,GPIO_PinSource10, GPIO_AF_4);2 ]: t" Y5 F& e/ U" _" B" Q
} @8 p5 x, ~9 `/ _' }% x
$ T |) k* M, @+ L
//IIC从模式配置,在配置时,需要设置地址,在这里设置为0XA0,而从设备的时钟属于被动模式,有IIC的主端确定。1 y# ?, c8 u. N8 ?
* ]8 y1 K) ?. L
void I2C_Configuration(void)( u5 V! ?) N8 h8 G. v/ a6 ~# {1 I
{
I2C_InitTypeDef I2C_InitStruct;
NVIC_InitTypeDef NVIC_InitStructure;% w2 d: i1 h1 i9 v" Z1 }
( }. d* z+ ~. u: V, d
/* I2C configuration */
I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;: f9 `0 j p5 K5 Q7 T
I2C_InitStruct.I2C_AnalogFilter = I2C_AnalogFilter_Enable;& c1 q# g6 w& Z. i' _
I2C_InitStruct.I2C_DigitalFilter = 0x00;3 }" \, n. E$ W9 R& I
I2C_InitStruct.I2C_OwnAddress1 = ADDR;
I2C_InitStruct.I2C_Ack = I2C_Ack_Enable;
I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStruct.I2C_Timing = 0xb0420f13; //100Kbits1 W1 a6 J4 Q9 j
/* I2C Peripheral Enable */6 Q1 y8 e' K/ f) {/ z
I2C_Cmd(I2C1, ENABLE);6 ~+ e( V/ y, j/ r: H9 h# L# f$ E- p
/* Apply I2C configuration after enabling it */! k0 z; Z8 T: C
I2C_Init(I2C1, &I2C_InitStruct);
I2C1->CR1 |= (I2C_CR1_ADDRIE | I2C_CR1_STOPIE | I2C_CR1_TXIE | I2C_CR1_RXIE);
//---------------------------- Peripheral and DMA interrupts Initialization ------------------
// Initialize I2C1 interrupts
/* Enable the IRQ channel */
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;6 t0 ~0 u3 k% u
/* Configure NVIC for I2C1 Interrupt */2 Y& E5 h6 `7 m# l6 _+ U
NVIC_InitStructure.NVIC_IRQChannel = I2C1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPriority = 2;
NVIC_Init(&NVIC_InitStructure); ) r2 c+ H* H2 ^8 d( B* n; H
* k$ u: ^& a/ ^2 ^! F
}
; E+ @' [+ [0 O$ U3 t) w
//下面是IIC中断函数的实现# l# Q( K( W: S# L' U! c4 {9 B
void I2c_Init(void)
{
I2C_GPIO_Configuration();
I2C_Configuration();
}
void I2C1_IRQHandler(void)
{5 q; @3 E! Z" o$ a
u32 AddCode;4 c. z& e* _/ {3 t
// I2C_ClearITPendingBit(I2C1, I2C_ISR_ADDR | I2C_ISR_STOPF |I2C_ISR_ADDCODE );9 U! f9 n6 D+ F% v5 Y# H2 z
__IO uint32_t I2CFlagStatus = 0x00000000;- k$ y" g0 R: `! [
I2CFlagStatus = (uint32_t)(I2C1->ISR & (uint16_t)0x0000100FE);9 I5 Z/ H# ~, w
) h; _; a1 {6 M) g0 p# s8 \5 w# S
// printf("recv data\r\n");3 e% D) L' T( q
if ((I2CFlagStatus & I2C_ISR_ADDR) != 0)$ i/ {$ a7 Y+ a% F J8 x$ L
{: f7 }4 O0 t4 s7 M
AddCode = (I2C1->ISR & 0xfe0000); //读取ADDCODE 32:17位
printf("匹配地址2 0x%x: \r\n",AddCode >> 17 );
. D% U% J4 n; T' ?2 u
if(I2C1->ISR&I2C_ISR_DIR) //tx mode+ W3 c7 } o$ v& j
{
printf("发送模式 \r\n");
Tx_count = 0;/ J, ~7 a R: e9 {$ [3 Y. M0 r% L
I2C1->ISR |= I2C_ISR_TXE;
I2C1->ICR |= I2C_ICR_ADDRCF;
1 r# Y+ |, @& j: V% p T
if(I2C_GetITStatus( I2C1, I2C_IT_RXNE) != 0)
{
Rx_buffer[Rx_count++]=I2C_ReceiveData(I2C1);6 I/ r: j: E' ^8 N5 j Q
if(Rx_count>=Rx_MAX)
{
Rx_count=0;/ b8 s! {( J+ x
//rx ok
}
printf("Rx_buffer : %s\r\n",Rx_buffer);
}
}
if((I2C1->ISR&I2C_ISR_DIR)==0) //rx mode# W7 h+ A; N* v; R
{
printf("接收模式 \r\n");% N2 U- a' Z. ~$ B
Rx_count= 0;. G$ I- F* \) D- c7 a0 ^: e" k
I2C1->ICR |= I2C_ICR_ADDRCF; * d o9 m% u, q/ b7 S/ h7 h
}
}$ ?- q" B) _4 Y
else if(I2C_GetITStatus( I2C1, I2C_IT_RXNE) != 0)
{
Rx_buffer[Rx_count++]=I2C_ReceiveData(I2C1);
if(Rx_count>=Rx_MAX) S1 L4 ~5 ^. e
{
Rx_count=0;2 v% e' n6 j, I, g5 W% K* ]5 [- x
//rx ok, h$ r5 a) w1 ^8 s7 K
}. d ~/ }/ m+ e( g1 K; k
printf("Rx_buffer : %s\r\n",Rx_buffer);
}
else if ((I2CFlagStatus & I2C_ISR_TXIS) != 0)
{5 u8 c- k5 ?" h. f
I2C_SendData(I2C1,Tx_buffer[Tx_count++]);
if(Tx_count >= Tx_MAX)
{8 u$ e/ t" y! _, D2 F- t; O
Tx_count = 0;
//tx ok
}" a( t$ _) w3 H( b
}1 \$ w* O0 u% j% o
else if ((I2CFlagStatus & I2C_ISR_STOPF) != 0)
{
printf("停止检查标志位 \r\n");
I2C1->ICR |= I2C_ICR_STOPCF;; V; v+ f2 p2 f3 J l
Rx_count = 0;9 c( t7 w7 ?4 ]. J6 p
Tx_count = 0;
}
}
3 h' Q. j! c9 x8 L9 ?" k: P
这个是可以匹配到ADDCODE ,但是没有接收到数据的,我没仔细看这个时序寄存器的配置。不知道是不是由于时序不匹配造成没有接收到数据,还是因为ack没有给出造成读不到数据的。3 ]0 @1 ?! E- H- G. x3 q
void I2C_GPIO_Configuration(void)6 `- z, I5 N+ n! h1 j
{) E6 o( d M" J( E4 ?
GPIO_InitTypeDef GPIO_InitStruct; 2 v; V% M. Q( q1 o1 i( Q8 @
1 f8 S7 s& f4 @. P: I' I
/* Enable GPIOA clock */' h- X) }+ n ?! Q" ]; K+ T
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
/*!< sEE_I2C Periph clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1 , ENABLE);
/*!< GPIO configuration */ " P% h3 x" P8 f9 X5 K
/*!< Configure sEE_I2C pins: SCL */6 }% l: P3 ~# N' {/ ~0 R
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;7 x' F! _* P ?' X% |5 Y7 s4 d
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;//GPIO_Mode_IN+ ~$ U9 R$ W' a7 ?; X; L
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_Level_3;' x( N. e* q# o3 Y- ~
GPIO_InitStruct.GPIO_OType = GPIO_OType_OD;//open-drain
GPIO_Init(GPIOA , &GPIO_InitStruct);7 j+ M% K c$ E7 p, ^8 ?/ h8 ~ x8 c
) X: X; F( T: `$ ]
/*!< Configure sEE_I2C pins: SDA */! B' a' P# i+ S( N1 _# ~
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;; }5 l/ s3 m: G( J7 n- C# Q+ y
GPIO_Init(GPIOA, &GPIO_InitStruct);8 Q# L( \6 Y4 F$ a7 I. V
) ?3 x: }4 P2 X' j" [' z
/* Connect PXx to I2C_SCL*/
GPIO_PinAFConfig( GPIOA , GPIO_PinSource9, GPIO_AF_4);
/* Connect PXx to I2C_SDA*/6 r9 f' W7 @& `" T- G6 o6 \. ]9 T1 A
GPIO_PinAFConfig( GPIOA ,GPIO_PinSource10, GPIO_AF_4);
}
//IIC从模式配置,在配置时,需要设置地址,在这里设置为0XA0,而从设备的时钟属于被动模式,有IIC的主端确定。, m0 N% I, Q/ ^& t2 ]
void I2C_Configuration(void)
{, L0 y; u8 X8 C7 o, p
I2C_InitTypeDef I2C_InitStruct; 8 v; S& M0 V1 v* j8 X
NVIC_InitTypeDef NVIC_InitStructure;9 U. ~& N# T( [8 w' w% s3 @, a. Z
0 K( z4 b) g- ~
/* I2C configuration */
I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;% A, X9 j5 l) d5 d% [% }
I2C_InitStruct.I2C_AnalogFilter = I2C_AnalogFilter_Enable;
I2C_InitStruct.I2C_DigitalFilter = 0x00;/ T$ y3 G# T( p& X" |# O1 Z
I2C_InitStruct.I2C_OwnAddress1 = ADDR;
I2C_InitStruct.I2C_Ack = I2C_Ack_Enable;
I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; 0 c' \* W( E( t8 K
I2C_InitStruct.I2C_Timing = 0xb0420f13; //100Kbits& ?- t* d% T$ N& }# v" E/ P
/* I2C Peripheral Enable */
I2C_Cmd(I2C1, ENABLE);. h3 u& ~" Q8 X( E0 m7 K0 ], _ N; b
/* Apply I2C configuration after enabling it */( ]4 q1 }% J# u, g
I2C_Init(I2C1, &I2C_InitStruct);
9 l2 _4 I/ i9 b
I2C1->CR1 |= (I2C_CR1_ADDRIE | I2C_CR1_STOPIE | I2C_CR1_TXIE | I2C_CR1_RXIE);# _, g7 n8 h9 f/ V9 e
//---------------------------- Peripheral and DMA interrupts Initialization ------------------
// Initialize I2C1 interrupts
/* Enable the IRQ channel */5 h, N& |9 H* Y2 n. x j& U9 [+ m
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;6 D. _1 t8 x6 @$ V g0 o2 O+ g2 R
* l6 G: S6 n) s3 T. a9 g
/* Configure NVIC for I2C1 Interrupt */' J! w6 _0 I) s8 D# O
NVIC_InitStructure.NVIC_IRQChannel = I2C1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPriority = 2;
NVIC_Init(&NVIC_InitStructure); 8 u' e' n( d! m7 w1 Z" z$ ?, t3 D
1 r. m# w0 J8 z- f/ h$ D' o
}3 ?2 D! l, t) V) F
7 M7 w7 N0 t& Z7 u% ?: K( \
//下面是IIC中断函数的实现; T' L9 b* m4 A$ v. k' E& N
) ^" O( b, C3 \
void I2c_Init(void)
{0 u) z p( y5 q& n4 P7 S7 k* ?1 t
I2C_GPIO_Configuration();) I7 \- \) F4 G4 Y# L% V8 J
I2C_Configuration();
}
void I2C1_IRQHandler(void)$ Q: D1 P a& v+ ^- m( u
{
u32 AddCode;3 D6 a' ?: l& u$ M% x
// I2C_ClearITPendingBit(I2C1, I2C_ISR_ADDR | I2C_ISR_STOPF |I2C_ISR_ADDCODE );
__IO uint32_t I2CFlagStatus = 0x00000000;& [* m0 a1 [/ p% M
I2CFlagStatus = (uint32_t)(I2C1->ISR & (uint16_t)0x0000100FE);
// printf("recv data\r\n");, m4 V/ S& N% O1 @
if ((I2CFlagStatus & I2C_ISR_ADDR) != 0)/ h D5 r3 G% [: x; q
{
AddCode = (I2C1->ISR & 0xfe0000); //读取ADDCODE 32:17位
printf("匹配地址2 0x%x: \r\n",AddCode >> 17 );0 z# h9 `* Z; }
if(I2C1->ISR&I2C_ISR_DIR) //tx mode
{
printf("发送模式 \r\n");! Y8 f5 g, ^& r8 f9 T
Tx_count = 0;
I2C1->ISR |= I2C_ISR_TXE;( }2 K- {: q2 d' y& o# r2 h
I2C1->ICR |= I2C_ICR_ADDRCF; ( N$ r! H$ S" r& R, |0 [
if(I2C_GetITStatus( I2C1, I2C_IT_RXNE) != 0)' u/ `: O* s2 Q( R
{3 P' ?, j U" X
Rx_buffer[Rx_count++]=I2C_ReceiveData(I2C1); V" X2 ?1 E' a9 n- m# g- j
if(Rx_count>=Rx_MAX)
{
Rx_count=0;
//rx ok1 L9 V4 j5 N% `6 K! @
}7 z$ B4 a+ ^" H, F( j. j
printf("Rx_buffer : %s\r\n",Rx_buffer);6 S" L3 B0 A3 ]7 H/ o8 |: O
}3 w) W1 z! t- V' U9 W9 j
} ' `9 L' w6 n S a h# B! h
if((I2C1->ISR&I2C_ISR_DIR)==0) //rx mode
{
printf("接收模式 \r\n");! i4 m& {+ X5 T$ C/ m
Rx_count= 0;8 p: N% \% M6 n1 {% c
I2C1->ICR |= I2C_ICR_ADDRCF; 2 E2 d% P4 R9 m. Q9 F6 s: l; r
}! K4 N- A- I3 F1 M9 x# N( t
}
else if(I2C_GetITStatus( I2C1, I2C_IT_RXNE) != 0)/ J8 p# ^" C: h1 B5 v
{
Rx_buffer[Rx_count++]=I2C_ReceiveData(I2C1);
if(Rx_count>=Rx_MAX)
{; [- w6 ^) Z9 _4 {6 F) Z- Y
Rx_count=0;& }5 g; a% ^( G& G8 M* w% J
//rx ok7 o2 e& v0 b! T& a. w4 Y ~; z
}# e3 R/ X8 c3 N5 l
printf("Rx_buffer : %s\r\n",Rx_buffer);6 u; ^' P) ~' i* z+ E9 B) ? p+ Q
}
else if ((I2CFlagStatus & I2C_ISR_TXIS) != 0)
{
I2C_SendData(I2C1,Tx_buffer[Tx_count++]);* N$ G6 Y' H9 o+ j4 @& ?& f
if(Tx_count >= Tx_MAX)3 I* F. q# r |* l2 N9 f$ d
{
Tx_count = 0;! ?! G" A$ Y( R1 m
//tx ok! v' P. w b, b! p' D: s1 [/ x
}, r6 _2 a- J6 U6 T! T
}9 |' ]: Z& {4 ?; b6 z
else if ((I2CFlagStatus & I2C_ISR_STOPF) != 0)
{+ ^) m/ h! l. F- I
printf("停止检查标志位 \r\n");
I2C1->ICR |= I2C_ICR_STOPCF;) e6 D# g9 o6 H6 D7 V
Rx_count = 0;$ l2 Y5 a k6 ^2 E0 ?' h5 {
Tx_count = 0;( {2 I0 \& s' X+ N: ?3 A% ]' I
}& v1 [4 H9 p# B" a/ i7 s, B
}
0 C. @8 Q5 G/ W