本帖最后由 dirty 于 2024-1-13 23:03 编辑
本篇讲述用CH32X035开发板点亮OLED.所使用到的oled模块0.91",像素点128*32,驱动芯片SSD1306G.模块资料放在附件里.
一.硬件准备
模块引脚VCC、GND、SDA、SCL,I2C驱动。SDA接PA11,SCL接PA10.
二.代码准备
硬件I2C寄存器方案遇到标志位阻塞情况,此功能实现使用IO模拟I2C方案驱动模块。
1.关于引脚定义及初始化
#define OLED_GPIO_PORT GPIOA
#define OLED_SDA_PIN GPIO_Pin_11//PA10
#define OLED_SCL_PIN GPIO_Pin_10//PA11
#define OLED_SCLK_Clr() GPIO_WriteBit(OLED_GPIO_PORT,OLED_SCL_PIN, 0) //IIC接口的时钟信号
#define OLED_SCLK_Set() GPIO_WriteBit(OLED_GPIO_PORT,OLED_SCL_PIN, 1)
#define OLED_SDIN_Clr() GPIO_WriteBit(OLED_GPIO_PORT,OLED_SDA_PIN, 0) //IIC接口的数据信号
#define OLED_SDIN_Set() GPIO_WriteBit(OLED_GPIO_PORT,OLED_SDA_PIN, 1)
#define IIC_READ_SDA GPIO_ReadInputDataBit(OLED_GPIO_PORT,OLED_SDA_PIN)
void OLED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure = {0};
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = OLED_SDA_PIN|OLED_SCL_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
2.关于I2c需要使用到的函数
<1>I2C延时
//延时
void IIC_delay(void)
{
u8 t=5; //3
while(t--);
}
<2>起始信号
void I2C_Start(void)
{
OLED_SDIN_Set();
OLED_SCLK_Set();
IIC_delay();
OLED_SDIN_Clr();
IIC_delay();
OLED_SCLK_Clr();
IIC_delay();
}
<3>结束信号
void I2C_Stop(void)
{
OLED_SDIN_Clr();
OLED_SCLK_Set();
IIC_delay();
OLED_SDIN_Set();
}
<4>等待信号响应
void I2C_WaitAck(void) //测数据信号的电平
{
uint8_t cnt=0;
OLED_SDIN_Set();
IIC_delay();
OLED_SCLK_Set();
IIC_delay();
while(IIC_READ_SDA)
{
cnt++;
if(cnt>1)//250
{
I2C_Stop();
break;
}
}
OLED_SCLK_Clr();
IIC_delay();
}
<5>写入一个字节
void Send_Byte(u8 dat)
{
u8 i;
for(i=0;i<8;i++)
{
OLED_SCLK_Clr();//将时钟信号设置为低电平
if(dat&0x80)//将dat的8位从最高位依次写入
{
OLED_SDIN_Set();
}
else
{
OLED_SDIN_Clr();
}
IIC_delay();
OLED_SCLK_Set();
IIC_delay();
OLED_SCLK_Clr();
dat<<=1;
}
}
3.驱动模块使用函数.
//向SSD1306写入一个字节。
//mode:数据/命令标志 0,表示命令;1,表示数据;
void OLED_WR_Byte(u8 dat,u8 mode)
{
I2C_Start();
Send_Byte(0x78);
I2C_WaitAck();
if(mode)
{
Send_Byte(0x40);
}
else
{
Send_Byte(0x00);
}
I2C_WaitAck();
Send_Byte(dat);
I2C_WaitAck();
I2C_Stop();
}
4.驱动OLED显示函数
void OLED_Display(void)
{
Delay_Ms(1500);
OLED_WR_Byte(0xAE,OLED_CMD);//--turn off oled panel
OLED_WR_Byte(0x00,OLED_CMD);//---set low column address
OLED_WR_Byte(0x10,OLED_CMD);//---set high column address
OLED_WR_Byte(0x40,OLED_CMD);//--set start line address Set Mapping RAM Display Start Line (0x00~0x3F)
OLED_WR_Byte(0x81,OLED_CMD);//--set contrast control register
OLED_WR_Byte(0xB4,OLED_CMD);// Set SEG Output Current Brightness //设置亮度0xCF
OLED_WR_Byte(0xA1,OLED_CMD);//--Set SEG/Column Mapping 0xa0左右反置 0xa1正常
OLED_WR_Byte(0xC8,OLED_CMD);//Set COM/Row Scan Direction 0xc0上下反置 0xc8正常
OLED_WR_Byte(0xA6,OLED_CMD);//--set normal display
OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
OLED_WR_Byte(0x1f,OLED_CMD);//--1/64 duty
OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset Shift Mapping RAM Counter (0x00~0x3F)
OLED_WR_Byte(0x00,OLED_CMD);//-not offset
OLED_WR_Byte(0xd5,OLED_CMD);//--set display clock divide ratio/oscillator frequency
OLED_WR_Byte(0x80,OLED_CMD);//--set divide ratio, Set Clock as 100 Frames/Sec
OLED_WR_Byte(0xD9,OLED_CMD);//--set pre-charge period
OLED_WR_Byte(0xF1,OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
OLED_WR_Byte(0xDA,OLED_CMD);//--set com pins hardware configuration
OLED_WR_Byte(0x00,OLED_CMD);
OLED_WR_Byte(0xDB,OLED_CMD);//--set vcomh
OLED_WR_Byte(0x40,OLED_CMD);//Set VCOM Deselect Level
OLED_WR_Byte(0x20,OLED_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02)
OLED_WR_Byte(0x02,OLED_CMD);//
OLED_WR_Byte(0x8D,OLED_CMD);//--set Charge Pump enable/disable
OLED_WR_Byte(0x14,OLED_CMD);//--set(0x10) disable
OLED_WR_Byte(0xA4,OLED_CMD);// Disable Entire Display On (0xa4/0xa5)
OLED_WR_Byte(0xA6,OLED_CMD);// Disable Inverse Display On (0xa6/a7)
OLED_WR_Byte(0xAF,OLED_CMD);
OLED_Clear();
OLED_DisplayTurn(1);
OLED_ColorTurn(0);
printf("data row:%d cloum:%d \r\n",sizeof(hz_oled)/sizeof(hz_oled[0]),sizeof(hz_oled[0])/sizeof(unsigned char));
memset(OLED_GRAM,0,sizeof(OLED_GRAM));
OLED_set_buff(0,0,hz_oled,0,2,2,sizeof(hz_oled)/sizeof(hz_oled[0]),sizeof(hz_oled[0])/sizeof(unsigned char),1,0);
OLED_set_buff(32,0,yw_oled,0,11,2,sizeof(yw_oled)/sizeof(yw_oled[0]),sizeof(yw_oled[0])/sizeof(unsigned char),1,0);
OLED_set_buff(0,16,yw_oled,11,8,2,sizeof(yw_oled)/sizeof(yw_oled[0]),sizeof(yw_oled[0])/sizeof(unsigned char),1,0);
OLED_set_buff(72,16,hz_oled,2,3,2,sizeof(hz_oled)/sizeof(hz_oled[0]),sizeof(hz_oled[0])/sizeof(unsigned char),1,0);
OLED_Refresh_t();
OLED_WR_Byte(0x2E,OLED_CMD); //停止水平滚动
Delay_Ms(8000);
OLED_WR_Byte(0x2A,OLED_CMD); //左右水平滚
OLED_WR_Byte(0x00,OLED_CMD); //dummy
OLED_WR_Byte(0x00,OLED_CMD); //滚动起始页
OLED_WR_Byte(0x00,OLED_CMD); //滚动帧速
OLED_WR_Byte(0x03,OLED_CMD); //滚动结束页
OLED_WR_Byte(0x00,OLED_CMD); //水平
OLED_WR_Byte(0x2F,OLED_CMD); //启动滚动运动
}
5.main函数
int main(void)
{
SystemCoreClockUpdate();
Delay_Init();
USART_Printf_Init(115200);
printf("SystemClk:%d\r\n",SystemCoreClock);
printf( "ChipID:%08x\r\n", DBGMCU_GetCHIPID() );
OLED_Init();
printf( "OLED_Init\r\n");
printf( "OLED to display!\r\n");
OLED_Display();
printf( "OLED display showing!\r\n");
while(1);
}
三.编译烧录,检查显示效果
程序驱动OLED静态显示与滚动现实两种模式。静态效果见下图,动态效果见附件
图1:oled静态显示
oled动态显示效果见及模块资料见文末。
至此,驱动oled 已达到预期效果。
oled_diaplay
|