- /**
- * @ingroup i2c_host
- * [url=home.php?mod=space&uid=247401]@brief[/url] This function writes data from the writeData to the bus
- * and then reads data from the Client and stores the received in the
- * readData. The function generates a Start condition on the bus and
- * will then send writeLength number of bytes contained in writeData.
- * The function will then insert a Repeated start condition and
- * proceed to read readLength number of bytes from the client.
- * The received bytes are stored in readData buffer. A Stop condition
- * is generated after the last byte has been received.
- *
- * If the Client NAKs the request or a bus error was encountered on
- * the bus, the transfer is terminated. The application can call
- * I2C1_ErrorGet() function to know that cause of the error.
- *
- * The function is non-blocking. It initiates bus activity and returns
- * immediately. The transfer is then completed in the peripheral
- * interrupt. For polling mode, user has to call I2C1_Tasks
- * in while loop. A transfer request cannot be placed when another
- * transfer is in progress. Calling this function when another function
- * is already in progress will cause the function to return false.
- *
- * @param [in] address - 7-bit / 10-bit Client address.
- * @param [in] writeData - pointer to write data buffer.
- * @param [in] writeLength - write data length in bytes.
- * @param [out] readData - pointer to read data buffer.
- * @param [in] readLength - read data length in bytes.
-
- * @return
- * true - The request was placed successfully and the bus activity was
- * initiated.
- * false - The request fails,if there was already a transfer in
- * progress when this function was called
- */
- bool I2C1_WriteRead(uint16_t address, uint8_t *writeData, size_t writeLength, uint8_t *readData, size_t readLength);
该函数的执行过程是:往指定的地址的设备写入数据后,再从该地址的设备读取数据。
参数一共5个:芯片的I2C总线地址,要写入的数据,写入数据的长度,读取的数据,读取的长度。
请注意写入的数据和读取的数据通过指针实现。
我们查看库函数实现的方式
- bool I2C1_WriteRead(uint16_t address, uint8_t *writeData, size_t writeLength, uint8_t *readData, size_t readLength)
- {
- bool retStatus = false;
- if (!I2C1_IsBusy())
- {
- i2c1Status.busy = true;
- i2c1Status.address = address;
- i2c1Status.switchToRead = true;
- i2c1Status.writePtr = writeData;
- i2c1Status.writeLength = writeLength;
- i2c1Status.readPtr = readData;
- i2c1Status.readLength = readLength;
- i2c1Status.errorState = I2C_ERROR_NONE;
- I2C1_WriteStart();
- retStatus = true;
- }
- return retStatus;
- }
通过以上代码我们了解到,这是一个非阻塞函数,进入函数后判断是否忙,如果不忙就执行相关的寄存器配置与执行操作并返回真,这里函数并未考虑到如果为假的情况,另外为真的话也未考虑是否执行成功。所以我们需要自己在程序里考虑这个问题,否则将会执行失败,或者错过执行。接下来我找一个I2C的芯片来执行读操作。
芯片的时序定义如上所示,可以看出读操作是标准的I2C时序。
示例代码如下:
- int main(void)
- {
- uint8_t val=0;
- uint8_t reg=0x00;
- SYSTEM_Initialize();
- // If using interrupts in PIC18 High/Low Priority Mode you need to enable the Global High and Low Interrupts
- // If using interrupts in PIC Mid-Range Compatibility Mode you need to enable the Global Interrupts
- // Use the following macros to:
- // Enable the Global Interrupts
- INTERRUPT_GlobalInterruptEnable();
- // Disable the Global Interrupts
- //INTERRUPT_GlobalInterruptDisable();
- printf("Hello\n");
- DELAY_milliseconds(3000);
- while(1)
- {
- DELAY_milliseconds(1000);
-
- I2C1_WriteRead(0x35,®,1,&val,1);
- while(I2C1_IsBusy());
- printf("REG%d=%x\n",reg,val);
- reg++;
- val=0;
- if(reg>30) reg=0;
-
- }
- }
我们往I2C地址为0x35的设备写入reg,并将读取的数据放到val,之后通过检测是否忙,如果忙就等待,等到写入完成后再执行打印结果的操作。
这里使用了阻塞的方式判断,也可以使用非阻塞方式,增加一个时间判断,防止程序卡死。
简单的示例如下所示:
- int main(void)
- {
- uint8_t val=0;
- uint8_t reg=0x00;
- uint8_t delay_time=0;
- SYSTEM_Initialize();
- // If using interrupts in PIC18 High/Low Priority Mode you need to enable the Global High and Low Interrupts
- // If using interrupts in PIC Mid-Range Compatibility Mode you need to enable the Global Interrupts
- // Use the following macros to:
- // Enable the Global Interrupts
- INTERRUPT_GlobalInterruptEnable();
- // Disable the Global Interrupts
- //INTERRUPT_GlobalInterruptDisable();
- printf("Hello\n");
- DELAY_milliseconds(3000);
- while(1)
- {
- DELAY_milliseconds(1000);
-
- I2C1_WriteRead(0x35,®,1,&val,1);
- while(I2C1_IsBusy()&&(delay_time++<20));
- printf("REG%d=%x\n",reg,val);
- reg++;
- val=0;
- delay_time=0;
- if(reg>30) reg=0;
-
- }
- }
最后我们看看读取的效果
最后补充一个先写后读取的示例,并测试对应的寄存器哪些位可以进行写操作。
- int main(void)
- {
- uint8_t val=0;
- uint8_t reg=0x00;
- uint8_t delay_time=0;
- SYSTEM_Initialize();
- uint8_t daa[2];
- daa[0]=0x04;
- daa[1]=0x00;
- // If using interrupts in PIC18 High/Low Priority Mode you need to enable the Global High and Low Interrupts
- // If using interrupts in PIC Mid-Range Compatibility Mode you need to enable the Global Interrupts
- // Use the following macros to:
- // Enable the Global Interrupts
- INTERRUPT_GlobalInterruptEnable();
- // Disable the Global Interrupts
- //INTERRUPT_GlobalInterruptDisable();
- printf("Hello\n");
- DELAY_milliseconds(3000);
- while(1)
- {
- DELAY_milliseconds(1000);
- I2C1_Write(0x35,daa,2);
- while(I2C1_IsBusy()&&(delay_time++<20));delay_time=0;
- reg=0x04;
- I2C1_WriteRead(0x35,®,1,&val,1);
- while(I2C1_IsBusy()&&(delay_time++<20));delay_time=0;
- printf("DAA[%x]---REG%d=%x\n",daa[1],reg,val);
- daa[1]++;
- }
- }
经过测试在0x04寄存器上,低4位中的BIT3是不能执行写操作的。
正常使用时候这么看明显的不好看,我们可以将函数进行封装使用,不仅方便阅读,还更容易调用,同时这么做不容易弄错。- void KT_Byte_Write(uint8_t kt_reg,uint8_t kt_dat)
- {
- uint8_t delay_time=0;
- uint8_t dats[2];
- dats[0] = kt_reg;
- dats[1] = kt_dat;
- I2C1_Write(0x35,dats,2);
- while(I2C1_IsBusy()&&(delay_time++<20));
- }
- uint8_t KT_Byte_Read(uint8_t kt_reg)
- {
- uint8_t val=0;
- uint8_t delay_time=0;
- I2C1_WriteRead(0x35,&kt_reg,1,&val,1);
- while(I2C1_IsBusy()&&(delay_time++<20));delay_time=0;
- return val;
- }
调用方式- int main(void)
- {
- SYSTEM_Initialize();
- uint8_t i=0;
- // Enable the Global Interrupts
- INTERRUPT_GlobalInterruptEnable();
- // Disable the Global Interrupts
- //INTERRUPT_GlobalInterruptDisable();
- printf("Hello\n");
- DELAY_milliseconds(3000);
- while(1)
- {
- for(i=0;i<10;i++)
- {
- DELAY_milliseconds(1000);
- KT_Byte_Write(0x04,i);
- printf("REG=%x\n",KT_Byte_Read(0x04));
- }
- }
- }
好了,基于我使用的这个芯片的I2C读写使用方式讲解完了,另外只要是标准I2C协议的芯片都可以这么使用。