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的全部内容,更多相关嵌入式系统内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复