STM32 + RTThread + UGUI

这篇具有很好参考价值的文章主要介绍了STM32 + RTThread + UGUI。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、概述

  • 开发板:STM32F103C8T6
  • 显示器:ST7735S
  • RT-Thread:5.0.0

玩过 GUI 的小伙伴都知道,界面的显示是一个个像素点组合起来的,那么直接构建出来炫酷的 GUI 还是相对比较困难的,所以我们一般都会使用一些 GUI 库来实现,比如 LVGL、QT、UGUI等,这样对于驱动开发的人员来说就相对比较简单了,

图形库应用的核心思想只需要提供一帧的缓冲区,我们只需要不断的将缓冲区的数据写入到 LCD 中即可,而缓冲区的内容由图形库实现,需要注意的是这个缓冲的创建方式,有的图形库会自己创建缓冲区,我们只需要负责刷新 LCD 的显示即可,而有的图形库是由驱动提供缓冲区,图形库负责写入。

二、RT-Thread 移植

移植 RT-Thread 不是此文章的重点,可以参考一下我之前的笔记,或者直接使用 RT-Thread Studio、STM32CubeMX等工具直接生成,这里我就不过多介绍了

三、LCD 驱动

使用过 RT-Thread 的小伙伴,都知道 RT-Thread 目前还不能直接使用工具生成我们想要的 LCD 驱动,所以这里我们只能根据标准的驱动进行编写了

  1. 驱动函数结构体

    /* 驱动函数实现的结构体 */
    #ifdef RT_USING_DEVICE_OPS
    const static struct rt_device_ops lcd_ops =
    {
        drv_lcd_init,
        RT_NULL,
        RT_NULL,
        RT_NULL,
        RT_NULL,
        drv_lcd_control
    };
    #endif
    
  2. 注册 LCD 设备

    int drv_lcd_hw_init(void)
    {
        rt_err_t result = RT_EOK;
        rt_uint32_t lcd_buff_size = lcd_buff_size = LCD_HEIGHT * LCD_WIDTH * 2;
        
        /* 创建LCD设备对象 */
        struct rt_device *device = &_lcd.lcd_dev;
        memset(&_lcd, 0x00, sizeof(_lcd));
    
        LOG_D("drv_lcd_hw_init!\n");
        
        /* 初始化lcd_lock信号量 */
        result = rt_sem_init(&_lcd.lcd_lock, "lcd_lock", 0, RT_IPC_FLAG_FIFO);
        if (result != RT_EOK)
        {
            LOG_E("init semaphore failed!\n");
            result = -RT_ENOMEM;
            goto __exit;
        }
        
        /* 设置 LCD 设备信息 */
        _lcd.lcd_info.height = LCD_HEIGHT;
        _lcd.lcd_info.width = LCD_WIDTH;
        _lcd.lcd_info.bits_per_pixel = LCD_BITS_PER_PIXEL;
        _lcd.lcd_info.pixel_format = RTGRAPHIC_PIXEL_FORMAT_RGB565;     // 图像的格式(RGB:565)
        
        /* LCD 显示缓冲区,大小为显示一帧图像所需空间 */
        _lcd.lcd_info.smem_len = lcd_buff_size;
        _lcd.lcd_info.framebuffer = rt_malloc(lcd_buff_size);
        if (_lcd.lcd_info.framebuffer == RT_NULL)
        {
            LOG_E("init frame buffer failed!\n");
            result = -RT_ENOMEM;
            goto __exit;
        }
        /* 将缓冲区初始化为 0xFF */
        memset(_lcd.lcd_info.framebuffer, 0xFF, lcd_buff_size);
    
    #ifdef RT_USING_DEVICE_OPS
        device->ops     = &lcd_ops;
    #else
        device->init    = drv_lcd_init;
        device->control = drv_lcd_control;
    #endif
    
        /* 注册 LCD 设备 */
        rt_device_register(device, "lcd", RT_DEVICE_FLAG_RDWR);
        
    __exit:
        if (result != RT_EOK)
        {
            rt_sem_detach(&_lcd.lcd_lock);
    
            if (_lcd.lcd_info.framebuffer)
            {
                rt_free(_lcd.lcd_info.framebuffer);
            }
        }
        return result;
        
    }
    
  3. LCD 控制函数的实现

    static rt_err_t drv_lcd_control(struct rt_device *device, int cmd, void *args)
    {
        // struct drv_lcd_device *lcd = LCD_DEVICE(device);
        LOG_D("drv_lcd_control cmd is: %d\n", cmd);
        switch (cmd)
        {
            case RTGRAPHIC_CTRL_RECT_UPDATE:
            {
                rt_sem_take(&_lcd.lcd_lock, RT_TICK_PER_SECOND / 20);
                /* 刷新缓冲区 */
    
                rt_sem_release(&_lcd.lcd_lock);
            }
            break;
            
            case RTGRAPHIC_CTRL_POWERON:
            {
                /* LCD 退出睡眠模式 */
            }
            break;
            
            case RTGRAPHIC_CTRL_POWEROFF:
            {
                /* LCD 进入睡眠模式 */
            }
            break;
            
            case RTGRAPHIC_CTRL_GET_INFO:
            {
                /* 获取 LCD 参数 */
                memcpy(args, &_lcd.lcd_info, sizeof(_lcd.lcd_info));
            }
            break;
        
            default:
                return -RT_EINVAL;
        }
    
        return RT_EOK;
    }
    
    
  4. LCD 驱动功能实现
    剩下的就比较简单了,只需要参考 LCD 提供的案例程序进行更改就好了,主要有实现如下

    • drv_lcd_init: 完成 LCD 的复位、初始化、首次清屏工作
    • drv_lcd_control: 完成 LCD 显示区域的刷新、屏幕参数的返回、亮屏和息屏等工作
      注意:具体实现参考后面的程序源码,相对比较简单,这里就不过多介绍了

四、UGUI 介绍

  1. 介绍
    µGUI 是一个用于嵌入式系统的免费开源图形库。 它独立于平台,可以轻松移植到几乎任何微控制器系统。 只要显示器能够显示图形,μGUI 就不受某种显示技术的限制。 因此,支持LCD、TFT、E-Paper、LED或OLED等显示技术。 整个模块由两个文件组成:ugui.c 和 ugui.h。
    注意:这里的介绍我直接引用了作者的描述

  2. 获取 UGUI
    github:https://github.com/xidongxu/ugui

  3. 文件目录
    STM32 + RTThread + UGUI

  4. 使用介绍

    • 移植: 我们主要实现 ugui_port.c,这里下载时已经提供了案例,所以我只需要在其中进行简单的修改
    • 使用: 使用相对比较简单,直接参考 “µGUI v0.3.pdf” 文档即可,直接没有难度

五、UGUI 移植

  1. 初始化
    直接在 ugui_port.c 文件中使用 INIT_COMPONENT_EXPORT(ugui_port_init) 进行自动初始化,如下图所示:
    STM32 + RTThread + UGUI

  2. lcd_open 函数
    这里不要做任何更改,从函数中可以看出 LCD 相关的参数获取,如下图所示:
    STM32 + RTThread + UGUI

  3. lcd_draw_pixel 函数
    主要功能是在缓冲区中写入一个像素点的颜色,如下图所示:
    STM32 + RTThread + UGUI

  4. ugui_port_thread_entry 函数
    这是线程的入口函数,主要目的是定期将缓冲区的数据写入到 LCD 中,下图所示:
    STM32 + RTThread + UGUI

注意:从以上步奏可以看出,移植 UGUI 时不需要更改任何参数,只需要在初始化时调用 ugui_port_init 函数即可。文章来源地址https://www.toymoban.com/news/detail-428102.html

六、程序源码

drv_lcd_st7735s.h

/**
 * @file drv_lcd_st7735s.h
 *
 */

#ifndef __DRV_LCD_ST7735S_H__
#define __DRV_LCD_ST7735S_H__

#include <rtthread.h>


#define LCD_HEIGHT                      20      // LCD 高像素
#define LCD_WIDTH                       128      // LCD 宽像素
#define LCD_BITS_PER_PIXEL              16      // 像素点的数据宽度

#define LCD_CS_PIN_TYPE                 GPIOA               // CS 引脚所在的组
#define LCD_CS_PIN                      GPIO_PIN_4          // 引脚编号
#define LCD_BCK_PIN                     GET_PIN(B, 1)       // 背光引脚
#define LCD_DC_PIN                      GET_PIN(B, 8)       // 数据引脚
#define LCD_RES_PIN                     GET_PIN(B, 9)       // 复位引脚

#define WHITE            0xFFFF
#define BLACK            0x0000
#define BLUE             0x001F
#define BRED             0XF81F
#define GRED             0XFFE0
#define GBLUE            0X07FF
#define RED              0xF800
#define MAGENTA          0xF81F
#define GREEN            0x07E0
#define CYAN             0x7FFF
#define YELLOW           0xFFE0
#define BROWN            0XBC40
#define BRRED            0XFC07
#define GRAY             0X8430
#define GRAY175          0XAD75
#define GRAY151          0X94B2
#define GRAY187          0XBDD7
#define GRAY240          0XF79E


#endif  /* __DRV_LCD_ST7735S_H__ */


drv_lcd_st7735s.c

/***************************************************************
文件名 : drv_lcd_st7735s.c
作者 : jiaozhu
版本 : V1.0
描述 : st7735s 显示驱动
其他 : 无
日志 : 初版 V1.0 2023/04/28
***************************************************************/

#include <board.h>
#include <rtthread.h>

#ifdef BSP_USING_LCD
#include "drv_spi.h"
#include <string.h>
#include "drv_lcd_st7735s.h"

//#define DRV_DEBUG
#define LOG_TAG             "drv.lcd"
#include <drv_log.h>



static struct rt_spi_device *spi_dev_lcd;

struct drv_lcd_device
{
    struct rt_device lcd_dev;

    struct rt_device_graphic_info lcd_info;

    struct rt_semaphore lcd_lock;
};

struct drv_lcd_device _lcd;

/**
 * @brief  LCD 命令写入,写入时数据引脚为低电平
 *
 * @param  cmd 命令
 * @retval 返回执行结果
 */
static rt_err_t lcd_write_cmd(const rt_uint8_t cmd)
{
    rt_size_t len;

    rt_pin_write(LCD_DC_PIN, PIN_LOW);

    len = rt_spi_send(spi_dev_lcd, &cmd, 1);

    if (len != 1)
    {
        LOG_I("lcd_write_cmd error. %d", len);
        return -RT_ERROR;
    }
    else
    {
        return RT_EOK;
    }
}

/**
 * @brief  LCD 数据写入,写入时数据引脚为高电平
 *
 * @param  cmd 命令
 * @retval 返回执行结果
 */
static rt_err_t lcd_write_data(const rt_uint8_t data)
{
    rt_size_t len;

    rt_pin_write(LCD_DC_PIN, PIN_HIGH);

    len = rt_spi_send(spi_dev_lcd, &data, 1);

    if (len != 1)
    {
        LOG_I("lcd_write_data error. %d", len);
        return -RT_ERROR;
    }
    else
    {
        return RT_EOK;
    }
}

/**
 * @brief  LCD 板级初始化
 *
 * @param  None
 * @retval int 初始化结果
 */
static int lcd_dev_init(void)
{
	
    lcd_write_cmd(0x11); //Sleep out
	rt_thread_delay(12); //Delay 12ms
	//------------------------------------ST7735S Frame Rate-----------------------------------------//
	lcd_write_cmd(0xB1);
	lcd_write_data(0x05);
	lcd_write_data(0x3C);
	lcd_write_data(0x3C);
	lcd_write_cmd(0xB2);
	lcd_write_data(0x05);
	lcd_write_data(0x3C);
	lcd_write_data(0x3C);
	lcd_write_cmd(0xB3);
	lcd_write_data(0x05);
	lcd_write_data(0x3C);
	lcd_write_data(0x3C);
	lcd_write_data(0x05);
	lcd_write_data(0x3C);
	lcd_write_data(0x3C);
	//------------------------------------End ST7735S Frame Rate-----------------------------------------//
	lcd_write_cmd(0xB4); //Dot inversion
	lcd_write_data(0x03);
	lcd_write_cmd(0xC0);
	lcd_write_data(0x28);
	lcd_write_data(0x08);
	lcd_write_data(0x04);
	lcd_write_cmd(0xC1);
	lcd_write_data(0XC0);
	lcd_write_cmd(0xC2);
	lcd_write_data(0x0D);
	lcd_write_data(0x00);
	lcd_write_cmd(0xC3);
	lcd_write_data(0x8D);
	lcd_write_data(0x2A);
	lcd_write_cmd(0xC4);
	lcd_write_data(0x8D);
	lcd_write_data(0xEE);
	//---------------------------------End ST7735S Power Sequence-------------------------------------//
	lcd_write_cmd(0xC5); //VCOM
	lcd_write_data(0x1A);
	lcd_write_cmd(0x36); //MX, MY, RGB mode
	lcd_write_data(0xC0);
	//------------------------------------ST7735S Gamma Sequence-----------------------------------------//
	lcd_write_cmd(0xE0);
	lcd_write_data(0x04);
	lcd_write_data(0x22);
	lcd_write_data(0x07);
	lcd_write_data(0x0A);
	lcd_write_data(0x2E);
	lcd_write_data(0x30);
	lcd_write_data(0x25);
	lcd_write_data(0x2A);
	lcd_write_data(0x28);
	lcd_write_data(0x26);
	lcd_write_data(0x2E);
	lcd_write_data(0x3A);
	lcd_write_data(0x00);
	lcd_write_data(0x01);
	lcd_write_data(0x03);
	lcd_write_data(0x13);
	lcd_write_cmd(0xE1);
	lcd_write_data(0x04);
	lcd_write_data(0x16);
	lcd_write_data(0x06);
	lcd_write_data(0x0D);
	lcd_write_data(0x2D);
	lcd_write_data(0x26);
	lcd_write_data(0x23);
	lcd_write_data(0x27);
	lcd_write_data(0x27);
	lcd_write_data(0x25);
	lcd_write_data(0x2D);
	lcd_write_data(0x3B);
	lcd_write_data(0x00);
	lcd_write_data(0x01);
	lcd_write_data(0x04);
	lcd_write_data(0x13);
	//------------------------------------End ST7735S Gamma Sequence-----------------------------------------//
	lcd_write_cmd(0x3A); //65k mode
	lcd_write_data(0x05);
	lcd_write_cmd(0x29); //Display on

    return RT_EOK;
}

/**
 * @brief  初始化 LCD 所需的引脚,并通过引脚复位 LCD
 *
 * @param  None
 * @retval None
 */
static void lcd_gpio_init(void)
{
    /* 配置引脚模式 */
    rt_pin_mode(LCD_DC_PIN, PIN_MODE_OUTPUT);
    rt_pin_mode(LCD_RES_PIN, PIN_MODE_OUTPUT);
    rt_pin_mode(LCD_BCK_PIN, PIN_MODE_OUTPUT);
	
	/* 通过引脚复位 LCD */
	rt_pin_write(LCD_BCK_PIN, PIN_LOW);
    rt_pin_write(LCD_RES_PIN, PIN_LOW);
    rt_thread_mdelay(12);
    rt_pin_write(LCD_RES_PIN, PIN_HIGH);
   
    /* 复位后延时一段时间,确保屏幕正常工作 */
    rt_thread_mdelay(12);
}

/**
 * @brief  初始化 LCD 所需的 SPI 外设
 *
 * @param  None
 * @retval int 操作结果
 */
static int lcd_spi_init(void)
{
    /* 配置 SPI 端口,并指定 CS 引脚为 PA4 */
    __HAL_RCC_GPIOA_CLK_ENABLE();
    rt_hw_spi_device_attach("spi1", "spi10", LCD_CS_PIN_TYPE, LCD_CS_PIN);
    
    /* 查找设备 */
    spi_dev_lcd = (struct rt_spi_device *)rt_device_find("spi10");
    if(RT_NULL == spi_dev_lcd)
    {
        LOG_E("Unable to find SPI device required for LCD");
        return RT_ERROR;
    }

    /* 配置 SPI */
    struct rt_spi_configuration cfg;
    cfg.data_width = 8;
    cfg.mode = RT_SPI_MASTER | RT_SPI_MODE_0 | RT_SPI_MSB;
    cfg.max_hz = 42 * 1000 * 1000; /* 42M,SPI max 42MHz,lcd 4-wire spi */
    spi_dev_lcd->bus ->owner = spi_dev_lcd;
    rt_spi_configure(spi_dev_lcd, &cfg);

    return RT_EOK;
}

 
 /**
 * @brief  设置需要绘图的区域
 *
 * @param   x1      start of x position
 * @param   y1      start of y position
 * @param   x2      end of x position
 * @param   y2      end of y position
 * @retval None
 */
static void lcd_draw_area_set(rt_uint16_t x1, rt_uint16_t y1, rt_uint16_t x2, rt_uint16_t y2)
{
    lcd_write_cmd(0x2a);
    lcd_write_data(x1 >> 8);
    lcd_write_data(x1);
    lcd_write_data(x2 >> 8);
    lcd_write_data(x2);

    lcd_write_cmd(0x2b);
    lcd_write_data(y1 >> 8);
    lcd_write_data(y1);
    lcd_write_data(y2 >> 8);
    lcd_write_data(y2);

    lcd_write_cmd(0x2C);
}

/**
 * @brief  LCD 清屏,将整个屏幕设定为指定颜色
 *
 * @param  color 清空的颜色
 * @retval None
 */
static void lcd_clear_screen(rt_uint16_t color)
{
    rt_uint16_t i, j;    
    rt_uint8_t data[2] = {0};

    data[0] = (color >> 8) & 0xFF;
    data[1] = color & 0xFF;
    
    /* 设置整个屏幕区域 */
    lcd_draw_area_set(0, 0, LCD_WIDTH - 1, LCD_HEIGHT - 1);
    
    /* 这里直接通过 SPI 发送数据,所以需要单独将数据引脚拉高 */
    rt_pin_write(LCD_DC_PIN, PIN_HIGH);
    
    if (_lcd.lcd_info.framebuffer != RT_NULL)
    {
        /* 重置缓冲区 */
        // memset(_lcd.lcd_info.framebuffer, color, _lcd.lcd_info.smem_len);
        
        for (j = 0; j < _lcd.lcd_info.smem_len / 2; j++)
        {
            _lcd.lcd_info.framebuffer[j * 2] =  data[0] ;
            _lcd.lcd_info.framebuffer[j * 2 + 1] = data[1];
        }
        
        rt_spi_send(spi_dev_lcd, _lcd.lcd_info.framebuffer, _lcd.lcd_info.smem_len);
    }
    else
    {
        for (i = 0; i < LCD_HEIGHT; i++)
        {
            for (j = 0; j < LCD_WIDTH; j++)
            {
                rt_spi_send(spi_dev_lcd, data, 2);
            }
        }
    }
}

/**
 * @brief  点亮 LED 屏幕
 * @param  None
 * @retval None
 */
static void lcd_display_on(void)
{
    rt_pin_write(LCD_BCK_PIN, PIN_HIGH);
}

/**
 * @brief  熄灭 LED 屏幕
 * @param  None
 * @retval None
 */
static void lcd_display_off(void)
{
    rt_pin_write(LCD_BCK_PIN, PIN_LOW);
}

/**
 * @brief  液晶显示器进入最小功耗模式,背光关闭
 * @param  None
 * @retval None
 */
static void lcd_enter_sleep(void)
{
    rt_pin_write(LCD_BCK_PIN, PIN_LOW);
    rt_thread_mdelay(5);
    lcd_write_cmd(0x10);
}

/**
 * @brief  液晶显示器关闭睡眠模式,背光灯打开
 * @param  None
 * @retval None
 */
static void lcd_exit_sleep(void)
{
    rt_pin_write(LCD_BCK_PIN, PIN_HIGH);
    rt_thread_mdelay(5);
    lcd_write_cmd(0x11);
    rt_thread_mdelay(120);
}

/**
 * @brief  设置光标位置
 * @param  Xpos 横坐标
 * @param  Ypos 纵坐标
 * @retval None
 */
// static void lcd_cursor_set(rt_uint16_t Xpos, rt_uint16_t Ypos)
// {
//     lcd_write_cmd(0x2A); 
// 	lcd_write_data(Xpos>>8); 
// 	lcd_write_data(Xpos&0XFF);	 
// 	lcd_write_cmd(0x2B); 
// 	lcd_write_data(Ypos>>8); 
// 	lcd_write_data(Ypos&0XFF);
// }


/**
 * @brief  LCD 驱动初始化
 * @param  device LCD 设备结构体
 * @retval None
 */
static rt_err_t drv_lcd_init(struct rt_device *device)
{
    LOG_D("drv_lcd_init!\n");
    
    if (lcd_spi_init() != RT_EOK)
    {
        return -RT_EINVAL;
    }
    
    lcd_gpio_init();
    
    if (lcd_dev_init() != RT_EOK)
    {
        return -RT_EINVAL;
    }
    
    /* 清屏 */
    lcd_clear_screen(WHITE);
    
    /* 初始化完成后,点亮屏幕 */
    rt_pin_write(LCD_BCK_PIN, PIN_HIGH);
    
    return RT_EOK;
}

/**
 * @brief  LCD 驱动的操作函数
 * @param  device LCD 设备结构体
 * @param  cmd 操作命令
 * @param  args 传入的参数
 * @retval None
 */
static rt_err_t drv_lcd_control(struct rt_device *device, int cmd, void *args)
{
    // struct drv_lcd_device *lcd = LCD_DEVICE(device);
    LOG_D("drv_lcd_control cmd is: %d\n", cmd);
    switch (cmd)
    {
        case RTGRAPHIC_CTRL_RECT_UPDATE:
        {
            rt_sem_take(&_lcd.lcd_lock, RT_TICK_PER_SECOND / 20);
            /* 刷新缓冲区 */
            if (_lcd.lcd_info.framebuffer)
            {
                /* 设置整个屏幕区域 */
                lcd_draw_area_set(0, 0, LCD_WIDTH - 1, LCD_HEIGHT - 1);
                /* 这里直接通过 SPI 发送数据,所以需要单独将数据引脚拉高 */
                rt_pin_write(LCD_DC_PIN, PIN_HIGH);
                rt_spi_send(spi_dev_lcd, _lcd.lcd_info.framebuffer, _lcd.lcd_info.smem_len);
            }
            
            /* 释放锁信号 */
            rt_sem_release(&_lcd.lcd_lock);
        }
        break;
        
        case RTGRAPHIC_CTRL_POWERON:
        {
            /* LCD 退出睡眠模式 */
            lcd_display_on();
            lcd_exit_sleep();
        }
        break;
        
        case RTGRAPHIC_CTRL_POWEROFF:
        {
            /* LCD 进入睡眠模式 */
            lcd_display_off();
            lcd_enter_sleep();
        }
        break;
        
        case RTGRAPHIC_CTRL_GET_INFO:
        {
            /* 获取 LCD 参数 */
            memcpy(args, &_lcd.lcd_info, sizeof(_lcd.lcd_info));
        }
        break;
        
    
        default:
            return -RT_EINVAL;
    }

    return RT_EOK;
}




/* 驱动函数实现的结构体 */
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops lcd_ops =
{
    drv_lcd_init,
    RT_NULL,
    RT_NULL,
    RT_NULL,
    RT_NULL,
    drv_lcd_control
};
#endif

/**
 * @brief  LCD 设备注册
 *
 * @param  None
 * @retval int 注册结果
 */
int drv_lcd_hw_init(void)
{
    rt_err_t result = RT_EOK;
    rt_uint32_t lcd_buff_size = lcd_buff_size = LCD_HEIGHT * LCD_WIDTH * 2;
    
    /* 创建LCD设备对象 */
    struct rt_device *device = &_lcd.lcd_dev;
    memset(&_lcd, 0x00, sizeof(_lcd));

    LOG_D("drv_lcd_hw_init!\n");
    
    /* 初始化lcd_lock信号量 */
    result = rt_sem_init(&_lcd.lcd_lock, "lcd_lock", 0, RT_IPC_FLAG_FIFO);
    if (result != RT_EOK)
    {
        LOG_E("init semaphore failed!\n");
        result = -RT_ENOMEM;
        goto __exit;
    }
    
    /* 设置 LCD 设备信息 */
    _lcd.lcd_info.height = LCD_HEIGHT;
    _lcd.lcd_info.width = LCD_WIDTH;
    _lcd.lcd_info.bits_per_pixel = LCD_BITS_PER_PIXEL;
    _lcd.lcd_info.pixel_format = RTGRAPHIC_PIXEL_FORMAT_RGB565;     // 图像的格式(RGB:565)
    
    /* LCD 显示缓冲区,大小为显示一帧图像所需空间 */
    _lcd.lcd_info.smem_len = lcd_buff_size;
    _lcd.lcd_info.framebuffer = rt_malloc(lcd_buff_size);
    if (_lcd.lcd_info.framebuffer == RT_NULL)
    {
        LOG_E("init frame buffer failed!\n");
        result = -RT_ENOMEM;
        goto __exit;
    }
    /* 将缓冲区初始化为 0xFF */
    memset(_lcd.lcd_info.framebuffer, 0xFF, lcd_buff_size);

#ifdef RT_USING_DEVICE_OPS
    device->ops     = &lcd_ops;
#else
    device->init    = drv_lcd_init;
    device->control = drv_lcd_control;
#endif

    /* 注册 LCD 设备 */
    rt_device_register(device, "lcd", RT_DEVICE_FLAG_RDWR);
    
__exit:
    if (result != RT_EOK)
    {
        rt_sem_detach(&_lcd.lcd_lock);

        if (_lcd.lcd_info.framebuffer)
        {
            rt_free(_lcd.lcd_info.framebuffer);
        }
    }
    return result;
    
}
INIT_DEVICE_EXPORT(drv_lcd_hw_init);

#endif /* BSP_USING_LCD */



到了这里,关于STM32 + RTThread + UGUI的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • [附源码] STM32F103C8T6+外接MCP4725 外部DAC

            STM32F103C8T6最小系统板是大家很常用的一款单片机,它内部有多个ADC模数转换通道,但并 没有DAC数模转换功能 ,当需要进行数字量转换为模拟量时就需要借助外部DAC。             MCP4725是具有非易失性存储器的单通道12位缓冲电压输出DAC。用户可将配置寄存器

    2024年02月04日
    浏览(50)
  • JQ8400语音模块-stm32f103c8t6(内含全代码)-亲测有效

    一.模块介绍 1.常见的JQ8400-FL语音模块有两种,一种是带3W功放,有4M的存储空间,可通过USB拷贝声音文件,通过单片机串口控制;另外一种是附有SD卡槽,用SD卡存储文件的文件(MP3格式)进行语音播报,也是通过单片机串口控制 2.我用的是二线串口通信,一线的没试过 3.程序

    2023年04月26日
    浏览(47)
  • MQ2烟雾传感器 - STM32F103C8T6-HAL库

    ADC.c 文件 ADC.h文件 main函数中的调用

    2024年04月26日
    浏览(43)
  • STM32F103C8T6+ESP8266WIFI+DHT11模块连接巴法云

    1.MCU:STM32F103C8T6 2.ESP8266:正点原子WIFI模块 3.串口模块:正点原子串口模块 我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客: ESP8266固件刷写 我用的是安信可的固件,可以在官网上下载。正点

    2023年04月27日
    浏览(70)
  • 【沧海拾昧】STM32F103C8T6/C6T6的ISP烧录

    #C0105 沧海茫茫千钟粟,且拾吾昧一微尘 ——《沧海拾昧集》@CuPhoenix 【阅前敬告】 沧海拾昧集仅做个人学习笔记之用,所述内容不专业不严谨不成体系 【如有问题必是本集记录有谬,切勿深究】   对于某种STM32F103C8T6/C6T6最小系统板,没有配置J-LINK/ST-LINK烧录口,此时可以

    2024年02月03日
    浏览(73)
  • STM32F103C8T6---定时器1&定时器8输出PWM信号注意事项

    博主今天在驱动定时器1的通道1输出PWM信号的时候,遇到了好多问题,在这里指出,警醒自己的同时希望能给各位带来帮助 首先,第一个错误, 第一:PA8引脚默认模式就是定时器1的通道一,我们在代码里面,直接 将PA8的输出模式改为复用推挽输出,不要去重定向它,也不要

    2024年02月16日
    浏览(47)
  • STM32单片机PWM控制实现电机调速度(小车运动,STM32F103C8T6&TB6612&TT电机)

    作者:公子易平 时间:2023/6/6 前段时间做一个智能小车的相关项目时,发现很少有人能够将STM32的PWM控制讲清楚,故而书此文,希望对后来的学习者有所帮助。 STM32F103C8T6最小系统板 直流TT电机 电机驱动芯片(TB6612) 杜邦线若干 接线情况: TB6612引脚说明: STM32主控芯片与TB6612接

    2024年02月15日
    浏览(48)
  • 蓝牙小车(基于stm32f103c8t6/HAL库/CubeMX/超详细,包含代码讲解和原理图)

    一、小车1.0——基本蓝牙小车(仅蓝牙遥控小车运动方向,本篇) 二、小车2.0——蓝牙小车PLUS(可以蓝牙控制方向+蓝牙直接调节车速) 三、小车3.0——避障小车(超声波+舵机云台) 四、小车4.0——无线手柄方向感知操控小车(mpu6050+双蓝牙透传) 五、双轮自平衡小车(HAL库版

    2023年04月09日
    浏览(54)
  • STM32F103C8T6+ESP-01S+MQTT服务器实现数据上传和接收(一)

    文章目录 STM32F103C8T6+ESP-01S+MQTT服务器实现数据的上传和接收(二) ESP-01S推荐使用安信可官网1471号固件,烧录配置如下图。 请替换其中里面的内容 使用PA9、PA10分别连接ESP8266的RXD、TXD引脚。 由于每次发送的AT指令都会被8266通过串口再发送回来,为了缓解串口的压力,并且更

    2024年04月17日
    浏览(51)
  • 【基于stm32f103C8T6-小程序智能家居项目实战-自绘PCB到实现功能一条龙+30分钟解决-各种bug已修复】

    阿熊智能家居演示 核心板 STM32F103C8T6 WIFI模块 ESP8266-01s 传感器 DHT11温湿度传感器 BH1750光照传感器 其他 LED OLED 4脚按键开关 CP2102(USB转TTL模块) 有源蜂鸣器(低电平触发) 金属膜电阻器 面包板(或PCB) 电源和导线 项目 数量 已购 价格 STM32F103C8T6 1 ESP8266-01s 1 DHT11温湿度传感器

    2024年04月28日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包