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

[复制链接]
1102|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 外设
  1. #include "stm32f10x.h"

  2. #define SSD1306_I2C_ADDRESS 0x3C  // SSD1306 I2C 地址

  3. // 配置I2C
  4. void I2C_Init_Config(void)
  5. {
  6.     // 启动 I2C 时钟
  7.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
  8.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

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

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

  23.     I2C_Init(I2C1, &I2C_InitStruct);
  24.     I2C_Cmd(I2C1, ENABLE);  // 启用 I2C1 外设
  25. }
配置 DMA
  1. void DMA_Init_Config(void)
  2. {
  3.     // 启动 DMA 时钟
  4.     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

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

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


 楼主| 捉虫天师 发表于 2025-2-25 15:00 | 显示全部楼层
初始化 SSD1306 OLED 显示器
你需要发送初始化命令序列到 SSD1306 显示器来配置它。SSD1306 初始化命令包括设置显示模式、对比度、屏幕反向显示等。
  1. void SSD1306_Init(void)
  2. {
  3.     uint8_t init_cmds[] = {
  4.         0xAE,  // Display off
  5.         0xD5, 0x80,  // Set display clock divide ratio/oscillator frequency
  6.         0xA8, 0x3F,  // Set multiplex ratio
  7.         0xD3, 0x00,  // Set display offset
  8.         0x40,  // Set display start line
  9.         0x8D, 0x14,  // Charge pump setting
  10.         0x20, 0x00,  // Set memory addressing mode
  11.         0xA0,  // Set segment remap
  12.         0xC0,  // Set COM output scan direction
  13.         0xDA, 0x12,  // Set COM pins hardware configuration
  14.         0x81, 0x7F,  // Set contrast control
  15.         0xA4,  // Entire display ON (Resume to RAM content display)
  16.         0xA6,  // Set normal display mode
  17.         0xD9, 0xF1,  // Set pre-charge period
  18.         0xDB, 0x40,  // Set VCOMH deselect level
  19.         0xAF   // Display ON
  20.     };
  21.    
  22.     for (uint8_t i = 0; i < sizeof(init_cmds); i++) {
  23.         I2C_Write(SSD1306_I2C_ADDRESS, init_cmds[i]);
  24.     }
  25. }


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

  2. void I2C_Write(uint8_t addr, uint8_t data)
  3. {
  4.     uint8_t buf[2] = {0x00, data};  // 0x00 表示控制字节
  5.     DMA_Init_Config();
  6.     // 配置 DMA 进行传输
  7.     DMA_Init(DMA1_Channel6, &DMA_InitStruct);  // 初始化 DMA1 通道6
  8.     DMA_Cmd(DMA1_Channel6, ENABLE);  // 启动 DMA
  9.     // 启动 I2C 传输
  10.     I2C_GenerateSTART(I2C1, ENABLE);
  11.     I2C_Send7bitAddress(I2C1, addr, I2C_Direction_Transmitter);
  12.     I2C_SendData(I2C1, buf[0]);
  13.     while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BTF) == RESET);
  14.     I2C_SendData(I2C1, buf[1]);
  15. }
 楼主| 捉虫天师 发表于 2025-2-25 15:00 | 显示全部楼层
将数据传输到 SSD1306
  1. void SSD1306_Display(uint8_t* data)
  2. {
  3.     for (int i = 0; i < 8; i++) {  // 控制行
  4.         I2C_Write(SSD1306_I2C_ADDRESS, 0xB0 + i);  // 设置页面地址(每个页面是 8 行)
  5.         I2C_Write(SSD1306_I2C_ADDRESS, 0x00);  // 设置低 4 位列地址
  6.         I2C_Write(SSD1306_I2C_ADDRESS, 0x10);  // 设置高 4 位列地址
  7.         // 启动 DMA 传输图像数据
  8.         for (int j = 0; j < 128; j++) {  // 设置每行的 128 列
  9.             I2C_TX_Buffer[j] = data[i * 128 + j];  // 填充数据缓冲区
  10.         }
  11.         DMA_Init_Config();
  12.         DMA_Cmd(DMA1_Channel6, ENABLE);  // 启动 DMA
  13.     }
  14. }


您需要登录后才可以回帖 登录 | 注册

本版积分规则

213

主题

3276

帖子

7

粉丝
快速回复 在线客服 返回列表 返回顶部