stm32 i2c通信 [操作寄存器+库函数]
作者:Changing发表时间:07-12 22:01分类:电子相关
I2C总线是由NXP(原PHILIPS)公司设计,有十分简洁的物理层定义,其特性如下:
- 只要求两条总线线路:一条串行数据线SDA,一条串行时钟线SCL;
- 每个连接到总线的器件都可以通过唯一的地址和一直存在的简单的主机/从机关系软件设定地址,主机可以作为主机发送器或主机接收器;
- 它是一个真正的多主机总线,如果两个或更多主机同时初始化,数据传输可以通过冲突检测和仲裁防止数据被破坏;
- 串行的8 位双向数据传输位速率在标准模式下可达100kbit/s,快速模式下可达400kbit/s,高速模式下可达3.4Mbit/s;
- 连接到相同总线的IC 数量只受到总线的最大电容400pF 限制。
其典型的接口连线如下:
I2C的协议很简单:
数据的有效性
在传输数据的时候,SDA线必须在时钟的高电平周期保持稳定,SDA的高或低电平状态只有在SCL 线的时钟信号是低电平时才能改变 。
起始和停止条件
SCL 线是高电平时,SDA 线从高电平向低电平切换,这个情况表示起始条件;
SCL 线是高电平时,SDA 线由低电平向高电平切换,这个情况表示停止条件。
字节格式
发送到SDA 线上的每个字节必须为8 位,每次传输可以发送的字节数量不受限制。每个字节后必须处理一个响应位。
应答响应
数据传输必须带响应,相关的响应时钟脉冲由主机产生。在响应的时钟脉冲期间发送器释放SDA 线(高)。
在响应的时钟脉冲期间,接收器必须将SDA 线拉低,使它在这个时钟脉冲的高电平期间保持稳定的低电平。
也就是说主器件发送完一字节数据后要接收一个应答位(低电平),从器件接收完一个字节后要发送一个低电平。
寻址方式(7位地址方式)
第一个字节的头7 位组成了从机地址,最低位(LSB)是第8 位,它决定了传输的 普通的和带重复开始条件的7位地址格式方向。第一个字节的最低位是
“0”,表示主机会写信息到被选中的从机;
“1”表示主机会向从机读信息。
当发送了一个地址后,系统中的每个器件都在起始条件后将头7 位与它自己的地址比较,如果一样,器件会判定它被主机寻址,至于是从机接收器还是从机发送器,都由R/W 位决定。
仲裁
I2C是所主机总线,每个设备都可以成为主机,但任一时刻只能有一个主机。
stm32至少有一个I2C接口,提供多主机功能,可以实现所有I2C总线的时序、协议、仲裁和定时功能,支持标准和快速传输两种模式,同时与SMBus 2.0兼容。
本实验直接操作寄存器实现对I2C总线结构的EEPROM AT24c02的写入和读取。AT24c02相关操作详见 单片机读取EEPROM(AT24C02)。
库函数实现使用stm32的两个I2C模拟I2C设备间的数据收发,并通过串口查看数据交换情况。
直接操作寄存器
首先需要配置I2C接口的时钟,相关寄存器如下:
I2C_CR2寄存器低五位:
FREQ[5:0]:I2C模块时钟频率 ,必须设置正确的输入时钟频率以产生正确的时序,允许的范围在2~36MHz之间:
000000:禁用 000001:禁用 000010:2MHz ... 100100:36MHz 大于100100:禁用。
用于设置I2C设备的输入时钟,本例使用的是PLCK1总线上的时钟所以为36Mhz;
时钟控制寄存器(I2C_CCR)低12位:
CCR[11:0]:快速/标准模式下的时钟控制分频系数(主模式),该分频系数用于设置主模式下的SCL时钟。
在I2C标准模式或SMBus模式下:
Thigh = CCR ×TPCLK1
Tlow = CCR ×TPCLK1
时钟周期为 T = Thigh + Tlow;
例如:在标准模式下,FREQR = 36 即36Mhz,产生200kHz的SCL的频率
时钟控制分频系数 = Freqr /2/f f 为想得到的频率
配置好时钟,还需要配置本机地址,I2C支持7位地址和10位地址,这里用的是7位地址:
自身地址寄存器1(I2C_OAR1)[7:1]:接口地址,地址的7~1位。
其他相关操作参见代码,有详细注释:
(system.h 和 stm32f10x_it.h 等相关代码参照 stm32 直接操作寄存器开发环境配置)
User/main.c
01
#include
02
#include "system.h"
03
#include "usart.h"
04
#include "i2c.h"
05
06
#define LED1 PAout(4)
07
#define LED2 PAout(5)
08
#define LED3 PAout(6)
09
#define LED4 PAout(7)
10
11
void
Gpio_Init(
void
);
12
13
int
main(
void
)
14
{
15
16
Rcc_Init(9);
17
18
Usart1_Init(72,9600);
19
20
Nvic_Init(1,0,I2C1_EV_IRQChannel,4);
21
22
Nvic_Init(0,0,I2C1_ER_IRQChannel,4);
23
24
Gpio_Init();
25
26
I2c_Init(0x30);
27
28
I2c_Start();
29
30
while
(1);
31
}
32
33
34
void
Gpio_Init(
void
)
35
{
36
RCC->APB2ENR |= 1<<2;
37
RCC->APB2ENR |= 1<<3;
38
39
40
GPIOA->CRL &= 0x0000FFFF;
41
GPIOA->CRL |= 0x33334444;
42
43
44
GPIOB->CRL &= 0x00FFFFFF;
45
GPIOB->CRL |= 0xFF000000;
46
47
48
49
GPIOA -> CRH &= 0xFFFFF00F;
50
GPIOA -> CRH |= 0x000008B0;
51
52
}
User/stm32f10x_it.c
001
#include "stm32f10x_it.h"
002
#include "system.h"
003
#include "stdio.h"
004
#include "i2c.h"
005
006
#define LED1 PAout(4)
007
#define LED2 PAout(5)
008
#define LED3 PAout(6)
009
#define LED4 PAout(7)
010
011
#define ADDRS_R 0xA1 //读操作地址
012
#define ADDRS_W 0xA0 //写操作地址
013
014
u8 go = 0;
015
016
void
I2C1_EV_IRQHandler(
void
)
017
{
018
u16 clear = 0;
019
020
if
(I2C1 -> SR1 & 1<<0 )
021
{
022
printf
(
"
I2C1 Start ..
"
);
023
024
switch
(go)
025
{
026
case
0:{
027
I2c_Write(ADDRS_W);
028
break
;
029
}
030
case
1:{
031
I2c_Write(ADDRS_W);
032
break
;
033
}
034
case
2:{
035
I2c_Write(ADDRS_R);
036
break
;
037
}
038
}
039
040
}
041
042
if
(I2C1 -> SR1 & 1<<1 )
043
{
044
printf
(
"
I2C1 has send address ..
"
);
045
clear = I2C1 -> SR2;
046
047
switch
(go)
048
{
049
case
0:{
050
I2c_Write(0x01);
051
break
;
052
}
053
054
case
1:{
055
I2c_Write(0x01);
056
break
;
057
}
058
case
2:{
059
delay(100000);
060
printf
(
"
Read 0x%X from At24c02 ,Address 0x01 ..
"
,I2c_Read());
061
I2c_Stop();
062
break
;
063
}
064
}
065
066
}
067
068
if
(I2C1 -> SR1 & 1<<2 )
069
{
070
071
072
switch
(go)
073
{
074
case
0:{
075
I2c_Write(0x86);
076
printf
(
"
Write 0x%X to At24c02 ,Address 0x01 ..
"
,0x86);
077
078
079
delay(10000);
080
go = 1;
081
I2c_Start();
082
break
;
083
}
084
085
case
1:{
086
087
delay(10000);
088
go = 2;
089
I2c_Start();
090
break
;
091
}
092
case
2:{
093
094
break
;
095
}
096
}
097
098
}
099
100
delay(100000);
101
LED3 = 1;
102
103
104
}
105
106
void
I2C1_ER_IRQHandler(
void
)
107
{
108
delay(100000);
109
LED4 = 1;
110
111
if
(I2C1->SR1 & 1<<10)
112
{
113
printf
(
"
ACK ERROR ..
"
);
114
115
I2C1->SR1 &=~(1<<10);
116
}
117
118
if
(I2C1->SR1 & 1<<14)
119
{
120
printf
(
"
Timeout ..
"
);
121
122
I2C1->SR1 &=~(1<<14);
123
}
124
125
if
(I2C1->SR1 & 1<<11)
126
{
127
printf
(
"
Overrun/Underrun ..
"
);
128
I2C1->SR1 &=~(1<<11);
129
}
130
131
if
(I2C1->SR1 & 1<<9)
132
{
133
printf
(
"
Arbitration lost ..
"
);
134
I2C1->SR1 &=~(1<<9);
135
}
136
137
if
(I2C1->SR1 & 1<<8)
138
{
139
printf
(
"
Bus error ..
"
);
140
I2C1->SR1 &=~(1<<8);
141
}
142
143
144
}
Library/src/i2c.c
view source
print?
01
#include "i2c.h"
02
03
void
I2c_Init(u16 Addr )
04
{
05
06
RCC -> APB1ENR |= 1<<21;
07
08
09
RCC->APB1RSTR |= 1<<21;
10
RCC->APB1RSTR &= ~(1<<21);
11
12
13
14
15
16
I2C1 -> CR2 |= 36 ;
17
18
19
I2C1 -> CCR |= 0<<15;
20
21
22
23
I2C1 -> CCR |= 90<<0;
24
25
26
I2C1 -> TRISE |= 37;
27
28
I2C1 -> CR1 |= 1<<10;
29
I2C1 -> CR1 |= 1<<6;
30
31
I2C1 -> OAR1 |= 0<<15;
32
33
I2C1 -> OAR1 |= 1<<14;
34
35
I2C1 -> OAR1 |= Addr <<1 ;
36
37
38
39
40
41
I2C1 -> CR2 |= 1<<9;
42
I2C1 -> CR2 |= 1<<8;
43
44
I2C1 -> CR1 |= 1<<0;
45
}
46
47
48
void
I2c_Start()
49
{
50
51
I2C1 -> CR1 |= 1<<8;
52
}
53
54
void
I2c_Stop()
55
{
56
I2C1 -> CR1 |= 1<<9;
57
}
58
59
60
void
I2c_Write(u8 data)
61
{
62
I2C1 -> DR = data;
63
}
64
65
u8 I2c_Read()
66
{
67
while
(!(I2C1 -> SR1 & 1<<6));
68
69
return
I2C1 -> DR;
70
}
71
72
void
I2c_End()
73
{
74
I2C1 -> CR1 &= ~(1<<0);
75
}
Library/inc/i2c.h
1
#include
2
3
void
I2c_Init(u16 Addr );
4
5
void
I2c_Start(
void
);
6
void
I2c_Stop(
void
);
7
void
I2c_Write(u8 data);
8
u8 I2c_Read(
void
);
9
void
I2c_End(
void
);
串口接收数据如下:
I2C1 Start ..
I2C1 has send address ..
Write 0x86 to At24c02 ,Address 0x01 ..
I2C1 Start ..
I2C1 has send address ..
I2C1 Start ..
I2C1 has send address ..
Read 0x86 from At24c02 ,Address 0x01 ..
库函数操作
main.c
001
#include "stm32f10x.h"
002
#include "stdio.h"
003
004
#define PRINTF_ON 1
005
006
void
RCC_Configuration(
void
);
007
void
GPIO_Configuration(
void
);
008
void
USART_Configuration(
void
);
009
void
I2C_Configuration(
void
);
010
void
NVIC_Configuration(
void
);
011
012
013
u8 I2C1_ADDRESS = 0x30;
014
u8 I2C2_ADDRESS = 0x31;
015
016
#define Size 4
017
018
vu8 I2C1_Buffer_Tx[Size] = {1,2,3,4};
019
vu8 I2C2_Buffer_Rx[Size] = {0};
020
021
u32 BufferSize = Size ;
022
023
int
main(
void
)
024
{
025
RCC_Configuration();
026
GPIO_Configuration();
027
USART_Configuration();
028
I2C_Configuration();
029
NVIC_Configuration();
030
031
I2C_GenerateSTART(I2C1,ENABLE);
032
033
while
(1);
034
}
035
036
void
I2C_Configuration(
void
)
037
{
038
I2C_InitTypeDef I2C_InitStructure;
039
040
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
041
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
042
I2C_InitStructure.I2C_OwnAddress1 = I2C1_ADDRESS;
043
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
044
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
045
I2C_InitStructure.I2C_ClockSpeed = 200000;
046
I2C_Init(I2C1,&I2C_InitStructure);
047
048
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
049
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
050
I2C_InitStructure.I2C_OwnAddress1 = I2C2_ADDRESS;
051
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
052
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
053
I2C_InitStructure.I2C_ClockSpeed = 200000;
054
I2C_Init(I2C2,&I2C_InitStructure);
055
056
057
I2C_ITConfig(I2C1,I2C_IT_EVT|I2C_IT_BUF,ENABLE);
058
I2C_ITConfig(I2C2,I2C_IT_EVT|I2C_IT_BUF,ENABLE);
059
060
I2C_Cmd(I2C1,ENABLE);
061
I2C_Cmd(I2C2,ENABLE);
062
}
063
064
void
NVIC_Configuration(
void
)
065
{
066
NVIC_InitTypeDef NVIC_InitStructure;
067
068
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
069
070
NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn;
071
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
072
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
073
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
074
NVIC_Init(&NVIC_InitStructure);
075
076
NVIC_InitStructure.NVIC_IRQChannel = I2C2_EV_IRQn;
077
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
078
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
079
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
080
NVIC_Init(&NVIC_InitStructure);
081
}
082
083
void
GPIO_Configuration(
void
)
084
{
085
GPIO_InitTypeDef GPIO_InitStructure;
086
087
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
088
089
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
090
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
091
GPIO_Init(GPIOB , &GPIO_InitStructure);
092
093
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11;
094
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
095
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
096
GPIO_Init(GPIOB , &GPIO_InitStructure);
097
098
099
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
100
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
101
GPIO_Init(GPIOA , &GPIO_InitStructure);
102
103
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
104
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
105
GPIO_Init(GPIOA , &GPIO_InitStructure);
106
}
107
108
void
RCC_Configuration(
void
)
109
{
110
111
ErrorStatus HSEStartUpStatus;
112
113
114
RCC_DeInit();
115
116
RCC_HSEConfig(RCC_HSE_ON);
117
118
HSEStartUpStatus = RCC_WaitForHSEStartUp();
119
120
if
(HSEStartUpStatus == SUCCESS)
121
{
122