我是靠谱客的博主 丰富皮卡丘,这篇文章主要介绍嵌入式系统:I2C,现在分享给大家,希望可以做个参考。

I2C

在这里插入图片描述


(一)I2C协议

1.通信方式

(1)同步串行

(2)半双工


2.电路连接
在这里插入图片描述
(1)引脚

  • SDA:串行数据引脚
  • SCL:同步串行时钟引脚

(2)引脚特性

  • I2C引脚模式为开漏模式

    • 一个总线多设备连接,防止短路(不会出现高低电平同时出现,损坏IO)
    • 外接上拉电阻,输出高电平

  • 线与逻辑,总线上只能有一个主设备(总线仲裁)

    • 总线被占用后,其他设备无法占用(SDA由高电平变为低电平,启动总线)

2.数据传输时序

在这里插入图片描述
(1)开始条件

  • SCL为高电平时,SDA由高电平变为低电平

(2)从机地址 + 读写命令

(3)数据收发

(4)停止条件

  • SCL为高电平时,SDA由低电平变为高电平

3.数据收发电平
在这里插入图片描述
(1)SCL处于高电平时,SDA电平稳定(从机接收数据)

(2)SCL处于低电平时,SDA电平变化(主机发送数据)


4.数据帧格式
在这里插入图片描述
(1)从机地址(7位地址 + 1位读写控制)

(2)1位应答位

(3)数据(8位)


(二)I2C读写数据流程

1.写数据流程

(1)主机启动总线(开始条件)

(2)主机发送从机地址 + 写命令,等待从机应答

(3)主机写从机寄存器地址,等待从机应答

(4)主机写数据,等待从机应答(可多字节写,但一次只能写一个字节,重复写)

(5)写操作完成,主机停止总线(停止条件)


2.读数据流程

(1)主机启动总线(开始条件)

(2)主机发送从机地址 + 写命令,等待从机应答

(3)主机写从机寄存器地址,等待从机应答

(4)主机重新启动总线

(5)主机发送从机地址 + 读命令,等待从机应答

(6)主机读取从机数据,主机发送应答信号(多字节读取,但一次只能读一个字节,重复读)

(7)读操作完成,主机停止总线(停止条件)


(三)编程

1.编程流程

(1)GPIO复用为I2C模式(硬件I2C)

  • 注意配置引脚为开漏模式
  • 内部上拉

(2)I2C功能配置

  • 波特率(时钟频率)
  • 主从模式
  • 从地址位数(7bit/10bit)
  • 应答信号使能

(3)I2C模块使能

(4)数据收发(按照时序)


2.编程实例

(1)寄存器版本

#include "msp.h"
#include "driverlib.h" 

void initI2C()
{
	//GPIO复用为I2C
	P1->SEL0 |= (BIT6 | BIT7);
	P1->SEL1 &=~(BIT6 | BIT7);
	
	//I2C功能配置
	//打开I2C寄存器配置
	EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_SWRST;
	
	//时钟源选择:3MHz
	EUSCI_B0->CTLW0 |= EUSCI_B_I2C_CLOCKSOURCE_SMCLK;
	//时钟分频:100kHz
	EUSCI_B0->BRW = 30;	
	//I2C模式、主机
	EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_MODE_3 | EUSCI_B_CTLW0_MST;
	
	//关闭寄存器配置
	EUSCI_B0->CTLW0 &=~EUSCI_B_CTLW0_SWRST;
}

int I2CsendByte(uint8_t SlaveAddr,uint8_t PointerAddr,uint8_t *SendData,uint8_t Num)
{
	int timeout = 100;
	
	//发送从机地址
	EUSCI_B0->I2CSA = SlaveAddr;
	
	//发送起始条件
	EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_TR | EUSCI_B_CTLW0_TXSTT;
	
	//等待起始条件发送完成
	while(EUSCI_B0->CTLW0 & EUSCI_B_CTLW0_TXSTT)
	{
		timeout--;
		if(timeout < 0)
			return 1;
	}
	
	//发送寄存器地址
	EUSCI_B0->TXBUF = PointerAddr;
	
	//等待传输完成
	timeout = 100;
	while(EUSCI_B0->TXBUF)
	{
		timeout--;
		if(timeout < 0)
			return 2;
	}
	
	while(Num)
	{
		EUSCI_B0->TXBUF = *SendData;
		
		timeout = 100;
		while(EUSCI_B0->TXBUF)
		{
			timeout--;
			if(timeout < 0)
				return 3;
		}
		
		SendData++;
		Num--;
	}
	
	//发送停止条件
	EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_TXSTP;
}

int I2CrecvByte(uint8_t SlaveAddr,uint8_t PointerAddr,uint8_t *RecvData,uint8_t Num)
{
	int timeout = 100;
	
	//发送从机地址
	EUSCI_B0->I2CSA = SlaveAddr;
	
	//发送起始条件
	EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_TR | EUSCI_B_CTLW0_TXSTT;
	
	//等待起始条件发送完成
	while(EUSCI_B0->CTLW0 & EUSCI_B_CTLW0_TXSTT)
	{
		timeout--;
		if(timeout < 0)
			return 4;
	}
	
	//发送寄存器地址
	EUSCI_B0->TXBUF = PointerAddr;
	
	//等待传输完成
	timeout = 100;
	while(EUSCI_B0->TXBUF)
	{
		timeout--;
		if(timeout < 0)
			return 5;
	}
	
	//发送停止条件
	EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_TXSTP;
	
	timeout = 100;
	while(EUSCI_B0->CTLW0 & EUSCI_B_CTLW0_TXSTP)
	{
		timeout--;
		if(timeout < 0)
			return 6;
	}
	
	//发送开始条件(接收模式下)
	EUSCI_B0->CTLW0 &=~EUSCI_B_CTLW0_TR;
	EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_TXSTT;
	
	//等待起始条件发送完成
	while(EUSCI_B0->CTLW0 & EUSCI_B_CTLW0_TXSTT)
	{
		timeout--;
		if(timeout < 0)
			return 7;
	}
	
	while(Num)
	{
		*RecvData = EUSCI_B0->RXBUF;
		RecvData++;
		Num--;
	}
	
	//发送停止条件
	EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_TXSTP;
}

void main()
{
	WDTCTL = WDTPW + WDTHOLD;
	
	initI2C();
	while(1);
}

(2)库函数版本

#include "msp.h"
#include "driverlib.h" 

void initI2C()
{
	//GPIO复用为I2C
	GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1,GPIO_PIN6 + GPIO_PIN7, GPIO_PRIMARY_MODULE_FUNCTION);
	
	//I2C功能配置
	eUSCI_I2C_MasterConfig i2cConfig;
	
	i2cConfig.selectClockSource		= EUSCI_B_I2C_CLOCKSOURCE_SMCLK;
	i2cConfig.i2cClk				= 3000000;
	i2cConfig.dataRate				= EUSCI_B_I2C_SET_DATA_RATE_100KBPS;
	i2cConfig.byteCounterThreshold	= 0;
	i2cConfig.autoSTOPGeneration	= EUSCI_B_I2C_NO_AUTO_STOP;
	
	
	I2C_initMaster(EUSCI_B1_BASE, &i2cConfig);
	
}

int SendI2CByte(uint8_t SlaveAddr,uint8_t PointerAddr,uint8_t *SendData,uint8_t Num)
{
	//提前设置好从机地址(这点与其他MCU不同)
	I2C_setSlaveAddress(EUSCI_B0_BASE,SlaveAddr);
	
	//发送模式
	I2C_setMode(EUSCI_B0_BASE,EUSCI_B_I2C_TRANSMIT_MODE);
	
	/* Clear any existing interrupt flag PL */
    I2C_clearInterruptFlag(EUSCI_B1_BASE,EUSCI_B_I2C_TRANSMIT_INTERRUPT0);

    /* Wait until ready to write PL */
    while (I2C_isBusBusy(EUSCI_B1_BASE));
	
	//发送开始条件 + 寄存器地址
	while(!I2C_masterSendMultiByteStartWithTimeout(EUSCI_B0_BASE,PointerAddr,EUSCI_B_I2C_TIMEOUT_28_MS))
		return 1;
	
	//发送数据
	while(Num)
	{
		while(!I2C_masterSendMultiByteNextWithTimeout(EUSCI_B0_BASE,*SendData,EUSCI_B_I2C_TIMEOUT_28_MS))
			return 2;
		SendData++;
		Num--;
	}
	
	I2C_masterSendMultiByteStop(EUSCI_B0_BASE);
	
}

int RecvI2CByte(uint8_t SlaveAddr,uint8_t PointerAddr,uint8_t *RecvData,uint8_t Num)
{
	//提前设置好从机地址(这点与其他MCU不同)
	I2C_setSlaveAddress(EUSCI_B0_BASE,SlaveAddr);
	
	//发送模式
	I2C_setMode(EUSCI_B0_BASE,EUSCI_B_I2C_TRANSMIT_MODE);
	
	/* Clear any existing interrupt flag PL */
    I2C_clearInterruptFlag(EUSCI_B1_BASE,EUSCI_B_I2C_TRANSMIT_INTERRUPT0);

    /* Wait until ready to write PL */
    while (I2C_isBusBusy(EUSCI_B1_BASE));
	
	//发送开始条件 + 寄存器地址
	while(!I2C_masterSendMultiByteStartWithTimeout(EUSCI_B0_BASE,PointerAddr,EUSCI_B_I2C_TIMEOUT_28_MS))
		return 3;
	
	//发送停止条件
	while(!I2C_masterSendMultiByteStopWithTimeout(EUSCI_B0_BASE,EUSCI_B_I2C_TIMEOUT_28_MS))
		return 4;
	
	//接收模式 + 开始条件
	I2C_masterReceiveStart(EUSCI_B0_BASE);
	
	while(Num)
	{
		/* Wait for RX buffer to fill */
		while(!(I2C_getInterruptStatus(EUSCI_B1_BASE,EUSCI_B_I2C_RECEIVE_INTERRUPT0)));
	

		/* Read from I2C RX register */
		*RecvData = I2C_masterReceiveMultiByteNext(EUSCI_B1_BASE);
		
		RecvData++;
		Num--;
	}
	
	I2C_masterReceiveMultiByteStop(EUSCI_B0_BASE);
	
}

void main()
{
	/* Disabling the Watchdog  */
    WDT_A_holdTimer();

	initI2C();

	while(1);
}

最后

以上就是丰富皮卡丘最近收集整理的关于嵌入式系统:I2C的全部内容,更多相关嵌入式系统内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(55)

评论列表共有 0 条评论

立即
投稿
返回
顶部