学习笔记:软件IIC代码实现

最近完成了一个产品电流采集测试方案,有点心得,记录一下,分两篇,一篇IIC通讯,一篇INA219电流采集模块使用介绍。

一.通讯协议简介

芯片间总线(Inter Interface Circuit,IIC),是应用广泛的芯片间串行扩展总线。目前世界上采用的IIC总线一共有两个规范,分别由荷兰飞利浦公司和日本索尼公司提出的,现在基本采用荷兰飞利浦的IIC总线的技术规范。
IIC通讯主要通过SCL(时钟)和SDA(数据)达到通讯的功能,SCL为时钟线,保证通讯信号的时许,SDA为数据线,数据主要通过此线来读取;

二.通讯详解

IIC总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定;只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。,但开始信号和结束信号不在这个限制范围内;
开始信号:在SCL和SDA同时处于高电平的情况下,拉低SDA,即为开始信号,可以开始数据传输;
结束信号:结束信号和开始信号相反,在SCL处于高电平,SDA处于低电平的情况下,拉高SDA,即为结束信号,结束数据传输;
应答信号:IIC通讯中,在SCL处于高电平时,读取数据;在八个周期后,接受端需要给出应答,即在SCL第九个高电平前,拉低SDA,即给出应答;一般发送数据时,需要判断设备是否有应答,来确认数据传输正常;
非应答信号:即数据传输结束时,不应答,跟应答相反就行;

三.代码实现

还有很多细节没有讲到,直接通过实例代码讲解会容易理解一点

1.IIC外设写数据

大概流程为:
1.写入7位设备地址+1位读写状态,1为读,0为写;假设设备地址为1111111,则写地址为:11111110,读地址为11111111;
2.IIC外设初始化,根据datasheet来定;一般是写入寄存器地址,然后再写入规定初始化的数据;
3.写入数据,初始化完成,再向目标寄存器写数据,步骤和初始化差不多,也是先写寄存器地址,再写数据;
第一步代码实现:

	SET_SCL;
    SET_SDA;
    sys_delay_iic();
    CLR_SDA;		// 开始信号
    sys_delay_iic();
    CLR_SCL;		// 数据传输
    for(i = 0;i<8;i++)
    {
        control_SDA(DEVICE_WRITE >> (7-i) & 0x1);
        sys_delay_iic();
        SET_SCL;
        sys_delay_iic();
        CLR_SCL;
    }
    sys_delay_iic();
    SET_SDA;
    sys_delay_iic();
    SET_SCL;
    while(SDA);		// 等待应答,这里需要优化,应该封装ACK函数判断,避免阻塞

开始信号和设备写地址0x8A
开始信号和设备写地址0x8A

第二步其实就是第一步的重复:

	CLR_SCL;    			//write INIT addr
    sys_delay_iic();
    for(i = 0;i<8;i++)
    {
        control_SDA(reg >> (7-i) & 0x1);
        sys_delay_iic();
        SET_SCL;
        sys_delay_iic();
        CLR_SCL;
        sys_delay_iic();
    }  
    SET_SCL;
    sys_delay_iic();
    SET_SDA;
    while(SDA);
    
    CLR_SCL;    			//write init high byte
    for(i = 0;i<8;i++)
    {
        control_SDA(write_data >> (15-i) & 0x1);
        sys_delay_iic();
        SET_SCL;
        sys_delay_iic();
        CLR_SCL;
        sys_delay_iic();
    }  
    SET_SCL;
    sys_delay_iic();
    SET_SDA;
    while(SDA);
  
    CLR_SCL;    			//write write init low byte
    for(i = 0;i<8;i++)
    {
        control_SDA(write_data >> (7-i) & 0x1);
        sys_delay_iic();
        SET_SCL;
        sys_delay_iic();
        CLR_SCL;
        sys_delay_iic();
    }  
    SET_SCL;
    sys_delay_iic();
    SET_SDA;
    while(SDA);
    
    CLR_SCL;
    sys_delay_iic();
    SET_SCL;
    sys_delay_iic();
    SET_SDA;		// 应答

寄存器地址:0x00,写入数据0x399f,然后结束信号结尾
寄存器地址:0x00,写入数据0x399f,然后结束信号结尾

第三步和第二步差不多,就不赘述了;

2.IIC外设读数据

读数据会比写数据复杂一点,大概流程为:
1.写入7位设备地址+1位读写状态,1为读,0为写;
2.IIC外设初始化,根据datasheet来定;
3.写入设备写地址(根据实际情况,需要重新发起通讯则需要这步,如果和上面两步连在一起,则省略);
4.写入目标寄存器地址;
5.重新发送开始信号,写入设备读地址;
6.释放SDA线,根据SCL读取数据;
前面三步和写差不多,直接从第5步开始,代码如下:

	sys_delay_iic();
    SET_SDA;
    sys_delay_iic();
    SET_SCL;
    sys_delay_iic();
    CLR_SDA;				// 开始信号
    sys_delay_iic();
    CLR_SCL;				// 写入设备读地址
    sys_delay_iic();
    for(i = 0;i<8;i++)
    {
        control_SDA(DEVICE_READ >> (7-i) & 0x1);
        SET_SCL;
        sys_delay_iic();
        CLR_SCL;
        sys_delay_iic();
    }
    SET_SCL;
    sys_delay_iic();
    SET_SDA;
    while(SDA);

开始信号+设备读地址0x8B,和写地址波形区别在于最后一位
开始信号+设备读地址0x8B,和写地址波形区别在于最后一位

第六步:

    sys_delay_iic();
    CLR_SCL;
    for(i = 0;i<8;i++)
    {
        sys_delay_iic();
        SET_SCL;
        sys_delay_iic();
        get_data_1 <<= 1;
        if(SDA)
            get_data_1++;
        CLR_SCL;
    }
    sys_delay_iic();
    CLR_SDA;

    sys_delay_iic();
    SET_SCL;
    sys_delay_iic();
    CLR_SCL;
    for(i = 0;i<8;i++)
    {
        sys_delay_iic();
        SET_SCL;
        sys_delay_iic();
        get_data_2 <<= 1;
        if(SDA)
            get_data_2++;
        CLR_SCL;
    }
    sys_delay_iic();
    CLR_SDA;   

获取的数据为0x0700
获取的数据为0x0700

以上便是整个实现软件IIC的流程了,本来是合在一起的逻辑,被拆开用来讲解了,有不对或疑问的地方欢迎大家提出探讨。

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值