【Nano Framework ESP32篇】使用 LCD 屏幕
在开始主题之前,先介绍一个刷固件工具。这个工具在 idf 中是集成的,不过,乐鑫也单独发布了这个工具—— esptool。下载链接:Releases · espressif/esptool · GitHub。这货是用 Python 写的,只是封装成了 exe,方便直接运行罢了。
在使用时,需要 -p 参数指定串口号,如 COM15,-b 指定波特率(可以省略)。下面咱们尝试用 flash_id 指令来获取 ESP32 的 Flash 信息。
esptool -p com13 flash_id
输出结果如下:
老周有很多块 esp 开发板,如你所见,这块板的 flash 是 16MB 的。请记住这个容量,待会刷 nanoCLR 时它会出事故。咱们再看看另一块板的 flash 信息。
这个是 8MB 的,注意在芯片名称后有个 revision 参数(修订号),因为找固件时,要考虑这个参数,3 以上的才能选 rev3 的固件,其他只能选 rev0。
有时候,固件也分有 PSRAM 和 无 PSRAM 的,不过这个一般能通用。
接下来,老周先说明一下如何解决 bootloader 的 Hash 验证导致的问题。咱们重现一下灾难现场:
A、找一个固件,解压。
B、咱们用上面 16MB 那个来刷。
esptool -p COM9 -b 115200 write_flash -fs 16MB -fm dio -ff 40m 0x1000 "E:\demo\bootloader.bin" 0x8000 "E:\demo\partitions_16mb.bin" 0x10000 "E:\demo\nanoCLR.bin"
write_flash 指令就是刷固件,把文件写入 Flash。它常用这些选项:
1、-fs:flash大小,如 8MB、16MB;
2、-fm:SPI 模式,如 dio、qio、dout;
3、-ff:通信速率,如 40m(一般就这个值)。
选项之后就是文件列表,列表按照 <偏移地址> <文件路径>的方式依次列出,比如上面的 0x1000 bootloader.bin 就是在0x1000处写入 bootloader。在 0x8000 处写入分区表。因为 flash 是 16MB 的,所以我就用 16MB 的分区表。
刷完后,打开串口读取一下信息,看看有没有正常启动 CLR。咱们不需要安装串口工具,在 VS Code 的扩展里面就有,叫 Serial Monitor,属于微软大法的一种。安装扩展后打开终端面板,你会看到有个串口监视器,切换过去,选择串口号,点击【开始监视】即可。
C、你会发现 ESP32 在无限重启。停止串口监视后查看错误。
不是 16MB 的吗,怎么变成 4MB 的。这里它是认为 Flash 是 4MB的,刷入了 16MB 的分区表,自然就会认为超出容量,所以后面的分区找不到了。
如果你的命令窗口还没关闭,你可以回去看看刚才执行 esptool 后输出的警告:
Warning: Image file at 0x1000 is protected with a hash checksum, so not changing the flash size setting. Use the --flash_size=keep option instead of --flash_size=16MB in order to remove this warning, or use the --dont-append-digest option for the elf2image command in order to generate an image file without a hash checksum
bootloader 在生成的时候嵌入了 SHA256 的哈希值,也就是说这个镜像在编译时是配置为 4MB 大小的。由于无法通过校验,只能按 4M 的大小来刷,16 MB 的分区当然超出范围了。乐鑫团队称将来的版本可能会取消这个校验,但目前是需要校验的。
解决方案:
方案1:刷固件时,选 4MB 的分区表。这是最简单的方案。
方案2:自己编译固件。如果你有配置 IDF 环境(注意是 4xx 版本的,不是最新的),然后 clone 下 nf-interpreter 项目,可以自己把 SDK 配置为 16MB,编译出来的 bootloader 就是匹配 16 MB 的。
方案3:这个好搞一些。直接编译个 bootloader 替换掉原来的,就不用重新编译 nanoCLR 了。
下面老周就演示一下如何进行方案3。bootloader 是通用的,不必考虑 IDF 版本。IDF 版本切换比较麻烦,可以用多个非安装版 VS Code,来配置多个环境,或者用多个 WSL 来配置也行。反正你爱咋弄就咋弄。或者直接写个脚本来配置环境变量,然后启动相关程序。
不过,这里咱们只用到 bootloader,可以用最新的 IDF 去编译,体积就大一点点,能刷进去的,不影响,毕竟在 0x1000 - 0x8000 的空间范围是够用的,不用也白浪费。
打开 VS Code,点击侧边栏上的乐鑫图标,选择“New Project Wizard”。
然后等待两年半,会打开一个配置页。
后面的串口号 ESP 芯片类型的可以不管,后面可以通过状态栏图标修改。然后点 Choose Template。
到了这里,要选一个项目模板。分组选 ESP-IDF,找到 get-start,用 sample_project 模板就行了,这个最简洁,比 hello XXX 还简洁。
选择好后,点 Create project using template <你选的模板> 按钮,然后它会提示你是否打开创建的项目,如果 Yes,会用新窗口打开。如果不想这么反人类,可以选 No,然后在 VS Code 中手动打开项目目录即可。
这个项目咱们不用写代码,在状态栏中找到 SDK 配置按钮,点它,然后等待两年半。
这个设置页经常会无响应,如果等了三年半还没打开配置页,可以点取消,然后重新点配置按钮。
配置页打开后,找到“Serial flasher config” 节点,注意是顶层节点,不是 Bootloader config 下面那个。把 Flash size 改为你要的大小,比如这里我要 16 MB。
设置好后点击页面顶部的 【保存】 按钮,最后关闭页面。
直接编译项目即可。这里老周是图方便,毕竟用项目来编译 bootloader 可以少很多麻烦。当然,bootloader 是可以单独编译的,在IDF的 components\bootloader\subproject 目录下就是独立的 bootloader 项目。不要直接在这里操作,而是把 subproject 目录中的内容复制到其他目录再编译,这可以保证 SDK 目录不受破坏。这种方法配置起来特烦,而且容易报一堆错,所以还是直接编译项目来得爽。
项目编译后会生成 bootloader.bin 文件,把它复制并替换 nanoCLR 中的 bootloader(在 build\bootloader 目录下找到 bootloader.bin 文件)。接着,重新刷一下 nanoCLR 固件。
esptool -c esp32 -p COM9 -b 115200 write_flash -fs 16MB -fm dio -ff 40m 0x1000 "E:\demo\bootloader.bin" 0x8000 "E:\demo\partitions_16mb.bin" 0x10000 "E:\demo\nanoCLR.bin"
刷写完成后,再打开串口监视器,你能看到你想要的东西(也可以用 flash_download_tool 来烧录的)。
启动 VS,打开 Device explorer,点“Ping Device” 按钮,如果看到 “XXX @ COM9 is active running nanoCLR.“ 的字样就说明没问题了。
----------------------------------------------------------------------------------------------------------------------------------
好了,正片现在开始。要在 .NET Nano 中使用 LCD 屏幕,必须使用带有图形驱动的固件,否则是无法运行的。因为 .NET 类库不带驱动。打开固件下载页:Cloudsmith - Repositories - .NET nanoFramework (net-nanoframework) - nanoframework-images (nanoframework-images) - Packages
点击 package groups,进入分组视图,这样找固件方便。
支持图形驱动的有以下几组:
a、ESP32_GenericDisplay_REV0:通用型,针对 revision < 3 的板子。
b、ESP32_PSRAM_BLE_GenericGraphic_REV3:通用版,支持 BLE,要求 Revision >= 3。
c、面向 M5Stack Core 或 Core 2 的固件;
d、面向 M5StickC 和 M5StickCPlus 的固件。
M5StickCPlus 2 是最新改进的,但 nanoCLR 没有区配,不过,经过老周测试,M5StickC Plus 2 能正常使用。M5StuckC Plus 2 老周有这个,黄色外壳,跟U盘差不多大。
M5Stack 的东西,说实话,价格偏高,做工也一般般。唯一的好处是有外壳(虽然外壳也是歪的),做成品放到项目上用比较方便。当然,如果批量使用也可以找人设计外壳,再给工厂批量做,这比买 M5Stack 的性价比高。
不过,老周今天拿来演示的是另一款。这款是高仿 M5Stack Core 的,价格便宜了一半,唯一不同的是,比 M5Stack 少了功放芯片,不能用 i2S 输出音频,喇叭是直接连到 GPIO 25 的,用 DAC 来输出。ESP32 的数模转换只有 8 位,所以音质嘛,也就是听个响。
这个开发板只能刷通用固件,即 ESP32_GenericDisplay_REV0。刚才老周已经用替换 bootloader 的方式刷了 16MB 的固件,待会咱们可以直接编程。
LCD 屏幕的驱动芯片,见得多的是 St77xx 和 iLi93xx。如 St7789、iLi9341 等。这些芯片虽然多,不过用法差不多,99.997% 用 SPI 协议,所以咱们也不用关心时序的事了。但有个别引脚也要注意的,如区分命令(Command)和数据(Data)的数据线,复位线等。
说是SPI 协议,但这些玩意儿有 N 多种接线方式,有单线、双、四、八、十六线通信的接法。不过,以老周浅薄的经验来看,单线和八线的见得多。
1、八线:即数据线有八根,D0 - D7,一根线发一个位,一起发送一次可以发一个字节。八根线统一由时钟线来控制,时钟快慢决定了发数据的速度。这种接线法太浪费 IO 口,ESP32 本身引脚不多,所以,ESP 系列开发板很少这种连接,倒是 K210 开发板较多。
2、单线:即一根数据线,由时钟线控制。ESP 系列开发板一般是这种接法。
由于只有一根线(MOSI),没有 MISO 连接,所以写的时候方便,读的时候就难搞。如果真要读,就得重新初始化 SPI,把连接数据线的引脚调为 MISO,读完后又重新初始化为写(MOSI)。想法是这样,但老周从未试过,毕竟这样折腾比较影响效率。最重要的是,LCD 屏最主要的任务是显示,咱们尽管向它写数据就够了,很少会读数据。
这里顺便解释一个容易被误解的事。很多大伙伴(不管你用C语言,Arduino 或别的)在入门的时候都遇到过屏幕无法点亮的事。然后大伙就各种自我检讨,是我协议设置不对吗?是我用的这个库封装有错?是我的板子挂了?还是……人品问题。如果你没做过什么见不得人的事,那不用怀疑人品。其实是大伙在看原理图时没认真看。K210 开发板一般不会单独接背光的线,所以你在 K210 开发上可以写寄存器来调光。可是,许多 ESP32 开发板是有一根专门的背光线的。例如,请看下面这个原理图。
这个图告诉你,G7 控制 LCD 的背光。再看另一张图。
这个比较复杂,背光开关 EN 接 G27,即 G27 是 LCD 背光控制线。SGM2578 控制电力分配(可能是带电池的原因,电池和外部供电的均衡),WS4622 是控制LED的 RGB 通道调光用的,和 WS 2812 等是一类货色。
这就是你点不亮屏幕的原因,背光线是独立连接的,你写驱动芯片的寄存器是不起作用的,你必须给背光线输出高电平,LCD 屏才会亮起。当然了,你给它输出 PWM 也行,还能调亮度呢,但可能会频闪;不想频闪的话可以用 DAC 给它输出模拟电压,也能达到调光的效果。
.NET Nano 封装的 .NET API 在 Graphics 包中,所以,打开 Nuget 包管理器,安装 nanoFramework.Graphics 包,另外,咱们要操作 SPI 和 GPIO(GPIO是那根背光线,我们要让屏幕亮起),还要安装以下三个包:
nanoFramework.System.Device.Spi;
nanoFramework.System.Device.Gpio;
nanoFramework.Hardware.Esp32
老周这款高仿板用的是 iLi9342C,用 iLi9341 的驱动也通用。还得安装一个 iLi9642 的专用包:nanoFramework.Graphics.Ili9342。如果你用的是其他芯片,可以安装对应的包,如 St7735 等。
先声明一下要用到的引脚,这个你要按照你的开发板来,找卖家要原理图。如果卖家不给或给的图是错的,可以退货。老周就因为这个原因退过两次货。
const int PIN_CLK = 18; // 时钟线
const int PIN_MOSI = 23; // 数据线
const int PIN_MISO = 34; // 用不上,但需要指定
const int LCD_DC = 27; // 命令/数据切换线
const int LCD_RESET = 33; // 复位线
const int LCD_CS = 14; // 片选
const int LCD_BL = 32; // 背光线
时钟线和数据线就不说了,和标准 SPI 的含义一样。有一条 D/C 线,有的叫 W/S 线,它的作用时:D/C 低电平时表示发送命令,D/C 高电平时表示发数据。复位线:高电平正常,低电平复位。在初始化时,先拉低复位线,然后进行各种初始化设置,完成后再把复位线拉高,复位完毕。
发送命令的过程:D/C线拉低 ----> 写入命令(通常就是一个字节);
发送数据的过程:D/C线拉高 ----> 写入数据(可能是一个字节,可能是多个,也可能是0个,如果没有数据,这个过程直接忽略)。
这几个驱动芯片用起来都差不多,就是写寄存器,甚至连寄存器的编号都相同。
当然,咱们用封装过的 iot 框架的目的,就是牺牲性能来换取开发应用的便捷,所以 .NET Nano 已经封装好了,咱们不用去写寄存器。使用 DisplayControl 类(nanoFramework.UI 命名空间)就能往 LCD 屏里写入颜色。这个类公开的都是静态成员,不用实例化。
1、初始化引脚功能。由于 ESP32 的引脚是复用的,所以对于 SPI 的时钟线、数据线要设置。
Configuration.SetPinFunction(PIN_MOSI, DeviceFunction.SPI1_MOSI);
Configuration.SetPinFunction(PIN_CLK, DeviceFunction.SPI1_CLOCK);
Configuration.SetPinFunction(PIN_MISO, DeviceFunction.SPI1_MISO);
2、先给背光线来一波高电平,不然LCD不亮。
GpioController ctrl = new();
var pinbl = ctrl.OpenPin(LCD_BL);
pinbl.SetPinMode(PinMode.Output);
pinbl.Write(PinValue.High);
3、配置控制屏幕的 SPI 参数,类型是 SpiConfiguration, 也是在 UI 命名空间下。
SpiConfiguration spicfg = new(
spiBus: 1,
chipselect: LCD_CS,
dataCommand: LCD_DC,
reset: LCD_RESET,
backLight: -1 // 这里不用指定背光线,要单独控制才有效
);
注意不要在这里指定 backLight 参数,点不亮的,因为许多板子,背光线不是集成在屏幕上,也就不会与屏幕直接连接,所以设置这个是无效的,我们刚刚单独处理了。
4、用 ScreenConfiguration 类配置屏幕参数,如宽度、高度,还有x、y坐标的偏移。这个偏移是需要的,因为不同的屏幕不一样,有的要偏移 45,有的则要偏移 52。这个可以通过实验不断调校,调到合适的值就好。主要是因为显示的内容不一定是从屏幕左上角开始的,经常会跑到屏幕外面。K210 的板子不用调整这个,但 ESP32 的板子需要调整,原因未知。
// 获取驱动
var driver = Ili9342.GraphicDriver; // 自定义初始化
driver.InitializationSequence = new byte[]
{
(byte)GraphicDriverCommandType.Command, 1, 0x21,
(byte)GraphicDriverCommandType.Command, 2, 0x3a, 0x55,
(byte)GraphicDriverCommandType.Command, 5, 0x2a, 0x00, 0x00, 0x01, 0x3f,
(byte)GraphicDriverCommandType.Command, 5, 0x2b, 0x00, 0x00, 0x00, 0xef,
(byte)GraphicDriverCommandType.Command, 1, 0x11,
(byte)GraphicDriverCommandType.Command, 1, 0x29
}; // 配置屏幕
ScreenConfiguration scrcfg = new(
0,
0,
320,
240,
driver
);
通过 Ili9342.GraphicDriver 静态成员可以获得相关的驱动。如果你的板子是 St7789,那就改为对应的类。注意上面代码中高亮的部分,即
driver.InitializationSequence = new byte[]
{
(byte)GraphicDriverCommandType.Command, 1, 0x21,
(byte)GraphicDriverCommandType.Command, 2, 0x3a, 0x55,
(byte)GraphicDriverCommandType.Command, 5, 0x2a, 0x00, 0x00, 0x01, 0x3f,
(byte)GraphicDriverCommandType.Command, 5, 0x2b, 0x00, 0x00, 0x00, 0xef,
(byte)GraphicDriverCommandType.Command, 1, 0x11,
(byte)GraphicDriverCommandType.Command, 1, 0x29
};
这里是设置初始化指令,这个是因为老周这个板特别,iLi9342 默认上电是正色显示的(即关闭反色),可是这块鸟板正色时它显示反色,反色时它却显示正色。所以,默认的初始化方式不适用,只能自己写寄存器了。其实这些芯片上电时很多默认值都能用的,并不需要改太多的寄存器。
老周简音介绍一下这个指令的格式。
1)这些指令就是 byte 数组;
2)多条指令可以连接写到一个数据组中;
3)每条指令的第一个字节代表指令类别。1 表示一条正常发送的指令(Command),0 表示 Sleep。你可别误会,这个 Sleep 不是让 LCD驱动芯片休眠,而是暂停一下(就像 Thread.Sleep 方法),SPI 不发送罢了。
4)如果是第一个字节是 Command,那么第二个字节是长度(SPI要发多少字节),从第三个字节起就是真正要发送的。比如,0x01,0x03,0x22,0x15,0x8d。第一个 0x01 表明它是一条正常发出的指令,第二个是 03 表示后面有三个字节,而 SPI 真正发送的是 0x22,0x15,0x8d。这三个字节中,0x22 表示驱动命令(寄存器),0x15和0x8d表示要写入寄存器的数据。
5)如果第一个字节是 Sleep,后面需要跟一个字节,表示暂停时长,单位是 10ms。比如,0x00,0x02,第一个 0x00 表示暂停,0x02 表示暂停 2 * 10 = 20 毫秒。
好,弄懂这个,咱们回头看看老周刚写的初始化命令:
=> 发送 0x21,单命令,没有参数,所以只有一个字节。0x21 本来是开启反色显示的,关闭反色显示是 0x20 寄存器。由于老周这块板不知怎么回事,是反过来的。
=> 发送 0x3a,设置像素格式为 16 位,RGB565。0x55 上这么来的:
第1-3位设置DBI,第5-7位设置DPI,请看下表:
为了减少不必要的麻烦,通常咱们内存处理的像素格式和显示屏显示的一样,所以左右两边都是 101,即5,合起来就是 0x55。
=> 发送 0x2a,设置列的坐标空间,即我们要写入屏幕像素的水平范围。这个屏幕的长是 320,所以,命令参数有四个字节。前两个表示起点,即0;后两个表示终点,0x01,0x3f 组合的16位整数是 319。坐标从 0 起算,320就是319。
=> 发送 0x3b 命令,表示行的坐标空间,参数也是四个字节,范围 0- 239(240即239,要减1)。
=> 发送 0x11 命令,表示让 LCD 离开休眠模式,从而唤醒屏幕,上电时默认休眠。
=> 发送 0x29 命令,打开显示模式,正常呈现画面。
在实例化 ScreenConfiguration 对象时,提供这些参数:
a、屏幕左上角坐标,我这里设置为 0,0,刚刚好,没有偏。如果你测试发现显示的内容跑到屏幕外了,就要适当设置一下偏移坐标,如x=45,y=52。
b、屏幕宽度和高度,这里是 320 * 240。
c、驱动对象,就是刚从 Ili9342.GraphicDriver 返回的。
5、初始化 DisplayControl。
_ = DisplayControl.Initialize(spicfg, scrcfg, 10240);
最后的参数 10240 是预先分配的内存大小,不要弄太大,开发板的运行内存小到无语,分配太大了容易爆。Initialize 方法返回实际可分配的内存,如果内存不够,返回的值可能比你指定的小。这里我不理它,直接忽略。
6、如果能正常使用,这个时候已经可以向屏幕写数据了,咱们把全屏幕填充为蓝色。
// 清空屏幕
DisplayControl.Clear();
ushort color = Color.Red.ToBgr565();
// 宽高
ushort dw = 80, dh = 80;
ushort[] bf = new ushort[dw * dh]; for(int i = 0; i < bf.Length; i++)
{
bf[i] = color;
} while (true)
{
for(ushort x = 0; x < 320; x+=80 )
{
for(ushort y = 0; y < 239; y += 80)
{
DisplayControl.Write(x, y, dw, dh, bf);
Thread.Sleep(300);
}
}
Thread.Sleep(1000);
DisplayControl.Clear();
}
像素格式是 16 位的,即,RGB 加起来16位,正好用一个 uint16 (ushort)可以表示。565表示 R 占5位,G 占6位,剩下5位留给 B。这里明显绿色多占了一位,难道 LCD 屏看上去有些绿。
DisplayControl 类虽然封装后调用方便,但这种封装……反正老周有意见。原因有:1、只能在初始化时修改寄存器,显示内容后无法改了;2、这东西耗内存。
所以,创建用来表示像素的 ushort 数组不能太大,否则会因为内存溢出而无法运行。320 * 240 个 ushort 值会报错。这样就不能一次性填充整个屏幕了,只能分块来填,每块 80 * 80,所以,横着填四块,坚着填三块。在填充完一块后,老周故意 Sleep 一下,这样我们在运行阶段能看到分块填充的效果。
好了,今天就水到这里了。
【Nano Framework ESP32篇】使用 LCD 屏幕的更多相关文章
- [原创].NET 分布式架构开发实战五 Framework改进篇
原文:[原创].NET 分布式架构开发实战五 Framework改进篇 .NET 分布式架构开发实战五 Framework改进篇 前言:本来打算这篇文章来写DAL的重构的,现在计划有点改变.之前的文章 ...
- uboot启动完成,kernel启动时lcd屏幕出现杂色解决办法
先说说开发环境吧: 1 内核:linux2.6.xx 2 uboot:买开发板带的 注释:在最后我又添加了问题得到完美解决的办法. 问题:uboot启动完成,kernel启动时lcd屏幕出现杂色(比如 ...
- Entity Framework 第二篇 事务
Entity Framework 事务 结合第一篇的代码 public class BaseRepository : ITransaction, IDisposable { private XFDb ...
- 和菜鸟一起学android4.0.3源码之lcd屏幕背光调节
周六的中午还是依旧来了公司,本来也没有打算来的,既然来了,那就把上次遗留下来的一些问题给解决吧,把android下的pwm调lcd背光给总结下吧.关于android的背光,是用pwm波来控制的,通过占 ...
- BLE MESH 学习[1] - ESP32 篇
BLE MESH 学习 BLE MESH 是一种蓝牙(n:m)组网的技术. 本篇先介绍 BLE MESH 到使用 ESP32 的官方示例对其进行学习讲解. 后面会进一步学习 SIG 的 BLE MES ...
- AM335x关于LCD屏幕的时钟PLL配置
主要参考的是AM335x的TRM的第8章PRCM模块和13章LCD Controller. 这里在LCD Controller里面的配置描述的比较详细了,分频和像素.消影值的设置等等.不在赘述,很多人 ...
- (Entity framework 应用篇)把权限判断封装在数据库访问层
这里,我只是以一个例子,说一下简单权限控制,通过这个例子,大家可以设计庞大的权限管理层,把权限控制封装到数据库访问层,这样程序员就不用再写权限判断的代码了 首先,先看看我数据库DBContext的定义 ...
- Entity Framework 第九篇 关于自增列的事务处理
如果一个表带有自增列的,那么在事务处理的过程中,如果抑制了提交,自增的序号就不会得到,如果我们需要得到那怎么办呢?可以临时提交,但是既然提交了就要考虑到事务回滚,否则无法满足数据的一致性 public ...
- Entity Framework 第一篇
这段时间研究了orm框架EF 写一写研究的历程和心得 先贴上核心代码 public interface ITransaction { bool IsTransaction { get;} void B ...
- android系统平台显示驱动开发简要:Samsung LCD接口篇『三』
平台信息: 内核:linux3.4.39系统:android4.4 平台:S5P4418(cortex a9) 作者:瘋耔(欢迎转载,请注明作者) 欢迎指正错误,共同学习.共同进步!! 关注博主新浪博 ...
随机推荐
- GitHub WebHook 使用教程
本文收录于 Github.com/niumoo/JavaNotes,Java 系列文档,数据结构与算法! 本文收录于网站:https://www.wdbyte.com/,我的公众号:程序猿阿朗 什么是 ...
- d3d12龙书阅读----绘制几何体(上)
d3d12龙书阅读----绘制几何体(上) 本节主要介绍了构建一个简单的彩色立方体所需流程与重要的api 下面主要结合立方体代码分析本节相关知识 顶点 输入装配器阶段的输入 首先,我们需要定义立方体的 ...
- docker-compose转义相关
环境变量值里面写$美元符号,用两个$符号来转义就可以了 下面的MYSQL_ROOT_PASSWORD的密码是lehuiguan!@#$,转义后写的变量就是lehuiguan!@#$$ environm ...
- IDEA MyBatis Log 插件,打印SQL语句
打开Settings->plugins 搜索插件 MyBatis Log点击安装,完成后重启IDEA即可. 点击Tools,选择 MyBatis Log Plugin ,会在下方打开一个窗口,这 ...
- Scala打印输出
1 package com.atguigu.chapter02 2 object TestCharType { 3 def main(args: Array[String]): Unit = { 4 ...
- python---nltk工具包安装
先在pycharm里安装nltk cmd进入Python输入 import nltk nltk.download()如果下载失败在github上下载语料库:https://github.com/nlt ...
- chrome开发者工具
官方文档 使用 DevTools 的工作区设置持久化 By Dave Gash Dave is a Tech Writer By Kayce Basques Technical Writer for ...
- #主席树,Dijkstra,哈希#CF464E The Classic Problem
题目 边权均为2的幂次的无向图,求 \(S\) 到 \(T\) 的最短路 \(n,m\leq 10^5\) 分析 最短路直接考虑用 Dijkstra,它需要维护松弛操作和堆, 那么也就是要重载加号和小 ...
- #trie#A 区间异或
题目 给定一个长度为\(n\)的序列,询问有多少个\((l,r),1\leq l\leq r\leq n\)满足 \[xor_{l\leq j\leq r}a_j\geq k \] 分析 显然跑一次前 ...
- MogDB/opengauss触发器简介(1)
MogDB/opengauss 触发器简介(1) 触发器是对应用动作的响应机制,当应用对一个对象发起 DML 操作时,就会产生一个触发事件(Event).如果该对象上拥有该事件对应的触发器,那么就会检 ...