對於stm32的硬件I2C確實有不盡人意的地方。但是還是可以實現的,畢竟使用stm32的硬件I2C確實比使用IO口來模擬簡單的多。下面的程序代碼是使用stm32F03ZET6的I2C1(PB6,PB7)和AT24C02的EEPROM來測試的。希望對於需要的朋友有幫助。
i2c.c
#include "iic.h"
#include "stm32f10x.h"
#include "usart.h"
u16 timeout=TIMEOUT;
/*i2c的初始化*/
void IIC1_Init()
{
GPIO_InitTypeDef GPIO_InitStruct;
I2C_InitTypeDef I2C_InitStruct;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
//GPIO的配置
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_OD;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStruct);
//IIC的配置
I2C_InitStruct.I2C_Ack=I2C_Ack_Enable;
I2C_InitStruct.I2C_AcknowledgedAddress=I2C_AcknowledgedAddress_7bit;
I2C_InitStruct.I2C_ClockSpeed=10000;
I2C_InitStruct.I2C_DutyCycle=I2C_DutyCycle_2;
I2C_InitStruct.I2C_Mode=I2C_Mode_I2C;
I2C_InitStruct.I2C_OwnAddress1=0x55;
I2C_Init(I2C1,&I2C_InitStruct);
I2C_Cmd(I2C1,ENABLE);
}
/*寫入一個字節*/
void IIC_WriteByte(u8 addr,u8 data)
{
I2C_EE_WaitEepromStandbyState();
I2C_GenerateSTART(I2C1,ENABLE);//發送起始信號
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT))//檢測 EV5事件
{
if((timeout--)==0)
printf("EV5 Fail");
} timeout=1000;
I2C_Send7bitAddress(I2C1,0xA0,I2C_Direction_Transmitter);//發送7位EEPROM的硬件地址
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))//檢測EV6事件
{
if((timeout--)==0)
printf("EV6 Fail");
} timeout=1000;
I2C_SendData(I2C1,addr);//發送操作的內存地址
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED))//檢測EV8事件
{
if((timeout--)==0)
printf("EV8 Fail");
} timeout=1000;
I2C_SendData(I2C1,data);//要寫入的數據(一個字節)
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED))//檢測EV8事件
{
if((timeout--)==0)
printf("EV8 Fail");
} timeout=1000;
I2C_GenerateSTOP(I2C1,ENABLE);//發送結束信號
}
/*讀取一個字節*/
u8 IIC_ReadByte(u8 addr)
{
u8 readtemp;
I2C_EE_WaitEepromStandbyState();//等待EEPROM釋放總線
I2C_GenerateSTART(I2C1,ENABLE);
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT))//5
{
if((timeout--)==0)
printf("EV5 Fail");
} timeout=1000;
I2C_Send7bitAddress(I2C1,0xA1,I2C_Direction_Transmitter);
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))//6
{
if((timeout--)==0)
printf("EV6 Fail");
} timeout=1000;
I2C_SendData(I2C1,addr);
while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS )
{
if((timeout--)==0)
printf("EV8 Fail");
} timeout=1000;
I2C_GenerateSTART(I2C1,ENABLE);
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT))
{
if((timeout--)==0)
printf("EV5 Fail");
} timeout=1000;
I2C_Send7bitAddress(I2C1,0xA0,I2C_Direction_Receiver);
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
{
if((timeout--)==0)
printf("EV6 Fail");
} timeout=1000;
I2C_AcknowledgeConfig(I2C1,DISABLE);
/* 檢測 EV7 事件 */
while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED) != SUCCESS )
{
if((timeout--)==0)
printf("EV7 Fail");
} timeout=1000;
/* 讀取接收數據 */
readtemp = I2C_ReceiveData(I2C1);
/* 停止信號 */
I2C_GenerateSTOP(I2C1,ENABLE);
return readtemp;
}
/*等待eeprom釋放總線*/
void I2C_EE_WaitEepromStandbyState(void)
{
do
{
I2C_GenerateSTART(I2C1, ENABLE);
while(I2C_GetFlagStatus(I2C1,I2C_FLAG_SB)==ERROR);//檢測EV5事件
I2C_Send7bitAddress(I2C1,0xA1,I2C_Direction_Transmitter);
}while(I2C_GetFlagStatus(I2C1,I2C_FLAG_ADDR)==ERROR);//
I2C_ClearFlag(I2C1, I2C_FLAG_AF);//清楚標誌位
I2C_GenerateSTOP(I2C1, ENABLE); //結束信號
}
/* 向eeprom中寫入n個數據*/
void I2C_WriteNumData(u8 addr,u8 *str, u8 numToWrite)
{
if((addr+numToWrite)>255)//避免寫入的數據超過總的內存
{
printf("refuse to write\n");
printf("please enter less than %d char\n",(255-addr));
}
else
{
printf("allow to write\n");
while(numToWrite)
{
IIC_WriteByte(addr,*str);
addr++;
str++;
numToWrite--;
}
printf("write success\n");
}
}
void I2C_ReadNumData(u8 addr,u8 *str,u8 numToRead)
{
while(numToRead)
{
*str=IIC_ReadByte(addr);
addr++;
str++;
numToRead--;
}
}
usart.c
#include "usart.h"
#include "stm32f10x.h"
void USART1_Init()
{
GPIO_InitTypeDef GPIO_InitStruct;
USART_InitTypeDef USART_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE);
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10;
GPIO_Init(GPIOA,&GPIO_InitStruct);
USART_InitStruct.USART_BaudRate=115200;
USART_InitStruct.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
USART_InitStruct.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;
USART_InitStruct.USART_Parity=USART_Parity_No;
USART_InitStruct.USART_StopBits=USART_StopBits_1;
USART_InitStruct.USART_WordLength=USART_WordLength_8b;
USART_Init(USART1,&USART_InitStruct);
USART_Cmd(USART1,ENABLE);
}
void USART1_SendByte(u8 data)
{
USART_SendData(USART1,data);
while(!USART_GetFlagStatus(USART1,USART_FLAG_TXE));
}
void USART1_SendStr(u8 *str)
{
unsigned int i=0;
for(i=0;*str!='\0';i++)
{
USART1_SendByte(*str);
str++;
}
while(!USART_GetFlagStatus(USART1,USART_FLAG_TC));
}
int fputc(int ch, FILE *f)
{
/* 發送一個字節數據到串口 */
USART_SendData(USART1, (uint8_t) ch);
/* 等待發送完畢 */
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
return (ch);
}
main.c
#include "stm32f10x.h"
#include "usart.h"
#include "iic.h"
#include <stdio.h>
int main()
{
u8 a[10]={9,8,7,6,5,4,3,2,1,0};
u8 b[10]={0};
u8 i=0;
USART1_Init();
IIC1_Init();
I2C_WriteNumData(125,a,10);
I2C_ReadNumData(125,b,10);
for(i=0;i<10;i++)
{
printf("%d\t",b[i]);
}
}