当前位置: 首页 > news >正文

STM32-14-FSMC_LCD

STM32-01-认识单片机
STM32-02-基础知识
STM32-03-HAL库
STM32-04-时钟树
STM32-05-SYSTEM文件夹
STM32-06-GPIO
STM32-07-外部中断
STM32-08-串口
STM32-09-IWDG和WWDG
STM32-10-定时器
STM32-11-电容触摸按键
STM32-12-OLED模块
STM32-13-MPU

文章目录

    • 1. 显示器分类
    • 2. LCD简介
    • 3. LCD驱动原理
    • 4. LCD驱动芯片
    • 5. LCD基本驱动步骤
    • 6. FSMC介绍
        • 1. FSMC简介
        • 2. FSMC框图
        • 3. FSMC时序
        • 4. FSMC地址映射
        • 5. FSMC相关寄存器
        • 6. FSMC相关库函数
    • 7. 代码实现

1. 显示器分类

显示器举例优点缺点
断码屏数码管、计算器、遥控器成本低,驱动简单,稳定色彩单一,显示内容少
点阵屏户外广告屏任意尺寸,亮度高贵,耗电,体积大
LCD屏显示器、电视屏、手机屏成本低,色彩好,薄,寿命长全彩稍差,漏光,拖影
OLED屏显示器、电视屏、手机屏自发光,色彩最好,超薄,功耗低比较贵,寿命短

2. LCD简介

  • 简介:

    Liquid Crystal Display,即液晶显示器,利用液晶导电后透光性可变的特性,配合显示器光源、彩色滤波片和电压控制等工艺,最终可以在液晶阵列上显示彩色的图像。目前,液晶显示技术以TN、STN、TFT三种技术为主,TFT-LCD即采用了TFT技术的液晶显示器,也叫薄膜晶体管液晶显示器。

  • 优点:

    1. 低成本:低至几块钱的价格
    2. 高解析度 :高达500像素(500ppi)的分辨率,显示细腻
    3. 高对比度:高达1000:1的对比度,色彩清晰艳丽
    4. 响应速度快:高达1ms相应速度,显示效果好
  • LCD的组成:
    在这里插入图片描述

    ​ LCD(液晶显示器)的基本组成包括以下几个主要部分:

    • 玻璃基板(Glass Substrates)

      • 上玻璃基板(Top Glass Substrate): 通常带有彩色滤光片,用于产生彩色图像。
      • 下玻璃基板(Bottom Glass Substrate): 上面布有电极和TFT(薄膜晶体管)阵列,用于控制液晶分子的排列。
    • 背光源(Backlight)

      背光源提供必要的光源,通常由LED组成,光通过液晶层后形成可见图像。背光源的重要组成部分有:

      • 导光板(Light Guide Plate): 将光均匀地分布在整个显示面板上。
      • 反射板(Reflector): 反射光线,提高亮度。
      • 扩散板(Diffuser): 使光均匀分布。
    • 驱动IC

      • 驱动IC是LCD屏幕的核心部件之一,负责控制液晶分子的排列,从而控制显示内容。驱动IC通常位于玻璃基板的边缘,通过电极与液晶层相连。驱动IC接收来自显示控制器的信号,并根据这些信号来调整液晶分子的排列,以实现所需的显示效果。
  • LCD接口分类:

    接口分辨率特性
    MCU≤800*480带SRAM,无需频繁刷新,无需大内存,驱动简单
    RGB≤1280*800不带SRAM,需要实时刷新,需要大内存,驱动稍微复杂
    MIPI4K不带SRAM,支持分辨率高,省电,大部分手机屏用此接口
    1. MCU接口
    • 特点:

      • 简单控制:MCU(Microcontroller Unit)接口通常用于小尺寸、低分辨率的显示屏。控制简单,适合使用嵌入式系统进行开发。
      • 低速数据传输:MCU接口的传输速度相对较低,适合显示静态图片和简单的UI界面。
      • 常见类型80806800并行接口是常见的MCU接口类型,通常有8位、16位、18位和24位数据线。
      • 应用场景:适用于家用电器、仪表盘、小型电子设备等不需要高刷新率和高分辨率显示的场景。
    • 优缺点:

      • 优点:控制简单、成本低、容易实现和调试。
      • 缺点:传输速度慢,不适合高分辨率和动态显示需求。
    1. RGB接口
    • 特点:

      • 高速数据传输:RGB接口通过多条并行数据线传输红、绿、蓝三种颜色的数据,适合高分辨率和高速刷新显示屏。
      • 色彩表现力强:支持24-bit、18-bit等高色深传输,能显示丰富的颜色细节。
      • 应用场景:广泛应用于笔记本电脑、平板电脑、电视和高端显示器。
    • 优缺点:

      • 优点:高传输速度、色彩丰富、适合动态视频和高分辨率图像。
      • 缺点:数据线多,连接复杂,布线成本高,对电磁干扰较敏感。
    1. MIPI接口
    • 特点:

      • 高带宽低功耗:MIPI(Mobile Industry Processor Interface) DSI(Display Serial Interface)是为移动设备设计的高带宽、低功耗接口,采用高速串行传输。
      • 差分信号传输:采用差分信号传输,具有抗干扰能力强的优点。
      • 集成度高:减少引脚数,提高数据传输效率,同时支持触摸屏控制信号的传输。
      • 应用场景:广泛应用于智能手机、平板电脑、可穿戴设备等便携式电子设备。
    • 优缺点:

      • 优点:传输速度快、功耗低、抗干扰能力强、引脚数少,适合高分辨率和动态显示需求。
      • 缺点:设计和实现较复杂,对硬件设计和信号完整性要求高。

      总结:

      • MCU接口适合低分辨率、低刷新率的显示应用,控制简单、成本低,但传输速度慢。
      • RGB接口适合高分辨率、高刷新率的显示应用,传输速度快、色彩表现力强,但布线复杂、成本高。
      • MIPI接口则适合移动设备和便携式电子设备,具有高带宽、低功耗和强抗干扰能力的特点,但实现较复杂。
  • ILI9341驱动芯片:
    在这里插入图片描述

    1. MCU接口:可以使用8、9、16或18位接口进行通信;
    2. SPI接口:可以使用3线或4线SPI接口进行通信;
    3. RGB接口:可以使用6、16或18位接口进行通信。
  • 三基色原理:
    在这里插入图片描述

    在计算机中,颜色通常使用32位的格式表示,称为ARGB888格式,其中A表示Alpha通道,R、G、B分别表示红、绿、蓝三个颜色通道。在单片机中,由于资源限制,颜色通常以16位或24位表示,分别称为RGB565和RGB888格式,其中RGB565使用16位来表示颜色,而RGB888使用24位来表示颜色。

3. LCD驱动原理

  • LCD驱动原理:

    LCD屏(MCU接口)驱动的核心是:驱动LCD驱动芯片
    在这里插入图片描述

  • LCD驱动过程:
    在这里插入图片描述

  • 8080时序:

    信号名称控制状态作用
    CS片选低电平选中器件,低电平有效,先选中,后操作
    WR写信号,上升沿有效,用于数据/命令写入
    RD读信号,上升沿有效,用于数据/命令读取
    RS数据/命令0=命/1=数表示当前是读写数据还是命令,也叫DC信号
    D[15:0]数据线双向数据线,可以写入/读取驱动IC数据
    • 写时序
      在这里插入图片描述

      void lcd_wr_data(uint16_t data)
      {LCD_RS(1);		/* 操作数据 */LCD_CS(0);		/* 选中 */LCD_DATA_OUT(data);	/* 数据 */LCD_WR(0);		/* WR低电平 */LCD_WR(1);		/* WR高电平 */LCD_CS(1);		/* 释放片选 */
      }
      
    • 读时序
      在这里插入图片描述

      uint16_t  lcd_rd_data(void)
      {uint16_t ram;  		/* 定义变量 */LCD_RS(1);          /* 操作数据 */LCD_CS(0);			/* 选中 */LCD_RD(0);			/* RD低电平 */ram = LCD_DATA_IN;  /* 读取数据 */LCD_RD(1);			/* RD高电平 */LCD_CS(1);			/* 释放片选 */return ram;		   /* 返回读数 */
      }
      

4. LCD驱动芯片

  • 驱动芯片用于控制LCD的各种显示功能,整体功能复杂。常见型号ILI9341/ST7789等 。

    一般我们只需要6条指令即可完成对LCD的基本使用

    指令(HEX)名称作用
    0XD3读ID用于读取LCD控制器的ID,区分型号用
    0X36访问控制设置GRAM读写方向,控制显示方向
    0X2A列地址一般用于设置X坐标
    0X2B页地址一般用于设置Y坐标
    0X2C写GRAM用于往LCD写GRAM数据
    0X2E读GRAM用于读取LCD的GRAM数据
    • 读ID指令
      在这里插入图片描述

      具体步骤:

      1. 设置RS为低电平(0),表示要发送命令;
      2. 将命令0xD3(读ID指令)写入数据线D[15:0];
      3. 将CS信号置为低电平,选中LCD驱动IC;
      4. 触发WR信号的上升沿,将命令写入LCD驱动IC;
      5. 将RS设置为高电平(1),表示要读取数据;
      6. 将CS信号保持低电平,继续选中LCD驱动IC;
      7. 触发RD信号的上升沿,从LCD驱动IC读取数据
      8. 读取数据线D[15:0]上的数据,这就是LCD控制器型号。
    • 访问控制指令
      在这里插入图片描述

      具体步骤:

      1. 设置RS为低电平(0),表示要发送命令;
      2. 将命令0x36(访问控制指令)写入数据线D[15:0];
      3. 将CS信号置为低电平,选中LCD驱动IC;
      4. 触发WR信号的上升沿,将命令写入LCD驱动IC;
      5. 设置RS为高电平(1),表示要写入参数数据;
      6. 将参数数据(MX, MY, MV, BGR)写入数据线D[15:0];
      7. 再次触发WR信号的上升沿,将参数数据写入LCD驱动IC;
      8. 将CS信号置为高电平,取消对LCD驱动IC的选中状态。

      在这里插入图片描述

    • X坐标设置指令
      在这里插入图片描述

      具体步骤:

      1. 设置RS为低电平(0),表示要发送命令;
      2. 将命令0x2A(X坐标设置指令)写入数据线D[15:0];
      3. 将CS信号置为低电平,选中LCD驱动IC;
      4. 触发WR信号的上升沿,将命令写入LCD驱动IC;
      5. 设置RS为高电平(1),表示要写入参数数据;
      6. 将起始坐标(SC)写入数据线D[15:0];
      7. 再次触发WR信号的上升沿,将起始坐标写入LCD驱动IC;
      8. 将结束坐标(EC)写入数据线D[15:0];
      9. 再次触发WR信号的上升沿,将结束坐标写入LCD驱动IC;
      10. 将CS信号置为高电平,取消对LCD驱动IC的选中状态。
    • Y坐标设置指令
      在这里插入图片描述

      具体步骤:

      1. 设置RS为低电平(0),表示要发送命令;
      2. 将命令0x2B(Y坐标设置指令)写入数据线D[15:0];
      3. 将CS信号置为低电平,选中LCD驱动IC;
      4. 触发WR信号的上升沿,将命令写入LCD驱动IC;
      5. 设置RS为高电平(1),表示要写入参数数据;
      6. 将起始坐标(SP)写入数据线D[15:0];
      7. 再次触发WR信号的上升沿,将起始坐标写入LCD驱动IC;
      8. 将结束坐标(EP)写入数据线D[15:0];
      9. 再次触发WR信号的上升沿,将结束坐标写入LCD驱动IC;
      10. 将CS信号置为高电平,取消对LCD驱动IC的选中状态。
    • 写GRAM指令
      在这里插入图片描述

      具体步骤:

      1. 设置RS为低电平(0),表示要发送命令;
      2. 将命令0x2C(写GRAM指令)写入数据线D[15:0];
      3. 将CS信号置为低电平,选中LCD驱动IC;
      4. 触发WR信号的上升沿,将命令写入LCD驱动IC;
      5. 设置RS为高电平(1),表示要写入数据;
      6. 准备要写入的像素点的颜色值(RGB565格式),写入数据线D[15:0];
      7. 再次触发WR信号的上升沿,将像素点的颜色值写入LCD驱动IC;
      8. 如果需要连续写入多个像素点,数据线会自动自增,无需重新设置坐标。
    • 读GRAM指令
      在这里插入图片描述

      具体步骤:

      1. 设置RS为低电平(0),表示要发送命令;
      2. 将命令0x2E(读GRAM指令)写入数据线D[15:0];
      3. 将CS信号置为低电平,选中LCD驱动IC;
      4. 触发WR信号的上升沿,将命令写入LCD驱动IC;
      5. 设置RS为高电平(1),表示要读取数据;
      6. 发送dummy数据,读取GRAM中的垃圾数据(dummy);
      7. 依次读取R1G1和B1R2数据,每次读取一个像素点的颜色;
      8. 根据RGB565格式的颜色值,提取出红色、绿色和蓝色通道的值,并返回合并后的颜色值。

      在这个过程中,需要连续读取3次数据,每次读取一个像素点的颜色值。其中,dummy数据用于丢弃GRAM中的垃圾数据,实际上不会被使用。而读取R1G1和B1R2数据则是实际的颜色值数据,需要根据RGB565格式进行处理,提取出红色、绿色和蓝色通道的值,最终合并成完整的颜色值。

      读取某个点颜色函数代码:

      uint16_t lcd_rd_data(void)
      {uint16_t ram;  		/* 定义变量 */DATA_IN_MODE();	    /* 设置数据输入 */LCD_RS(1);          /* 操作数据 */LCD_CS(0);			/* 选中 */LCD_RD(0);		    /* RD低电平 */ram = LCD_DATA_IN;  /* 读取数据 */LCD_RD(1);		    /* RD高电平 */LCD_CS(1);			/* 释放片选 */DATA_OUT_MODE();	/* 设置数据输出 */return ram;		   /* 返回读数 */
      }uint16_t lcd_read_point(uint16_t x, uint16_t y)
      {uint16_t r = 0, g = 0, b = 0;	/* 定义变量 */lcd_set_cursor(x, y);		/* 设置坐标 */lcd_wr_regno(0X2E);		    /* 发读点命令 */r = lcd_rd_data();  		/* 假读 */r = lcd_rd_data();  		/* 读rg */b = lcd_rd_data(); 		    /* 读b */g = r & 0XFF;       	    /* 得到g值 */return (((r >> 11) << 11) | ((g >> 2) << 5) | (b >> 11));
      }
      

      将红色、绿色和蓝色分量组合成一个16位的颜色值并返回:

      • 红色分量:将 r 右移11位,获得红色分量的高5位,再左移11位放到返回值的高5位。
      • 绿色分量:将 g 右移2位,获得绿色分量的高6位,再左移5位放到返回值的中6位。
      • 蓝色分量:将 b 右移11位,获得蓝色分量的高5位,直接放到返回值的低5位。

      这段代码通过指定坐标,发送读取命令,读取并组合红、绿、蓝三种颜色的分量,最后返回组合后的16位颜色值。每个颜色分量都经过适当的移位和合并操作,以符合16位颜色格式。

5. LCD基本驱动步骤

  • LCD驱动的一般过程

    1. 电源初始化

      • 打开LCD电源并进行复位。
      • 配置电源电压、时钟等参数。
    2. 硬件接口初始化

      • 根据LCD的接口类型(MCU接口、RGB接口、MIPI接口等)配置MCU的GPIO引脚和通信协议。
        在这里插入图片描述
    3. 寄存器配置

      • 通过写入特定命令到LCD控制器寄存器来配置显示参数,例如分辨率、颜色格式、扫描方向等。
    4. 内存映射

      • 将LCD的显示内存映射到MCU的地址空间,方便后续的读写操作。
    5. 显示测试

      • 进行显示测试,例如填充屏幕、显示图像等,确保LCD初始化成功。

    8080底层操作函数

    8080接口是一种并行通信接口,常用于LCD与MCU之间的数据传输。8080底层操作函数:

    /* 8080 写数据 */
    void lcd_wr_data (uint16_t data)
    {LCD_RS(1);          /* 操作数据 */LCD_CS(0);          /* 选中 */LCD_DATA_OUT(data); /* 数据 */LCD_WR(0);          /* WR低电平 */LCD_WR(1);          /* WR高电平 */LCD_CS(1);          /* 释放片选 */
    }/* 8080 写命令 */
    void lcd_wr_regno(uint16_t regno)
    {LCD_RS(0);          /* RS=0,表示写寄存器 */LCD_CS(0);          /* 选中 */LCD_DATA_OUT(regno);/* 命令 */LCD_WR(0);          /* WR低电平 */LCD_WR(1);          /* WR高电平 */LCD_CS(1);          /* 释放片选 */
    }
    

    初始化LCD

    初始化LCD的过程包括设置电源、配置寄存器和初始化显示内存等步骤。

    /* 初始化LCD */
    void lcd_init(void)
    {GPIO_InitTypeDef gpio_init_struct;LCD_BL_GPIO_CLK_ENABLE();   /* LCD_BL脚时钟使能 */LCD_CS_GPIO_CLK_ENABLE();   /* LCD_CS脚时钟使能 */LCD_WR_GPIO_CLK_ENABLE();   /* LCD_WR脚时钟使能 */LCD_RD_GPIO_CLK_ENABLE();   /* LCD_RD脚时钟使能 */LCD_RS_GPIO_CLK_ENABLE();   /* LCD_RS脚时钟使能 */LCD_DATA_GPIO_CLK_ENABLE(); /* LCD_DATA脚时钟使能 */__HAL_RCC_AFIO_CLK_ENABLE();__HAL_AFIO_REMAP_SWJ_NOJTAG(); /* 禁止JTAG, 使能SWD, 释放PB3,PB4两个引脚做普通IO用 */gpio_init_struct.Pin = LCD_BL_GPIO_PIN;gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;            /* 推挽复用 */gpio_init_struct.Pull = GPIO_PULLUP;                    /* 上拉 */gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;          /* 高速 */HAL_GPIO_Init(LCD_BL_GPIO_PORT, &gpio_init_struct);     /* LCD_BL引脚模式设置(推挽输出) */gpio_init_struct.Pin = LCD_CS_GPIO_PIN;HAL_GPIO_Init(LCD_CS_GPIO_PORT, &gpio_init_struct);     /* 初始化LCD_CS引脚 */gpio_init_struct.Pin = LCD_WR_GPIO_PIN;HAL_GPIO_Init(LCD_WR_GPIO_PORT, &gpio_init_struct);     /* 初始化LCD_WR引脚 */gpio_init_struct.Pin = LCD_RD_GPIO_PIN;HAL_GPIO_Init(LCD_RD_GPIO_PORT, &gpio_init_struct);     /* 初始化LCD_RD引脚 */gpio_init_struct.Pin = LCD_RS_GPIO_PIN;HAL_GPIO_Init(LCD_RS_GPIO_PORT, &gpio_init_struct);     /* 初始化LCD_RS引脚 */gpio_init_struct.Pin = LCD_DATA_GPIO_PIN;gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;            /* 推挽输出 */HAL_GPIO_Init(LCD_DATA_GPIO_PORT, &gpio_init_struct);   /* LCD_DATA引脚模式设置 */LCD_WR(1);                  /* WR 默认高电平 */LCD_RD(1);                  /* RD 默认高电平 */LCD_CS(1);                  /* CS 默认高电平 */LCD_RS(1);                  /* RS 默认高电平 */LCD_DATA_OUT(0XFFFF);       /* DATA 默认高电平 *//* 读取ID */lcd_wr_regno(0xD3);lcddev.id = lcd_rd_data();  /* 假读 */lcddev.id = lcd_rd_data();  /* 00 */lcddev.id = lcd_rd_data();  /* 93 */lcddev.id <<= 8;lcddev.id |= lcd_rd_data();  /* 41 */printf("lcddev_id:%#x \r\n", lcddev.id);/* 完成初始化序列 */if (lcddev.id == 0x9341)lcd_ex_ili9341_reginit();elselcd_ex_st7789_reginit();/* 对LCD控制结构体赋值 */lcddev.width = 240;lcddev.height = 320;lcddev.setxcmd = 0x2A;lcddev.setycmd = 0x2B;lcddev.wramcmd = 0x2C;lcd_wr_regno(lcddev.setxcmd);lcd_wr_data(0);lcd_wr_data(0);lcd_wr_data((lcddev.width - 1) >> 8);lcd_wr_data((lcddev.width - 1) & 0XFF);lcd_wr_regno(lcddev.setycmd);lcd_wr_data(0);lcd_wr_data(0);lcd_wr_data((lcddev.height - 1) >> 8);lcd_wr_data((lcddev.height - 1) & 0XFF);/* 设置扫描方向 */lcd_write_reg(0x36, 1 << 3);/* 点亮背光 */LCD_BL(1);/* lcd_clear */lcd_clear(0xFFFF);
    }
    

    实现画点函数

    画点函数用于在指定位置显示一个像素点。

    /* 画点 */
    void lcd_draw_point(uint16_t x, uint16_t y, uint16_t color)
    {lcd_set_cursor(x, y);lcd_write_ram_prepare();lcd_wr_data(color);
    }
    

    实现读点函数

    读点函数用于读取指定位置的像素点颜色值。

    /* LCD读数据 */
    uint16_t lcd_rd_data(void)
    {volatile uint16_t ram;  /* 防止被优化 */GPIO_InitTypeDef gpio_init_struct;/* LCD_DATA 引脚模式设置, 上拉输入, 准备接收数据 */gpio_init_struct.Pin = LCD_DATA_GPIO_PIN;gpio_init_struct.Mode = GPIO_MODE_INPUT;gpio_init_struct.Pull = GPIO_PULLUP;gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(LCD_DATA_GPIO_PORT, &gpio_init_struct); LCD_RS(1);              /* RS=1,表示操作数据 */LCD_CS(0);LCD_RD(0);lcd_opt_delay(2);ram = LCD_DATA_IN;      /* 读取数据 */LCD_RD(1);LCD_CS(1);/* LCD_DATA 引脚模式设置, 推挽输出, 恢复输出状态 */gpio_init_struct.Pin = LCD_DATA_GPIO_PIN;gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;gpio_init_struct.Pull = GPIO_PULLUP;gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(LCD_DATA_GPIO_PORT, &gpio_init_struct);   return ram;
    }/* 读点 */
    uint16_t  lcd_read_point (uint16_t x, uint16_t y)
    {uint16_t r = 0, g = 0, b = 0;   /* 定义变量 */lcd_set_cursor(x, y);           /* 设置坐标 */lcd_wr_regno(0X2E);             /* 发读点命令 */r = lcd_rd_data();              /* 假读 */r = lcd_rd_data();              /* 读rg */b = lcd_rd_data();              /* 读b */g = r & 0XFF;                   /* 得到g值 */return (((r >> 11) << 11) | ((g >> 2) << 5) | (b >> 11));
    }
    

6. FSMC介绍

1. FSMC简介
  • Flexible Static Memory Controller灵活的静态存储控制器
  • 用途: 用于驱动SRAM,NOR FLASH,NAND FLASH及PC卡类型的存储器。 它的主要作用是简化对这些存储器的访问,通过配置FSMC外设,可以直接使用指针操作来修改存储单元的内容,而不需要程序员去实现复杂的时序控制。
  • 配置好FSMC后,可以定义一个指针指向这些存储器的地址,然后通过对指针的操作来读写存储单元的内容。FSMC会自动完成读写命令和数据访问操作,不需要程序员去关心时序控制的细节。
  • FSMC外设配置好就可以模拟出时序。F1/ F4(407)系列大容量型号,且引脚数目在100脚以上的芯片都有FSMC接口,F4/F7/H7系列就是FMC接口。
2. FSMC框图

在这里插入图片描述

  1. 时钟逻辑控制

    时钟控制逻辑负责生成和管理FSMC操作所需的时钟信号。这些时钟信号用于同步FSMC内部操作以及与外部设备的通信。主要功能包括:

    • 时钟源选择:FSMC可以从系统时钟或其他预定时钟源获取时钟信号。时钟源的选择可能通过配置寄存器进行设置。
    • 时钟分频:FSMC内部可以对输入时钟信号进行分频,以生成适合不同操作速度的时钟。分频比通过特定的配置寄存器设置。
    • 时钟启停控制:根据需要,可以启动或停止FSMC的时钟,以节省功耗。时钟控制逻辑负责在需要时准确地启动或停止时钟信号。
  2. 控制单元

    FSMC控制单元是FSMC的核心部分,负责管理与外部存储器的交互。主要功能包括:

    • 地址映射:将处理器生成的虚拟地址映射到外部存储器的物理地址。这涉及地址总线和片选信号的生成和管理。
    • 读写控制:生成读写操作的控制信号(如读使能、写使能)。这些信号用于协调处理器与外部存储器之间的数据传输。
    • 时序控制:FSMC控制单元负责控制读写操作的时序,以确保与外部存储器的通信符合时序要求。这包括设置和保持时间的控制。
    • 数据总线管理:管理数据总线的方向和数据传输。在读操作时,将外部存储器的数据传送到处理器;在写操作时,将处理器的数据传送到外部存储器。
    • 错误检测与纠正:在数据传输过程中进行错误检测,并在可能的情况下进行纠正,以确保数据完整性。
  3. 通信引脚

    通信引脚是FSMC与外部设备(如SRAM、NOR Flash、NAND Flash等)进行实际物理连接的接口。主要引脚包括:
    在这里插入图片描述

  • 使用FSMC驱动LCD
    在这里插入图片描述

    右边是FSMC控制屏幕的过程,使用的是HADDR总线, CPU通过HADDR总线将控制信息发送给FSMC,然后FSMC再控制SRAM。 8080总线是CPU直接控制屏幕的方式,而HADDR总线是通过配置FSMC来控制屏幕的方式 。

3. FSMC时序

在这里插入图片描述

  • 模式1
    • 这种模式适用于 SRAM/CRAM 存储器,其时序特性如下:
      • 在读操作时,输出使能(OE)在读时序片选过程不翻转。
      • 存在 NBL(Narrow Bus Low)信号,用于指示总线宽度。
      • 不存在 NADV(NAND Address Valid)信号。
  • 拓展模式
    • 拓展模式相对于模式1来说,读写时序时间参数设置可以不同,以满足存储器读写时序不一样的需求。
    • 拓展模式包括了模式A、模式B/2、模式C 和模式D,针对不同类型的存储器有不同的时序特性:
      • 模式A:适用于 SRAM/PSRAM(CRAM)存储器,与模式1类似,但是在读操作时,输出使能(OE)在读时序片选过程翻转。
      • 模式B/2:适用于 NOR FLASH 存储器,读操作时输出使能(OE)在读时序片选过程不翻转,不存在 NBL 信号,但有 NADV 信号。
      • 模式C:也适用于 NOR FLASH 存储器,读操作时输出使能(OE)在读时序片选过程翻转,不存在 NBL 信号,但有 NADV 信号。
      • 模式D:适用于带地址扩展的异步操作,读操作时输出使能(OE)在读时序片选过程翻转,不存在 NBL 信号,有 NADV 信号,且存在地址保存时间。
        在这里插入图片描述
4. FSMC地址映射

在这里插入图片描述

针对FSMC存储块划分,可以进一步解释如下:

  1. 外部存储器划分为四个存储块:这意味着STM32可以与四个不同的外部存储器设备通信,每个设备都具有独立的存储空间。
  2. 每个存储块大小为256M字节:每个存储块都有256M字节的存储空间,可以容纳大量的数据。
  3. FSMC存储块1划分为四个区:存储块1是FSMC的一个特定区域,它被分成了四个区域,每个区域管理64M字节的空间。这种划分方式可以帮助对存储器进行更灵活的管理和组织。
  • HADDR与FSMC_A关系
    在这里插入图片描述

  • LCD的RS信号线与地址线关系
    在这里插入图片描述

5. FSMC相关寄存器
  • FSMC_BCR4FSMC_BTR4FSMC_BWTR4寄存器
    在这里插入图片描述

  • FSMC_BCRx寄存器
    在这里插入图片描述

  • FSMC_BTRx寄存器
    在这里插入图片描述

  • FSMC_BWTRx寄存器
    在这里插入图片描述
    在这里插入图片描述

6. FSMC相关库函数
HAL_StatusTypeDef HAL_SRAM_Init ( SRAM_HandleTypeDef *hsram, FSMC_NORSRAM_TimingTypeDef *Timing, FSMC_NORSRAM_TimingTypeDef *ExtTiming )

参数:

  1. SRAM_HandleTypeDef *hsram:这是指向 SRAM 句柄结构的指针。该结构包含了 SRAM 模块的配置信息,如 SRAM 的基地址、数据宽度、存储器库编号等。
  2. FSMC_NORSRAM_TimingTypeDef *Timing:这是指向 SRAM 读写访问时序结构的指针。FSMC_NORSRAM_TimingTypeDef 结构定义了时序参数,如地址设置时间、数据保持时间、总线转换时间、时钟分频、数据延迟和访问模式等。
  3. FSMC_NORSRAM_TimingTypeDef *ExtTiming:这是指向扩展模式时序结构的指针(如果使用的话)。扩展模式允许在某些操作需要不同的时序时应用额外的时序配置。

功能:

HAL_SRAM_Init 函数通过配置 FSMC 接口中的时序参数来初始化 SRAM 设备。具体步骤如下:

  1. 句柄初始化:函数首先初始化 SRAM 句柄 (hsram),包括设置基地址和其他配置参数。
  2. 时序配置:设置 FSMC 的读写时序参数,这包括:
    • 地址设置时间:在片选之前设置地址的时间。
    • 数据保持时间:在操作完成之前保持数据的时间。
    • 访问模式:如异步模式。
  3. FSMC 配置:配置 FSMC 外设的时序参数,具体包括:
    • 设置 FSMC 控制寄存器,定义存储器类型、数据宽度、存储器库和读写时序参数。
    • 配置控制信号,如片选、输出使能和写入使能线。
  4. 扩展模式(可选):如果提供了 ExtTiming 参数(非空),函数将配置扩展模式时序参数。扩展模式允许对某些操作使用不同的读写时序。
  5. 启用 FSMC:一旦设置了时序配置,启用 FSMC 控制器开始与 SRAM 通信。

7. 代码实现

  • LCD初始化函数

    void lcd_init(void)
    {GPIO_InitTypeDef gpio_init_struct;FSMC_NORSRAM_TimingTypeDef fsmc_read_handle;FSMC_NORSRAM_TimingTypeDef fsmc_write_handle;LCD_CS_GPIO_CLK_ENABLE();   /* LCD_CS脚时钟使能 */LCD_WR_GPIO_CLK_ENABLE();   /* LCD_WR脚时钟使能 */LCD_RD_GPIO_CLK_ENABLE();   /* LCD_RD脚时钟使能 */LCD_RS_GPIO_CLK_ENABLE();   /* LCD_RS脚时钟使能 */LCD_BL_GPIO_CLK_ENABLE();   /* LCD_BL脚时钟使能 */gpio_init_struct.Pin = LCD_CS_GPIO_PIN;gpio_init_struct.Mode = GPIO_MODE_AF_PP;                /* 推挽复用 */gpio_init_struct.Pull = GPIO_PULLUP;                    /* 上拉 */gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;          /* 高速 */HAL_GPIO_Init(LCD_CS_GPIO_PORT, &gpio_init_struct);     /* 初始化LCD_CS引脚 */gpio_init_struct.Pin = LCD_WR_GPIO_PIN;HAL_GPIO_Init(LCD_WR_GPIO_PORT, &gpio_init_struct);     /* 初始化LCD_WR引脚 */gpio_init_struct.Pin = LCD_RD_GPIO_PIN;HAL_GPIO_Init(LCD_RD_GPIO_PORT, &gpio_init_struct);     /* 初始化LCD_RD引脚 */gpio_init_struct.Pin = LCD_RS_GPIO_PIN;HAL_GPIO_Init(LCD_RS_GPIO_PORT, &gpio_init_struct);     /* 初始化LCD_RS引脚 */gpio_init_struct.Pin = LCD_BL_GPIO_PIN;gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;            /* 推挽输出 */HAL_GPIO_Init(LCD_BL_GPIO_PORT, &gpio_init_struct);     /* LCD_BL引脚模式设置(推挽输出) */g_sram_handle.Instance = FSMC_NORSRAM_DEVICE;g_sram_handle.Extended = FSMC_NORSRAM_EXTENDED_DEVICE;g_sram_handle.Init.NSBank = FSMC_NORSRAM_BANK4;                        /* 使用NE4 */g_sram_handle.Init.DataAddressMux = FSMC_DATA_ADDRESS_MUX_DISABLE;     /* 地址/数据线不复用 */g_sram_handle.Init.MemoryDataWidth = FSMC_NORSRAM_MEM_BUS_WIDTH_16;    /* 16位数据宽度 */g_sram_handle.Init.BurstAccessMode = FSMC_BURST_ACCESS_MODE_DISABLE;   /* 是否使能突发访问,仅对同步突发存储器有效,此处未用到 */g_sram_handle.Init.WaitSignalPolarity = FSMC_WAIT_SIGNAL_POLARITY_LOW; /* 等待信号的极性,仅在突发模式访问下有用 */g_sram_handle.Init.WaitSignalActive = FSMC_WAIT_TIMING_BEFORE_WS;      /* 存储器是在等待周期之前的一个时钟周期还是等待周期期间使能NWAIT */g_sram_handle.Init.WriteOperation = FSMC_WRITE_OPERATION_ENABLE;       /* 存储器写使能 */g_sram_handle.Init.WaitSignal = FSMC_WAIT_SIGNAL_DISABLE;              /* 等待使能位,此处未用到 */g_sram_handle.Init.ExtendedMode = FSMC_EXTENDED_MODE_ENABLE;           /* 读写使用不同的时序 */g_sram_handle.Init.AsynchronousWait = FSMC_ASYNCHRONOUS_WAIT_DISABLE;  /* 是否使能同步传输模式下的等待信号,此处未用到 */g_sram_handle.Init.WriteBurst = FSMC_WRITE_BURST_DISABLE;              /* 禁止突发写 *//* FSMC读时序控制寄存器 */fsmc_read_handle.AddressSetupTime = 0;      /* 地址建立时间(ADDSET)为1个HCLK 1/72M = 13.9ns (实际 > 200ns) */fsmc_read_handle.AddressHoldTime = 0;       /* 地址保持时间(ADDHLD) 模式A是没有用到 *//* 因为液晶驱动IC的读数据的时候,速度不能太快,尤其是个别奇葩芯片 */fsmc_read_handle.DataSetupTime = 15;        /* 数据保存时间(DATAST)为16个HCLK = 13.9 * 16 = 222.4ns */fsmc_read_handle.AccessMode = FSMC_ACCESS_MODE_A;    /* 模式A *//* FSMC写时序控制寄存器 */fsmc_write_handle.AddressSetupTime = 0;     /* 地址建立时间(ADDSET)为1个HCLK = 13.9ns */fsmc_write_handle.AddressHoldTime = 0;      /* 地址保持时间(ADDHLD) 模式A是没有用到 *//* 某些液晶驱动IC的写信号脉宽,最少也得50ns */fsmc_write_handle.DataSetupTime = 1;        /* 数据保存时间(DATAST)为2个HCLK = 13.9 * 2 = 27.8ns (实际 > 200ns) */fsmc_write_handle.AccessMode = FSMC_ACCESS_MODE_A;   /* 模式A */HAL_SRAM_Init(&g_sram_handle, &fsmc_read_handle, &fsmc_write_handle);delay_ms(50);/* 尝试9341 ID的读取 */lcd_wr_regno(0XD3);lcddev.id = lcd_rd_data();  /* dummy read */lcddev.id = lcd_rd_data();  /* 读到0X00 */lcddev.id = lcd_rd_data();  /* 读取0x93 */lcddev.id <<= 8;lcddev.id |= lcd_rd_data(); /* 读取0x41 */if (lcddev.id != 0X9341)    /* 不是 9341 , 尝试看看是不是 ST7789 */{lcd_wr_regno(0X04);lcddev.id = lcd_rd_data();      /* dummy read */lcddev.id = lcd_rd_data();      /* 读到0X85 */lcddev.id = lcd_rd_data();      /* 读取0X85 */lcddev.id <<= 8;lcddev.id |= lcd_rd_data();     /* 读取0X52 */if (lcddev.id == 0X8552)        /* 将8552的ID转换成7789 */{lcddev.id = 0x7789;}if (lcddev.id != 0x7789)        /* 也不是ST7789, 尝试是不是 NT35310 */{lcd_wr_regno(0XD4);lcddev.id = lcd_rd_data();  /* dummy read */lcddev.id = lcd_rd_data();  /* 读回0X01 */lcddev.id = lcd_rd_data();  /* 读回0X53 */lcddev.id <<= 8;lcddev.id |= lcd_rd_data(); /* 这里读回0X10 */if (lcddev.id != 0X5310)    /* 也不是NT35310,尝试看看是不是NT35510 */{/* 发送秘钥(厂家提供,照搬即可) */lcd_write_reg(0xF000, 0x0055);lcd_write_reg(0xF001, 0x00AA);lcd_write_reg(0xF002, 0x0052);lcd_write_reg(0xF003, 0x0008);lcd_write_reg(0xF004, 0x0001);lcd_wr_regno(0xC500);           /* 读取ID高8位 */lcddev.id = lcd_rd_data();      /* 读回0X55 */lcddev.id <<= 8;lcd_wr_regno(0xC501);           /* 读取ID低8位 */lcddev.id |= lcd_rd_data();     /* 读回0X10 */delay_ms(5);if (lcddev.id != 0X5510)        /* 也不是NT5510,尝试看看是不是SSD1963 */{lcd_wr_regno(0XA1);lcddev.id = lcd_rd_data();lcddev.id = lcd_rd_data();  /* 读回0X57 */lcddev.id <<= 8;lcddev.id |= lcd_rd_data(); /* 读回0X61 */if (lcddev.id == 0X5761)lcddev.id = 0X1963; /* SSD1963读回的ID是5761H,为方便区分,我们强制设置为1963 */}}}}/* 特别注意, 如果在main函数里面屏蔽串口1初始化, 则会卡死在printf* 里面(卡死在f_putc函数), 所以, 必须初始化串口1, 或者屏蔽掉下面* 这行 printf 语句 !!!!!!!*/printf("LCD ID:%x\r\n", lcddev.id); /* 打印LCD ID */if (lcddev.id == 0X7789){lcd_ex_st7789_reginit();    /* 执行ST7789初始化 */}else if (lcddev.id == 0X9341){lcd_ex_ili9341_reginit();   /* 执行ILI9341初始化 */}else if (lcddev.id == 0x5310){lcd_ex_nt35310_reginit();   /* 执行NT35310初始化 */}else if (lcddev.id == 0x5510){lcd_ex_nt35510_reginit();   /* 执行NT35510初始化 */}else if (lcddev.id == 0X1963){lcd_ex_ssd1963_reginit();   /* 执行SSD1963初始化 */lcd_ssd_backlight_set(100); /* 背光设置为最亮 */}lcd_display_dir(0); /* 默认为竖屏 */LCD_BL(1);          /* 点亮背光 */lcd_clear(WHITE);
    }
    
  • 主函数

    int main(void)
    {uint8_t lcd_id[12];HAL_Init();                                         /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9);                 /* 设置时钟, 72Mhz */delay_init(72);                                     /* 延时初始化 */usart_init(115200);                                 /* 串口初始化为115200 */led_init();                                         /* 初始化LED */oled_init();lcd_init();                                         /* 初始化LCD */sprintf((char *)lcd_id, "LCD ID:%04X", lcddev.id);  /* 将LCD ID打印到lcd_id数组 */while (1){lcd_show_string(10, 40, 240, 32, 32, "STM32", GREEN);lcd_show_string(10, 80, 240, 24, 24, "TFTLCD TEST", BLUE);lcd_show_string(10, 110, 240, 16, 16, "ATOM@ALIENTEK", RED);lcd_show_string(10, 130, 240, 16, 12, (char *)lcd_id, RED); /* 显示LCD ID */oled_show_string(0, 5, "STM32", 24);oled_show_string(0, 33, "TFTLCD TEST", 16);oled_show_string(0, 51, "ATOM@ALIENTEK", 12);oled_refresh_gram(); LED0_TOGGLE(); /*红灯闪烁*/delay_ms(1000);}
    }
    
  • 实验结果
    在这里插入图片描述

声明:资料来源(战舰STM32F103ZET6开发板资源包)

  1. Cortex-M3权威指南(中文).pdf
  2. STM32F10xxx参考手册_V10(中文版).pdf
  3. STM32F103 战舰开发指南V1.3.pdf
  4. STM32F103ZET6(中文版).pdf
  5. 战舰V4 硬件参考手册_V1.0.pdf

相关文章:

STM32-14-FSMC_LCD

STM32-01-认识单片机 STM32-02-基础知识 STM32-03-HAL库 STM32-04-时钟树 STM32-05-SYSTEM文件夹 STM32-06-GPIO STM32-07-外部中断 STM32-08-串口 STM32-09-IWDG和WWDG STM32-10-定时器 STM32-11-电容触摸按键 STM32-12-OLED模块 STM32-13-MPU 文章目录 1. 显示器分类2. LCD简…...

linux nohup命令详解:持久运行命令,无视终端退出

nohup &#xff08;全称为 “no hang up”&#xff09;&#xff0c;用于运行一个命令&#xff0c;使其在你退出 shell 或终端会话后继续运行。 基本语法 nohup command [arg1 ...] [&> output_file] &command 是你想要运行的命令。[arg1 ...] 是该命令的参数。&am…...

PS系统教程09

修复照片 修饰工具 污点修复画笔工具&#xff08;J&#xff09; 主要作用&#xff1a;去除一些污点或者不需要的 【&#xff1a;缩小】&#xff1a;放大 目标&#xff1a;去掉这两个点 修复画笔工具 也就是说我们要有取样点 选择修复画笔工具按住Alt键吸取周边相近颜色松开单机…...

2024089期传足14场胜负前瞻

2024089期售止时间为6月3日&#xff08;周一&#xff09;22点00分&#xff0c;敬请留意&#xff1a; 本期1.5以下赔率5场&#xff0c;1.5-2.0赔率5场&#xff0c;其他场次是平半盘、平盘。本期14场难度偏低。以下为基础盘前瞻&#xff0c;大家可根据自身判断&#xff0c;复选增…...

备战十一届大唐杯国赛预选赛

这次省赛带了太多个省一了&#xff0c;具体可看下面的图片&#xff0c;只放了一部分。目前根据可靠消息&#xff0c;应该还有个预选赛和去年一样&#xff0c;就是还会考一次仿真。如果说通过了就是国二起步然后去北方工业争夺国一国二&#xff0c;没过的话就是国三。 每…...

安装 Android Studio 2024.1.1.6(Koala SDK35)和过程问题解决

记录更新Android Studio版本及适配Android V应用配置的一些过程问题。 安装包&#xff1a;android-studio-2024.1.1.6-windows.exe原版本&#xff1a;Android Studio23.2.1.23 Koala 安装过程 Uninstall old version 不会删除原本配置&#xff08;左下角提示&#xff09; Un…...

美团一面:什么是CAS?有什么优缺点?我说你说的是AtomicInteger吗?

引言 传统的并发控制手段&#xff0c;如使用synchronized关键字或者ReentrantLock等互斥锁机制&#xff0c;虽然能够有效防止资源的竞争冲突&#xff0c;但也可能带来额外的性能开销&#xff0c;如上下文切换、锁竞争导致的线程阻塞等。而此时就出现了一种乐观锁的策略&#x…...

【linux】(2)文件内容排序sort

sort 是一个用于排序文件内容的命令行工具&#xff0c;在 Linux 和 Unix 系统中非常常用。 基本用法 sort [OPTION]... [FILE]...常用选项 按数值排序 -n sort -n filename例子&#xff1a;对包含数值的文件进行排序。 按字典顺序排序 -d sort -d filename例子&#xff1…...

css 图片上添加模糊背景的文字内容

html部分 <div class"onlogo"> <img src"../assets/img/banner.png" /><div class"imgText"><div class"title">一体化电子印章应用服务</div><div class"content">为企业提供安全可靠…...

Python3 函数参数

前言 本文主要介绍python中的函数参数&#xff0c;主要内容包括形式参数与实际参数的概念、位置参数、关键字参数、默认参数、可变参数。 文章目录 前言一、形式参数与实际参数的概念二、位置参数&#xff08;也叫必需参数&#xff09;三、关键字参数四、默认参数五、可变参数…...

精准检测,可燃气体报警系统的技术原理与特点

在现代化的工业生产与日常生活中&#xff0c;可燃气体泄露事故频发&#xff0c;给人们的生命和财产安全带来了严重威胁。 因此&#xff0c;可燃气体报警检测系统的应用变得尤为重要。它不仅能够实时监测环境中的可燃气体浓度&#xff0c;还能在发现异常情况时及时报警&#xf…...

6月2(信息差)

&#x1f30d;特斯拉&#xff1a;Model3高性能版预计6月中旬开启首批交付 &#x1f384;微软对开源字体 Cascadia Code 进行重大更新 ✨天猫618加码引爆消费热潮 截至晚9点185个品牌成交破亿 1.瑞士清洁科技公司Librec开发废旧锂离子电池回收技术&#xff0c;可回收电池90%的…...

先锋文汇发稿技巧方法

v&#xff1a;yangwei013049 看到标题&#xff0c;有的同志也许会说&#xff0c;投稿就是把稿子发走就行了呗&#xff0c;这要讲究什么方法呢&#xff1f;其实&#xff0c;投稿里面也有学问。不会投稿&#xff0c;方法不当&#xff0c;往往得不到好的效果。 从我多年的实践和…...

无人机推流/RTMP视频推拉流EasyDSS无法卸载软件是什么原因?

视频推拉流/直播点播EasyDSS平台支持音视频采集、视频推拉流、播放H.265编码视频、存储、分发等视频能力服务&#xff0c;在应用场景中可实现视频直播、点播、转码、管理、录像、检索、时移回看等。此外&#xff0c;平台还支持用户自行上传视频文件&#xff0c;也可将上传的点播…...

QML信号连接到c++的槽函数(五)

文章目录 前言一、QML Signal and Handler Event System二、QML信号连接到c++的槽函数代码实例1. 创建一个QML 工程2. 用C++ 实现一个QML Types3. 代码实例4. 运行结果总结参考资料前言 本文主要介绍,如何将QML 中的信号连接到C++ 中的槽函数 软硬件环境: 硬件:PC 软件:wi…...

[Windows] 植物大战僵尸杂交版

游戏包含冒险模式、挑战模式、生存模式三种不同玩法。冒险模式主打关卡闯关&#xff0c;挑战模式则挑战特殊设计的关卡&#xff0c;生存模式结合无尽模式和特殊地图&#xff0c;各具特色。玩家可根据喜好自由选择模式&#xff0c;体验不同的游戏乐趣。快来尝试这款独特的pvz游戏…...

JVM之【GC-可达性分析算法】

在Java虚拟机&#xff08;JVM&#xff09;中&#xff0c;可达性分析算法&#xff08;Reachability Analysis&#xff09;用于垃圾收集&#xff0c;以确定哪些对象是“可达”的&#xff0c;即哪些对象仍然有用&#xff0c;哪些对象可以被回收。下面是对可达性分析算法及其底层实…...

【机器学习】——驱动智能制造的青春力量,优化生产、预见故障、提升质量

目录 一.优化生产流程 1.1 数据收集 1.2 数据预处理 1.3 模型训练 1.4 优化建议 1.5 示例代码 二.预测设备故障 2.1 数据收集 2.2 数据预处理 2.3 模型训练 2.4 故障预测 2.5 示例代码 三.提升产品质量 3.1 数据收集 3.2 数据预处理 3.3 模型训练 3.4 质量提升…...

Python实用代码片段分享(三)

在今天的博文中&#xff0c;我们将继续分享一些Python编程中非常实用的代码片段。这些代码片段将帮助你更高效地处理常见任务&#xff0c;从字符转换到数据类型检查&#xff0c;应有尽有。 1. ord函数和chr函数 Python的ord()函数可以返回Unicode字符对应的ASCII码值&#xf…...

树形结构-CRUD接口

先看一下效果&#xff1a;整体的效果 新增效果 --默认值是 default 修改效果 - 大致效果如上 --------------------------------------------------------------------------------------------------------------------------------- 下面讲解代码如何实现的 根据你使用…...

【Qt知识】Qt窗口坐标系

Qt的窗口坐标体系遵循标准的计算机图形坐标系统规则 Qt窗口坐标体系特点 坐标原点&#xff1a;窗口坐标体系的原点位于窗口的左上角&#xff0c;即坐标(0, 0)位置。 轴方向&#xff1a; X轴&#xff1a;向右为正方向&#xff0c;随着X坐标值的增加&#xff0c;元素在窗口中从…...

SAP Build引言

前言 SAP Build 似乎是一个整合了很多低代码或无代码产品的平台&#xff0c;最早的时候应该都是各自分开的几个产品&#xff0c;近年合并到一块上了SAP Build平台 现在看官网的介绍应该是有三四个产品被集成进来了&#xff0c;分别是SAP IRPA&#xff0c;SAP Workflow&#xf…...

2024上海国际钢丝绳及吊索具展览会

2024上海国际钢丝绳及吊索具展览会 2024 Shanghai International Wire Rope and Hanger Exhibition 时间&#xff1a;2024年12月18日--20日 地点&#xff1a;上海新国际博览中心 详询主办方陆先生 I38&#xff08;前三位&#xff09; I82I&#xff08;中间四位&#xff…...

记一次mysql索引优化

生产日志告警出现一条慢 sql 告警, 通过 sql 监控平台拿到 这条sql 语句是 : SELECTid,report_id,report_detail_id,item_code,report_type,photo FROM**** 表 WHEREdel_flag 0 AND (report_type 1 AND report_detail_id IN ( 1742 )) 之后用 explain 分析这条 sql 的命中…...

【Javascript系列】Terser通过调用API来实现代码的压缩和优化功能

Terser通过调用API来实现代码的压缩和优化功能 起源通过API来调用API调用过程中的一个隐含的技术点 - 异步调用和Promise对象官方文档中的一个有点容易忽略和混淆的地方关于Promise 起源 书接 上回&#xff0c;对Terser的功能做了一个初步的探索。在官方的主页上&#xff0c;有…...

嵌入式期末复习

一、选择题&#xff08;20&#xff09; 二、判断题&#xff08;10&#xff09; 三、填空题&#xff08;10&#xff09; 主机-目标机的文件传输方式主要有串口传输方式、网络传输方式、USB接口传输方式、JTAG接口传输方式、移动存储设备方式。常用的远程调试技术主要有 插桩/st…...

生信算法7 - 核酸序列Fasta和蛋白PDB文件读写与检索

python 3.9实现以下算法。 1. 简单的写文件和读文件 # 写 file1 open(count.txt,w) file1.write(this is a test) file1.close()# 读 file2 open(my_file) print(file2.read())2. 将列表内容写入文本文件 # 生成100-500数字列表 data [i * 100 for i in range(1, 6)] pri…...

【Python】Python异步编程

Python 异步编程 异步编程 异步编程是一种编程范式&#xff0c;通过非阻塞的方式执行任务&#xff0c;允许程序在等待某些操作&#xff08;如I/O操作、网络请求、数据库查询等&#xff09;完成时&#xff0c;继续执行其他任务。这与同步编程&#xff08;或阻塞编程&#xff09…...

pytorch笔记:自动混合精度(AMP)

1 理论部分 1.1 FP16 VS FP32 FP32具有八个指数位和23个小数位&#xff0c;而FP16具有五个指数位和十个小数位Tensor内核支持混合精度数学&#xff0c;即输入为半精度&#xff08;FP16&#xff09;&#xff0c;输出为全精度&#xff08;FP32&#xff09; 1.1.1 使用FP16的优缺…...

R语言ggplot2包绘制世界地图

数据和代码获取&#xff1a;请查看主页个人信息&#xff01;&#xff01;&#xff01; 1. 数据读取与处理 首先&#xff0c;从CSV文件中读取数据&#xff0c;并计算各国每日收入的平均签证成本。 library(tidyverse) ​ df <- read_csv("df.csv") %>% group_…...