OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 4810|回复: 7

I2C软件模拟程序库

[复制链接]

7

主题

103

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
311
金钱
311
注册时间
2015-8-18
在线时间
63 小时
发表于 2016-1-3 22:48:34 | 显示全部楼层 |阅读模式
本帖最后由 feisheng168 于 2016-1-3 23:27 编辑

今天我给大家分享一下我写的I2C软件模拟程序库的用法,写的不好不要见谅呀。

  因为大家每次为写I2C协议都很麻烦,尤其是多个总线I2C,协议重复写还要重命名,IO底层也要全部复制改写。
  每次还要考虑拉还是不拉,搞得头晕!!!

  这个IC2软件优点有一下几点:
  1. 它可以实现一个你不知道I2C协议是什么的也可以灵活运用。
  2,它只需配置很少底层就可以完成所有操作。
  3. 它可以实现多个总线自动切换功能。
  4,他有多处检测判断总线异常报警。


  I2C库分为两大部分,
  1. i2c.c:         i2c协议.
     i2c.h:         i2c协议头文件.
  2. i2c_config.c    i2c外设配置(配置相应单片机).
     i2c_config.h    i2c外设配置头文件(配置相应单片机引导头文件).

  第一部分我们是不用动的,第二部分是要配置的,
  基本每种单片机我们只需要修改一次(i2c_config.c)这个文件

  以后再用时只需修改i2c_config.h 即可
  下面我说一下关键的配置i2c_config.h的几个定义;

<1> #define I2C_AUTU_WAIT    1          /*屏蔽此宏定义自动等待应答信号关闭*/
<2>#define I2C_WAIT_MAX_CLOCK 200      /*I2C检测应答等待最大时钟*/
<3>#define I2C_SHORT_DELAY  168*3      /*通讯时短暂延时(根据IC协议修改(一般为2.5us~10us))*/

<1> 这个是ACK用的,如果它没有屏蔽表示ACK等待I2C从设发送应答信号,等待到退出;
<2>I2C检测应答等待最大时钟,如果<1>没有屏蔽它为最大等待周期,如果屏蔽它为等待200约两百个时钟,在读ACK;

<3>这个为最重要的一步了,因为上边两个参数可以不修改,但这个必须修改,根据每个平台不一样就要修改大概计算方法近似值
一般I2C为400K-100K 那么每个周期应该为(2.5us~10us);这个定义I2C_SHORT_DELAY值约表示最小周期值;我们来计算一下F4=168M
168次为1us,所以168*3=3us 其实实际CPU要比计算要大,就是说CPU运行后肯定时间比3us长,这个我们就不用管了,只要满足I2C工作就可以了。

呵呵,说了这么多我们来个实战演习
本次I2C库以F4为例,做一用法介绍;24C02读写一个或多个字节

开始,
1。上面的参数我已配好
2。配置IO口(i2c_config.c)程序我也已配好
3.大家现在在F4上只需配置这个

#define I2C1_CHANNEL  1
#define I2C2_CHANNEL  2
#define I2C3_CHANNEL  3

#define I2C1_SCL_PIN                 GPIO_Pin_8
#define I2C1_SCL_GPIO         GPIOB
#define I2C1_SCL_CLOCK  RCC_AHB1Periph_GPIOB
#define I2C1_SDA_PIN                GPIO_Pin_9
#define I2C1_SDA_GPIO         GPIOB
#define I2C1_SDA_CLOCK  RCC_AHB1Periph_GPIOB

#define I2C2_SCL_PIN                 GPIO_Pin_6
#define I2C2_SCL_GPIO         GPIOF
#define I2C2_SCL_CLOCK  RCC_AHB1Periph_GPIOF
#define I2C2_SDA_PIN                GPIO_Pin_7
#define I2C2_SDA_GPIO         GPIOF
#define I2C2_SDA_CLOCK  RCC_AHB1Periph_GPIOF

#define I2C3_SCL_PIN                 GPIO_Pin_2
#define I2C3_SCL_GPIO         GPIOC
#define I2C3_SCL_CLOCK  RCC_AHB1Periph_GPIOC
#define I2C3_SDA_PIN                GPIO_Pin_3
#define I2C3_SDA_GPIO         GPIOC
#define I2C3_SDA_CLOCK  RCC_AHB1Periph_GPIOC

我已经帮大家写了3个总线了,已经可以满足常用的了
如果我们的系统中没有3个总线怎么办?

解决的办法,如果只有一个那我们把它3个写一样,如果是2个我们把后两个写一样,如果三个那正好。
配置好上面3个接口后我们现在就可以用了,用之前我们先要执行
I2C_Initialization();  /*I2C初始化*/程序,它来初始化我们的IO口的。下来看程序

int main(void)
{
  unsigned char i=0;
  unsigned char data[2]={1,2};
  unsigned char buf[8]={0,1,2,3,4,5,6,7};
  unsigned char tbuf[8];

I2C_write_data(0,&data[0],1);写一个字节
I2C_read_ndata(0,&data[1],1);读一个字节

if(data[0]==data[1])
{
  //ok;
}
else
{
   //error;
}

I2C_write_data(0,buf,8);写8个字节
Delayms(10);//根据E2ROM规定他要延时等E2PROM烧写完毕。
I2C_read_ndata(0,tbuf,8);读8个字节
}

呵呵自动切换在哪里呀,I2C_write_data,I2C_read_ndata
这两个程序在哪里呀;
大家看下面就是24C02内部程序了,自动切换在读写程序里了,呵呵
#include "i2c.h"

#define E2_ADDR  0xA0
//**I2C写数据**//
void I2C_write_data(unsigned int addr,unsigned char *buffer,unsigned char n)
{
        unsigned char r;
        I2C_ChannelSelection(I2C1_CHANNEL);

        while(I2C_CheckBusBusy()!=0);  //检查总线忙碌 //

        I2C_Start();
        I2C_SendByte(E2_ADDR);
        while(I2C_CheckAck()!=0);
        I2C_SendByte(addr);
        while(I2C_CheckAck()!=0);         
        for(r=0 ; r<n ; r++)
        {        
           I2C_SendByte(buffer[r]);
           while(I2C_CheckAck()!=0);
        }
        I2C_Stop();
}
//**I2C读数据**//
void I2C_read_ndata(unsigned int addr,unsigned char *buffer,unsigned char count)
{
        unsigned char i;
        I2C_ChannelSelection(I2C1_CHANNEL);

        while(I2C_CheckBusBusy()!=0);  //检查总线忙碌 //

        I2C_Start();
        I2C_SendByte(E2_ADDR);
        while(I2C_CheckAck()!=0);
        I2C_SendByte(addr);
        while(I2C_CheckAck()!=0);         
        I2C_Start();
        I2C_SendByte(E2_ADDR+1);
        while(I2C_CheckAck()!=0);
        for(i=0 ; i<count ; i++)
        {
                buffer = I2C_ReadByte();
                if(i<count-1)
                I2C_ReadAck();
        }
        I2C_NoAck();
        I2C_Stop();
}

呵呵看到了吧只需在读写前加

I2C_ChannelSelection(I2C1_CHANNEL);这个函数就可以啦
I2C1_CHANNEL就是我们开始填写的总线通道了,呵呵讲到这里我估计大家也迷糊,不如你们把附件带入你们的F4移植看看,就明白啦。


今天就讲到这里不会的可以提问,呵呵我写的程序如果大家发现有什么错误可要多多提醒呀,谢谢。!!!!!!
全部附件:
test.rar (4.57 KB, 下载次数: 542)
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

120

主题

7878

帖子

13

精华

资深版主

Rank: 8Rank: 8

积分
12012
金钱
12012
注册时间
2013-9-10
在线时间
427 小时
发表于 2016-1-4 08:09:30 | 显示全部楼层
大神呀,谢谢分享!!!,原子哥要来酷了
回复 支持 反对

使用道具 举报

48

主题

537

帖子

2

精华

金牌会员

Rank: 6Rank: 6

积分
1369
金钱
1369
注册时间
2014-2-13
在线时间
169 小时
发表于 2016-1-4 08:16:54 | 显示全部楼层
这种可移植的东西越多越好啊,顶顶!
回复 支持 反对

使用道具 举报

13

主题

123

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
242
金钱
242
注册时间
2013-1-6
在线时间
20 小时
发表于 2016-1-4 10:10:34 | 显示全部楼层
cool,不解释
回复 支持 反对

使用道具 举报

2

主题

34

帖子

0

精华

初级会员

Rank: 2

积分
130
金钱
130
注册时间
2016-1-2
在线时间
13 小时
发表于 2016-1-4 11:01:03 | 显示全部楼层
酷呀!
回复 支持 反对

使用道具 举报

120

主题

7878

帖子

13

精华

资深版主

Rank: 8Rank: 8

积分
12012
金钱
12012
注册时间
2013-9-10
在线时间
427 小时
发表于 2016-1-4 13:00:17 | 显示全部楼层
增加可裁剪多个IIC接口功能就更完美了,比如支持1个、支持2个、支持3个。。。通过宏定义进行修改
回复 支持 反对

使用道具 举报

1

主题

6

帖子

0

精华

新手入门

积分
11
金钱
11
注册时间
2016-1-5
在线时间
1 小时
发表于 2016-1-5 17:40:11 | 显示全部楼层
灰常感谢
回复 支持 反对

使用道具 举报

5

主题

44

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
451
金钱
451
注册时间
2016-7-25
在线时间
74 小时
发表于 2017-5-13 14:34:38 | 显示全部楼层
mark!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-9 08:45

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表