通信协议(1)——IIC

  • 基于stm32f407
  • 小结关于iic的内容,附模拟iic代码

一、IIC简介

  • IIC(也叫I2C)是一种两线式串行总线,由数据线SDA时钟线SCL组成
  • 属于串行同步半双工通信方式。(即带时钟同步信号;允许双向传输,但同一个时刻只允许单方向传输
  • iic总线的物理补拓结构如下,SCL和SDA都有上拉电阻,所以总线空闲时通常被拉高
    在这里插入图片描述
  • 总线上控制SCL电平变化的设备为主设备,每一个设备都可以作为主设备或从设备,任何时刻只允许有一个主机
  • 数据传输以字节为单位
  • 总线上可挂载多个设备,为了避免收发错误,绝大多数iic芯片都带有固定地址。一般通信时,主设备先发地址激活对应从设备,再进行数据传输
  • 通常单片机上都带有硬件IIC,直接使用可以不用深究通信过程,但这会导致程序移植困难,且有些单片机硬件IIC设计不好,所以通常用操作IO口模拟软件IIC使用
  • 可在CPU与IC;IC与IC间传输

二、IIC通信协议

I2C协议规定,总线上数据的传输必须以一个起始信号作为开始,以一个结束信号作为结束

1、三种信号

(1) 开始信号:

  • SCL为高电平时,SDA从低电平向高电平跳变。
  • 由主机发送
  • 从设备收到这个就知道要即将开始数据传输
  • 在起始条件产生后,总线处于忙状态,由本次数据传输的主从设备独占,其他I2C器件无法访问总线;而在停止条件产生后,本次数据传输的主从设备将释放总线,总线回归空闲状态

(2)结束信号:

  • SCL为高电平时,SDA从高电平向低电平跳变。
  • 由主机发送
  • 从设备接到后即停止数据接收,这时主从之间就没什么关系了,从机可以进行独立的数据处理或进入休眠等,甚至可以作为主机发起下一次数据传输

(3) 应答信号

  • 从机收到8bit数据后,向主机发送一个特定脉冲,分为应答信号ACK(从机发送0)和非应答信号NACK(从机发送1)
  • 由收信方(主或从)发送
  • 从机收到应答后根据情况判断是否继续传输数据,若没有收到应答,可判断为受控单元故障
    在这里插入图片描述

2、数据传输

主从机建立联系后,一字节数据传输过程如下

  • 先由主机拉低SCL
  • 当SCL为低时,发信方将要发送的位,按从高到低的顺序,以高低电平形式写入SDA
  • 主机拉高SCL,收信方检测SDA电平,记录该位。这段时间内要保证SCL高电平稳定
  • 8位数据传输完成后,发信方释放SDA,由收信方操作SDA发出一个应答信号
    在这里插入图片描述

需要注意以下几点:

  • 数字电路电平变化需要建立时间和保持时间,在模拟IIC时必须留够延时,保证电平已经变化并稳定。具体时间应查看iic设备手册,若没有详细说明就延时稍微长一点
  • 收信方只在SCL为高时检测SDA电平
  • 除了起始和结束信号外,SDA只有在SCL为低时才能变化,否则会被误判为起始/结束信号。所以传输间隙,主机完成一位数据收发后都要立刻拉低SCL,避免SCL为高时SDA抖动造成误判
  • 某些IIC设备支持快速设备等待慢速设备(看手册)。对于这种设备,如果一接收器件在完成其他功能(如一内部中断)前不能接收另一数据的完整字节时,它可以保持时钟线SCL为低,以促使发送器进入等待状态;当接收器准备好接受数据的其它字节并释放时钟SCL后,数据传输继续进行。若收发双方硬件IIC都支持,那么两者可以自行协调;若其中一方硬件IIC不支持,可以不做处理;若一方硬件IIC支持,另一边是软件模拟IIC,则要检测SCL电平,响应慢速方的延时要求。(通常不用)

了解了三种信号和数据的传输方式后,我们已经了解了如何进行完整的一个最小包IIC数据(8bit数据+1bit应答)传输,比如:
在这里插入图片描述

  • 其中SCL全部、SDA的起始/结束信号由主机控制
  • SDA的8bit数据由发送方(主或从)控制
  • SDA的1bit应答由接收方(主或从)控制

3、主从设备配对

前面提到过,为了在总线上的总多设备中匹配主机和从机,需要进行配对,方法如下:

  • 主机发送起始信号
  • 主机发送8bit寻址数据,从高到低为:7bit从机地址+1bit读写标志。读写标志0表示主设备向从设备写数据,1表示主设备向从设备读数据
  • 第9个周期,对应从设备发送应答信号,标志已建立通信

4、通信协议

接下来可以看一看设备间的通信协议了。特别注意的是模拟IIC一定要按照从机的硬件IIC要求设计。具体的通信时序大同小异,一般分为以下三种:

(1)主机向从机写入n字节
在这里插入图片描述

  • 主机发送 起始信号
  • 主机发送 7bit从机地址+写标志
  • 从机应答 ACK (配对完成)
  • 主机发送 8bit数据
  • 从机应答 ACK
  • 主机发送 停止信号

(2)主机从从机读出n字节
在这里插入图片描述
主机发送 起始信号

  • 主机发送 7bit从机地址+读标志
  • 从机应答 ACK (配对完成)
  • 从机发送 8bit数据
  • 主机应答 ACK
  • 从机发送 8bit数据
  • 主机应答 NACK (主机作为接受方时,这个应答可省略)
  • 主机发送 停止信号

(3)混合读写

在这里插入图片描述

  • 其实就是把读写过程混合了,中间的停止改成了重复的开始信号,这样效率较高

注意:这些只是抽象出来一般化的三种情况,不代表适用所有iic器件,但是所有iic器件的三种信号和通信方式是一样的。具体的数据发送格式和时序一定要按照iic器件手册中的读写时序图来编程

三、模拟iic代码

#include "myiic.h"
#include "delay.h"

//-----------------------------------------------------------
//IO方向(应在myiic.h里)
#define SDA_IN()  {GPIOC->MODER&=~(3<<(9*2));GPIOC->MODER|=0<<9*2;}	//PB9ÊäÈëģʽ
#define SDA_OUT() {GPIOC->MODER&=~(3<<(9*2));GPIOC->MODER|=1<<9*2;} //PB9Êä³öģʽ
//IO操作(应在myiic.h里) 
#define IIC_SCL    PCout(8) //SCL
#define IIC_SDA    PCout(9) //SDA	 
#define READ_SDA   PCin(9)  //ÊäÈëSDA 
//-----------------------------------------------------------

void IIC_Init(void)
{			
  GPIO_InitTypeDef  GPIO_InitStructure;

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  GPIO_Init(GPIOC, &GPIO_InitStructure);
  IIC_SCL=1;			//stm32f4位带操作,拉高PC8
  IIC_SDA=1;			//stm32f4位带操作,拉高PC9
}


void IIC_Start(void)
{
	SDA_OUT();     		//sda配置为输出模式
	IIC_SDA=1;	  	  
	IIC_SCL=1;
	delay_us(4);
 	IIC_SDA=0;
	delay_us(4);
	IIC_SCL=0;			//发送完成后拉低SCL,避免SDA抖动出现误判
}	  	


void IIC_Stop(void)
{
	SDA_OUT();
	IIC_SCL=0;
	IIC_SDA=0;
 	delay_us(4);
	IIC_SCL=1; 
	IIC_SDA=1;
	delay_us(4);							   	
}


u8 IIC_Wait_Ack(void)
{
	u8 ucErrTime=0;
	SDA_IN();      			//SDA设为输入,由于上拉电阻,这是SDA实际为高
	IIC_SDA=1;delay_us(1);	//位带操作ODR寄存器,只有SDA输出模式才有用,这句其实没用,就是方便看状态
	IIC_SCL=1;delay_us(1);	 
	while(READ_SDA)			//读SDA电平,若从机应答ACK应受到低
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			IIC_Stop();
			return 1;
		}
	}
	IIC_SCL=0;   
	return 0;  
} 

void IIC_Ack(void)
{
	IIC_SCL=0;
	SDA_OUT();
	IIC_SDA=0;
	delay_us(2);
	IIC_SCL=1;
	delay_us(2);
	IIC_SCL=0;
}
    
void IIC_NAck(void)
{
	IIC_SCL=0;
	SDA_OUT();
	IIC_SDA=1;
	delay_us(2);
	IIC_SCL=1;
	delay_us(2);
	IIC_SCL=0;
}					 		

//IIC发一个字节
//返回从机有无应答
//1有
//0无			  
void IIC_Send_Byte(u8 txd)
{                        
    u8 t;   
		SDA_OUT(); 	    
    IIC_SCL=0;//À­µÍʱÖÓ¿ªÊ¼Êý¾Ý´«Êä
    for(t=0;t<8;t++)
    {              
        IIC_SDA=(txd&0x80)>>7;
        txd<<=1; 	  
				delay_us(2);   //¶ÔTEA5767ÕâÈý¸öÑÓʱ¶¼ÊDZØÐëµÄ
				IIC_SCL=1;
				delay_us(2); 
				IIC_SCL=0;	
				delay_us(2);
    }	 
} 	    

//IIC读一个字节
//ack非零发应答ACK,否则发非应答NACK
u8 IIC_Read_Byte(unsigned char ack)
{
	unsigned char i,receive=0;
	SDA_IN();//SDAÉèÖÃΪÊäÈë
  	for(i=0;i<8;i++ )
	{
    	IIC_SCL=0; 
    	delay_us(2);
		IIC_SCL=1;
    	receive<<=1;
    	if(READ_SDA)receive++;   
			delay_us(1); 
  }				
	
  if (!ack)
    IIC_NAck();//·¢ËÍnACK
  else
    IIC_Ack(); //·¢ËÍACK   
  return receive;
}

上述程序在stm32f407平台测试通过

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

云端FFF

所有博文免费阅读,求打赏鼓励~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值