您的位置:首页 > 其它

基于stm32单片机的模拟IIC时序(附源码)

2017-12-30 16:11 302 查看
我下面要说的是基于stm32单片机的模拟IIC时序,以及是一些要注意的事项;结合自己所做的MMA7455加速度传感器,我把模拟IIC的源代码贴了出来,大家可以参考一下。

1.因为在IIC协议中,当总线空闲的时候,SDA和SCL都为高电平,所以硬件电路中SDA和SCL引脚都要接上拉电阻。

2.注意开始信号,停止信号,响应信号,非响应信号的时序,特别是要留意高低电平时间的延时:

3.应答信号分为主机应答和从机应答:
    主机应答是在主机从从机中读取数据时每次读取完一个字节的数据后主机给从机的一个应答信号,表示主机已收到数据了。
    从机应答是指主机给从机发送数据时从机给主机的应答,给一个应答就代表从机已经收到了数据,为主机接下来的工作做个判断。主机在核查从机的应答信号的时候,必须先将SDA总线拉高,释放总线。
    非应答信号是主机给从机的,当读取完一字节数据以后,主机不再去读取数据就给从机一个非应答信号,接着一个停止信号,直接给停止信号也是可以结束此次读操作,但是会对后面的操作带来影响。





主机发送一个字节的数据,从高位开始发送。SCL位高电平的时候,数据必须保持稳定,所以可以在SCL为低电平时组织数据,SCL为高电平时发送或者接收数据;同理读取数据也是类似的。




4.SCL是单向的,由master控制。SDA是双向的,master可以控制,slaver也可以控制。
主机给从机写入数据时,SDA在SCL低电平的时候变化,SDA在SCL高电平的时候保持不变,也就是说在SCL上升沿时写入数据。
主机从从机读取数据时,SDA在SCL高电平的时候变化,SDA在SCL低电平的时候保持不变,也就是说在SCL下升沿时读出数据。
需要注意的是:写入数据时就是要先改变SDA的值再去制造一个SCL的上升沿,读取数据时就是要先改变SDA的值再去制造一个SCL的下降沿,先后顺序必须把握好。
下面是我在用MMA7455加速度传感器时,写的IIC时序;程序已验证过可使用,大家可以参考一下

 C Code 
1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

#define mma7455addree  0x3a                                           //每个设备有还会有自己的设备地址
#define sdah GPIO_SetBits(GPIOA,GPIO_Pin_0)
#define sclh GPIO_SetBits(GPIOA,GPIO_Pin_1)

#define sdal GPIO_ResetBits(GPIOA,GPIO_Pin_0)
#define scll GPIO_ResetBits(GPIOA,GPIO_Pin_1)

void sdain()

{

    GPIO_InitTypeDef i2csdain;

    i2csdain.GPIO_Pin = GPIO_Pin_0;
    i2csdain.GPIO_Mode = GPIO_Mode_IN_FLOATING;        //设置为浮空输入

    GPIO_Init(GPIOA, &i2csdain);

}

void sdaout()

{

    GPIO_InitTypeDef i2csdaout;    

    i2csdaout.GPIO_Pin = GPIO_Pin_0;

    i2csdaout.GPIO_Mode = GPIO_Mode_Out_PP;

    i2csdaout.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(GPIOA, &i2csdaout);

}

void sclout()

{

    GPIO_InitTypeDef i2csclout;

    SystemInit();

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    i2csclout.GPIO_Pin = GPIO_Pin_1;

    i2csclout.GPIO_Mode = GPIO_Mode_Out_PP;

    i2csclout.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(GPIOA, &i2csclout);

}

void i2cst()                     //启动信号的函数

{
    sdaout();

    sclh;

    sdah;

    Delay_us(10);

    sdal;

    Delay_us(5);

    scll;

}

void i2ced()               //停止信号的函数

{

    sdaout();

    sdal;

    sclh;

    Delay_us(10);

    sdah;

    Delay_us(5);

}

void i2cack()             //等待信号,当发送器发送一个数据之后,需要等待从接收端发过来的应答信号,主机等待从机应答

{

    unsigned  char i;

    sdain();

    sclh;

    Delay_us(5);

    while((GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == 1) && (i < 250))  i++;    //检测到SDA为低,也就是从机产生了应答信号或者从机没有应答信号,导致超时,都会跳出该函数。
    scll;

    Delay_us(10);

}

void i2cwrda(unsigned char da)
                     //写入一个字节的函数

{

    unsigned char i, temp, temp1;

    sdaout();

    scll;

    temp1 = da;

    for(i = 0; i < 8; i++)

    {

        scll;

        temp = temp1;

        temp = temp & 0x80; 

        if(temp == 0x80)

        {

            sdah;

        }

        else

        {

            sdal;

        }

        Delay_us(15);

        sclh;

        Delay_us(15);

        temp1 = temp1 << 1;

    }

}

unsigned char i2creda()        
                    //读取一个字节的函数

{

    unsigned char i, j;

    sdain();

    for(i = 0; i < 8; i++)

    {

        sclh;

        Delay_us(5);

        j = (j << 1) | GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0);

        scll;

        Delay_us(5);

    }

    return j;

}

void mma7455Write(unsigned char addr, unsigned char dat)
   //往 mma7455的addr地址写入addr数据
{

    i2cst();

    i2cwrda(0x3a);

    i2cack();

    i2cwrda(addr);

    i2cack();

    i2cwrda(dat);

    i2cack();

    i2ced();

}

unsigned char mma7455Read(unsigned char addr)
       //读取mma7455的addr地址的数据

{

    unsigned char num1;

    i2cst();

    i2cwrda(0x3a);

    i2cack();

    i2cwrda(addr);

    i2cack();

    i2cst();

    i2cwrda(0x3b);

    i2cack();

    num1 = i2creda();

    i2ced();

    return (num1);

}
 

其实多机通信可以用一个简单的办法解决,只要在只要在上面mma7455Write,mma7455Read函数中用if语句根据不同的标志位选择相应的设备地址,要读取地址即可。大家可以去试一下!

这是我个人的一些总结,有什么不对的望指正!大家一起进步!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: