在线时间28 小时
UID3450027
注册时间2018-11-12
NXP金币0
TA的每日心情 | 无聊 2024-6-3 15:51 |
---|
签到天数: 19 天 连续签到: 1 天 [LV.4]偶尔看看III
中级会员
 
- 积分
- 246
- 最后登录
- 2024-9-4
|
用的是LPC1768的单片机,I2C芯片是AT24C02。用中断的方式进行I2C传输,但是发现每次读出数据的前16byte的高四位是上次写数据最后16位的高四位。如下图(包含逻辑分析仪的结果):
代码如下:
/*****************************************************************************
* i2c.c: I2C C file for NXP LPC17xx Family Microprocessors
*****************************************************************************/
#include "i2c_periph.h"
// 定义用于和I2C中断传递信息的全局变量
volatile uint8_t I2C0_Slave_Addr; // I2C器件从地址
volatile uint32_t I2C0_Buffer_Addr; // I2C器件内部子地址
volatile uint8_t I2C0_Buffer_AddrType; // I2C子地址字节数
volatile uint8_t *pI2C0_Data; // 数据缓冲区指针
volatile uint32_t I2C0_Byte_Num; // 要读取/写入的数据个数
volatile uint8_t I2C0_End_Flag; // I2C总线结束标志:结束总线是置1
volatile uint8_t I2C_Buffer_Dir; // 子地址控制。0--子地址已经处理或者不需要子地址 1--读取操作 2--写操作
void I2C_Delay(uint32_t data)
{
uint32_t i,j,k;
for(i=0;i<data;i++)
for(j=0;j<19;j++)
for(k=0;k<1000;k++);
}
/*****************************************************************************
** Function name: I2C_Init()
*****************************************************************************/
void I2C0_Init( uint32_t I2cMode )
{
LPC_SC->PCONP |= (1 << 7); //使能功率控制寄存器,i2c0--7,i2c1--19,i2c2--26默认都是使能的,
//还有选择时钟,默认所有外设时钟都是cclk/4即为CPU主频时钟
LPC_PINCON -> PINSEL1 |= (1UL<<22)|(1U<<24);// P0.27 - SDA0; P0.28 -- SCL0
LPC_PINCON -> PINMODE_OD0 |= (1ul<<27)|(1ul<<28); //引脚开漏设置,I2C0默认开漏模式,但是I2C1和I2C2需要设置开漏模式
// LPC_PINCON -> I2CPADCFG |= (1UL<<0)|(1UL<<2); //配置成高速模式
LPC_I2C0->I2SCLL = I2SCLL_SCLL;
LPC_I2C0->I2SCLH = I2SCLH_SCLH;
if ( I2cMode == I2C_Slave ) { LPC_I2C0->I2ADR0 = 0xA0;} //装入器件从地址
NVIC_EnableIRQ(I2C0_IRQn); //使能I2C0中断
LPC_I2C0->I2CONSET = I2CONSET_I2EN; //使能I2C接口
}
/*****************************************************************************
** Function name: I2C0_中断服务函数
*****************************************************************************/
void I2C0_IRQHandler(void)
{
uint8_t StateValue;
StateValue = LPC_I2C0->I2STAT & 0xf8; // I2C状态寄存器只有3~7位为有效位
switch ( StateValue )
{
case 0x08: // 已发送起始条件
if (I2C_Buffer_Dir == 1){ LPC_I2C0->I2DAT = I2C0_Slave_Addr &0xfe;} // 存放刚发送或接收的一个字节,发送从机地址,不含读写位
else{ LPC_I2C0->I2DAT = I2C0_Slave_Addr;}
LPC_I2C0->I2CONCLR = I2CONCLR_SIC|I2CONCLR_STAC; // 清除中断标志位、起始标志位
break;
case 0x10: // 已发送重复起始条件,再发送从机地址包含读写位
LPC_I2C0->I2DAT = I2C0_Slave_Addr;
LPC_I2C0->I2CONCLR = I2CONCLR_SIC|I2CONCLR_STAC; // 清除中断标志位、起始标志位
break;
case 0x18: // 已接收ACK 发送数据
case 0x28: // 已发送I2DAT中的数据,已接收ACK
if (I2C_Buffer_Dir == 0){ // 子地址已经处理或者不需要子地址
if(I2C0_Byte_Num>0){ // 写入数据
LPC_I2C0->I2DAT = *pI2C0_Data++;
LPC_I2C0->I2CONCLR = I2CONCLR_SIC|I2CONCLR_STAC; // 清除中断标志位、起始标志位
I2C0_Byte_Num--;
I2C_Delay(1);
}
else{
LPC_I2C0->I2CONSET = I2CONSET_STO; // 置位停止标志位
LPC_I2C0->I2CONCLR = I2CONCLR_SIC|I2CONCLR_STAC; // 清除中断标志位、起始标志位
I2C0_End_Flag =1;
}
}
if(I2C_Buffer_Dir == 1){ // 读取操作
if(I2C0_Buffer_AddrType == 2){
LPC_I2C0->I2DAT = ((I2C0_Buffer_Addr >> 8) & 0xff);
LPC_I2C0->I2CONCLR = I2CONCLR_SIC|I2CONCLR_STAC; // 清除中断标志位、起始标志位
I2C0_Buffer_AddrType--;
break;
}
if(I2C0_Buffer_AddrType == 1){ // 字节数为1
LPC_I2C0->I2DAT = (I2C0_Buffer_Addr & 0xff);
LPC_I2C0->I2CONCLR = I2CONCLR_SIC|I2CONCLR_STAC; // 清除中断标志位、起始标志位
I2C0_Buffer_AddrType--;
break;
}
if(I2C0_Buffer_AddrType == 0){
LPC_I2C0->I2CONCLR = I2CONCLR_SIC; // 清除中断标志位
LPC_I2C0->I2CONSET = I2CONSET_STA; // 置位起始标志位
I2C_Buffer_Dir = 0;
break;
}
}
if ( I2C_Buffer_Dir == 2 ){ // 写操作
if(I2C0_Buffer_AddrType > 0){
if(I2C0_Buffer_AddrType == 2){ // 字节数为2
LPC_I2C0->I2DAT = ((I2C0_Buffer_Addr >> 8) & 0xff);
LPC_I2C0->I2CONCLR = I2CONCLR_SIC|I2CONCLR_STAC; // 清除中断标志位、起始标志位
I2C0_Buffer_AddrType--;
break;
}
if(I2C0_Buffer_AddrType == 1){ // 字节数为1
LPC_I2C0->I2DAT = (I2C0_Buffer_Addr & 0xff);
LPC_I2C0->I2CONCLR = I2CONCLR_SIC|I2CONCLR_STAC; // 清除中断标志位、起始标志位
I2C0_Buffer_AddrType--;
I2C_Buffer_Dir = 0;
break;
}
}
}
break;
case 0x40: //已发送SLA+R,已接收ACK
if (I2C0_Byte_Num <= 1){LPC_I2C0->I2CONCLR = I2CONCLR_AAC;} ///////////清除应答标志位
else{LPC_I2C0->I2CONSET = I2CONSET_AA;} //置位应答标志位
LPC_I2C0->I2CONCLR = I2CONCLR_SIC|I2CONCLR_STAC; //清除中断标志位、起始标志位
break;
case 0x20: //已发送SLA+W,已接收非应答
case 0x30: //已发送I2DAT中的数据,已接收非应答
case 0x38:
case 0x48:
LPC_I2C0->I2CONCLR = I2CONCLR_SIC|I2CONCLR_STAC; //清除中断标志位、起始标志位
I2C0_End_Flag = 0xFF;
break;
case 0x50: //已接收数据字节,已返回ACK8
*pI2C0_Data++ = LPC_I2C0->I2DAT;
I2C0_Byte_Num--;
if(I2C0_Byte_Num ==1){LPC_I2C0->I2CONCLR = I2CONCLR_AAC|I2CONCLR_SIC|I2CONCLR_STAC;} //接收最后一个字节 STA,SI,AA = 0
else{
LPC_I2C0->I2CONSET = I2CONSET_AA; //置位应答标志位
LPC_I2C0->I2CONCLR = I2CONCLR_SIC|I2CONCLR_STAC; //清除中断标志位、起始标志位
}
break;
case 0x58: //已接收数据字节,已返回非应答
*pI2C0_Data++ = LPC_I2C0->I2DAT; //读出数据
LPC_I2C0->I2CONSET = I2CONSET_STO;
LPC_I2C0->I2CONCLR = I2CONCLR_SIC|I2CONCLR_STAC; //清除中断标志位、起始标志位
I2C0_End_Flag = 1;
break;
default:
break;
}
}
/********************************************************************************
** Function name:I2C_WriteByte
** Descriptions :向有子地址器件写入N字节数据
** parameters :Slave 器件从地址
** Addr_Type 子地址结构 1-单字节地址 3-8+X结构 2-双字节地址
** Buff_Addr 器件内部物理地址
** *p 将要写入的数据的指针
** Num 将要写入的数据的个数
** Returned value: 1 操作成功
** 0 操作失败
*********************************************************************************/
uint8_t I2C0_WriteByte(uint8_t Slave, uint8_t Addr_Type, uint32_t Buff_Addr, uint8_t *p, uint32_t Num)
{
if (Num > 0) // 如果读取的个数为0,则返回错
{
if (Addr_Type == 1) // 单字节
{
I2C0_Slave_Addr = Slave; // 读器件的从地址
I2C0_Buffer_Addr = Buff_Addr; // 器件子地址
I2C0_Buffer_AddrType = 1; // 器件子地址为1字节
}
if (Addr_Type == 2) // 双字节
{
I2C0_Slave_Addr = Slave; // 读器件的从地址
I2C0_Buffer_Addr = Buff_Addr; // 器件子地址
I2C0_Buffer_AddrType = 2; // 器件子地址为1字节
}
if (Addr_Type == 3) // 8+x结构
{
I2C0_Slave_Addr = Slave + ((Buff_Addr >> 7 )& 0x0e); // 读器件的从地址
I2C0_Buffer_Addr = Buff_Addr; // 器件子地址
I2C0_Buffer_AddrType = 1; // 器件子地址为1字节
}
pI2C0_Data = p; // 数据
I2C0_Byte_Num = Num; // 数据个数
I2C_Buffer_Dir = 2; // 有子地址,写操作
I2C0_End_Flag = 0;
LPC_I2C0->I2CONCLR = I2CONCLR_AAC|I2CONCLR_SIC|I2CONCLR_STAC; // 向该寄存器写1清零相应的位
LPC_I2C0->I2CONSET = I2CONSET_STA|I2CONSET_I2EN; // 起始标志置位 I2C接口使能
while(I2C0_End_Flag == 0){};
if(I2C0_End_Flag){I2C_Delay(20);return 1;} // 低到高跳变结束总线
else{I2C_Delay(20);return 0;}
}
I2C_Delay(20);
return 0;
}
/****************************************************************************************
** Function name:I2C_ReadNByte
** Descriptions: 从有子地址器件任意地址开始读取N字节数据
** parameters: sla 器件从地址
** suba_type 子地址结构 1-单字节地址 2-8+X结构 2-双字节地址
** suba 器件子地址
** s 数据接收缓冲区指针
** num 读取的个数
** Returned value: 1 操作成功
** 0 操作失败
*****************************************************************************************/
uint8_t I2C0_ReadByte (uint8_t Slave, uint8_t Addr_Type, uint32_t Buff_Addr, uint8_t *p, uint32_t Num)
{
if (Num > 0)
{
if (Addr_Type == 1)
{
I2C0_Slave_Addr = Slave + 1; // 读器件的从地址,R=1
I2C0_Buffer_Addr = Buff_Addr; // 器件子地址
I2C0_Buffer_AddrType = 1; // 器件子地址为1字节
}
if (Addr_Type == 2)
{
I2C0_Slave_Addr = Slave + 1; // 读器件的从地址,R=1
I2C0_Buffer_Addr = Buff_Addr; // 器件子地址
I2C0_Buffer_AddrType = 2; // 器件子地址为1字节
}
if (Addr_Type == 3)
{
I2C0_Slave_Addr = Slave + ((Buff_Addr >> 7 )& 0x0e) + 1; // 读器件的从地址,R=1
I2C0_Buffer_Addr = Buff_Addr & 0x0ff; // 器件子地址
I2C0_Buffer_AddrType = 1; // 器件子地址为1字节
}
pI2C0_Data = p; // 数据接收缓冲区指针
I2C0_Byte_Num = Num; // 要读取的个数
I2C_Buffer_Dir = 1; // 有子地址读
I2C0_End_Flag = 0;
LPC_I2C0->I2CONCLR = I2CONCLR_AAC|I2CONCLR_SIC|I2CONCLR_STAC; // 向该寄存器写1清零相应的位
LPC_I2C0->I2CONSET = I2CONSET_STA|I2CONSET_I2EN; // 起始标志置位 I2C接口使能
while(I2C0_End_Flag == 0){};
if(I2C0_End_Flag){I2C_Delay(20);return 1;} // 低到高跳变结束总线
else{I2C_Delay(20);return 0;}
}
I2C_Delay(20);
return 0;
}
/******************************************************************************
** End Of File
******************************************************************************/
程序工程如下:
|
-
逻辑分析仪
-
-
I2C.rar
415.89 KB, 下载次数: 0, 下载积分: 威望 1
工程
|