OLED显示采用IIC通信协议,使用软模拟,不采用硬件IIC通信,初学,有优化的地方麻烦指出。

//IO操作函数	 GPIOC簇
#define IIC_SCL    GPIO_Pin_2 //SCL
#define IIC_SDA    GPIO_Pin_4 //SDA	 
#define IIC_SCL_PORT  GPIOA			   //端口号
#define	IIC_SDA_PORT  GPIOA

//初始化IIC
void IIC_init(void)
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	
    //初始化IIC的引脚所在GPIO簇
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
	
	//SCL_GPIO初始化
	GPIO_InitStructure.GPIO_Pin=IIC_SCL; 
	GPIO_InitStructure.GPIO_Mode= GPIO_Mode_OUT; //输出模式
	GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;  //开漏输出
	GPIO_InitStructure.GPIO_Speed=GPIO_High_Speed; //引脚响应速度
	GPIO_Init(IIC_SCL_PORT, &GPIO_InitStructure);
	
	//SDA_GPIO初始化
	GPIO_InitStructure.GPIO_Pin=IIC_SDA; 
	GPIO_InitStructure.GPIO_Mode= GPIO_Mode_OUT; //输入模式
	GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;  //开漏输出
	GPIO_InitStructure.GPIO_Speed=GPIO_High_Speed; //引脚响应速度
	GPIO_Init(IIC_SDA_PORT, &GPIO_InitStructure);

    GPIO_WriteBit(IIC_SCL_PORT, IIC_SCL, Bit_SET);
    GPIO_WriteBit(IIC_SDA_PORT, IIC_SDA, Bit_SET);	
}

//配置SDA数据线为输出模式
void IIC_SDA_OUT(void)
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	
	//SDA GPIO初始化
	GPIO_InitStructure.GPIO_Pin=IIC_SDA; 
	GPIO_InitStructure.GPIO_Mode= GPIO_Mode_OUT; 
	GPIO_InitStructure.GPIO_OType=GPIO_OType_OD; //开漏输出
	GPIO_InitStructure.GPIO_Speed=GPIO_High_Speed;
	
	GPIO_Init(IIC_SDA_PORT, &GPIO_InitStructure);
}

//配置SDA数据线为输入
void IIC_SDA_IN(void)
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	
	//SDA GPIO初始化
	GPIO_InitStructure.GPIO_Pin=IIC_SDA; 
	GPIO_InitStructure.GPIO_Mode= GPIO_Mode_IN; 
	GPIO_InitStructure.GPIO_Speed=GPIO_High_Speed;
	GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP; //上拉,仅对输入有效
	
	GPIO_Init(IIC_SDA_PORT, &GPIO_InitStructure);
}

/*
    产生应答回应
*/
void IIC_ACK(void)
{
	IIC_SDA_OUT();
    GPIO_WriteBit(IIC_SCL_PORT, IIC_SCL, Bit_RESET);
	GPIO_WriteBit(IIC_SDA_PORT, IIC_SDA, Bit_RESET);
	Delay_us(2);
	GPIO_WriteBit(IIC_SCL_PORT, IIC_SCL, Bit_SET);
	Delay_us(2);
	GPIO_WriteBit(IIC_SCL_PORT, IIC_SCL, Bit_RESET);

}


/*
    不产生应答回应
*/
void IIC_NOACK(void)
{
	
	IIC_SDA_OUT();
    GPIO_WriteBit(IIC_SCL_PORT, IIC_SCL, Bit_RESET);
	GPIO_WriteBit(IIC_SDA_PORT, IIC_SDA, Bit_SET);
	Delay_us(2);
	GPIO_WriteBit(IIC_SCL_PORT, IIC_SCL, Bit_SET);
	Delay_us(2);
	GPIO_WriteBit(IIC_SCL_PORT, IIC_SCL, Bit_RESET);

}


/*
    等待应答信号
    note:
        1为接收应答失败
        0为接收应答成功
*/

/*
    GPIO_ReadInputDataBit(GPIOC, IIC_SDA)它持续检查SDA线的状态,等待从设备将其拉低以产生应答信号。
    如果SDA线一直保持高电平,time计数器会增加,直到超过255,
    这时会调用IIC_stop()函数停止I2C通信,并返回1表示应答失败。
    这种超时机制防止了因从设备故障或其他原因导致的死锁。
    如果从设备产生了应答信号(即SDA线被拉低),则SCL线会被重置为低电平,
    以结束当前的通信周期。然后函数返回0,表示应答成功。
*/
uint8_t WAIT_ACK(void)
{
	uint8_t time = 0;
	IIC_SDA_IN();//为了释放SDA线,让从设备能够将其拉低以产生应答信号。
	GPIO_WriteBit(IIC_SDA_PORT, IIC_SDA, Bit_SET);
	Delay_us(2);
	GPIO_WriteBit(IIC_SCL_PORT, IIC_SCL, Bit_SET);
	Delay_us(2);
	while(GPIO_ReadInputDataBit(IIC_SDA_PORT, IIC_SDA))
	{
		time++;
		if(time>250)
		{
			IIC_stop();
			return 1;
		}
	}
	GPIO_WriteBit(IIC_SCL_PORT, IIC_SCL, Bit_RESET);
	return 0;
}


/*
    IIC产生起始信号
*/
void IIC_start(void)
{
	IIC_SDA_OUT();
	GPIO_WriteBit(IIC_SCL_PORT, IIC_SCL, Bit_SET);
    GPIO_WriteBit(IIC_SDA_PORT, IIC_SDA, Bit_SET);
	Delay_us(4);//根据被控对象决定
	GPIO_WriteBit(IIC_SDA_PORT, IIC_SDA, Bit_RESET); //拉低数据线
	Delay_us(4);
	GPIO_WriteBit(IIC_SCL_PORT, IIC_SCL, Bit_RESET); //钳住总线,等待数据开始传输
}

/*
    IIC产生停止信号
*/
void IIC_stop(void)
{
	IIC_SDA_OUT();
	GPIO_WriteBit(IIC_SCL_PORT, IIC_SCL, Bit_SET);
	GPIO_WriteBit(IIC_SDA_PORT, IIC_SDA, Bit_RESET);
	Delay_us(4);//根据被控对象决定
	GPIO_WriteBit(IIC_SDA_PORT, IIC_SDA, Bit_SET);
}


/*
    IIC发送一个字节
*/
void IIC_send_byte(uint8_t data)
{
	int i = 0;
	IIC_SDA_OUT();
	GPIO_WriteBit(IIC_SCL_PORT, IIC_SCL, Bit_RESET);
	for(i=0; i<8; i++)
	{
		if((data&0X80) > 0)
		{
			GPIO_WriteBit(IIC_SDA_PORT, IIC_SDA, Bit_SET);
		}
		else
		{
			GPIO_WriteBit(IIC_SDA_PORT, IIC_SDA, Bit_RESET);
		}
		data<<=1;
        Delay_us(2);
		GPIO_WriteBit(IIC_SCL_PORT, IIC_SCL, Bit_SET);
		Delay_us(2);
		GPIO_WriteBit(IIC_SCL_PORT, IIC_SCL, Bit_RESET);
		Delay_us(2);
	}
}


/*
    IIC读取一个字节
*/
uint8_t IIC_read_byte(uint8_t ack)
{
	int i = 0;
	uint8_t rec_data = 0;
	IIC_SDA_IN();
	for(i=0; i<8; i++)
	{
        GPIO_WriteBit(IIC_SCL_PORT, IIC_SCL, Bit_RESET);
		Delay_us(2);
		GPIO_WriteBit(IIC_SCL_PORT, IIC_SCL, Bit_SET);
		rec_data<<=1;
		if(GPIO_ReadInputDataBit(IIC_SDA_PORT, IIC_SDA))
		{
			rec_data++;
		}
		Delay_us(2);
	}
	//应答
	if(ack)
	{
		IIC_ACK();
	}
	else
	{
		IIC_NOACK();
	}
	return rec_data;
}


#include "oled_font.h"
#include "iic.h"

void OLED_WriteCommand(uint8_t Command)
{
	IIC_start();
	IIC_send_byte(0x78); 	//从机地址,并且写数据
	WAIT_ACK();
	IIC_send_byte(0x00);     //
	WAIT_ACK();
	IIC_send_byte(Command); // 写入命令
	WAIT_ACK();
	IIC_stop();
}

void OLED_WriteData(uint8_t Data)
{
	IIC_start();
	IIC_send_byte(0x78); 	//从机地址
	WAIT_ACK();
	IIC_send_byte(0x40);
	WAIT_ACK();
	IIC_send_byte(Data); 	// 写入命令
	WAIT_ACK();
	IIC_stop();
}

/*
	OLED设置光标位置
*/
void OLED_SetCursor(uint8_t Y, uint8_t X)
{
    OLED_WriteCommand(0xB0 | Y);                 // 设置Y位置
    OLED_WriteCommand(0x10 | ((X & 0xF0) >> 4)); // 设置X位置高4位
    OLED_WriteCommand(0x00 | (X & 0x0F));        // 设置X位置低4位
}

/*
	OLED清屏
 */
void OLED_Clear(void)
{
    uint8_t i, j;
    for (j = 0; j < 8; j++)
    {
        OLED_SetCursor(j, 0);
        for (i = 0; i < 128; i++)
        {
            OLED_WriteData(0x00);
        }
    }
}

/*
	OLED显示一个字符
 */
void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char)
{
    uint8_t i;
    OLED_SetCursor((Line - 1) * 2, (Column - 1) * 8); 		// 设置光标位置在上半部分
    for (i = 0; i < 8; i++)
    {
        OLED_WriteData(OLED_F8x16[Char - ' '][i]); 			// 显示上半部分内容
    }
    OLED_SetCursor((Line - 1) * 2 + 1, (Column - 1) * 8); 	// 设置光标位置在下半部分
    for (i = 0; i < 8; i++)
    {
        OLED_WriteData(OLED_F8x16[Char - ' '][i + 8]); 		// 显示下半部分内容
    }
}

/*
	OLED显示字符串
 */
void OLED_ShowString(uint8_t Line, uint8_t Column, char *String)
{
    uint8_t i;
    for (i = 0; String[i] != '\0'; i++)
    {
        OLED_ShowChar(Line, Column + i, String[i]);
    }
}void OLED_Init(void)
{
  

	Delay_ms(100);

    OLED_WriteCommand(0xAE); // 关闭显示

    OLED_WriteCommand(0xD5); // 设置显示时钟分频比/振荡器频率
    OLED_WriteCommand(0x80);

    OLED_WriteCommand(0xA8); // 设置多路复用率
    OLED_WriteCommand(0x3F);

    OLED_WriteCommand(0xD3); // 设置显示偏移
    OLED_WriteCommand(0x00);

    OLED_WriteCommand(0x40); // 设置显示开始行

    OLED_WriteCommand(0xA1); // 设置左右方向,0xA1正常 0xA0左右反置

    OLED_WriteCommand(0xC8); // 设置上下方向,0xC8正常 0xC0上下反置

    OLED_WriteCommand(0xDA); // 设置COM引脚硬件配置
    OLED_WriteCommand(0x12);

    OLED_WriteCommand(0x81); // 设置对比度控制
    OLED_WriteCommand(0xCF);

    OLED_WriteCommand(0xD9); // 设置预充电周期
    OLED_WriteCommand(0xF1);

    OLED_WriteCommand(0xDB); // 设置VCOMH取消选择级别
    OLED_WriteCommand(0x30);

    OLED_WriteCommand(0xA4); // 设置整个显示打开/关闭

    OLED_WriteCommand(0xA6); // 设置正常/倒转显示

    OLED_WriteCommand(0x8D); // 设置充电泵
    OLED_WriteCommand(0x14);

    OLED_WriteCommand(0xAF); // 开启显示

    OLED_Clear(); // OLED清屏
}
int main ()
{
 //初始化IIC
	IIC_init();
	
    ///初始化OLED
	OLED_Init();
    
    //写入数据到OLED,并显示
	OLED_ShowString(3,3,"Hello,World!");
	while(1)
	{
		
		
	}
}