I2C全称Inter-Integrated Circuit,直接翻译过来就是内部集成电路,由飞利浦公司在1980年代为了让主板、嵌入式系统或手机用以连接低速周边设备而发明。 I2C 总线在物理连接上非常简单,分别由SDA(串行数据线)和SCL(串行时钟线)及上拉电阻组成。通信原理是通过对SCL和SDA线高低电平时序的控制,来产生I2C总线协议所需要的信号进行数据的传递。在总线空闲状态时,这两根线一般被上面所接的上拉电阻拉高,保持着高电平。I2C通信方式为半双工,只有一根SDA线,同一时间只可以单向通信。
MM32F5330内置 2 个 I2C 接口, 能够工作于多主模式或从模式, 支持标准(100 Kbps)、 快速模式(400 Kbps)和快速扩展模式(1 Mbps), 支持 7 位或 10 位寻址。 支持 SMBus。所有的 I2C 接口都可以使用 DMA 操作。
开发板上集成了一颗EEPROM,例程里有它的驱动代码,这里就不再重新驱动了,改用I2C来驱动OLED
初始化I2C
void APP_I2CInit(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
I2C_InitTypeDef I2C_InitStruct;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
I2C_DeInit(I2C2);
I2C_StructInit(&I2C_InitStruct);
I2C_InitStruct.I2C_Mode = I2C_MODE_MASTER;
I2C_InitStruct.I2C_OwnAddress = I2C_OWN_ADDRESS;
I2C_InitStruct.I2C_ClockSpeed = 100000;
I2C_Init(I2C2, &I2C_InitStruct);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource8, GPIO_AF_4);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource9, GPIO_AF_4);
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_Init(GPIOC, &GPIO_InitStruct);
I2C_Cmd(I2C2, ENABLE);
}
I2C读写方法
#define MM32I2C_TIMEOUT 0xFFFF
uint8_t YUYY_HARDI2C_WaitFlag(I2C_TypeDef *i2cx,uint32_t flag,FlagStatus status)
{
uint16_t timeout = MM32I2C_TIMEOUT;
while(I2C_GetFlagStatus(i2cx, flag) != status)
{
timeout -= 1;
if(timeout == 0)
return 1;
}
return 0;
}
uint8_t YUYY_HARDI2C_SendDatas(I2C_TypeDef *i2cx,uint8_t *datas,uint8_t datalen)
{
uint8_t i=0;
while(i<datalen)
{
if(YUYY_HARDI2C_WaitFlag(i2cx,I2C_STATUS_FLAG_TFE,SET))
{
I2C_GenerateSTOP(i2cx, ENABLE);
return 2;
}
I2C_SendData(i2cx, datas[i]);
i += 1;
}
return 0;
}
uint8_t YUYY_HARDI2C_ReadDatas(I2C_TypeDef *i2cx,uint8_t *datas,uint8_t datalen)
{
uint8_t i=0;
while(i<datalen)
{
I2C_ReadCmd(i2cx);
if(YUYY_HARDI2C_WaitFlag(i2cx,I2C_STATUS_FLAG_RFNE,SET))
{
I2C_GenerateSTOP(i2cx, ENABLE);
return 2;
}
datas[i] = I2C_ReceiveData(i2cx);
i += 1;
}
return 0;
}
uint8_t YUYY_HARDI2C_MasterSendDatasWithOption(I2C_TypeDef *i2cx,uint8_t devaddr,uint8_t option,uint8_t *datas,uint16_t datalen)
{
uint8_t err = 0;
if(!i2cx)
return 1;
I2C_TargetAddressConfig(i2cx,devaddr<<1);
err = YUYY_HARDI2C_SendDatas(i2cx,datas,datalen);
if(option & YUYY_I2C_SEND_STOP)
{
YUYY_HARDI2C_WaitFlag(i2cx,I2C_STATUS_FLAG_TFE,SET);
I2C_GenerateSTOP(i2cx, ENABLE);
YUYY_HARDI2C_WaitFlag(i2cx,I2C_STATUS_FLAG_TFE,SET);
}
return err;
}
uint8_t YUYY_HARDI2C_MasterReadDatasWithOption(I2C_TypeDef *i2cx,uint8_t devaddr,uint8_t option,uint8_t *datas,uint16_t datalen)
{
uint8_t err = 0;
if(!i2cx)
return 1;
I2C_TargetAddressConfig(i2cx,devaddr<<1);
err = YUYY_HARDI2C_ReadDatas(i2cx,datas,datalen);
if(option & YUYY_I2C_SEND_STOP)
{
I2C_GenerateSTOP(i2cx, ENABLE);
YUYY_HARDI2C_WaitFlag(i2cx,I2C_STATUS_FLAG_TFE,SET);
}
return err;
}
uint8_t YUYY_HARDI2C_MasterSendRegDatas(I2C_TypeDef *i2cx,uint8_t devaddr,uint8_t *reg,uint8_t reglen,uint8_t *datas,uint16_t datalen)
{
uint8_t err = 0;
if(!i2cx)
return 1;
err = YUYY_HARDI2C_MasterSendDatasWithOption(i2cx,devaddr,0,reg,reglen);
if(err == 0)
err = YUYY_HARDI2C_MasterSendDatasWithOption(i2cx,devaddr,YUYY_I2C_SEND_STOP,datas,datalen);
return err;
}
uint8_t YUYY_HARDI2C_MasterReadRegDatas(I2C_TypeDef *i2cx,uint8_t devaddr,uint8_t *reg,uint8_t reglen,uint8_t *datas,uint16_t datalen)
{
uint8_t err = 0;
if(!i2cx)
return 1;
if(reglen > 0)
{
err = YUYY_HARDI2C_SendDatas(i2cx,reg,reglen);
if(err == 0 && YUYY_HARDI2C_WaitFlag(i2cx,I2C_STATUS_FLAG_TFE,SET))
err = 4;
}
if(err == 0)
err = YUYY_HARDI2C_MasterReadDatasWithOption(i2cx,devaddr,YUYY_I2C_SEND_STOP,datas,datalen);
return err;
}
这个OLED是SSD1315驱动的,网上可以搜到具体的驱动代码,或者可以看我过往发的帖子,这里就不放完整代码了,只放上初始化代码
YUYY_OLED_SSD1315_DEV_Type oled_dev;
void APP_OledInit()
{
oled_dev.i2cx = I2C2;
oled_dev.i2c_senddatas_func = (YUYY_OLED_SSD1315_I2CSendDatasFunc_Type)YUYY_HARDI2C_MasterSendReg8Datas;
YUYY_OLED_SSD1315_Init(&oled_dev);
YUYY_OLED_SSD1315_ClearScreen(&oled_dev);
YUYY_OLED_SSD1315_DisplayString8x16(&oled_dev,0,0,0,"MM32F5330 TEST");
YUYY_OLED_SSD1315_DisplayString8x16(&oled_dev,0,2,0," I2C OLED");
YUYY_OLED_SSD1315_DisplayString8x16(&oled_dev,0,4,0," bbs.21ic.com");
YUYY_OLED_SSD1315_DisplayString8x16(&oled_dev,0,6,0,"Code by yuyy1989");
}
运行效果
I2C总线上可以挂载多个从设备,接下来就再增加个温湿度传感器,用I2C读取温湿度传感器的数据,并显示在OLED屏幕上,这里用的是DHTC12温湿度传感器,性能如下图
DHTC12驱动代码在以往的帖子里有,这里就不放代码了,只放上初始化代码
YUYY_DHTC12_DEV_Type dhtc12_dev;
void APP_DHTC12Init(void)
{
dhtc12_dev.i2cx = I2C2;
dhtc12_dev.delayms_func = YUYY_DelayMs;
dhtc12_dev.i2c_readregdatas_func = (YUYY_DHTC12_I2CReadRegDatasFunc_Type)YUYY_HARDI2C_MasterReadRegDatas;
dhtc12_dev.i2c_sendregdatas_func = (YUYY_DHTC12_I2CSendRegDatasFunc_Type)YUYY_HARDI2C_MasterSendRegDatas;
YUYY_DHTC12_Init(&dhtc12_dev);
}
int main(void)
{
int16_t temp,humi;
char out[20];
uart_init();
led_init();
APP_I2CInit();
APP_OledInit();
APP_DHTC12Init();
while (1)
{
YUYY_DelayMs(100);
led_toggle(LED_NO_1);
if(!YUYY_DHTC12_ReadHT(&dhtc12_dev,&temp,&humi))
{
sprintf(out,"T:%03.1f H:%03.1f%%\n",temp/10.0,humi/10.0);
YUYY_OLED_SSD1315_DisplayString8x16(&oled_dev,0,4,0,out);
}
}
}
运行效果
|
|