跟着原子学I2C

这篇具有很好参考价值的文章主要介绍了跟着原子学I2C。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

I2C通讯

1、IIC总线介绍

集成电路总线,是一种同步串行半双工通信总线。

总线or协议?!

总线是数据传输通道,协议是数据传输规则。

跟着原子学I2C

1、1介绍

a、由时钟线SCL和数据线SDA组成,并且都接上拉电阻,确保总线空闲状态为高电平。

b、总线支持多设备连接,允许多主机存在,每个设备都有一个唯一的地址。

c、连接到总线上的数目受总线的最大电容400pf限制

d、数据传输速率:标准模式100k bit/s 快速模式400k bit/s 高速模式3.4M bit/s。

1、2归纳

三个信号: 起始信号、停止信号、应答信号。

两个注意:数据有效性、数据传输顺序。

一个状态:空闲状态。

起始信号:当SCL为高电平时,SDA从高电平变为低电平。

停止信号:当SCL为高电平时,SDA从低电平变为高电平。

应答信号:上拉电阻影响下SDA默认为高,而从机拉低SDA就是确认收到数据,为ACK,如果没有收到,为NACK。

数据先发送高位,数据以字节(8bit)传输,数据在SCL高电平稳定。

空闲状态:SCL、SDA都是高电平。

1、3跟着正点原子写代码

起始信号

/*SDA、SCL开始都处于高电平,SCL为高电平期间,SDA从高到低跳变*/
void iic_start(void)
{
 IIC_SDA(1);
 IIC_SCL(1);
 IIC_delay();//delay时间看器件
 IIC_SDA(0);
 IIC_delay();
 IIC_SCL(0);//SCL拉低,钳住总线,准备发送/接收数据
 IIC_delay();
}

停止信号

/*SCL为高电平期间,SDA从低电平往高电平跳变*/
void iic_stop(void)
{ 
   IIC_SDA(0);
   IIC_delay();
   IIC_SCL(1);
   IIC_delay();
   IIC_SDA(1);
   IIC_delay();
}

检测应答信号(主机)

//return:  1:fail  0:succeed
uint8_t iic_wait_ack(void) 
{
   IIC_SDA(1);//主机释放SDA线
   IIC_delay();
   IIC_SCL(1);//从机返回ACK
   IIC_delay();
   if(IIC_READ_SDA)//SCL高电平读取SDA状态
   {
      iic_stop();//SDA高电平表示从机NACK
      return 1;
   }
   IIC_SCL(0);
   iic_delay();
   return 0;
}

发送应答信号

void iic_ack(void)
{ 
  IIC_SCL(0);
  IIC_delay();
  IIC_SDA(0);
  IIC_delay();
  IIC_SCL(1);
  IIC_delay();
}

发送非应答信号

void iic_ack(void)
{   
IIC_SCL(0); 
IIC_delay();
IIC_SDA(1);
IIC_delay(); 
IIC_SCL(1); 
IIC_delay();
}
发送1字节数据
void  iic_send_byte(uint8_t  data)
{
  for(uint8_t t=0;t<8;t++)
  {
      IIC_SDA((data&0x80)>>7);
      IIC_delay(); 
      IIC_SCL(1); 
      IIC_delay();
      IIC_SCL(0);
      data<<=1;//左移1位,用于下一次发送   
    }
    IIC_SDA(1);//发送完成,主机释放SDA线
    
}

读取1字节数据

void  iic_read_byte(uint8_t  ack)
{
  uint8_t receive =0;
  for(uint8_t t=0;t<8;t++)
  {
  receive<<1;//高位先输出,先收到的数据位要左移
  IIC_SCL(1);
  IIC_delay();
  if(IIC_READ_SDA)receive++;
  IIC_SCL(0);
  IIC_delay();
  }
  if(!ack)iic_nack();
  else iic_ack();
  return receive;
}

1、4找个NFC芯片测试代码

/**
 * @brief       NFC读取数据
 * @param      NFC读数据
 * @retval     NFC
 */
uint8_t NFC_readData(uint8_t add1,uint8_t add2)
{   
    uint8_t data;
    iic_start();
    iic_send_byte(0xae);
    iic_wait_ack();
    iic_send_byte(add1);
    iic_wait_ack();
    iic_send_byte(add2);
    iic_wait_ack();
    iic_start();
    iic_send_byte(0xaf);
    iic_wait_ack();
    data =iic_read_byte(1);
    iic_nack();
    iic_stop();
    
    return data;

}


/**
 * @brief       NFC写入数据
 * @param      NFC写数据
 * @retval     NFC
 */
void NFC_writeData(uint8_t add1,uint8_t add2,uint8_t data)
{
    
    iic_start();
    iic_send_byte(0xae);
    iic_wait_ack();
    iic_send_byte(add1);
    iic_wait_ack();
    iic_send_byte(add2);
    iic_wait_ack();
    iic_send_byte(data);
    iic_wait_ack();
    iic_stop();  
    
}

以上代码添加到正点原子HAL库I2C实验工程里,具体代码如下:

myiic.c文件

/**
 ****************************************************************************************************
 * @file        myiic.c
 * @author      正点原子团队(ALIENTEK)
 * @version     V1.0
 * @date        2020-04-24
 * @brief       IIC 驱动代码
 * @license     Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
 ****************************************************************************************************
 * @attention
 *
 * 实验平台:正点原子 STM32F103开发板
 * 在线视频:www.yuanzige.com
 * 技术论坛:www.openedv.com
 * 公司网址:www.alientek.com
 * 购买地址:openedv.taobao.com
 *
 * 修改说明
 * V1.0 20200424
 * 第一次发布
 *
 ****************************************************************************************************
 */

#include "./BSP/IIC/myiic.h"
#include "./SYSTEM/delay/delay.h"

/**
 * @brief       初始化IIC
 * @param       无
 * @retval      无
 */
void iic_init(void)
{
    GPIO_InitTypeDef gpio_init_struct;

    IIC_SCL_GPIO_CLK_ENABLE();  /* SCL引脚时钟使能 */
    IIC_SDA_GPIO_CLK_ENABLE();  /* SDA引脚时钟使能 */

    gpio_init_struct.Pin = IIC_SCL_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;        /* 推挽输出 */
    gpio_init_struct.Pull = GPIO_PULLUP;                /* 上拉 */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;      /* 高速 */
    HAL_GPIO_Init(IIC_SCL_GPIO_PORT, &gpio_init_struct);/* SCL */

    gpio_init_struct.Pin = IIC_SDA_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_OUTPUT_OD;        /* 开漏输出 */
    HAL_GPIO_Init(IIC_SDA_GPIO_PORT, &gpio_init_struct);/* SDA */
    /* SDA引脚模式设置,开漏输出,上拉, 这样就不用再设置IO方向了, 开漏输出的时候(=1), 也可以读取外部信号的高低电平 */

    iic_stop();     /* 停止总线上所有设备 */
}

/**
 * @brief       IIC延时函数,用于控制IIC读写速度
 * @param       无
 * @retval      无
 */
static void iic_delay(void)
{
    delay_us(2);    /* 2us的延时, 读写速度在250Khz以内 */
}

/**
 * @brief       产生IIC起始信号
 * @param       无
 * @retval      无
 */
void iic_start(void)
{
    IIC_SDA(1);
    IIC_SCL(1);
    iic_delay();
    IIC_SDA(0);     /* START信号: 当SCL为高时, SDA从高变成低, 表示起始信号 */
    iic_delay();
    IIC_SCL(0);     /* 钳住I2C总线,准备发送或接收数据 */
    iic_delay();
}

/**
 * @brief       产生IIC停止信号
 * @param       无
 * @retval      无
 */
void iic_stop(void)
{
    IIC_SDA(0);     /* STOP信号: 当SCL为高时, SDA从低变成高, 表示停止信号 */
    iic_delay();
    IIC_SCL(1);
    iic_delay();
    IIC_SDA(1);     /* 发送I2C总线结束信号 */
    iic_delay();
}

/**
 * @brief       等待应答信号到来
 * @param       无
 * @retval      1,接收应答失败
 *              0,接收应答成功
 */
uint8_t iic_wait_ack(void)
{
    uint8_t waittime = 0;
    uint8_t rack = 0;

    IIC_SDA(1);     /* 主机释放SDA线(此时外部器件可以拉低SDA线) */
    iic_delay();
    IIC_SCL(1);     /* SCL=1, 此时从机可以返回ACK */
    iic_delay();

    while (IIC_READ_SDA)    /* 等待应答 */
    {
        waittime++;

        if (waittime > 250)
        {
            iic_stop();
            rack = 1;
            break;
        }
    }

    IIC_SCL(0);     /* SCL=0, 结束ACK检查 */
    iic_delay();
    return rack;
}

/**
 * @brief       产生ACK应答
 * @param       无
 * @retval      无
 */
void iic_ack(void)
{
    IIC_SDA(0);     /* SCL 0 -> 1  时 SDA = 0,表示应答 */
    iic_delay();
    IIC_SCL(1);     /* 产生一个时钟 */
    iic_delay();
    IIC_SCL(0);
    iic_delay();
    IIC_SDA(1);     /* 主机释放SDA线 */
    iic_delay();
}

/**
 * @brief       不产生ACK应答
 * @param       无
 * @retval      无
 */
void iic_nack(void)
{
    IIC_SDA(1);     /* SCL 0 -> 1  时 SDA = 1,表示不应答 */
    iic_delay();
    IIC_SCL(1);     /* 产生一个时钟 */
    iic_delay();
    IIC_SCL(0);
    iic_delay();
}

/**
 * @brief       IIC发送一个字节
 * @param       data: 要发送的数据
 * @retval      无
 */
void iic_send_byte(uint8_t data)
{
    uint8_t t;
    
    for (t = 0; t < 8; t++)
    {
        IIC_SDA((data & 0x80) >> 7);    /* 高位先发送 */
        iic_delay();
        IIC_SCL(1);
        iic_delay();
        IIC_SCL(0);
        data <<= 1;     /* 左移1位,用于下一次发送 */
    }
    IIC_SDA(1);         /* 发送完成, 主机释放SDA线 */
}

/**
 * @brief       IIC读取一个字节
 * @param       ack:  ack=1时,发送ack; ack=0时,发送nack
 * @retval      接收到的数据
 */
uint8_t iic_read_byte(uint8_t ack)
{
    uint8_t i, receive = 0;

    for (i = 0; i < 8; i++ )    /* 接收1个字节数据 */
    {
        receive <<= 1;  /* 高位先输出,所以先收到的数据位要左移 */
        IIC_SCL(1);
        iic_delay();

        if (IIC_READ_SDA)
        {
            receive++;
        }
        
        IIC_SCL(0);
        iic_delay();
    }

    if (!ack)
    {
        iic_nack();     /* 发送nACK */
    }
    else
    {
        iic_ack();      /* 发送ACK */
    }

    return receive;
}


/**
 * @brief       code卡读取数据
 * @param       code卡读数据
 * @retval      code卡
 */

void code_readData(uint8_t add)
{
    uint8_t data;
    iic_start();
    iic_send_byte(0xa0);
    iic_wait_ack();
    iic_send_byte(add);
    iic_wait_ack();
    iic_send_byte(0xa1);
    iic_wait_ack();
    data =iic_read_byte(1);
    iic_stop();
    
}

/**
 * @brief       NFC读取数据
 * @param      NFC读数据
 * @retval     NFC
 */

uint8_t NFC_readData(uint8_t add1,uint8_t add2)
{   
    uint8_t data;
    iic_start();
    iic_send_byte(0xae);
    iic_wait_ack();
    iic_send_byte(add1);
    iic_wait_ack();
    iic_send_byte(add2);
    iic_wait_ack();
    iic_start();
    iic_send_byte(0xaf);
    iic_wait_ack();
    data =iic_read_byte(1);
    iic_nack();
    iic_stop();
    
    return data;

}


/**
 * @brief       NFC写入数据
 * @param      NFC写数据
 * @retval     NFC
 */
void NFC_writeData(uint8_t add1,uint8_t add2,uint8_t data)
{
    
    iic_start();
    iic_send_byte(0xae);
    iic_wait_ack();
    iic_send_byte(add1);
    iic_wait_ack();
    iic_send_byte(add2);
    iic_wait_ack();
    iic_send_byte(data);
    iic_wait_ack();
    iic_stop();  
    
}









在main.c中调用:



int main(void)
{


    HAL_Init();                                 /* 初始化HAL库 */
    sys_stm32_clock_init(RCC_PLL_MUL9);         /* 设置时钟, 72Mhz */
    delay_init(72);                             /* 延时初始化 */
    usart_init(115200);                         /* 串口初始化为115200 */
    usmart_dev.init(72);                        /* 初始化USMART */
    iic_init();

    while (1)
    {
      //  NFC
       uint8_t  data; 
     
      NFC_writeData(0,64,0x88);
       
       NFC_readData(0,64);
        
        delay_ms(1000);
         delay_ms(1000);

    }
}

看一下效果:

写数据效果如下:

跟着原子学I2C

 读数据效果如下:

跟着原子学I2C

 请注意:读数据要注意

先写新地址,在写两个寄存器地址后,在i2cstart一下,发送度数据指令,在读数据!!!

我之前写的读数据代码是这样的(错误代码如下):

/**
 * @brief       NFC读取数据
 * @param      NFC读数据
 * @retval     NFC
 */
uint8_t NFC_readData(uint8_t add1,uint8_t add2)
{   
    uint8_t data;
    iic_start();
    iic_send_byte(0xaf);
    iic_wait_ack();
    iic_send_byte(add1);
    iic_wait_ack();
    iic_send_byte(add2);
    iic_wait_ack();
    iic_send_byte(0xaf);
    iic_wait_ack();
    data =iic_read_byte(1);
    iic_nack();
    iic_stop();
    
    return data;

}

这样波形根本不对,发送芯片地址有回应,发送寄存器地址没有回应。(错误波形如下)

跟着原子学I2C

完整工程已上传到github,注意测试时I2C从机的芯片地址看数据手册。文章来源地址https://www.toymoban.com/news/detail-414497.html

到了这里,关于跟着原子学I2C的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • I2C总线驱动

    SOC芯片平台的外设分为: 一级外设:外设控制器集成在SOC芯片内部 二级外设:外设控制器由另一块芯片负责,通过一些通讯总线与SOC芯片相连 Inter-Integrated Circuit: 字面意思是用于“集成电路之间”的通信总线,简写:IIC(或者I2C) i2c传输的要点就是: 传输一个字节 后面必然

    2024年02月15日
    浏览(40)
  • STM32-I2C通讯

    I2C( Inter-Integrated Circuit )是一种通用的总线协议。它是由Philips(飞利浦)公司,现NXP(恩智浦)半导体开发的一种 简单的双向两线制 总线协议标准。 I2C有两根双向的信号线,一根数据线SDA用于收发数据,一根时钟线SCL用于通信双方时钟的同步。 支持同步,半双工,带数据应答,

    2024年03月14日
    浏览(43)
  • day9 STM32 I2C总线通信

            I2C(Inter-Integrated Circuit)总线(也称IIC或I2C)是由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备,是微电子通信控制领域广泛采用的一种总线标准。         它是同步通信的一种特殊形式,具有接口线少,控制方式简单,期间封装形式少,通

    2024年02月12日
    浏览(51)
  • STM32 I2C通讯+MPU6050通讯演示

    1.I2C通讯简介 I2C(Inter IC Bus)是由Philips公司开发的一种通用数据总线; 两根通信线:SCL(Serial Clock)、SDA(Serial Data); 同步,半双工,带数据应答; 支持总线挂载多设备(一主多从、多主多从) 2.硬件电路 所有I2C设备的SCL连在一起,SDA连在一起; 设备的SCL和SDA均要配置

    2024年01月21日
    浏览(70)
  • STM32完成软件I2C通讯

    今天的重点是利用STM32的软件方案和MPU60506轴姿态传感器建立通讯,今天只完成了简单的发送地址和接收应答的部分,特此记录一下过程,以后忘记可以随时翻出来看看。 先介绍最基本的I2C通讯的最基本的6个时序: 一:起始条件:SCL高电平期间,SDA从高电平切换到低电平 时

    2024年04月13日
    浏览(40)
  • AT24C02(I2C总线)通信的学习

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 学习AT24C02(I2C总线)芯片 RAM()存储速度较快,但容易丢失数据。ROM(Read Only Memory)存储速度较慢,但掉电不丢失数据。在使用时需要两者结合先存入RAM再转存到ROM中。 AT24C02是一种可以实现掉电不丢失

    2024年02月20日
    浏览(46)
  • STM32之I2C总线知识和HAL库函数

    一、 I2C总线知识 I2C总线物理拓扑结构 I2C 总线在物理连接上非常简单,分别由SDA(串行数据线)和SCL(串行时钟线)及上拉电阻组成。通信原理是通过对SCL和SDA线高低电平时序的控制,来 产生I2C总线协议所需要的信号进行数据的传递。在总线空闲状态时,这两根线一般被上面所接

    2024年02月21日
    浏览(44)
  • 【51单片机】AT24C20数据帧(I2C总线)

    🎊专栏【51单片机】 🍔喜欢的诗句:更喜岷山千里雪 三军过后尽开颜。 🎆音乐分享【Love Story】 🥰大一同学小吉,欢迎并且感谢大家指出我的问题🥰 小吉先向大家道个歉,因为最近在期末突击,所以文章久久没有更新,也请大家多多见谅😥 目录   🎁I2C总线 🏳️‍🌈

    2024年02月08日
    浏览(67)
  • 51单片机——模拟I2C总线与AT24C02通信

    目录 一、写在前面 二、功能描述 三、主要模块介绍 3.1 I2C总线介绍 3.2 I2C总线协议 3.2.1数据有效规定 3.2.2起始信号和停止信号  3.2.3 发送应答和接收应答 3.2.4 主机发送一个字节和接收一个字节 3.3 AT24C02介绍 3.3 字节写和随机读 四、测试文件test.c 五、现象描述 AT24C02芯片有I

    2024年02月14日
    浏览(53)
  • I2C总线驱动:裸机版、应用层的使用、二级外设驱动三种方法

    SOC芯片平台的外设分为: 一级外设:外设控制器集成在SOC芯片内部 二级外设:外设控制器由另一块芯片负责,通过一些通讯总线与SOC芯片相连 Inter-Integrated Circuit: 字面意思是用于“集成电路之间”的通信总线,简写:IIC(或者I2C) i2c传输的要点就是: 传输一个字节 后面必然

    2024年02月09日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包