赞
踩
如图:I2C片上外设挂载在APB1总线上面,并且I2C1由复用重映射,I2C2没有重映射。
TDR -Transmit Data Register -发送数据寄存器
RDR -Receive Data Register -接收数据寄存器
CR -Control Register -控制寄存器
SR1 -Status Register 1 -状态寄存器1
SR2 -Status Register 2 -状态寄存器2
CCR -Clock Control Register -时钟控制寄存器
SR1:状态寄存器1
SB:起始位发送完成,0代表没有起始位产生,1代表检测到了起始位。
AF/ADDR:AF代表接收到NAK,寻址失败AF=1;ADDR代表选址成功,寻址成功-ADDR=1。
TXE:发送数据寄存器TDR空,1代表空,0代表非空。
RXNE:接收数据寄存器RDR非空,1代表非空,0代表空。
BTF:发送完成。1代表发送完成
SR2:状态寄存器2
TRA
BUSY:用于查询总线的空闲状态,0为空闲,1为忙。
MSL
CR:控制寄存器
PE:SCL的开关。
START:用于产生一个起始位,写入1代表发送一个起始位。
ACK:用于产生一个应答信号。
我们使用I2C1,初始化SCL和SDA所连接的IO口,把他们配置为复用开漏模式。
//1 .开启GPIOB挂载的总线时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
//初始化IO引脚
GPIO_InitTypeDef GPIOInitStruct;
GPIOInitStruct.GPIO_Mode = GPIO_Mode_AF_OD;//复用输出开漏模式
GPIOInitStruct.GPIO_Pin = GPIO_Pin_6 |GPIO_Pin_7;
GPIOInitStruct.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOB,&GPIOInitStruct);
//2 .开启I2C挂载APB1总线的时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);//开启时钟
RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1,ENABLE);//对I2C1进行复位
RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1,DISABLE);//对I2C1进行释放
标志模式下:波特率max = 100K,当波特率>=100K时,就按照快速模式进行。快速模式下:波特率max = 400K。
I2C_DutyCycle:在快速模式下,配置时钟信号的形状,即时钟信号的占空比。2:1 = 低电平:高电平/16:9 = 低电平:高电平
下面灰色是工作在从机模式下才需要进行配置的。
//3 .配置I2C1的参数
I2C_InitTypeDef I2CInitStruct;
I2CInitStruct.I2C_ClockSpeed = 400000;//配置波特率,最高400K
I2CInitStruct.I2C_Mode = I2C_Mode_I2C;//标准的I2C模式,一般不使用SMBus
I2CInitStruct.I2C_DutyCycle = I2C_DutyCycle_2;//2:1
I2C_Init(I2C1,&I2CInitStruct);
//4 .使能I2C
I2C_Cmd(I2C1,ENABLE);//闭合开关,PE
//1 .等待总线空闲
while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY) == SET);
//2 .发送起始位
I2C_GenerateSTART(I2C1,ENABLE);
while(I2C_GetFlagStatus(I2C1,I2C_FLAG_SB) == RESET);//起始位发送完成
发送地址前先清除AF标志位,
//3 .发送地址 //3.1 清除标志位AF I2C_ClearFlag(I2C1,I2C_FLAG_AF); //3.2 发送8为数据,7+1 I2C_SendData(I2C1,SlaveADDr & 0xfe); //3.3 等待发送成功 while(I2C_GetFlagStatus(I2C1,I2C_FLAG_ADDR) == RESET) { if(I2C_GetFlagStatus(I2C1,I2C_FLAG_AF) == SET)//地址发送失败了 { ret = ERROR; goto STOP; } } STOP: I2C_GenerateSTOP(I2C1,ENABLE);//发送停止位 while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY) == SET);//等待总线空闲
发送数据前先清除ADDR标志位,清除ADDR(先读SR1寄存器,再度SR2寄存器)。
//4 .发送数据 //4.1 清除ADDR标志位 I2C_ReadRegister(I2C1,I2C_Register_SR1);//读取SR1 I2C_ReadRegister(I2C1,I2C_Register_SR2);//读取SR2 //4.2 向TDR寄存器写入数据 uint32_t i; for(i = 0; i < Size ;i++)//Size是数据数组的个数 { while(I2C_GetFlagStatus(I2C1,I2C_FLAG_TXE) == RESET)//等待TXE为1 { if(I2C_GetFlagStatus(I2C1,I2C_FLAG_AF) == SET) { ret = ERROR; goto STOP; } } I2C_SendData(I2C1,pData[i]);//向TDR写入数据 } while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BTF) == RESET)//等待发送完成 { if(I2C_GetFlagStatus(I2C1,I2C_FLAG_AF) == SET) { ret = ERROR; goto STOP; } }
最终代码①:
//1 .等待总线空闲 while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY) == SET); //2 .发送起始位 I2C_GenerateSTART(I2C1,ENABLE); while(I2C_GetFlagStatus(I2C1,I2C_FLAG_SB) == RESET);//起始位发送完成 //3 .发送地址 //3.1 清除标志位AF I2C_ClearFlag(I2C1,I2C_FLAG_AF); //3.2 发送8为数据,7+1 I2C_SendData(I2C1,SlaveADDr & 0xfe); //3.3 等待发送成功 while(I2C_GetFlagStatus(I2C1,I2C_FLAG_ADDR) == RESET) { if(I2C_GetFlagStatus(I2C1,I2C_FLAG_AF) == SET)//地址发送失败了 { ret = ERROR; goto STOP; } } //4 .发送数据 //4.1 清除ADDR标志位 I2C_ReadRegister(I2C1,I2C_Register_SR1);//读取SR1 I2C_ReadRegister(I2C1,I2C_Register_SR2);//读取SR2 //4.2 向TDR寄存器写入数据 uint32_t i; for(i = 0; i < Size ;i++) { while(I2C_GetFlagStatus(I2C1,I2C_FLAG_TXE) == RESET)//等待TXE为1 { if(I2C_GetFlagStatus(I2C1,I2C_FLAG_AF) == SET) { ret = ERROR; goto STOP; } } I2C_SendData(I2C1,pData[i]); } while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BTF) == RESET)//等待发送完成 { if(I2C_GetFlagStatus(I2C1,I2C_FLAG_AF) == SET) { ret = ERROR; goto STOP; } } //5 .发送STOP STOP: I2C_GenerateSTOP(I2C1,ENABLE); while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY) == SET);
代码测试:通过向OLED模式发送指令将其屏幕点亮
#include "stm32f10x.h" void App_I2C_Init(void); void App_I2C_Send(uint8_t SlaveADDr,uint8_t* pData,uint16_t Size); int main(void) { //OLED指令 uint8_t oled_init_command[] = { 0x00, // Command Stream 0xa8, 0x3f, // Set MUX Ratio 0xd3, 0x00, // Set Display Offset 0x40, // Set Display Start Line 0xa0, // Set Segment re-map 0xc0, // Set COM Output Scan Direction 0xda, 0x02, // Set COM Pins hardware configuration 0x81, 0x7f, // Set Contrast Control 0xa5, // Enable Entire Display On 0xa6, // Set Normal Display 0xd5, 0x80, // Set OSC Frequency 0x8d, 0x14, // Enable charge pump regulator 0xaf, // Display on }; App_I2C_Init(); App_I2C_Send(0x78, oled_init_command, sizeof(oled_init_command)/sizeof(uint8_t)); while(1) { } } void App_I2C_Init(void) { //1 .开启GPIOB挂载的总线时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); //初始化IO引脚 GPIO_InitTypeDef GPIOInitStruct; GPIOInitStruct.GPIO_Mode = GPIO_Mode_AF_OD;//复用输出开漏模式 GPIOInitStruct.GPIO_Pin = GPIO_Pin_6 |GPIO_Pin_7; GPIOInitStruct.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(GPIOB,&GPIOInitStruct); //2 .开启I2C挂载APB1总线的时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);//开启时钟 RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1,ENABLE);//对I2C1进行复位 RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1,DISABLE);//对I2C1进行释放 //3 .配置I2C1的参数 I2C_InitTypeDef I2CInitStruct; I2CInitStruct.I2C_ClockSpeed = 400000;//配置波特率,最高400K I2CInitStruct.I2C_Mode = I2C_Mode_I2C;//一般不使用SMBus I2CInitStruct.I2C_DutyCycle = I2C_DutyCycle_2;//2:1 I2C_Init(I2C1,&I2CInitStruct); //4 .使能I2C I2C_Cmd(I2C1,ENABLE); } void App_I2C_Send(uint8_t SlaveADDr,uint8_t* pData,uint16_t Size) { ErrorStatus ret = SUCCESS; //1 .等待总线空闲 while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY) == SET); //2 .发送起始位 I2C_GenerateSTART(I2C1,ENABLE); while(I2C_GetFlagStatus(I2C1,I2C_FLAG_SB) == RESET);//起始位发送完成 //3 .发送地址 //3.1 清除标志位AF I2C_ClearFlag(I2C1,I2C_FLAG_AF); //3.2 发送8为数据,7+1 I2C_SendData(I2C1,SlaveADDr & 0xfe); //3.3 等待发送成功 while(I2C_GetFlagStatus(I2C1,I2C_FLAG_ADDR) == RESET) { if(I2C_GetFlagStatus(I2C1,I2C_FLAG_AF) == SET)//地址发送失败了 { ret = ERROR; goto STOP; } } //4 .发送数据 //4.1 清除ADDR标志位 I2C_ReadRegister(I2C1,I2C_Register_SR1);//读取SR1 I2C_ReadRegister(I2C1,I2C_Register_SR2);//读取SR2 //4.2 向TDR寄存器写入数据 uint32_t i; for(i = 0; i < Size ;i++) { while(I2C_GetFlagStatus(I2C1,I2C_FLAG_TXE) == RESET)//等待TXE为1 { if(I2C_GetFlagStatus(I2C1,I2C_FLAG_AF) == SET) { ret = ERROR; goto STOP; } } I2C_SendData(I2C1,pData[i]); } while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BTF) == RESET)//等待发送完成 { if(I2C_GetFlagStatus(I2C1,I2C_FLAG_AF) == SET) { ret = ERROR; goto STOP; } } //5 .发送STOP STOP: I2C_GenerateSTOP(I2C1,ENABLE); while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY) == SET); }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。