I2C
实习的第一个任务是调stm32f4的I2C接口,从机是SGM58031
SGM58031 I2C读写时序图
I2C程序
/***************************通信函数*******************************/
void I2C3_start(i2c_t i2c, uint8_t address, uint8_t direction)
{
while(I2C_GetFlagStatus(i2c->base, I2C_FLAG_BUSY));
//start signal
I2C_GenerateSTART(i2c->base, ENABLE);
while(!I2C_CheckEvent(i2c->base, I2C_EVENT_MASTER_MODE_SELECT));
//7λµØÖ·
I2C_Send7bitAddress(i2c->base, address, direction);
if(direction == I2C_Direction_Transmitter)
{
while(!I2C_CheckEvent(i2c->base, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
}
else if(direction == I2C_Direction_Receiver)
{
while(!I2C_CheckEvent(i2c->base, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
}
}
I2C3_start()就代表时序图中的Frame1,包含2个操作。
①主机发出start信号
②往地址线写7位地址加1位读写位
uint8_t I2C_read_ack(i2c_t i2c)
{
uint8_t data;
// enable acknowledge of recieved data
I2C_AcknowledgeConfig(i2c->base, ENABLE);
// wait until one byte has been received
while( !I2C_CheckEvent(i2c->base, I2C_EVENT_MASTER_BYTE_RECEIVED) );
// read data from I2C data register and return data byte
data = I2C_ReceiveData(i2c->base);
return data;
}
I2C_read_ack()代表读时序中的Frame4
①接收1byte的数据
②数据接收完成后给发送机一个ACK信号,表示接收完成可以进行下一个数据传输
uint8_t I2C_read_nack(i2c_t i2c)
{
uint8_t data;
// disabe acknowledge of received data
// nack also generates stop condition after last byte received
// see reference manual for more info
I2C_AcknowledgeConfig(i2c->base, DISABLE);
I2C_GenerateSTOP(i2c->base, ENABLE);
// wait until one byte has been received
while( !I2C_CheckEvent(i2c->base, I2C_EVENT_MASTER_BYTE_RECEIVED) );
// read data from I2C data register and return data byte
data = I2C_ReceiveData(i2c->base);
return data;
}
I2C_read_nack()读一个byte不返回ACK信号
void I2C3_write(i2c_t i2c, uint8_t data)
{
I2C_SendData(i2c->base, data);
// wait for I2C1 EV8_2 --> byte has been transmitted
while(!I2C_CheckEvent(i2c->base, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
}
I2C3_write()向总线写一个byte数据
void I2C_stop(i2c_t i2c)
{
// Send I2C1 STOP Condition
I2C_GenerateSTOP(i2c->base, ENABLE);
}
I2C_stop()对应上图中的stop by master,发出stop信号
uint16_t I2C_Read_Word(i2c_t i2c, uint8_t address, uint8_t Reg_addr)
{
uint8_t high=0x00;
uint8_t low=0x00;
uint16_t Word=0x0000;
I2C3_start(i2c,address,I2C_Direction_Transmitter);
I2C3_write(i2c,Reg_addr);
I2C_stop(i2c);
I2C3_start(i2c,address,I2C_Direction_Receiver);
high=I2C_read_ack(i2c);
low=I2C_read_nack(i2c);
Word=(high<<8)+low;
//printf("%d \n",Word);
return Word;
}
void I2C_Write_Word(i2c_t i2c, uint8_t address, uint8_t Reg_addr, uint16_t set_value)
{
uint8_t high=0x00;
uint8_t low=0x00;
low=set_value&0x00ff;
high=(set_value>>8)&0x00ff;
I2C3_start(i2c,address,I2C_Direction_Transmitter);
I2C3_write(i2c,Reg_addr);
I2C3_write(i2c,high);
I2C3_write(i2c,low);
I2C_stop(i2c);
}
读写2bytes函数,由前面的通信函数组合起来,不容易出错
//封装
typedef struct i2c_device* i2c_t;
struct i2c_device {
I2C_TypeDef * base;
uint32_t CLK;
void (*setup)(i2c_t);
};
///
/***************i2c3封装主要******************/
///
void __attribute__((weak)) target_i2c3_setup()
{
pin_rcc_config(); //使能引脚时钟
pin_AF_config(); //引脚复用
I2C3_gpio_setup(); //I2C_gpio¹Ü½ÅÉèÖÃ
}
static void __i2c3_setup(i2c_t i2c)
{
target_i2c3_setup();
}
struct i2c_device i2c3 = {
I2C3,
RCC_APB1Periph_I2C3,
__i2c3_setup,
};
/
/*************硬件I2C初始化函数子函数*****************/
/
//使能引脚时钟
void pin_rcc_config()
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);
}
//使能硬件I2C时钟
void i2c3_rcc_config(i2c_t i2c)
{
RCC_APB1PeriphClockCmd(i2c->CLK,ENABLE);
}
//管脚复用为I2C
void pin_AF_config()
{
GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_I2C3);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource9, GPIO_AF_I2C3);
}
//I2C_gpio管脚设置
void I2C3_gpio_setup()
{
GPIO_InitTypeDef GPIO_InitStructure;
//PC9 SDA PA8 SCL
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_Init(GPIOC, &GPIO_InitStructure);
}
//硬件I2C参数设置
void i2c_param_config(i2c_t i2c)
{
I2C_InitTypeDef I2C_InitStructure;
I2C_DeInit(i2c->base);
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = 0x00;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_ClockSpeed = 10000;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_Init(i2c->base, &I2C_InitStructure);
}
///
/*************硬件I2C初始化****************/
///
void I2C3_Init(i2c_t i2c)
{
i2c3_rcc_config(i2c);
i2c->setup(i2c);
i2c_param_config(i2c);
I2C_Cmd(i2c->base,ENABLE);
}
封装以及硬件初始化函数
感受
搞清楚每个函数做了什么,对应着时序来写应该就不会出错