打印
[STM32F1]

使用STM32F103的DMA功能驱动I2C的SSD1306,分辨率为124*64

[复制链接]
60|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
捉虫天师|  楼主 | 2025-2-25 14:59 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
要使用 STM32F103 的 DMA 功能驱动 I2C 通信和控制 SSD1306 OLED 显示器(分辨率 128x64),可以通过以下几个步骤实现:

配置 I2C 外设,使其能够与 SSD1306 OLED 显示器进行通信。
使用 DMA 进行数据传输,将显示数据(例如图像或文本)从内存传输到 I2C 外设的缓冲区。
初始化 SSD1306 并配置 I2C DMA,以通过 I2C 协议将显示数据传输到 OLED 屏幕。
步骤 1: 配置 STM32F103 的 I2C 外设
首先,您需要启用 STM32F103 的 I2C 外设,并配置 DMA 来支持 I2C 数据传输。

配置 I2C 外设
#include "stm32f10x.h"

#define SSD1306_I2C_ADDRESS 0x3C  // SSD1306 I2C 地址

// 配置I2C
void I2C_Init_Config(void)
{
    // 启动 I2C 时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

    // 配置 I2C1 引脚(假设使用 PB6 (SCL) 和 PB7 (SDA))
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;  // I2C SCL, SDA
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD;  // 开漏输出
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStruct);

    // 配置 I2C1 外设
    I2C_InitTypeDef I2C_InitStruct;
    I2C_InitStruct.I2C_ClockSpeed = 100000;  // I2C 时钟频率 100kHz
    I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;  // I2C 工作模式
    I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2;  // 标准模式 50% 占空比
    I2C_InitStruct.I2C_OwnAddress1 = 0x00;  // 自己的地址
    I2C_InitStruct.I2C_Ack = I2C_Ack_Enable;  // 启用应答
    I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;  // 7 位地址模式

    I2C_Init(I2C1, &I2C_InitStruct);
    I2C_Cmd(I2C1, ENABLE);  // 启用 I2C1 外设
}
配置 DMA
void DMA_Init_Config(void)
{
    // 启动 DMA 时钟
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

    // 配置 DMA1 通道6(I2C1 数据传输)
    DMA_InitTypeDef DMA_InitStruct;
    DMA_StructInit(&DMA_InitStruct);
    DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&I2C1->DR;  // 外设地址(I2C 数据寄存器)
    DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)I2C_TX_Buffer;   // 内存地址
    DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralDST;  // 外设数据传输方向
    DMA_InitStruct.DMA_BufferSize = sizeof(I2C_TX_Buffer);  // 数据大小
    DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  // 外设地址不递增
    DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;  // 内存地址递增
    DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;  // 外设数据大小 8 位
    DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;  // 内存数据大小 8 位
    DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;  // 单次传输模式
    DMA_InitStruct.DMA_Priority = DMA_Priority_High;  // 高优先级
    DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;  // 非内存到内存传输

    DMA_Init(DMA1_Channel6, &DMA_InitStruct);  // 初始化 DMA1 通道6
    DMA_Cmd(DMA1_Channel6, ENABLE);  // 启动 DMA
}


使用特权

评论回复
沙发
捉虫天师|  楼主 | 2025-2-25 15:00 | 只看该作者
初始化 SSD1306 OLED 显示器
你需要发送初始化命令序列到 SSD1306 显示器来配置它。SSD1306 初始化命令包括设置显示模式、对比度、屏幕反向显示等。
void SSD1306_Init(void)
{
    uint8_t init_cmds[] = {
        0xAE,  // Display off
        0xD5, 0x80,  // Set display clock divide ratio/oscillator frequency
        0xA8, 0x3F,  // Set multiplex ratio
        0xD3, 0x00,  // Set display offset
        0x40,  // Set display start line
        0x8D, 0x14,  // Charge pump setting
        0x20, 0x00,  // Set memory addressing mode
        0xA0,  // Set segment remap
        0xC0,  // Set COM output scan direction
        0xDA, 0x12,  // Set COM pins hardware configuration
        0x81, 0x7F,  // Set contrast control
        0xA4,  // Entire display ON (Resume to RAM content display)
        0xA6,  // Set normal display mode
        0xD9, 0xF1,  // Set pre-charge period
        0xDB, 0x40,  // Set VCOMH deselect level
        0xAF   // Display ON
    };
   
    for (uint8_t i = 0; i < sizeof(init_cmds); i++) {
        I2C_Write(SSD1306_I2C_ADDRESS, init_cmds[i]);
    }
}


配置 I2C DMA 传输
为了使用 DMA 传输数据到 SSD1306 显示器,您需要通过 I2C 使用 DMA 模式。以下是一个使用 I2C 和 DMA 传输显示数据的基本框架。
uint8_t I2C_TX_Buffer[128];  // 用于传输的数据缓冲区

void I2C_Write(uint8_t addr, uint8_t data)
{
    uint8_t buf[2] = {0x00, data};  // 0x00 表示控制字节
    DMA_Init_Config();
    // 配置 DMA 进行传输
    DMA_Init(DMA1_Channel6, &DMA_InitStruct);  // 初始化 DMA1 通道6
    DMA_Cmd(DMA1_Channel6, ENABLE);  // 启动 DMA
    // 启动 I2C 传输
    I2C_GenerateSTART(I2C1, ENABLE);
    I2C_Send7bitAddress(I2C1, addr, I2C_Direction_Transmitter);
    I2C_SendData(I2C1, buf[0]);
    while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BTF) == RESET);
    I2C_SendData(I2C1, buf[1]);
}

使用特权

评论回复
板凳
捉虫天师|  楼主 | 2025-2-25 15:00 | 只看该作者
将数据传输到 SSD1306
void SSD1306_Display(uint8_t* data)
{
    for (int i = 0; i < 8; i++) {  // 控制行
        I2C_Write(SSD1306_I2C_ADDRESS, 0xB0 + i);  // 设置页面地址(每个页面是 8 行)
        I2C_Write(SSD1306_I2C_ADDRESS, 0x00);  // 设置低 4 位列地址
        I2C_Write(SSD1306_I2C_ADDRESS, 0x10);  // 设置高 4 位列地址
        // 启动 DMA 传输图像数据
        for (int j = 0; j < 128; j++) {  // 设置每行的 128 列
            I2C_TX_Buffer[j] = data[i * 128 + j];  // 填充数据缓冲区
        }
        DMA_Init_Config();
        DMA_Cmd(DMA1_Channel6, ENABLE);  // 启动 DMA
    }
}


使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

208

主题

3202

帖子

7

粉丝