【WCH】CH32F203硬件I2C驱动SSD1306 OLED

【WCH】CH32F203硬件I2C驱动SSD1306 OLED


  • 《关于CH32F203程序下载方式说明》
  • 本驱动例程基于:CH32F203C8
  • 驱动显示效果

I2C接口

  • 采用I2C1进行驱动
 I2C1_SCL(PB8)
 I2C1_SDA(PB9).

实现对 I2C SSD1306读写操作函数

void I2C_WriteByte(uint8_t addr, uint8_t data)
{
    //检测IIC的总线忙,如果忙则阻止程序运行
    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));
    //产生IIC启动信号
    I2C_GenerateSTART(I2C1, ENABLE);
    //检查主机模式是否选择完成
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
    //发送8位数据, 向I2C1发送oled地址,主从模式
    I2C_Send7bitAddress(I2C1, OLED_ADDRESS, I2C_Direction_Transmitter);
    //检查主机发送字节是否结束
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
    //发送addr 寄存器的地址
    I2C_SendData(I2C1, addr);
    //检查主机字节发送是否结束
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING));
    //通过IICx发送数据
    I2C_SendData(I2C1, data);
    //检查字节发送是否结束
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
    //停止信号结束
    I2C_GenerateSTOP(I2C1, ENABLE);
}

/**
 * @brief	OLED写入命令
 * @param cmd - 待写入命令
 * @note	移植时,请使用自己的底层API实现
*/
static void OLED_Write_Cmd(uint8_t cmd)
{

    //使用HAL库的API实现
	I2C_WriteByte(0x00, cmd);

}
/**
 * @brief	OLED写入数据
 * @param cmd - 待写入数据
 * @note	移植时,请使用自己的底层API实现
*/
static void OLED_Write_Dat(uint8_t dat)
{
    //使用HAL库的API实现
	I2C_WriteByte(0x40, dat);
}

OLED驱动内容

  • oled.c
#include "oled.h"
#include "oledfont.h"


void I2C_WriteByte(uint8_t addr, uint8_t data)
{
    //检测IIC的总线忙,如果忙则阻止程序运行
    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));
    //产生IIC启动信号
    I2C_GenerateSTART(I2C1, ENABLE);
    //检查主机模式是否选择完成
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
    //发送8位数据, 向I2C1发送oled地址,主从模式
    I2C_Send7bitAddress(I2C1, OLED_ADDRESS, I2C_Direction_Transmitter);
    //检查主机发送字节是否结束
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
    //发送addr 寄存器的地址
    I2C_SendData(I2C1, addr);
    //检查主机字节发送是否结束
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING));
    //通过IICx发送数据
    I2C_SendData(I2C1, data);
    //检查字节发送是否结束
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
    //停止信号结束
    I2C_GenerateSTOP(I2C1, ENABLE);
}

//OLED的显存
//存放格式如下.
//[0]0 1 2 3 ... 127
//[1]0 1 2 3 ... 127
//[2]0 1 2 3 ... 127
//[3]0 1 2 3 ... 127
//[4]0 1 2 3 ... 127
//[5]0 1 2 3 ... 127
//[6]0 1 2 3 ... 127
//[7]0 1 2 3 ... 127

/**
 * @brief	OLED写入命令
 * @param cmd - 待写入命令
 * @note	移植时,请使用自己的底层API实现
*/
static void OLED_Write_Cmd(uint8_t cmd)
{

    //使用HAL库的API实现
	I2C_WriteByte(0x00, cmd);

}
/**
 * @brief	OLED写入数据
 * @param cmd - 待写入数据
 * @note	移植时,请使用自己的底层API实现
*/
static void OLED_Write_Dat(uint8_t dat)
{
    //使用HAL库的API实现
	I2C_WriteByte(0x40, dat);
}

/**
 * @brief	OLED设置显示位置
 * @param x - X方向位置
 * @param y - Y方向位置
*/
void OLED_Set_Pos(uint8_t x, uint8_t y)
{
    OLED_Write_Cmd(0xb0 + y);
    OLED_Write_Cmd(((x & 0xf0) >> 4) | 0x10);
    OLED_Write_Cmd((x & 0x0f) | 0x01);
}
/**
 * @brief	OLED开启显示
*/
void OLED_Display_On(void)
{
    OLED_Write_Cmd(0X8D);  //SET DCDC命令
    OLED_Write_Cmd(0X14);  //DCDC ON
    OLED_Write_Cmd(0XAF);  //DISPLAY ON
}
/**
 * @brief	OLED关闭显示
*/
void OLED_Display_Off(void)
{
    OLED_Write_Cmd(0X8D);  //SET DCDC命令
    OLED_Write_Cmd(0X10);  //DCDC OFF
    OLED_Write_Cmd(0XAE);  //DISPLAY OFF
}
/**
 * @brief	OLED清屏函数(清屏之后屏幕全为黑色)
*/
void OLED_Clear(void)
{
    uint8_t i, n;
    for(i = 0; i < 8; i++)
    {
        OLED_Write_Cmd(0xb0 + i);  //设置页地址(0~7)
        OLED_Write_Cmd(0x00);      //设置显示位置—列低地址
        OLED_Write_Cmd(0x10);      //设置显示位置—列高地址
        for(n = 0; n < 128; n++)
        {
            OLED_Write_Dat(0);
        }
    }
}
/**
 * @brief	OLED显示全开(所有像素点全亮)
*/
void OLED_On(void)
{
    uint8_t i, n;
    for(i = 0; i < 8; i++)
    {
        OLED_Write_Cmd(0xb0 + i);  //设置页地址(0~7)
        OLED_Write_Cmd(0x00);      //设置显示位置—列低地址
        OLED_Write_Cmd(0x10);      //设置显示位置—列高地址
        for(n = 0; n < 128; n++)
        {
            OLED_Write_Dat(1);
        }
    }
}
/**
 * @brief	在指定位置显示一个ASCII字符
 * @param x - 0 - 127
 * @param y - 0 - 7
 * @param chr  - 待显示的ASCII字符
 * @param size - ASCII字符大小
 * 				字符大小有12(6*8)/16(8*16)两种大小
*/
void OLED_ShowChar(uint8_t x, uint8_t y, uint8_t chr, uint8_t size)
{
    uint8_t c = 0, i = 0;

    c = chr - ' ';
    if(x > 128 - 1)
    {
        x = 0;
        y++;
    }

    if(size == 16)
    {
        OLED_Set_Pos(x, y);
        for(i = 0; i < 8; i++)
        {
            OLED_Write_Dat(F8X16[c * 16 + i]);
        }
        OLED_Set_Pos(x, y + 1);
        for(i = 0; i < 8; i++)
        {
            OLED_Write_Dat(F8X16[c * 16 + i + 8]);
        }
    }
    else
    {
        OLED_Set_Pos(x, y);
        for(i = 0; i < 6; i++)
        {
            OLED_Write_Dat(F6x8[c][i]);
        }
    }
}
/**
 * @brief	OLED 专用pow函数
 * @param m - 底数
 * @param n - 指数
*/
static uint32_t oled_pow(uint8_t m, uint8_t n)
{
    uint32_t result = 1;
    while(n--)result *= m;
    return result;
}
/**
 * @brief	在指定位置显示一个整数
 * @param x - 0 - 127
 * @param y - 0 - 7
 * @param num - 待显示的整数(0-4294967295)
 * @param	len - 数字的位数
 * @param size - ASCII字符大小
 * 				字符大小有12(6*8)/16(8*16)两种大小
*/
void OLED_ShowNum(uint8_t x, uint8_t y, uint32_t num, uint8_t len, uint8_t size)
{
    uint8_t t, temp;
    uint8_t enshow = 0;
    for(t = 0; t < len; t++)
    {
        temp = (num / oled_pow(10, len - t - 1)) % 10;
        if(enshow == 0 && t < (len - 1))
        {
            if(temp == 0)
            {
                OLED_ShowChar(x + (size / 2)*t, y, ' ', size);
                continue;
            }
            else enshow = 1;

        }
        OLED_ShowChar(x + (size / 2)*t, y, temp + '0', size);
    }
}
/**
 * @brief	在指定位置显示一个字符串
 * @param x - 0 - 127
 * @param y - 0 - 7
 * @param chr - 待显示的字符串指针
 * @param size - ASCII字符大小
 * 				字符大小有12(6*8)/16(8*16)两种大小
*/
void OLED_ShowString(uint8_t x, uint8_t y, char* chr, uint8_t size)
{
    uint8_t j = 0;
    while(chr[j] != '\0')
    {
        OLED_ShowChar(x, y, chr[j], size);
        x += 8;
        if(x > 120)
        {
            x = 0;
            y += 2;
        }
        j++;
    }
}
/**
 * @brief	在指定位置显示一个汉字
 * @param x  - 0 - 127
 * @param y  - 0 - 7
 * @param no - 汉字在中文字库数组中的索引(下标)
 * @note	中文字库在oledfont.h文件中的Hzk数组中,需要提前使用软件对汉字取模
*/
void OLED_ShowCHinese(uint8_t x, uint8_t y, uint8_t no)
{
    uint8_t t, adder = 0;
    OLED_Set_Pos(x, y);
    for(t = 0; t < 16; t++)
    {
        OLED_Write_Dat(Hzk[2 * no][t]);
        adder += 1;
    }
    OLED_Set_Pos(x, y + 1);
    for(t = 0; t < 16; t++)
    {
        OLED_Write_Dat(Hzk[2 * no + 1][t]);
        adder += 1;
    }
}
/**
 * @brief	在指定位置显示一幅图片
 * @param x1,x2  - 0 - 127
 * @param y1,y2  - 0 - 7(8表示全屏显示)
 * @param BMP - 图片数组地址
 * @note	图像数组BMP存放在bmp.h文件中
*/
void OLED_DrawBMP(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t BMP[])
{
    uint16_t j = 0;
    uint8_t x, y;

    if(y1 % 8 == 0)
    {
        y = y1 / 8;
    }
    else
    {
        y = y1 / 8 + 1;
    }
    for(y = y0; y < y1; y++)
    {
        OLED_Set_Pos(x0, y);
        for(x = x0; x < x1; x++)
        {
            OLED_Write_Dat(BMP[j++]);
        }
    }
}

/**
 * @brief	OLED初始化
*/
void OLED_Init(void)
{

    Delay_Ms(100);

    OLED_Write_Cmd(0xAE);//--display off
    OLED_Write_Cmd(0x00);//---set low column address
    OLED_Write_Cmd(0x10);//---set high column address
    OLED_Write_Cmd(0x40);//--set start line address
    OLED_Write_Cmd(0x81); // contract control
    OLED_Write_Cmd(0xFF);//--128
    OLED_Write_Cmd(0xA1);//set segment remap
    OLED_Write_Cmd(0xC8);//Com scan direction
    OLED_Write_Cmd(0xA6);//--normal / reverse
    OLED_Write_Cmd(0xA8);//--set multiplex ratio(1 to 64)
    OLED_Write_Cmd(0x3F);//--1/32 duty
    OLED_Write_Cmd(0xD3);//-set display offset
    OLED_Write_Cmd(0x00);//
    OLED_Write_Cmd(0xD5);//set osc division
    OLED_Write_Cmd(0x80);
    OLED_Write_Cmd(0xD9);//Set Pre-Charge Period
    OLED_Write_Cmd(0xF1);//
    OLED_Write_Cmd(0xDA);//set com pin configuartion
    OLED_Write_Cmd(0x12);//
    OLED_Write_Cmd(0xDB);//set Vcomh
    OLED_Write_Cmd(0x40);//
    OLED_Write_Cmd(0x20);
    OLED_Write_Cmd(0x02);
    OLED_Write_Cmd(0x8D);//set charge pump enable
    OLED_Write_Cmd(0x14);//
    OLED_Write_Cmd(0xA4);
    OLED_Write_Cmd(0xA6);
    OLED_Write_Cmd(0xAF);//--turn on oled panel

    OLED_Clear();
    OLED_Set_Pos(0, 0);
}

  • oled.h文件
#ifndef __OLED_H
#define __OLED_H

#include "debug.h"

#define OLED_ADDRESS  0x78 // oled模块从机地址
/* OLED控制用函数 */
void OLED_Set_Pos(uint8_t x, uint8_t y);
void OLED_Display_On(void);
void OLED_Display_Off(void);
void OLED_Clear(void);
void OLED_On(void);

/* OLED功能函数 */
void OLED_ShowChar(uint8_t x,uint8_t y,uint8_t chr,uint8_t size);
void OLED_ShowNum(uint8_t x,uint8_t y,uint32_t num,uint8_t len,uint8_t size);
void OLED_ShowString(uint8_t x,uint8_t y, char *chr,uint8_t size);	 
void OLED_ShowCHinese(uint8_t x,uint8_t y,uint8_t no);
void OLED_DrawBMP(uint8_t x0, uint8_t y0,uint8_t x1, uint8_t y1,uint8_t BMP[]);

/* OLED初始化 */
void OLED_Init(void);

#endif  

main主程序

/********************************** (C) COPYRIGHT *******************************
* File Name          : main.c
* Author             : WCH
* Version            : V1.0.0
* Date               : 2021/08/08
* Description        : Main program body.
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/

/*
 *@Note
 7-bit address mode, master/slave mode, transceiver routine:
 I2C1_SCL(PB8)\I2C1_SDA(PB9).
 This routine demonstrates that Master sends and Slave receives.
 Note:The two boards download the Master and Slave programs respectively,
       and power on at the same time.
     Hardware connection:
		           PB8--PB8
               PB9--PB9

*/

#include "debug.h"
#include 
#include "oled.h"
#include "bmp.h"


/*********************************************************************
 * @fn      IIC_Init
 *
 * @brief   Initializes the IIC peripheral.
 *
 * @return  none
 */
void IIC_Init(u32 bound, u16 address)
{
    GPIO_InitTypeDef GPIO_InitStructure = {0};
    I2C_InitTypeDef I2C_InitTSturcture = {0};

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
    GPIO_PinRemapConfig(GPIO_Remap_I2C1, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    I2C_InitTSturcture.I2C_ClockSpeed = bound;
    I2C_InitTSturcture.I2C_Mode = I2C_Mode_I2C;
    I2C_InitTSturcture.I2C_DutyCycle = I2C_DutyCycle_16_9;
    I2C_InitTSturcture.I2C_OwnAddress1 = address;
    I2C_InitTSturcture.I2C_Ack = I2C_Ack_Enable;
    I2C_InitTSturcture.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    I2C_Init(I2C1, &I2C_InitTSturcture);

    I2C_Cmd(I2C1, ENABLE);


    I2C_AcknowledgeConfig(I2C1, ENABLE);


}

/*********************************************************************
 * @fn      main
 *
 * @brief   Main program.
 *
 * @return  none
 */
int main(void)
{

    Delay_Init();
    USART_Printf_Init(115200);
    printf("SystemClk:%d\r\n", SystemCoreClock);
    IIC_Init(400000, 0x30);//400KHz,地址随便填写
    OLED_Init();
    printf("Init \r\n");
    while(1)
    {
        OLED_Clear();
        OLED_ShowChar(0, 0, 'A', 16);
        OLED_ShowChar(0, 2, 'B', 16);
        OLED_ShowChar(0, 4, 'C', 16);
        OLED_ShowChar(0, 6, 'D', 16);

        OLED_ShowChar(15, 0, 'A', 12);
        OLED_ShowChar(15, 1, 'B', 12);
        OLED_ShowChar(15, 2, 'C', 12);
        OLED_ShowChar(15, 3, 'D', 12);
        OLED_ShowChar(15, 4, 'E', 12);
        OLED_ShowChar(15, 5, 'F', 12);
        OLED_ShowChar(15, 6, 'G', 12);
        OLED_ShowChar(15, 7, 'H', 12);

        OLED_ShowString(30, 0, "Perseverance", 12);//x,y,字符串,字体大小

        OLED_ShowCHinese(35, 2, 0);//汉字显示
        OLED_ShowCHinese(65, 2, 1);
        OLED_ShowCHinese(95, 2, 2);

        OLED_ShowString(36, 6, "Hello World", 16);

        Delay_Ms(3000);
        OLED_DrawBMP(0, 0, 128, 8, BMP1);

        Delay_Ms(3000);

    }
}

程序源码

链接: https://pan.baidu.com/s/1Fbl9OCCL42NTcUqTt4nc5w
提取码: up2m

你可能感兴趣的:(WCH,-,CH32F203系列,CH32F203,ssd1306)