从零开始动手DIY一台桌面宠物狗(直播帖手动滑稽.jpg)——【二】

在这里插入图片描述

一、代码路径

上一篇末尾更新了代码路径
https://github.com/Kunlun-Donkey/desktop-dog-Bruce.git
可以使用git命令去下载到本地:

git clone https://github.com/Kunlun-Donkey/desktop-dog-Bruce.git

这一篇我们使用git down下来的代码去完成点灯操作,验证OK后添加驱动代码,添加软件i2c的驱动代码和oled的显示接口
IO引脚如下

#define SDA_Pin GPIO_PIN_4
#define SDA_GPIO_Port GPIOA
#define SCL_Pin GPIO_PIN_5
#define SCL_GPIO_Port GPIOA

二、下载后的代码编译通过后尝试电灯操作

使用PB0点了一个灯看起来是OK的,代码工程没啥问题

  while (1)
  {
    /* USER CODE END WHILE */

    /* Test GPIOB0 LED, Set hight level */
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
    /* USER CODE END 3 */
  }
  /* USER CODE END 3 */

在这里插入图片描述

三、添加OLED驱动代码

我们使用0.96寸四引脚OLED作为显示屏,用来显示表情或者图片等信息,0.96寸OLED使用1306作为驱动芯片,支持I2C驱动和OLED驱动,为了简单我们使用I2C驱动,HAL库里面有I2C的驱动库,可以快速开发OLED代码。新增代码如下。

// OLED.c
// Send command to OLED
static void OLED_Write_Command(uint8_t command) {
    Soft_I2C_Start();
    Soft_I2C_Write(OLED_I2C_ADDRESS);
    Soft_I2C_Write(0x00);
    Soft_I2C_Write(command);
    Soft_I2C_Stop();
}

// Send data to OLED
static void OLED_Write_Data(uint8_t data) {
    Soft_I2C_Start();
    Soft_I2C_Write(OLED_I2C_ADDRESS);
    Soft_I2C_Write(0x40);
    Soft_I2C_Write(data);
    Soft_I2C_Stop();
}

void OLED_Init(void) {
    Soft_I2C_Init();
    // Initialization sequence for SSD1306
    OLED_Write_Command(0xAE); // Display off
    OLED_Write_Command(0x20); // Set Memory Addressing Mode
    OLED_Write_Command(0x10); // 00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid
    OLED_Write_Command(0xB0); // Set Page Start Address for Page Addressing Mode,0-7
    OLED_Write_Command(0xC8); // Set COM Output Scan Direction
    OLED_Write_Command(0x00); // ---set low column address
    OLED_Write_Command(0x10); // ---set high column address
    OLED_Write_Command(0x40); // --set start line address
    OLED_Write_Command(0x81); // --set contrast control register
    OLED_Write_Command(0xFF);
    OLED_Write_Command(0xA1); // --set segment re-map 0 to 127
    OLED_Write_Command(0xA6); // --set normal display
    OLED_Write_Command(0xA8); // --set multiplex ratio(1 to 64)
    OLED_Write_Command(0x3F); //
    OLED_Write_Command(0xA4); // 0xa4,Output follows RAM content;0xa5,Output ignores RAM content
    OLED_Write_Command(0xD3); // -set display offset
    OLED_Write_Command(0x00); // -not offset
    OLED_Write_Command(0xD5); // --set display clock divide ratio/oscillator frequency
    OLED_Write_Command(0xF0); // --set divide ratio
    OLED_Write_Command(0xD9); // --set pre-charge period
    OLED_Write_Command(0x22); //
    OLED_Write_Command(0xDA); // --set com pins hardware configuration
    OLED_Write_Command(0x12);
    OLED_Write_Command(0xDB); // --set vcomh
    OLED_Write_Command(0x20); // 0x20,0.77xVcc
    OLED_Write_Command(0x8D); // --set DC-DC enable
    OLED_Write_Command(0x14); //
    OLED_Write_Command(0xAF); // --turn on oled panel
}

void OLED_Clear(void) {
    for (uint8_t i = 0; i < 8; i++) {
        OLED_Write_Command(0xB0 + i); // Set page address
        OLED_Write_Command(0x00); // Set low column address
        OLED_Write_Command(0x10); // Set high column address
        for (uint8_t j = 0; j < 128; j++) {
            OLED_Write_Data(0x00);
        }
    }
}

void OLED_Display_On(void) {
    OLED_Write_Command(0x8D); // Set DC-DC enable
    OLED_Write_Command(0x14); //
    OLED_Write_Command(0xAF); // Display ON
}

void OLED_Display_Off(void) {
    OLED_Write_Command(0x8D); // Set DC-DC disable
    OLED_Write_Command(0x10); //
    OLED_Write_Command(0xAE); // Display OFF
}

void OLED_Set_Pos(uint8_t x, uint8_t y) {
    OLED_Write_Command(0xB0 + y);
    OLED_Write_Command(((x & 0xF0) >> 4) | 0x10);
    OLED_Write_Command((x & 0x0F) | 0x01);
}

void OLED_ShowChar(uint8_t x, uint8_t y, char chr) {
    // Implement character display function
}

void OLED_ShowString(uint8_t x, uint8_t y, char *chr) {
    // Implement string display function
}

void OLED_ShowImage(uint8_t x, uint8_t y, const uint8_t *image, uint8_t width, uint8_t height) {
    for (uint8_t i = 0; i < height / 8; i++) {
        OLED_Set_Pos(x, y + i);
        for (uint8_t j = 0; j < width; j++) {
            OLED_Write_Data(image[i * width + j]);
        }
    }
}

void OLED_ShowGIF(const uint8_t **frames, uint8_t frame_count, uint8_t width, uint8_t height, uint16_t delay) {
    for (uint8_t i = 0; i < frame_count; i++) {
        OLED_ShowImage(0, 0, frames[i], width, height);
        HAL_Delay(delay);
    }
}

软件I2C代码

#include "soft_i2c.h"
#include "gpio.h"

#define SDA_HIGH() HAL_GPIO_WritePin(SDA_GPIO_Port, SDA_Pin, GPIO_PIN_SET)
#define SDA_LOW()  HAL_GPIO_WritePin(SDA_GPIO_Port, SDA_Pin, GPIO_PIN_RESET)
#define SCL_HIGH() HAL_GPIO_WritePin(SCL_GPIO_Port, SCL_Pin, GPIO_PIN_SET)
#define SCL_LOW()  HAL_GPIO_WritePin(SCL_GPIO_Port, SCL_Pin, GPIO_PIN_RESET)
#define SDA_READ() HAL_GPIO_ReadPin(SDA_GPIO_Port, SDA_Pin)

void Soft_I2C_Delay(void) {
    for (volatile int i = 0; i < 100; i++);
}

void Soft_I2C_Init(void) {
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    // Configure SDA and SCL pins as open-drain
    GPIO_InitStruct.Pin = SDA_Pin | SCL_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(SDA_GPIO_Port, &GPIO_InitStruct);

    SDA_HIGH();
    SCL_HIGH();
}

void Soft_I2C_Start(void) {
    SDA_HIGH();
    SCL_HIGH();
    Soft_I2C_Delay();
    SDA_LOW();
    Soft_I2C_Delay();
    SCL_LOW();
}

void Soft_I2C_Stop(void) {
    SDA_LOW();
    SCL_HIGH();
    Soft_I2C_Delay();
    SDA_HIGH();
    Soft_I2C_Delay();
}

void Soft_I2C_Write(uint8_t data) {
    for (int i = 0; i < 8; i++) {
        if (data & 0x80) {
            SDA_HIGH();
        } else {
            SDA_LOW();
        }
        data <<= 1;
        SCL_HIGH();
        Soft_I2C_Delay();
        SCL_LOW();
        Soft_I2C_Delay();
    }
    SDA_HIGH();
    SCL_HIGH();
    Soft_I2C_Delay();
    SCL_LOW();
}

uint8_t Soft_I2C_Read(uint8_t ack) {
    uint8_t data = 0;
    SDA_HIGH();
    for (int i = 0; i < 8; i++) {
        SCL_HIGH();
        Soft_I2C_Delay();
        data = (data << 1) | SDA_READ();
        SCL_LOW();
        Soft_I2C_Delay();
    }
    if (ack) {
        SDA_LOW();
    } else {
        SDA_HIGH();
    }
    SCL_HIGH();
    Soft_I2C_Delay();
    SCL_LOW();
    SDA_HIGH();
    return data;
}

有一点需要注意的,开启stm32f1xx_hal_conf.h中的使能HAL_I2C_MODULE_ENABLEd去使能的I2C是硬件I2C,我们建议还是使用软件I2C方便点,我的代码提交记录最新的是软件i2c,soft_i2c.c
在这里插入图片描述
在这里插入图片描述

<think>好的,用户想在STM32平台上生成小狗OLED表情,需要教程或代码示例。首先,我需要根据用户提供的引用内容来整理相关信息。引用中提到I2C是连接OLED的重要方式,特别是江协科技的教程里提到了OLED的初始化和显示字符串、数字的代码示例[^1][^2][^4]。另外,用户还提到了硬件I2C读写MPU6050的例子,这可能对处理I2C通信中的超时问题有帮助[^5]。 首先,用户需要确保OLED的硬件连接正确,使用I2C协议的话,需要接SCL和SDA引脚,并正确初始化。根据引用中的代码示例,主函数里调用了OLED_Init()来初始化屏幕,然后显示字符串和数字。显示图像的话,可能需要将小狗的图像转换为位图数组,然后使用OLED_DrawBMP函数显示。 接下来,生成小狗表情可能需要用到动画,这涉及到多帧图像的切换。用户需要在代码中设置一个计数器或者定时器,定期切换显示的图像帧,从而实现动画效果。引用中的Encoder_GetCount()函数可能用来获取编码器的计数值,但这里可能需要改用定时器中断来触发帧切换。 另外,需要注意I2C通信的稳定性。引用5提到的超时处理函数MPU6050_WaitEvent可以用来避免I2C操作时的死等,确保在通信失败时能够及时处理,防止程序卡死。这可能需要在OLED的驱动代码中加入类似的超时检测机制,提高可靠性。 总结步骤应该是:1.硬件连接;2.初始化OLEDI2C;3.小狗图像转换为位图数据;4.编写显示函数;5.实现动画循环。需要提醒用户检查OLED库是否支持位图显示,或者是否需要自行编写该功能。另外,提供示例代码的结构,比如主循环中如何切换帧,并引用相关的函数和初始化步骤。最后,可能需要注意内存限制,确保位图数据不超过STM32的Flash或RAM容量。</think>在STM32平台上实现OLED显示小狗表情需要结合I2C通信协议和图形显示技术,以下是具体实现步骤和代码示例: --- ### **一、硬件准备** 1. **OLED模块**:选择0.96寸I2C接口OLED(参考) 2. **STM32开发板**:如STM32F103C8T6 3. **接线示例**: - SCL -> PB6(I2C1时钟线) - SDA -> PB7(I2C1数据线) - VCC -> 3.3V - GND -> GND --- ### **、软件实现** #### 1. **OLED初始化** ```c #include "stm32f10x.h" #include "oled.h" int main() { OLED_Init(); // 初始化OLED OLED_Clear(); // 清屏 // ...后续代码 } ``` #### 2. **定义小狗表情位图** 使用取模工具(如PCtoLCD)将图片转换为16进制数组: ```c // 小狗静止帧(示例数据) const uint8_t dog_static[] = { 0x00,0x00,0x80,0xC0,0xE0,0xF0,0xF8,0xFC, 0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF // ...补充完整位图数据 }; // 小狗眨眼帧(动态效果) const uint8_t dog_blink[] = { // ...类似格式的位图数据 }; ``` #### 3. **显示控制逻辑** ```c void ShowDogAnimation() { uint8_t frame = 0; while(1) { if(frame % 10 == 0) { // 每10次循环切换动作 OLED_DrawBMP(0, 0, 16, 16, dog_blink); // 显示眨眼帧 } else { OLED_DrawBMP(0, 0, 16, 16, dog_static); // 默认静态帧 } OLED_Refresh(); // 刷新屏幕 Delay_ms(100); // 控制动画速度 frame++; } } ``` #### 4. **超时处理优化** ```c // 参考MPU6050的超时检测机制 void OLED_I2C_Write(uint8_t data) { // ...I2C发送逻辑 if(I2C_GetFlagStatus(I2C1, I2C_FLAG_AF) == SET) { I2C_ClearFlag(I2C1, I2C_FLAG_AF); // 应答失败处理 return; } } ``` --- ### **三、关键注意事项** 1. **内存优化**:建议将位图数据存储在Flash而非RAM(使用`const`修饰) 2. **刷新率控制**:动画间隔建议50-200ms以避免闪烁 3. **多帧动画**:可扩展为多帧数组实现复杂动作: ```c const uint8_t* dog_anim[] = {dog_frame1, dog_frame2, dog_frame3}; ``` --- ### **四、实验结果** 程序运行后OLED将循环显示小狗的静态表情和眨眼动画,通过调整帧数据和延迟时间可控制动画流畅度。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值