STM32 + RTThread + UGUI

news2025/1/11 4:21:11

一、概述

  • 开发板: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:GitHub - xidongxu/ugui: Open source graphics library ugui ported to rtthread

  3. 文件目录

  4. 使用介绍

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

五、UGUI 移植

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

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

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

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

注意:从以上步奏可以看出,移植 UGUI 时不需要更改任何参数,只需要在初始化时调用 ugui_port_init 函数即可。

六、程序源码

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 */

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/927946.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

反射机制-体会反射的动态性案例(尚硅谷Java学习笔记)

// 举例01 public class Reflect{ // 静态性 public Person getInstance(){return new Person(); }// 动态性 public T<T> getInstance(String className) throws Exception{Calss clzz Class.forName(className);Constructor con class.getDeclaredConstructor();con…

如何赋能音频行业更多创新 荔枝集团邀请华为云专家共探AIGC新动向

在互联网新时代&#xff0c;随着AIGC和大语言模型的技术突破&#xff0c;为音频产品提供了更多创新的可能性。8月25日下午&#xff0c;一场有关AIGC的技术交流论坛在位于广州的荔枝集团总部召开&#xff0c;并邀请华为云AI领域技术专家进行分享。华为云AIGC首席架构师&#xff…

网深科技与中科方德完成兼容性认证

网深科技的产品NetInside可观测性分析平台与国产中科方德主流操作系统完成兼容性适配&#xff0c;系统名称&#xff1a;方德高可信服务器操作系统V4.0&#xff0c;系统运行稳定&#xff0c;性能卓越&#xff0c;完美兼容&#xff0c;能够为广大用户提供灵活、专业、直观可视性&…

centos下配置SFTP且限制用户访问目录

一、SFTP使用场景 ftp是大多数网站的文件传输选择工具&#xff0c;但ftp并不是非常安全&#xff0c;并且在centos上搭建的vsftpd也非常的不稳定&#xff0c;偶尔会出现权限问题&#xff0c;例如500、或是账号密码不正确等等。 而SFTP是基于默认的22端口&#xff0c;是ssh内含…

23款奔驰GLS450升级原厂电动吸合门,体验绅士的关门状态

电吸门的工作原理是在门框(或门板边缘)上安装一个电磁线圈。当门打开时&#xff0c;电流会流过线圈&#xff0c;形成电磁场。这样&#xff0c;由于磁力的作用&#xff0c;当门靠近门框关闭时&#xff0c;门会自动关闭。 另外&#xff0c;电吸门也有有用的一面。如果下车&#…

生成地图展示【Python思路】

# 1.导包 import json from pyecharts.charts import Map #导入关于编写地图的包 from pyechart.options import * #全局设置# 2.得到地图对象 map Map()# 3.打开事先准备好的JSON数据文件 f open("D:/Typora 记事本/notebook/Python/Exercise_data/疫情.txt",&…

江西武功山旅游攻略(周末两日游)

一、 往返路线 1: 出发路线 周五晚上上海出发坐火车&#x1f684;到江西萍乡(11.5小时,卧铺550左右) 打车到江西武功山景区,120-150元左右,人均30元,1小时10分左右到达 或者 &#x1f697;到达萍乡北之后 出站后步行200米到长途汽车站&#xff0c;乘旅游巴士直达武功山游…

Centos 7.6 安装mongodb

以下是在CentOS 7.6上安装MongoDB的步骤&#xff1a; 打开终端并以root用户身份登录系统。 创建一个新的MongoDB存储库文件 /etc/yum.repos.d/mongodb-org-4.4.repo 并编辑它。 sudo vi /etc/yum.repos.d/mongodb-org-4.4.repo在编辑器中&#xff0c;添加下面的内容到文件中并…

GB28181开发------录像查询(设备视音频文件检索)

文件检索主要用区域、设备、录像时间段、录像地点、录像内容为条件进行查询,用 Message消息发 送检索请求和返回查询结果,传送结果的 Message消息可以发送多条,应支持附录 N 多响应消息传输 的要求。文件检索请求和应答命令采用 MANSCDP协议格式定义,详细描述见 A.2.4文件目录检…

Airbnb在中国不得势的主要原因是什么?Airbnb还有可能回来吗?

其实在年轻人的群体中,Airbnb还是相当出名的。想当初一开始出现的时候,很多人都为之疯狂,也在Airbnb上直接创下了众多房源输出,并且订单数量激增的地步。但是到了2021年,Airbnb却是以悄无声息的方式推出了中国市场,几乎没有什么通告,最终很多的用户都是在想要下载更新的时候才发…

springcloud3 GateWay章节-Nacos+gateway(跨域,filter过滤等)

一 常用工具类 1.1 结构 1.2 跨域 Configuration public class CorsConfig {Beanpublic CorsWebFilter corsFilter() {CorsConfiguration config new CorsConfiguration();config.addAllowedMethod("*");config.addAllowedOrigin("*");config.addAllowe…

Django(6)-django项目自动化测试

Django 应用的测试应该写在应用的 tests.py 文件里。测试系统会自动的在所有以 tests 开头的文件里寻找并执行测试代码。 我们的 polls 应用现在有一个小 bug 需要被修复&#xff1a;我们的要求是如果 Question 是在一天之内发布的&#xff0c; Question.was_published_recentl…

手把手叫你用VS2019写个WebApi(可以供网页、手机、电脑三端连接使用)从网页访问后端并在后端通过EF获取sqlserver中的数据

先新建项目&#xff0c;选择ASP.NET Web应用程序(.NET Framework) 创建完成后直接运行会在代码的Scripts.Render("~/bundles/modernizr")处报错&#xff0c;如下图 解决方法&#xff1a; 然后可以正常运行&#xff0c;运行后界面如下&#xff1a; 然后你在网址栏中输…

C语言基础之——数组

前言&#xff1a;本篇文章&#xff0c;我们将对一维数组&#xff0c;和二维数组进行展开式的讲解&#xff0c;并进行实际应用。 目录 一.一维数组 1.一维数组的创建和初始化 &#xff08;1&#xff09;数组的创建 &#xff08;2&#xff09;数组的初始化 2.一维数组的使用…

全行业线上商城系统一体化平台,个性化设计-免费更新-亿发

移动互联网成为了现代人生活中不可或缺的一部分。人们已经习惯了通过手机应用完成日常任务&#xff0c;从购物到社交&#xff0c;都能在手指间直接搞定。 随着小程序的兴起&#xff0c;2023年的线上商城系统在不断发展的数字化环境中&#xff0c;如今&#xff0c;线上商城正以…

行业报告 | 2023人工智能发展白皮书

原创 | 文 BFT机器人 在科技日新月异的今天&#xff0c;人工智能已成为最具革命性的技术之一&#xff0c;有望对人类社会生活产生显著的影响。过去几年&#xff0c;人工智能相关理论研究技术创新、软硬件升级等整体推进&#xff0c;极大地促进了人工智能行业的发展。 进入2022…

【BurpSuite常用功能介绍】

BurpSuite的使用 1.运行BurpSuite 2.代理设置 打开软件后&#xff0c;我们第一件事就应该去调试软件和浏览器的代理&#xff0c;让BURP能够正常工作抓包 proxy--options&#xff0c;我端口默认使用8080 然后我们打开一个浏览器&#xff0c;进入代理设置 (注意一点&#xff0…

JAVA switch case 穿透问题

1&#xff0c;前提 其实开发中很少会用到switch &#xff0c;一般更倾向于if-else&#xff0c; 但是最近接手的项目&#xff0c;前人写的代码都用switch &#xff0c; 但是我一直以来对switch 的理解就跟if一样&#xff0c; 然后项目运用的时候才发现这玩意居然还有穿透问题 …

python 模块openpyxl 读取写入.xlsx文件

Python操作Excel的模块有很多&#xff0c;并且各有优劣&#xff0c;不同模块支持的操作和文件类型也有不同。下面是各个模块的支持情况&#xff1a; xlrd&#xff1a;xlrd 读取.xls文件xlwings&#xff1a;xlwings 读取写入Excel文件xlwt&#xff1a;xlwt 写入.xls文件 一、…

Springboot集成RocketMQ——简单使用

目录 1.MQ选型 2.RocketMQ基本架构 3.Springboot集成RocketMQ 4.顺序消息 5.延时消息 6.事务消息 1.MQ选型 目前市面上的MQ选型&#xff1a;主要分为3个类型 Kafka&#xff1a;吞吐量大&#xff0c;且性能好&#xff0c;集群高可用&#xff1b;会丢失数据&#xff0c;功…