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)
{
}
}