I2C?的配置
{
I2C_InitTypeDef I2C_InitStructure;
GPIO_InitTypeDef GPIO_InitA;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);//使能I2C1,I2C2的時鐘
RCC_I2CCLKConfig(RCC_I2C1CLK_SYSCLK);//時鐘源設定
GPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_1); ?//配置PB8 成第二功能引腳 I2C1_SCL
GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_1); ?//配置PB9 成第二功能引腳 I2C1_SDA
GPIO_InitA.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
GPIO_InitA.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitA.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitA.GPIO_OType = GPIO_OType_PP;
GPIO_InitA.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOB, &GPIO_InitA);
I2C_InitStructure.I2C_Mode = I2C_Mode_SMBusHost;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_AnalogFilter = I2C_AnalogFilter_Enable;
I2C_InitStructure.I2C_DigitalFilter = 0x01;
I2C_InitStructure.I2C_OwnAddress1 = 0x00;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_Timing = 0x0090174F;
I2C_Init(I2C1, &I2C_InitStructure);
I2C_Cmd(I2C1, ENABLE);
}
一樣的配置方案,I2C_Timing的意思請移步本博客GY30那篇文章。?
I2C引腳為PB8 與PB9(使用的C8T6,f4p6可以用PA的)
#define AT24C16_Base_Address 0xA0
void AT24C16_WriteByte(uint8_t Page,uint8_t WordAddress,uint8_t Data);
uint8_t AT24C16_ReadByte(uint8_t Page,uint8_t WordAddress);
void AT24C16_PageWrite(uint8_t Page,uint8_t WordAddress,uint8_t Length,uint8_t* Data);
void AT24C16_SequentialRead(uint8_t Page,uint8_t WordAddress, uint8_t length , uint8_t* p);
下面是相關函數:
void AT24C16_WriteByte(uint8_t Page,uint8_t WordAddress,uint8_t Data)
{
if(WordAddress > 0x10)
{
return;
}
WordAddress |= ( Page & 0x0F ) << 4;
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) != RESET);//IF BUSY
I2C_TransferHandling(I2C1,AT24C16_Base_Address | ( ( Page & 0xF0 ) >> 3 ),2,I2C_AutoEnd_Mode,I2C_Generate_Start_Write);
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_TXIS) == RESET);//If Write OK
I2C_SendData(I2C1,WordAddress);
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_TXIS) == RESET);//If Write OK
I2C_SendData(I2C1,Data);
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_STOPF) == RESET);
}
uint8_t AT24C16_ReadByte(uint8_t Page,uint8_t WordAddress)
{
uint8_t Recev = 0x00;
if(WordAddress > 0x10)
{
return 0;
}
WordAddress |= ( Page & 0x0F ) << 4;
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) != RESET);//IF BUSY
I2C_TransferHandling(I2C1,AT24C16_Base_Address | ( ( Page & 0xF0 ) >> 3 ),1,I2C_SoftEnd_Mode,I2C_Generate_Start_Write);
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_TXIS) == RESET);//If Write OK
I2C_SendData(I2C1,WordAddress);
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_TC) == RESET);
I2C_TransferHandling(I2C1,AT24C16_Base_Address | ( ( Page & 0xF0 ) >> 3 ),1,I2C_AutoEnd_Mode,I2C_Generate_Start_Read);
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE) == RESET);
Recev = I2C_ReceiveData(I2C1);
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_STOPF) == RESET);
return Recev;
}
下面是頁讀取,頁寫入:
void AT24C16_PageWrite(uint8_t Page,uint8_t WordAddress,uint8_t Length,uint8_t* Data)
{
uint8_t i = 0;
if(WordAddress > 0x10)
{
return;
}
WordAddress |= ( Page & 0x0F ) << 4;
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) != RESET);//IF BUSY
I2C_TransferHandling(I2C1,AT24C16_Base_Address | ( ( Page & 0xF0 ) >> 3 ),Length + 1,I2C_AutoEnd_Mode,I2C_Generate_Start_Write);
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_TXIS) == RESET);//If Write OK
I2C_SendData(I2C1,WordAddress);
for(i = 0;i < Length; i++)
{
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_TXIS) == RESET);//If Write OK
I2C_SendData(I2C1,Data[i]);
}
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_STOPF) == RESET);
}
void AT24C16_SequentialRead(uint8_t Page,uint8_t WordAddress, uint8_t length , uint8_t* p)
{
uint8_t i;
if(WordAddress > 0x10)
{
return;
}
WordAddress |= ( Page & 0x0F ) << 4;
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) != RESET);//IF BUSY
I2C_TransferHandling(I2C1,AT24C16_Base_Address | ( ( Page & 0xF0 ) >> 3 ),1,I2C_SoftEnd_Mode,I2C_Generate_Start_Write);
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_TXIS) == RESET);//If Write OK
I2C_SendData(I2C1,WordAddress);
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_TC) == RESET);
I2C_TransferHandling(I2C1,AT24C16_Base_Address | ( ( Page & 0xF0 ) >> 3 ),length,I2C_AutoEnd_Mode,I2C_Generate_Start_Read);
for(i = 0;i < length;i++)
{
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE) == RESET);
p[i] = I2C_ReceiveData(I2C1);
}
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_STOPF) == RESET);
}
感覺沒什么說的,GY30那篇文章基本都說完了,添點小知識點吧。
I2C_AutoEnd_Mode,顧名思義,操作length字節后自動添加STOP。?
I2C_SoftEnd_Mode ,同樣顧名思義,操作length字節后需要手動添加STOP。( I2C_GenerateSTOP() )?
這個模式比自動多了一步,需要 I2C_GetFlagStatus(I2C1, I2C_FLAG_TC) ,Translate Completed,是否傳輸完成,自動模式下訪問這個會得到Reset值,然而手動模式下需要訪問他,然后生成Stop。
然后……差不多了吧?舉個 上面網址的例子吧,我覺得很多人不會看……
所以在編寫程序對AT24C16第100頁的第3個字節進行寫數據的時候,步驟如下:?
1)發送起始信號;?
2)發送器件地址0XA6(1010 0110,1010是固定地址,011是頁地址的高三位,0表示寫操作);?
3)發送操作地址0X43(0100 0011,0100是頁地址的低四位,0011是頁地址偏移量,即第100頁內的第三個字節,?
4)發送要寫的數據,?
5)發送終止信號。
我相信各位最起碼都看了AT24C16的地址了,0xA0。(再次引用暢學電子網的圖片)?
P0P1P2為頁地址高三位,發送的字地址(WordAddress)高四位為頁地址的第四位,低四位為字地址。?
AT24C16有128頁,每頁16bytes。所以正好匹配上。?
寫的間隔至少為5ms,否則用循環等待的話I2C會卡死。
以上。?
評論
查看更多