dirty 发表于 2024-1-13 23:00

【CH32X035评估板】--OLED显示

本帖最后由 dirty 于 2024-1-13 23:03 编辑

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;本篇讲述用CH32X035开发板点亮OLED.所使用到的oled模块0.91&quot;,像素点128*32,驱动芯片SSD1306G.模块资料放在附件里.</p>

<p>一.硬件准备</p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;模块引脚VCC、GND、SDA、SCL,I2C驱动。SDA接PA11,SCL接PA10.</p>

<p>二.代码准备</p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;硬件I2C寄存器方案遇到标志位阻塞情况,此功能实现使用IO模拟I2C方案驱动模块。</p>

<p>1.关于引脚定义及初始化</p>

<pre>
<code>#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, &amp;GPIO_InitStructure);

}</code></pre>

<p>2.关于I2c需要使用到的函数</p>

<p>&lt;1&gt;I2C延时</p>

<pre>
<code>//延时
void IIC_delay(void)
{
        u8 t=5;       //3
        while(t--);
}</code></pre>

<p>&lt;2&gt;起始信号</p>

<pre>
<code>void I2C_Start(void)
{
        OLED_SDIN_Set();
        OLED_SCLK_Set();
        IIC_delay();
        OLED_SDIN_Clr();
        IIC_delay();
        OLED_SCLK_Clr();
        IIC_delay();
}</code></pre>

<p>&lt;3&gt;结束信号</p>

<pre>
<code>void I2C_Stop(void)
{
        OLED_SDIN_Clr();
        OLED_SCLK_Set();
        IIC_delay();
       
        OLED_SDIN_Set();
}</code></pre>

<p>&lt;4&gt;等待信号响应</p>

<pre>
<code>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&gt;1)//250
                {
                        I2C_Stop();
                        break;
                }
        }
        OLED_SCLK_Clr();
        IIC_delay();
}</code></pre>

<p>&lt;5&gt;写入一个字节</p>

<pre>
<code>void Send_Byte(u8 dat)
{
        u8 i;
        for(i=0;i&lt;8;i++)
        {
                OLED_SCLK_Clr();//将时钟信号设置为低电平
                if(dat&amp;0x80)//将dat的8位从最高位依次写入
                {
                        OLED_SDIN_Set();
                }
                else
                {
                        OLED_SDIN_Clr();
                }
                IIC_delay();
                OLED_SCLK_Set();
                IIC_delay();
                OLED_SCLK_Clr();
                dat&lt;&lt;=1;
}
}</code></pre>

<p>3.驱动模块使用函数.</p>

<pre>
<code>//向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();
}</code></pre>

<p>4.驱动OLED显示函数</p>

<pre>
<code>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 addressSet 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 &amp; 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),sizeof(hz_oled)/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),sizeof(hz_oled)/sizeof(unsigned char),1,0);
        OLED_set_buff(32,0,yw_oled,0,11,2,sizeof(yw_oled)/sizeof(yw_oled),sizeof(yw_oled)/sizeof(unsigned char),1,0);
       
        OLED_set_buff(0,16,yw_oled,11,8,2,sizeof(yw_oled)/sizeof(yw_oled),sizeof(yw_oled)/sizeof(unsigned char),1,0);
        OLED_set_buff(72,16,hz_oled,2,3,2,sizeof(hz_oled)/sizeof(hz_oled),sizeof(hz_oled)/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); //启动滚动运动

}
</code></pre>

<p>5.main函数</p>

<pre>
<code>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);
}
</code></pre>

<p>三.编译烧录,检查显示效果</p>

<p>&nbsp; &nbsp; &nbsp;程序驱动OLED静态显示与滚动现实两种模式。静态效果见下图,动态效果见附件</p>

<div style="text-align: center;"></div>

<div style="text-align: center;">图1:oled静态显示</div>

<p>&nbsp;&nbsp;&nbsp;&nbsp;oled动态显示效果见及模块资料见文末。</p>

<p>&nbsp;</p>

<p>&nbsp; &nbsp; 至此,驱动oled 已达到预期效果。</p>

<p>&nbsp;</p>

<p>1fe978dcf979d4487a6cb5439677ab6a<br />
&nbsp;</p>

<p>&nbsp;</p>

lugl4313820 发表于 2024-1-13 23:03

<p>这个OLED挺小的,楼主可以试一下硬件I2C,应该效果比这个还要好。</p>

dirty 发表于 2024-1-13 23:09

lugl4313820 发表于 2024-1-13 23:03
这个OLED挺小的,楼主可以试一下硬件I2C,应该效果比这个还要好。

<p>哇,你这秒评呀。手头只有这么个oled<img height="28" src="https://bbs.eeworld.com.cn/static/editor/plugins/hkemoji/sticker/facebook/rolling-on-the-floor-laughing_1f923.png" width="28" />&nbsp;。两者效果差不多一样的。后面看情况再尝试下另一实现方案。</p>

lugl4313820 发表于 2024-1-13 23:16

dirty 发表于 2024-1-13 23:09
哇,你这秒评呀。手头只有这么个oled&nbsp;。两者效果差不多一样的。后面看情况再尝试下另一实现方案。

<p>如果经常玩的话,可以搞个iic ,一个spi的,这样更加有得玩。</p>

freebsder 发表于 2024-1-15 19:32

<p>谢谢分享,期待后续!</p>

mingkong12 发表于 2024-7-3 02:31

可以上传一下完整工程吗求求!
页: [1]
查看完整版本: 【CH32X035评估板】--OLED显示