I2C硬件方式程序改造目录
STM32F103驱动OLED I2C硬件方式程序改造
研究小车自带的OLED I2C程序,I2C是用GPIO软件模拟出来的,查阅STM32F103 芯片有I2C通信功能,于是,对原驱动程序进行适当修改,改为I2C硬件方式驱动。查阅相关资料,主要参考了“STM32F103C8T6引脚定义” 、“STM32F103xx固件函数库用户手册”、网文“【STM32F103笔记】9、I2C通信——玩转OLED(OLED命令详解)” 详见:http://t.csdnimg.cn/jUvkR
修改函数 void OLED_I2C_Init(void)
原函数
/*引脚配置*/
#define OLED_W_SCL(x) GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)(x))
#define OLED_W_SDA(x) GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)(x))
/*引脚初始化*/
void OLED_I2C_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_Init(GPIOB, &GPIO_InitStructure);
OLED_W_SCL(1);
OLED_W_SDA(1);
}
修改后程序
**注意:**I2C2InitStruct.I2C_ClockSpeed = 150000;//设置时钟频率,这个值不能高于 400KHz 这个值太高,OLED_ShowBinNum函数显示不正常,我的实验板是这样!!!
/*引脚初始化*/
void OLED_I2C_Init(void)
{
GPIO_InitTypeDef PB1011InitStruct;
I2C_InitTypeDef I2C2InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
PB1011InitStruct.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
PB1011InitStruct.GPIO_Mode = GPIO_Mode_AF_OD;
PB1011InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &PB1011InitStruct);
I2C2InitStruct.I2C_Mode = I2C_Mode_I2C; //设置 I2C 为 I2C 模式
I2C2InitStruct.I2C_DutyCycle = I2C_DutyCycle_2; //I2C 快速模式 Tlow / Thigh = 2 (时钟工作频率高于 100KHz)下才有意义
I2C2InitStruct.I2C_Ack = I2C_Ack_Enable; // 使能应答(ACK)
I2C2InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; //设置第一个设备自身地址为 7 位地址
I2C2InitStruct.I2C_ClockSpeed = 150000;//设置时钟频率,这个值不能高于 400KHz 这个值太高,OLED_ShowBinNum函数显示不正常
I2C_Init(I2C2, &I2C2InitStruct); //I2C初始化
I2C_Cmd(I2C2, ENABLE); //使能 I2C 外设
}
修改void OLED_I2C_Start(void)
原程序
/**
* @brief I2C开始
* @param 无
* @retval 无
*/
void OLED_I2C_Start(void)
{
OLED_W_SDA(1);
OLED_W_SCL(1);
OLED_W_SDA(0);
OLED_W_SCL(0);
}
修改后程序
/**
* @brief I2C开始
* @param 无
* @retval 无
*/
void OLED_I2C_Start(void)
{
// 发出Start信号并检测EV5
I2C_GenerateSTART(I2C2, ENABLE);
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));
}
修改void OLED_I2C_Stop(void)
原程序
/**
* @brief I2C停止
* @param 无
* @retval 无
*/
void OLED_I2C_Stop(void)
{
OLED_W_SDA(0);
OLED_W_SCL(1);
OLED_W_SDA(1);
}
修改后程序
/**
* @brief I2C停止
* @param 无
* @retval 无
*/
void OLED_I2C_Stop(void)
{
// 发送Stop信号
I2C_GenerateSTOP(I2C2, ENABLE);
}
修改 void OLED_I2C_SendByte(uint8_t Byte)
原程序
/**
* @brief I2C发送一个字节
* @param Byte 要发送的一个字节
* @retval 无
*/
void OLED_I2C_SendByte(uint8_t Byte)
{
uint8_t i;
for (i = 0; i < 8; i++)
{
OLED_W_SDA(Byte & (0x80 >> i));
OLED_W_SCL(1);
OLED_W_SCL(0);
}
OLED_W_SCL(1); //额外的一个时钟,不处理应答信号
OLED_W_SCL(0);
}
修改后程序
/**
* @brief I2C发送一个字节
* @param Byte 要发送的一个字节
* @retval 无
*/
void OLED_I2C_SendByte(uint8_t Byte)
{
// 发送数据(寄存器地址或命令,一般来说,向I2C通信对应的设备发送数据,是对其某个寄存器发送数据,或者发送对应的命令及数据),并检测EV8
I2C_SendData(I2C2, Byte);
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
}
新增函数 void OLED_I2C_Send7bitAddress(uint8_t slave_addr)
该函数用来发送从机地址
/**
* @brief I2C发送7位地址
* @param slave_addr 要发送的7位地址
* @retval 无
*/
void OLED_I2C_Send7bitAddress(uint8_t slave_addr)
{
// 发送地址并检测EV6
I2C_Send7bitAddress(I2C2, slave_addr, I2C_Direction_Transmitter);
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
}
修改void OLED_WriteCommand(uint8_t Command)
原程序
/**
* @brief OLED写命令
* @param Command 要写入的命令
* @retval 无
*/
void OLED_WriteCommand(uint8_t Command)
{
OLED_I2C_Start();
OLED_I2C_SendByte(0x78); //从机地址
OLED_I2C_SendByte(0x00); //写命令
OLED_I2C_SendByte(Command);
OLED_I2C_Stop();
}
修改后程序
/**
* @brief OLED写命令
* @param Command 要写入的命令
* @retval 无
*/
void OLED_WriteCommand(uint8_t Command)
{
OLED_I2C_Start();
OLED_I2C_Send7bitAddress(0x78); //从机地址
OLED_I2C_SendByte(0x00); //写命令
OLED_I2C_SendByte(Command);
OLED_I2C_Stop();
}
修改void OLED_WriteData(uint8_t Data)
原程序
/**
* @brief OLED写数据
* @param Data 要写入的数据
* @retval 无
*/
void OLED_WriteData(uint8_t Data)
{
OLED_I2C_Start();
OLED_I2C_SendByte(0x78); //从机地址
OLED_I2C_SendByte(0x40); //写数据
OLED_I2C_SendByte(Data);
OLED_I2C_Stop();
}
修改后程序
/**
* @brief OLED写数据
* @param Data 要写入的数据
* @retval 无
*/
void OLED_WriteData(uint8_t Data)
{
OLED_I2C_Start();
OLED_I2C_Send7bitAddress(0x78); //从机地址
OLED_I2C_SendByte(0x40); //写数据
OLED_I2C_SendByte(Data);
OLED_I2C_Stop();
}
其他程序没有改动。
在主程序中进行程序测试:
int main(void)
{
OLED_Init();
OLED_ShowChar(1,1,'F');
OLED_ShowString(1,3,"XG nihao!");
OLED_ShowNum(2,1,1000,4);
OLED_ShowSignedNum(2,7,-991,3);
OLED_ShowHexNum(3,1,0xff01,4);
OLED_ShowBinNum(4,1,0xff01,16);
while (1)
{
}
}
显示图片 通信速度:150000
显示图片 通信速度:200000

1112





