基于Kinetis系列微控制器K60芯片的I2C接口函数程序说明1
作者:互联网
I2C、I2C或IIC通信提供了一种可以与若干设备之间进行通信的方法。
在总线最大负载下,该接口可被设计为100 kbit/s的传输速率。
该接口处理信息波特率最大可达系统时钟的二十分之一,以此减少总线负载。
最大总线电容为400pf限制了设备的最大通信长度和可连接从设备数。
I2C模块具有以下特点:
• 兼容IIC-bus规格
• Multimaster操作
• 软件可编程为64种不同的串行时钟频率之一
• Software-selectable确认位
• 中断驱动的逐字节数据传输
• 主从切换下自动仲裁
• 呼叫地址识别中断
• 启动和停止信号的产生和检测
• 重复启动信号的产生和检测
• 确认位产生和检测
• bus忙检测
• General调用识别
• 10位地址扩展
• 可编程故障输入筛选
• 低功率模式唤醒slave地址匹配
• 多从地址支持
• DMA支持
具体初始化代码如下:
重点:
1.MULT = 2 对应 mul = 4
2.ICR = 0x17 ICR为Clock rate时钟频率
从I2C Divider and Hold Values可得:
ICR SCL Divider SDA Hold Value SCL Hold (Start) Value SCL Hold (Stop) Value
17 128 21 58 65
则 I2C baud rate = bus speed (Hz)/(mul × SCL divider) 即 135MHz/(4 × 128) = 263.6718kHz
void I2C_Init(I2Cn I2CNum)
{
if(I2CNum == I2CNUM0)
{
SIM_SCGC4 |= SIM_SCGC4_I2C0_MASK; //开启 I2C0时钟
PORTA_PCR12 = PORT_PCR_MUX(8);// 配置 I2C0功能的 GPIO 接
PORTA_PCR12 = PORTA_PCR12|(1<<5);//设置为开漏模式
PORTA_PCR11 = PORT_PCR_MUX(8);
PORTA_PCR11 = PORTA_PCR11|(1<<5);//设置为开漏模式
}
I2C_F_REG(I2Cx[I2CNum]) = I2C_F_MULT(2) | I2C_F_ICR(0x17) ; //频率 / 波特率 frequency
I2C_C1_REG(I2Cx[I2CNum]) = I2C_C1_IICEN_MASK;//使能 IIC0模块
// //无论I2C接口被配置成主机模式还是从机模式,收到一串数据后自动发送应答信号
// I2C_C1_REG(I2Cx[I2CNum]) &= ~I2C_C1_TXAK_MASK; //使能I2C0自动应答信号
}
IIC开始信号产生
void DrvI2CStart (I2Cn I2CNum)
{
I2C_C1_REG(I2Cx[I2CNum]) |= I2C_C1_TX_MASK + I2C_C1_MST_MASK;
}
再次产生开始信号
void DrvI2CReStart(I2Cn I2CNum)
{
I2C_C1_REG(I2Cx[I2CNum]) |= I2C_C1_RSTA_MASK ;
}
停止信号
void DrvI2CStop (I2Cn I2CNum)
{
I2C_C1_REG(I2Cx[I2CNum]) &= ~(I2C_C1_MST_MASK + I2C_C1_TX_MASK);//暂停信号
}
写一个字节
void DrvI2CWriteByte (I2Cn I2CNum, U8 Byte)
{
I2C_D_REG(I2Cx[I2CNum]) = Byte;
}
读一个字节
U8 DrvI2CReadByte(I2Cn I2CNum)
{
U8 Temp;
Temp = I2C_D_REG(I2Cx[I2CNum]);
return Temp;
}
启动IIC传输
void I2C_StartTransmission (I2Cn I2CNum, U8 SlaveID, IIC_MASTER_RW_MODE Mode)
{
SlaveID = ( SlaveID << 1 ) | Mode ; //确定写地址和读地址
DrvI2CStart(I2CNum);//send start signal
DrvI2CWriteByte(I2CNum, SlaveID);//send ID with W/R bit
}
I2C设置等待应答信号,开启则等待,关闭则不等待
void DrvI2CWaitAck(I2Cn I2CNum, IIC_ACK_MODE ModeType)
{
U16 Timeout;
if(ModeType == I2C_ACK_ON)
{
while(!(I2C_S_REG(I2Cx[I2CNum]) & I2C_S_IICIF_MASK))
{
if(Timeout>60000) //超时判断
{
break;
}
else
{
Timeout++;
}
}
I2C_S_REG(I2Cx[I2CNum]) |= I2C_S_IICIF_MASK;
}
else
{
I2C_C1_REG(I2Cx[I2CNum]) |= I2C_C1_TXAK_MASK; //关闭I2C的ACK
}
}
I2C主机读写模式配置
void DrvI2CSetMasterWRMode(I2Cn I2CNum, IIC_MASTER_RW_MODE ModeType)
{
if(ModeType == I2C_MASTER_READ)
{
I2C_C1_REG(I2Cx[I2CNum]) &= (~I2C_C1_TX_MASK);
}
else
{
I2C_C1_REG(I2Cx[I2CNum]) |= ( I2C_C1_TX_MASK);
}
}
延时
void DrvTimeDelay(U32 Timeout)
{
U32 Cnt;
for(Cnt = 0; Cnt < Timeout; Cnt++)
{
}
}
读取IIC设备指定地址寄存器的数据
U8 I2C_ReadAddr(I2Cn I2CNum, U8 SlaveID, U8 Addr)
{
U8 result;
I2C_StartTransmission (I2CNum, SlaveID, I2C_MASTER_WRITE);//Send Slave Address
DrvI2CWaitAck(I2CNum, I2C_ACK_ON);
DrvI2CWriteByte(I2CNum, Addr);//Write Register Address
DrvI2CWaitAck(I2CNum, I2C_ACK_ON);
DrvI2CReStart(I2CNum);//Do a repeated start
DrvI2CWriteByte(I2CNum, ( SlaveID << 1) | I2C_MASTER_READ );//Send Slave Address
DrvI2CWaitAck(I2CNum, I2C_ACK_ON);
DrvI2CSetMasterWRMode(I2CNum, I2C_MASTER_READ);//Put in Rx Mode
DrvI2CWaitAck(I2CNum, I2C_ACK_OFF);//Turn off ACK since this is second to last byte being read
result = DrvI2CReadByte(I2CNum);//Dummy read 虚假读取
DrvI2CWaitAck(I2CNum, I2C_ACK_ON);
DrvI2CStop(I2CNum);//Send stop since about to read last byte
result = I2C_D_REG(I2Cx[I2CNum]);//Read byte
return result;
}
写IIC设备指定地址寄存器的数据
void I2C_WriteAddr(I2Cn I2CNum, U8 SlaveID, U8 Addr, U8 Data)
{
I2C_StartTransmission(I2CNum, SlaveID, I2C_MASTER_WRITE); //启动传输
DrvI2CWaitAck(I2CNum, I2C_ACK_ON);
DrvI2CWriteByte(I2CNum, Addr); //写地址
DrvI2CWaitAck(I2CNum, I2C_ACK_ON);
DrvI2CWriteByte(I2CNum, Data); //写数据
DrvI2CWaitAck(I2CNum, I2C_ACK_ON);
DrvI2CStop(I2CNum);
DrvTimeDelay(5000); //延时太短的话,可能写出错
}
写IIC设备指定地址寄存器的数据 16位
void I2C_WriteAddr16(I2Cn I2CNum, U8 SlaveID, U8 Addr, U16 Data)
{
I2C_StartTransmission(I2CNum, SlaveID, I2C_MASTER_WRITE); //启动传输
DrvI2CWaitAck(I2CNum, I2C_ACK_ON);
DrvI2CWriteByte(I2CNum, Addr); //写地址
DrvI2CWaitAck(I2CNum, I2C_ACK_ON);
DrvI2CWriteByte(I2CNum, (U8)(Data>>8)); //写数据
DrvI2CWaitAck(I2CNum, I2C_ACK_ON);
DrvI2CWriteByte(I2CNum, (U8)Data); //写数据
DrvI2CWaitAck(I2CNum, I2C_ACK_ON);
DrvI2CStop(I2CNum);
DrvTimeDelay(5000); //延时太短的话,可能写出错
}
标签:I2Cn,U8,ACK,Kinetis,K60,C1,I2C,I2CNum,接口函数 来源: https://blog.csdn.net/weibo_csdn/article/details/113354653