37. RGBLCD实验
一、RGBLCD显示原理简介
1、像素点
于一个“小灯“,不管是液晶屏,还是手机,平板,RGBLCD屏幕他都是有由一个个的彩色小灯构成的。彩色点阵屏每个像素点有三个小灯,红色、绿色和蓝色,也叫做RGB。RGB就是光的三原色。通过调整RGB三种颜色的比例,就可以实现姹紫千红的世界。
2、分辨率
要想显示文字,图片,视频等等就需要很多个像素点,分辨率说的就是像素点的个数,1080P、720P、2K、4K,8K。1080P=19201080,表示一行有1920个像素点,一列有1080个。显示器有尺寸!24村,27村、55寸。尺寸不变的情况下,分辨率越高,显示效果越精细。4K=38402160相当于4个1080P
正点原子的RGB屏幕有:4.3寸480272,800480,7寸的800480和1024600,10.1寸的1280800。
Iphone4屏幕尺寸是3.5寸,960640分辨率,PPI=327.
3、像素格式
如何将RGB三种颜色进行量化,每种颜色用8bit表示,RGB就需要888共24bit。可以描述出2^24=中颜色16777216=1677万种颜色。现在流行10bit,HDR10,支持HDR效果的10bit面板,RGB10 10 10。
在RGB888的基础上在加上8bit的ALPHA通道,也就是透明通道,ARGB8888=32位。
4、LCD屏幕接口
RGB格式的屏幕,一般叫做RGB接口屏。
屏幕接口有:MIPI、LVDS、MCU、RGB接口。
正点原子屏幕ID:使用ID可以识别出不同的屏幕,在RGBLCD屏幕上对R7,G7,B7焊接上拉或下拉电阻实现不同的ID。,
正点原子的ALPHA地板RGB屏幕接口用了3个3157模拟开关。原因是防止LCD屏幕上的ID电阻影响到6ULL的启动。
5、LCD时间参数和LCD时序
水平:
HSYNC:水平同步信号,行同步信号,当出现HSYNC信号的时候表示新的一行开始显示
1、产生HSYNC信号,表示新的一行开始显示,HSYNC信号得维持一段时间,这个时间叫做HSPW。
2、HSYNC信号完成以后,需要一段时间延时,这段时间叫做HBP。
3、显示1024个像素点的数据,1024个clk。
3、一行像素显示完成以后,到HSYNC下一行信号的产生之间有个延时,叫做HFP。
因此真正显示一行所需的时间计时HSPW+HBP+WIDTH(屏幕水平像素点个数,比如1024)+HFP=20+140+1024+160=1344CLK.
垂直:
VSYNC:垂直同步信号,帧同步信号,当出现VSYNC信号的时候表示新的一帧开始显示。
1、VSYNC信号,持续一段时间,位VSPW。
2、VSYNC信号完成以后,需要一段时间,叫做VBP
3、VBP信号结束以后,就是要显示的行数,比如600行,
4、所有的行显示完成以后,一段VFP延时,
(VSPW+VBP+height(600)+VFP)* (HSPW+HBP+WIDTH(1024)+HFP)=
像素时钟:
6、显存
显存:显示存储空间,采用ARGB8888=32bit=4B。这4个字节的数据表示一个像素点的信息,必须得存起来。10246004=2.5MB。因此需要流出2.5MB的内存给LCD用,方法很简单,直接定义一个32位的数组,u32 lcdframe[1024*600];
二、6ULL LCDIF控制器接口原理
1、我们使用DOTCLK接口,也就是VSYNC、HSYNC、ENABLE(DE)和DOTCLK(PCLK)
2、LCDIF_CTRL寄存器,bit0必须置1,bit1设置数据格式24位全部有效,设置为0。Bit5设置LCDIF接口工作在主机模式下,要置1。Bit9:8设置输入像素格式位24bit,写3。Bit11:10,设置数据传输宽度位24bit,写3。Bit13:12设置数据交换,我们不需要交换设置位0。Bit15:14设置输入数据交换,不交换设置位0。Bit17置1,LCDIF工作在DOTCLK模式下。Bit19必须置1,因为工作在DOTCL模式。Bit31是复位功能必须置0.
3、LCDIF_CTRL1寄存器的bit19:16设置位0X7。24位的格式,
4、LCDIF_TRANSFER_COUNT寄存器的bit15:0是LCD一行的像素数,1024。Bit31:16是LCD一共有多少行,600行。
5、LCDIF_VDCTRL0寄存器,bit17:0为vspw参数。Bit20设置vsync信号的宽度单位 ,设置为1。Bit21设置为1。Bit24设置ENABLE信号极性,为0的时候是低电平有效,为1是高电平,我们设置为1。Bit25设置CLK信号极性,设置为0.。bit26设置HSYNC信号极性,设置0,低电平有效,bit27设置VSYNC信号极性,设置为0,低电平有效。Bit28设置1,开始ENABLE信号。Bit29设置为0,VSYNC输出。
6、LCDIF_VDCTRL1寄存器为两个VSYNC信号之间的长度,那就是VSPW+ VBPD+HEIGHT+VFP。
7、CDIF_VDCTRL2寄存器bit17:0是两个HSYNC信号之间的长度,那就是hspw+hbp+width+hfp。Bit31:18为hspw。
8、LCDIF_VDCTRL3寄存器,bit15:0是vbp+vspw。Bit27:16是hbp+hspw。
9、LCDIF_VDCTRL4寄存器,bit17:0是一行有多少个像素点,1024
10、LCDIF_CUR_BUF,LCD当前缓存,显存首地址。
11、LCDIF_NEXT_BUF,LCD下一帧数据首地址。
12、LCD IO初始化。
三、LCD像素时钟的设置。
LCD需要一个CLK信号,这个时钟信号是6ULL的CLK引脚发送给RGB LCD的。比如7寸1024600的屏幕需要51.2MHz的CLK。
LCDIF_CLK_ROOT就是6ULL的像素时钟。我们设置PLL5(video PLL)为LCD的时钟源,
PLL5 CLK=FrefDIV_SELECT=,DIV_SELECT就是CCM_ANALOG_PLL_VIDEO的bit6:0,也就是DIV_SELEC位,可选范围27-54。设置PLL_VIDEO寄存器的bit20:19为2,表示1分频。设置CCM_ANALOG_MISC2寄存器的bit31:30为0,也就是VIDOE_DIV为0,1分频。
我们不是用小数分频器,因此CCM_ANALOG_PLL_VIDEO_NUM=0,在设置CCM_ALALOG_PLL_VIDEO_DENOM=0。
CCM_CSCDR2寄存器的bit17:15,设置LCDIF_PRE_CLK_SEL,选择LCDIF_CLK_ROOT的时钟源,设置为0x2。表示LCDIF时钟源为PLL5。Bit14:12为LCDIF_PRED位,设置前级分频,可以设置07,分别对应18分频。
CCM_CBCMR寄存器,bit25:23为LCDIF_PODF,设置第二级分频,可以设置为07,分别对应18分频。
继续设置CCM_CSCDR2寄存器的bit11:9为LCDIF_CLK_SEL,选择LCD CLK的最终时钟源,设置为0,LCDIF的最终时钟源来源于pre-muxed LCDIF clock
四、LCD驱动程序编写
1、如果使用的正点原子的开发板和RGB屏幕,那么在驱动LCD之前,要先读取屏幕ID。
//bsp_lcd.c
#include "bsp_lcd.h"
#include "bsp_gpio.h"
#include "bsp_delay.h"
#include "stdio.h"/* 液晶屏参数结构体 */
struct tftlcd_typedef tftlcd_dev;/** @description : 始化LCD* @param : 无* @return : 无*/
void lcd_init(void)
{lcdgpio_init(); /* 初始化IO */lcdclk_init(32, 3, 5); /* 初始化LCD时钟 */lcd_reset(); /* 复位LCD */delayms(10); /* 延时10ms */lcd_noreset(); /* 结束复位 *//* TFTLCD参数结构体初始化 */tftlcd_dev.height = 600; tftlcd_dev.width = 1024;tftlcd_dev.pixsize = 4; /* ARGB8888模式,每个像素4字节 */tftlcd_dev.vspw = 3;tftlcd_dev.vbpd = 20;tftlcd_dev.vfpd = 12;tftlcd_dev.hspw = 20;tftlcd_dev.hbpd = 140;tftlcd_dev.hfpd = 160;tftlcd_dev.framebuffer = LCD_FRAMEBUF_ADDR; tftlcd_dev.backcolor = LCD_WHITE; /* 背景色为白色 */tftlcd_dev.forecolor = LCD_BLACK; /* 前景色为黑色 *//* 初始化ELCDIF的CTRL寄存器* bit [31] 0 : 停止复位* bit [19] 1 : 旁路计数器模式* bit [17] 1 : LCD工作在dotclk模式* bit [15:14] 00 : 输入数据不交换* bit [13:12] 00 : CSC不交换* bit [11:10] 11 : 24位总线宽度* bit [9:8] 11 : 24位数据宽度,也就是RGB888* bit [5] 1 : elcdif工作在主模式* bit [1] 0 : 所有的24位均有效*/LCDIF->CTRL |= (1 << 19) | (1 << 17) | (0 << 14) | (0 << 12) |(3 << 10) | (3 << 8) | (1 << 5) | (0 << 1);/** 初始化ELCDIF的寄存器CTRL1* bit [19:16] : 0X7 ARGB模式下,传输24位数据,A通道不用传输*/ LCDIF->CTRL1 = 0X7 << 16; /** 初始化ELCDIF的寄存器TRANSFER_COUNT寄存器* bit [31:16] : 高度* bit [15:0] : 宽度*/LCDIF->TRANSFER_COUNT = (tftlcd_dev.height << 16) | (tftlcd_dev.width << 0);/** 初始化ELCDIF的VDCTRL0寄存器* bit [29] 0 : VSYNC输出* bit [28] 1 : 使能ENABLE输出* bit [27] 0 : VSYNC低电平有效* bit [26] 0 : HSYNC低电平有效* bit [25] 0 : DOTCLK上升沿有效* bit [24] 1 : ENABLE信号高电平有效* bit [21] 1 : DOTCLK模式下设置为1* bit [20] 1 : DOTCLK模式下设置为1* bit [17:0] : vsw参数*/LCDIF->VDCTRL0 = 0; //先清零LCDIF->VDCTRL0 = (0 << 29) | (1 << 28) | (0 << 27) |(0 << 26) | (0 << 25) | (1 << 24) |(1 << 21) | (1 << 20) | (tftlcd_dev.vspw << 0);/** 初始化ELCDIF的VDCTRL1寄存器* 设置VSYNC总周期*/ LCDIF->VDCTRL1 = tftlcd_dev.height + tftlcd_dev.vspw + tftlcd_dev.vfpd + tftlcd_dev.vbpd; //VSYNC周期/** 初始化ELCDIF的VDCTRL2寄存器* 设置HSYNC周期* bit[31:18] :hsw* bit[17:0] : HSYNC总周期*/ LCDIF->VDCTRL2 = (tftlcd_dev.hspw << 18) | (tftlcd_dev.width + tftlcd_dev.hspw + tftlcd_dev.hfpd + tftlcd_dev.hbpd);/** 初始化ELCDIF的VDCTRL3寄存器* 设置HSYNC周期* bit[27:16] :水平等待时钟数* bit[15:0] : 垂直等待时钟数*/ LCDIF->VDCTRL3 = ((tftlcd_dev.hbpd + tftlcd_dev.hspw) << 16) | (tftlcd_dev.vbpd + tftlcd_dev.vspw);/** 初始化ELCDIF的VDCTRL4寄存器* 设置HSYNC周期* bit[18] 1 : 当使用VSHYNC、HSYNC、DOTCLK的话此为置1* bit[17:0] : 宽度*/ LCDIF->VDCTRL4 = (1<<18) | (tftlcd_dev.width);/** 初始化ELCDIF的CUR_BUF和NEXT_BUF寄存器* 设置当前显存地址和下一帧的显存地址*/LCDIF->CUR_BUF = (unsigned int)tftlcd_dev.framebuffer;LCDIF->NEXT_BUF = (unsigned int)tftlcd_dev.framebuffer;lcd_enable(); /* 使能LCD */delayms(10);lcd_clear(LCD_WHITE); /* 清屏 */}/** IO引脚: LCD_DATA00 -> LCD_B0* LCD_DATA01 -> LCD_B1* LCD_DATA02 -> LCD_B2* LCD_DATA03 -> LCD_B3* LCD_DATA04 -> LCD_B4* LCD_DATA05 -> LCD_B5* LCD_DATA06 -> LCD_B6* LCD_DATA07 -> LCD_B7** LCD_DATA08 -> LCD_G0* LCD_DATA09 -> LCD_G1* LCD_DATA010 -> LCD_G2* LCD_DATA011 -> LCD_G3* LCD_DATA012 -> LCD_G4* LCD_DATA012 -> LCD_G4* LCD_DATA013 -> LCD_G5* LCD_DATA014 -> LCD_G6* LCD_DATA015 -> LCD_G7** LCD_DATA016 -> LCD_R0* LCD_DATA017 -> LCD_R1* LCD_DATA018 -> LCD_R2 * LCD_DATA019 -> LCD_R3* LCD_DATA020 -> LCD_R4* LCD_DATA021 -> LCD_R5* LCD_DATA022 -> LCD_R6* LCD_DATA023 -> LCD_R7** LCD_CLK -> LCD_CLK* LCD_VSYNC -> LCD_VSYNC* LCD_HSYNC -> LCD_HSYNC* LCD_DE -> LCD_DE* LCD_BL -> GPIO1_IO08 *//** @description : LCD GPIO初始化* @param : 无* @return : 无*/
void lcdgpio_init(void)
{gpio_pin_config_t gpio_config;/* 1、IO初始化复用功能 */IOMUXC_SetPinMux(IOMUXC_LCD_DATA00_LCDIF_DATA00,0);IOMUXC_SetPinMux(IOMUXC_LCD_DATA01_LCDIF_DATA01,0);IOMUXC_SetPinMux(IOMUXC_LCD_DATA02_LCDIF_DATA02,0);IOMUXC_SetPinMux(IOMUXC_LCD_DATA03_LCDIF_DATA03,0);IOMUXC_SetPinMux(IOMUXC_LCD_DATA04_LCDIF_DATA04,0);IOMUXC_SetPinMux(IOMUXC_LCD_DATA05_LCDIF_DATA05,0);IOMUXC_SetPinMux(IOMUXC_LCD_DATA06_LCDIF_DATA06,0);IOMUXC_SetPinMux(IOMUXC_LCD_DATA07_LCDIF_DATA07,0);IOMUXC_SetPinMux(IOMUXC_LCD_DATA08_LCDIF_DATA08,0);IOMUXC_SetPinMux(IOMUXC_LCD_DATA09_LCDIF_DATA09,0);IOMUXC_SetPinMux(IOMUXC_LCD_DATA10_LCDIF_DATA10,0);IOMUXC_SetPinMux(IOMUXC_LCD_DATA11_LCDIF_DATA11,0);IOMUXC_SetPinMux(IOMUXC_LCD_DATA12_LCDIF_DATA12,0);IOMUXC_SetPinMux(IOMUXC_LCD_DATA13_LCDIF_DATA13,0);IOMUXC_SetPinMux(IOMUXC_LCD_DATA14_LCDIF_DATA14,0);IOMUXC_SetPinMux(IOMUXC_LCD_DATA15_LCDIF_DATA15,0);IOMUXC_SetPinMux(IOMUXC_LCD_DATA16_LCDIF_DATA16,0);IOMUXC_SetPinMux(IOMUXC_LCD_DATA17_LCDIF_DATA17,0);IOMUXC_SetPinMux(IOMUXC_LCD_DATA18_LCDIF_DATA18,0);IOMUXC_SetPinMux(IOMUXC_LCD_DATA19_LCDIF_DATA19,0);IOMUXC_SetPinMux(IOMUXC_LCD_DATA20_LCDIF_DATA20,0);IOMUXC_SetPinMux(IOMUXC_LCD_DATA21_LCDIF_DATA21,0);IOMUXC_SetPinMux(IOMUXC_LCD_DATA22_LCDIF_DATA22,0);IOMUXC_SetPinMux(IOMUXC_LCD_DATA23_LCDIF_DATA23,0);IOMUXC_SetPinMux(IOMUXC_LCD_CLK_LCDIF_CLK,0); IOMUXC_SetPinMux(IOMUXC_LCD_ENABLE_LCDIF_ENABLE,0); IOMUXC_SetPinMux(IOMUXC_LCD_HSYNC_LCDIF_HSYNC,0);IOMUXC_SetPinMux(IOMUXC_LCD_VSYNC_LCDIF_VSYNC,0);IOMUXC_SetPinMux(IOMUXC_GPIO1_IO08_GPIO1_IO08,0); /* 背光BL引脚 *//* 2、配置LCD IO属性 *bit 16:0 HYS关闭*bit [15:14]: 0 默认22K上拉*bit [13]: 0 pull功能*bit [12]: 0 pull/keeper使能 *bit [11]: 0 关闭开路输出*bit [7:6]: 10 速度100Mhz*bit [5:3]: 111 驱动能力为R0/7*bit [0]: 1 高转换率*/IOMUXC_SetPinConfig(IOMUXC_LCD_DATA00_LCDIF_DATA00,0xB9);IOMUXC_SetPinConfig(IOMUXC_LCD_DATA01_LCDIF_DATA01,0xB9);IOMUXC_SetPinConfig(IOMUXC_LCD_DATA02_LCDIF_DATA02,0xB9);IOMUXC_SetPinConfig(IOMUXC_LCD_DATA03_LCDIF_DATA03,0xB9);IOMUXC_SetPinConfig(IOMUXC_LCD_DATA04_LCDIF_DATA04,0xB9);IOMUXC_SetPinConfig(IOMUXC_LCD_DATA05_LCDIF_DATA05,0xB9);IOMUXC_SetPinConfig(IOMUXC_LCD_DATA06_LCDIF_DATA06,0xB9);IOMUXC_SetPinConfig(IOMUXC_LCD_DATA07_LCDIF_DATA07,0xB9);IOMUXC_SetPinConfig(IOMUXC_LCD_DATA08_LCDIF_DATA08,0xB9);IOMUXC_SetPinConfig(IOMUXC_LCD_DATA09_LCDIF_DATA09,0xB9);IOMUXC_SetPinConfig(IOMUXC_LCD_DATA10_LCDIF_DATA10,0xB9);IOMUXC_SetPinConfig(IOMUXC_LCD_DATA11_LCDIF_DATA11,0xB9);IOMUXC_SetPinConfig(IOMUXC_LCD_DATA12_LCDIF_DATA12,0xB9);IOMUXC_SetPinConfig(IOMUXC_LCD_DATA13_LCDIF_DATA13,0xB9);IOMUXC_SetPinConfig(IOMUXC_LCD_DATA14_LCDIF_DATA14,0xB9);IOMUXC_SetPinConfig(IOMUXC_LCD_DATA15_LCDIF_DATA15,0xB9);IOMUXC_SetPinConfig(IOMUXC_LCD_DATA16_LCDIF_DATA16,0xB9);IOMUXC_SetPinConfig(IOMUXC_LCD_DATA17_LCDIF_DATA17,0xB9);IOMUXC_SetPinConfig(IOMUXC_LCD_DATA18_LCDIF_DATA18,0xB9);IOMUXC_SetPinConfig(IOMUXC_LCD_DATA19_LCDIF_DATA19,0xB9);IOMUXC_SetPinConfig(IOMUXC_LCD_DATA20_LCDIF_DATA20,0xB9);IOMUXC_SetPinConfig(IOMUXC_LCD_DATA21_LCDIF_DATA21,0xB9);IOMUXC_SetPinConfig(IOMUXC_LCD_DATA22_LCDIF_DATA22,0xB9);IOMUXC_SetPinConfig(IOMUXC_LCD_DATA23_LCDIF_DATA23,0xB9);IOMUXC_SetPinConfig(IOMUXC_LCD_CLK_LCDIF_CLK,0xB9);IOMUXC_SetPinConfig(IOMUXC_LCD_ENABLE_LCDIF_ENABLE,0xB9);IOMUXC_SetPinConfig(IOMUXC_LCD_HSYNC_LCDIF_HSYNC,0xB9);IOMUXC_SetPinConfig(IOMUXC_LCD_VSYNC_LCDIF_VSYNC,0xB9);IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO08_GPIO1_IO08,0xB9); /* 背光BL引脚 *//* GPIO初始化 */gpio_config.direction = kGPIO_DigitalOutput; /* 输出 */gpio_config.outputLogic = 1; /* 默认关闭背光 */gpio_init(GPIO1, 8, &gpio_config); /* 背光默认打开 */gpio_pinwrite(GPIO1, 8, 1); /* 打开背光 */
}/** @description : LCD时钟初始化, LCD时钟计算公式如下:* LCD CLK = 24 * loopDiv / prediv / div* @param - loopDiv : loopDivider值* @param - loopDiv : lcdifprediv值* @param - div : lcdifdiv值* @return : 无*/
void lcdclk_init(unsigned char loopDiv, unsigned char prediv, unsigned char div)
{/* 先初始化video pll * VIDEO PLL = OSC24M * (loopDivider + (denominator / numerator)) / postDivider*不使用小数分频器,因此denominator和numerator设置为0*/CCM_ANALOG->PLL_VIDEO_NUM = 0; /* 不使用小数分频器 */CCM_ANALOG->PLL_VIDEO_DENOM = 0; /** PLL_VIDEO寄存器设置* bit[13]: 1 使能VIDEO PLL时钟* bit[20:19] 2 设置postDivider为1分频* bit[6:0] : 32 设置loopDivider寄存器*/CCM_ANALOG->PLL_VIDEO = (2 << 19) | (1 << 13) | (loopDiv << 0); /** MISC2寄存器设置* bit[31:30]: 0 VIDEO的post-div设置,时钟源来源于postDivider,1分频*/CCM_ANALOG->MISC2 &= ~(3 << 30);CCM_ANALOG->MISC2 = 0 << 30;/* LCD时钟源来源与PLL5,也就是VIDEO PLL */CCM->CSCDR2 &= ~(7 << 15); CCM->CSCDR2 |= (2 << 15); /* 设置LCDIF_PRE_CLK使用PLL5 *//* 设置LCDIF_PRE分频 */CCM->CSCDR2 &= ~(7 << 12); CCM->CSCDR2 |= (prediv - 1) << 12; /* 设置分频 *//* 设置LCDIF分频 */CCM->CBCMR &= ~(7 << 23); CCM->CBCMR |= (div - 1) << 23; /* 设置LCD时钟源为LCDIF_PRE时钟 */CCM->CSCDR2 &= ~(7 << 9); /* 清除原来的设置 */CCM->CSCDR2 |= (0 << 9); /* LCDIF_PRE时钟源选择LCDIF_PRE时钟 */
}/** @description : 复位ELCDIF接口* @param : 无* @return : 无*/
void lcd_reset(void)
{LCDIF->CTRL = 1<<31; /* 强制复位 */
}/** @description : 结束复位ELCDIF接口* @param : 无* @return : 无*/
void lcd_noreset(void)
{LCDIF->CTRL = 0<<31; /* 取消强制复位 */
}/** @description : 使能ELCDIF接口* @param : 无* @return : 无*/
void lcd_enable(void)
{LCDIF->CTRL |= 1<<0; /* 使能ELCDIF */
}/** @description : 画点函数 * @param - x : x轴坐标* @param - y : y轴坐标* @param - color : 颜色值* @return : 无*/
inline void lcd_drawpoint(unsigned short x,unsigned short y,unsigned int color)
{ *(unsigned int*)((unsigned int)tftlcd_dev.framebuffer + tftlcd_dev.pixsize * (tftlcd_dev.width * y+x))=color;
}/** @description : 读取指定点的颜色值* @param - x : x轴坐标* @param - y : y轴坐标* @return : 读取到的指定点的颜色值*/
inline unsigned int lcd_readpoint(unsigned short x,unsigned short y)
{ return *(unsigned int*)((unsigned int)tftlcd_dev.framebuffer + tftlcd_dev.pixsize * (tftlcd_dev.width * y + x));
}/** @description : 清屏* @param - color : 颜色值* @return : 读取到的指定点的颜色值*/
void lcd_clear(unsigned int color)
{unsigned int num;unsigned int i = 0; unsigned int *startaddr=(unsigned int*)tftlcd_dev.framebuffer; //指向帧缓存首地址num=(unsigned int)tftlcd_dev.width * tftlcd_dev.height; //缓冲区总长度for(i = 0; i < num; i++){startaddr[i] = color;}
}/** @description : 以指定的颜色填充一块矩形* @param - x0 : 矩形起始点坐标X轴* @param - y0 : 矩形起始点坐标Y轴* @param - x1 : 矩形终止点坐标X轴* @param - y1 : 矩形终止点坐标Y轴* @param - color : 要填充的颜色* @return : 读取到的指定点的颜色值*/
void lcd_fill(unsigned short x0, unsigned short y0, unsigned short x1, unsigned short y1, unsigned int color)
{ unsigned short x, y;if(x0 < 0) x0 = 0;if(y0 < 0) y0 = 0;if(x1 >= tftlcd_dev.width) x1 = tftlcd_dev.width - 1;if(y1 >= tftlcd_dev.height) y1 = tftlcd_dev.height - 1;for(y = y0; y <= y1; y++){for(x = x0; x <= x1; x++)lcd_drawpoint(x, y, color);}
}
//bsp_lcd.h
#ifndef _BSP_LCD_H
#define _BSP_LCD_H#include "imx6ul.h"/* 颜色 */
#define LCD_BLUE 0x000000FF
#define LCD_GREEN 0x0000FF00
#define LCD_RED 0x00FF0000
#define LCD_CYAN 0x0000FFFF
#define LCD_MAGENTA 0x00FF00FF
#define LCD_YELLOW 0x00FFFF00
#define LCD_LIGHTBLUE 0x008080FF
#define LCD_LIGHTGREEN 0x0080FF80
#define LCD_LIGHTRED 0x00FF8080
#define LCD_LIGHTCYAN 0x0080FFFF
#define LCD_LIGHTMAGENTA 0x00FF80FF
#define LCD_LIGHTYELLOW 0x00FFFF80
#define LCD_DARKBLUE 0x00000080
#define LCD_DARKGREEN 0x00008000
#define LCD_DARKRED 0x00800000
#define LCD_DARKCYAN 0x00008080
#define LCD_DARKMAGENTA 0x00800080
#define LCD_DARKYELLOW 0x00808000
#define LCD_WHITE 0x00FFFFFF
#define LCD_LIGHTGRAY 0x00D3D3D3
#define LCD_GRAY 0x00808080
#define LCD_DARKGRAY 0x00404040
#define LCD_BLACK 0x00000000
#define LCD_BROWN 0x00A52A2A
#define LCD_ORANGE 0x00FFA500
#define LCD_TRANSPARENT 0x00000000/* LCD显存地址 */
#define LCD_FRAMEBUF_ADDR (0x89000000)/* LCD控制参数结构体 */
struct tftlcd_typedef{unsigned short height; /* LCD屏幕高度 */unsigned short width; /* LCD屏幕宽度 */unsigned char pixsize; /* LCD每个像素所占字节大小 */unsigned short vspw;unsigned short vbpd;unsigned short vfpd;unsigned short hspw;unsigned short hbpd;unsigned short hfpd;unsigned int framebuffer; /* LCD显存首地址 */unsigned int forecolor; /* 前景色 */unsigned int backcolor; /* 背景色 */
};extern struct tftlcd_typedef tftlcd_dev;/* 函数声明 */
void lcd_init(void);
void lcdgpio_init(void);
void lcdclk_init(unsigned char loopDiv, unsigned char prediv, unsigned char div);
void lcd_reset(void);
void lcd_noreset(void);
void lcd_enable(void);
void video_pllinit(unsigned char loopdivi, unsigned char postdivi);inline void lcd_drawpoint(unsigned short x,unsigned short y,unsigned int color);
inline unsigned int lcd_readpoint(unsigned short x,unsigned short y);
void lcd_clear(unsigned int color);
void lcd_fill(unsigned short x0, unsigned short y0, unsigned short x1, unsigned short y1, unsigned int color);
#endif
五、LCD操作API函数编写
//bsp_lcdapi.c
#include "bsp_lcdapi.h"
#include "font.h" /** @description : 画线函数* @param - x1 : 线起始点坐标X轴* @param - y1 : 线起始点坐标Y轴* @param - x2 : 线终止点坐标X轴* @param - y2 : 线终止点坐标Y轴* @return : 无*/
void lcd_drawline(unsigned short x1, unsigned short y1, unsigned short x2, unsigned short y2)
{u16 t; int xerr = 0, yerr = 0, delta_x, delta_y, distance; int incx, incy, uRow, uCol; delta_x = x2 - x1; /* 计算坐标增量 */delta_y = y2 - y1; uRow = x1; uCol = y1; if(delta_x > 0) /* 设置单步方向 */ incx = 1;else if(delta_x==0) /* 垂直线 */incx = 0; else {incx = -1;delta_x = -delta_x;} if(delta_y>0)incy=1; else if(delta_y == 0) /* 水平线 */incy=0;else{incy = -1;delta_y = -delta_y;} if( delta_x > delta_y) /*选取基本增量坐标轴 */distance = delta_x; else distance = delta_y; for(t = 0; t <= distance+1; t++ ) /* 画线输出 */{ lcd_drawpoint(uRow, uCol, tftlcd_dev.forecolor);/* 画点 */xerr += delta_x ; yerr += delta_y ; if(xerr > distance) { xerr -= distance; uRow += incx; } if(yerr > distance) { yerr -= distance; uCol += incy; } }
} /** @description : 画矩形函数* @param - x1 : 矩形坐上角坐标X轴* @param - y1 : 矩形坐上角坐标Y轴* @param - x2 : 矩形右下角坐标X轴* @param - y2 : 矩形右下角坐标Y轴* @return : 无*/
void lcd_draw_rectangle(unsigned short x1, unsigned short y1, unsigned short x2, unsigned short y2)
{lcd_drawline(x1, y1, x2, y1);lcd_drawline(x1, y1, x1, y2);lcd_drawline(x1, y2, x2, y2);lcd_drawline(x2, y1, x2, y2);
}/** @description : 在指定位置画一个指定大小的圆* @param - x0 : 圆心坐标X轴* @param - y0 : 圆心坐标Y轴* @param - y2 : 圆形半径* @return : 无*/
void lcd_draw_Circle(unsigned short x0,unsigned short y0,unsigned char r)
{int mx = x0, my = y0;int x = 0, y = r;int d = 1 - r; while(y > x) /* y>x即第一象限的第1区八分圆 */{lcd_drawpoint(x + mx, y + my, tftlcd_dev.forecolor);lcd_drawpoint(y + mx, x + my, tftlcd_dev.forecolor);lcd_drawpoint(-x + mx, y + my, tftlcd_dev.forecolor);lcd_drawpoint(-y + mx, x + my, tftlcd_dev.forecolor);lcd_drawpoint(-x + mx, -y + my, tftlcd_dev.forecolor);lcd_drawpoint(-y + mx, -x + my, tftlcd_dev.forecolor);lcd_drawpoint(x + mx, -y + my, tftlcd_dev.forecolor);lcd_drawpoint(y + mx, -x + my, tftlcd_dev.forecolor);if( d < 0){d = d + 2 * x + 3;}else{d= d + 2 * (x - y) + 5;y--;}x++;}
}/** @description : 在指定位置显示一个字符* @param - x : 起始坐标X轴* @param - y : 起始坐标Y轴* @param - num : 显示字符* @param - size: 字体大小, 可选12/16/24/32* @param - mode: 叠加方式(1)还是非叠加方式(0)* @return : 无*/
void lcd_showchar(unsigned short x, unsigned short y,unsigned char num, unsigned char size, unsigned char mode)
{ unsigned char temp, t1, t;unsigned short y0 = y;unsigned char csize = (size / 8+ ((size % 8) ? 1 : 0)) * (size / 2); /* 得到字体一个字符对应点阵集所占的字节数 */ num = num - ' '; /*得到偏移后的值(ASCII字库是从空格开始取模,所以-' '就是对应字符的字库) */for(t = 0; t < csize; t++){ if(size == 12) temp = asc2_1206[num][t]; /* 调用1206字体 */else if(size == 16)temp = asc2_1608[num][t]; /* 调用1608字体 */else if(size == 24)temp = asc2_2412[num][t]; /* 调用2412字体 */else if(size == 32)temp = asc2_3216[num][t]; /* 调用3216字体 */else return; /* 没有的字库 */for(t1 = 0; t1 < 8; t1++){ if(temp & 0x80)lcd_drawpoint(x, y, tftlcd_dev.forecolor);else if(mode==0)lcd_drawpoint(x, y, tftlcd_dev.backcolor);temp <<= 1;y++;if(y >= tftlcd_dev.height) return; /* 超区域了 */ if((y - y0) == size){y = y0;x++;if(x >= tftlcd_dev.width) return; /* 超区域了 */break;}} }
} /** @description : 计算m的n次方* @param - m : 要计算的值* @param - n : n次方* @return : m^n次方.*/
unsigned int lcd_pow(unsigned char m,unsigned char n)
{unsigned int result = 1; while(n--) result *= m; return result;
}/** @description : 显示指定的数字,高位为0的话不显示* @param - x : 起始坐标点X轴。* @param - y : 起始坐标点Y轴。* @param - num : 数值(0~999999999)。* @param - len : 数字位数。* @param - size: 字体大小* @return : 无*/
void lcd_shownum(unsigned short x, unsigned short y, unsigned int num, unsigned char len,unsigned char size)
{ unsigned char t, temp;unsigned char enshow = 0; for(t = 0; t < len; t++){temp = (num / lcd_pow(10, len - t - 1)) % 10;if(enshow == 0 && t < (len - 1)){if(temp == 0){lcd_showchar(x + (size / 2) * t, y, ' ', size, 0);continue;}else enshow = 1; }lcd_showchar(x + (size / 2) * t, y, temp + '0', size, 0); }
} /** @description : 显示指定的数字,高位为0,还是显示* @param - x : 起始坐标点X轴。* @param - y : 起始坐标点Y轴。* @param - num : 数值(0~999999999)。* @param - len : 数字位数。* @param - size : 字体大小* @param - mode : [7]:0,不填充;1,填充0.* [6:1]:保留* [0]:0,非叠加显示;1,叠加显示.* @return : 无*/
void lcd_showxnum(unsigned short x, unsigned short y, unsigned int num, unsigned char len, unsigned char size, unsigned char mode)
{ unsigned char t, temp;unsigned char enshow = 0; for(t = 0; t < len; t++){temp = (num / lcd_pow(10, len - t- 1)) % 10;if(enshow == 0 && t < (len - 1)){if(temp == 0){if(mode & 0X80) lcd_showchar(x + (size / 2) * t, y, '0', size, mode & 0X01); else lcd_showchar(x + (size / 2) * t, y , ' ', size, mode & 0X01); continue;}else enshow=1; }lcd_showchar( x + (size / 2) * t, y, temp + '0' , size , mode & 0X01); }
} /** @description : 显示一串字符串* @param - x : 起始坐标点X轴。* @param - y : 起始坐标点Y轴。* @param - width : 字符串显示区域长度* @param - height : 字符串显示区域高度* @param - size : 字体大小* @param - p : 要显示的字符串首地址* @return : 无*/
void lcd_show_string(unsigned short x,unsigned short y,unsigned short width,unsigned short height,unsigned char size,char *p)
{ unsigned char x0 = x;width += x;height += y;while((*p <= '~') &&(*p >= ' ')) /* 判断是不是非法字符! */ { if(x >= width) {x = x0; y += size;}if(y >= height) break; /* 退出 */lcd_showchar(x, y, *p , size, 0);x += size / 2;p++;}
}
//bsp_lcdapi.h
#ifndef BSP_LCDAPI_H
#define BSP_LCDAPI_H
#include "imx6ul.h"
#include "bsp_lcd.h"/* 函数声明 */
void lcd_drawline(unsigned short x1, unsigned short y1, unsigned short x2, unsigned short y2);
void lcd_draw_rectangle(unsigned short x1, unsigned short y1, unsigned short x2, unsigned short y2);
void lcd_draw_Circle(unsigned short x0,unsigned short y0,unsigned char r);
void lcd_showchar(unsigned short x,unsigned short y,unsigned char num,unsigned char size, unsigned char mode);
unsigned int lcd_pow(unsigned char m,unsigned char n);
void lcd_shownum(unsigned short x, unsigned short y, unsigned int num, unsigned char len,unsigned char size);
void lcd_showxnum(unsigned short x, unsigned short y, unsigned int num, unsigned char len, unsigned char size, unsigned char mode);
void lcd_show_string(unsigned short x,unsigned short y,
unsigned short width, unsigned short height, unsigned char size,char *p);#endif
//main.c
#include "bsp_clk.h"
#include "bsp_delay.h"
#include "bsp_led.h"
#include "bsp_beep.h"
#include "bsp_key.h"
#include "bsp_int.h"
#include "bsp_uart.h"
#include "stdio.h"
#include "bsp_lcd.h"
#include "bsp_lcdapi.h"/* 背景颜色索引 */
unsigned int backcolor[10] = {LCD_BLUE, LCD_GREEN, LCD_RED, LCD_CYAN, LCD_YELLOW, LCD_LIGHTBLUE, LCD_DARKBLUE, LCD_WHITE, LCD_BLACK, LCD_ORANGE}; /** @description : main函数* @param : 无* @return : 无*/
int main(void)
{unsigned char index = 0;unsigned char state = OFF;int_init(); /* 初始化中断(一定要最先调用!) */imx6u_clkinit(); /* 初始化系统时钟 */delay_init(); /* 初始化延时 */clk_enable(); /* 使能所有的时钟 */led_init(); /* 初始化led */beep_init(); /* 初始化beep */uart_init(); /* 初始化串口,波特率115200 */lcd_init(); /* 初始化LCD */tftlcd_dev.forecolor = LCD_RED; lcd_show_string(10,10,400,32,32,(char*)"ZERO-IMX6UL ELCD TEST"); /* 显示字符串 */lcd_draw_rectangle(10, 52, 1014, 290); /* 绘制矩形框 */lcd_drawline(10, 52,1014, 290); /* 绘制线条 */lcd_drawline(10, 290,1014, 52); /* 绘制线条 */lcd_draw_Circle(512, 171, 119); /* 绘制圆形 */while(1) { index++;if(index == 10)index = 0;lcd_fill(0, 300, 1023, 599, backcolor[index]);lcd_show_string(800,10,240,32,32,(char*)"INDEX="); /*显示字符串 */lcd_shownum(896,10, index, 2, 32); /* 显示数字,叠加显示 */state = !state;led_switch(LED0,state);delayms(1000); /* 延时一秒 */}return 0;
}
//start.S
/***************************************************************
描述 : ZERO-I.MX6UL/I.MX6ULL开发板启动文件,完成C环境初始化,C环境初始化完成以后跳转到C代码。
**************************************************************/.global _start /* 全局标号 *//** 描述: _start函数,首先是中断向量表的创建* 参考文档:ARM Cortex-A(armV7)编程手册V4.0.pdf P42,3 ARM Processor Modes and Registers(ARM处理器模型和寄存器)* ARM Cortex-A(armV7)编程手册V4.0.pdf P165 11.1.1 Exception priorities(异常)*/
_start:ldr pc, =Reset_Handler /* 复位中断 */ ldr pc, =Undefined_Handler /* 未定义中断 */ldr pc, =SVC_Handler /* SVC(Supervisor)中断 */ldr pc, =PrefAbort_Handler /* 预取终止中断 */ldr pc, =DataAbort_Handler /* 数据终止中断 */ldr pc, =NotUsed_Handler /* 未使用中断 */ldr pc, =IRQ_Handler /* IRQ中断 */ldr pc, =FIQ_Handler /* FIQ(快速中断)未定义中断 *//* 复位中断 */
Reset_Handler:cpsid i /* 关闭全局中断 *//* 关闭I,DCache和MMU * 采取读-改-写的方式。*/mrc p15, 0, r0, c1, c0, 0 /* 读取CP15的C1寄存器到R0中 */bic r0, r0, #(0x1 << 12) /* 清除C1寄存器的bit12位(I位),关闭I Cache */bic r0, r0, #(0x1 << 2) /* 清除C1寄存器的bit2(C位),关闭D Cache */bic r0, r0, #0x2 /* 清除C1寄存器的bit1(A位),关闭对齐 */bic r0, r0, #(0x1 << 11) /* 清除C1寄存器的bit11(Z位),关闭分支预测 */bic r0, r0, #0x1 /* 清除C1寄存器的bit0(M位),关闭MMU */mcr p15, 0, r0, c1, c0, 0 /* 将r0寄存器中的值写入到CP15的C1寄存器中 */#if 0/* 汇编版本设置中断向量表偏移 */ldr r0, =0X87800000dsbisbmcr p15, 0, r0, c12, c0, 0dsbisb
#endif/* 设置各个模式下的栈指针,* 注意:IMX6UL的堆栈是向下增长的!* 堆栈指针地址一定要是4字节地址对齐的!!!* DDR范围:0X80000000~0X9FFFFFFF*//* 进入IRQ模式 */mrs r0, cpsrbic r0, r0, #0x1f /* 将r0寄存器中的低5位清零,也就是cpsr的M0~M4 */orr r0, r0, #0x12 /* r0或上0x13,表示使用IRQ模式 */msr cpsr, r0 /* 将r0 的数据写入到cpsr_c中 */ldr sp, =0x80600000 /* 设置IRQ模式下的栈首地址为0X80600000,大小为2MB *//* 进入SYS模式 */mrs r0, cpsrbic r0, r0, #0x1f /* 将r0寄存器中的低5位清零,也就是cpsr的M0~M4 */orr r0, r0, #0x1f /* r0或上0x13,表示使用SYS模式 */msr cpsr, r0 /* 将r0 的数据写入到cpsr_c中 */ldr sp, =0x80400000 /* 设置SYS模式下的栈首地址为0X80400000,大小为2MB *//* 进入SVC模式 */mrs r0, cpsrbic r0, r0, #0x1f /* 将r0寄存器中的低5位清零,也就是cpsr的M0~M4 */orr r0, r0, #0x13 /* r0或上0x13,表示使用SVC模式 */msr cpsr, r0 /* 将r0 的数据写入到cpsr_c中 */ldr sp, =0X80200000 /* 设置SVC模式下的栈首地址为0X80200000,大小为2MB */cpsie i /* 打开全局中断 */
#if 0/* 使能IRQ中断 */mrs r0, cpsr /* 读取cpsr寄存器值到r0中 */bic r0, r0, #0x80 /* 将r0寄存器中bit7清零,也就是CPSR中的I位清零,表示允许IRQ中断 */msr cpsr, r0 /* 将r0重新写入到cpsr中 */
#endifb main /* 跳转到main函数 *//* 未定义中断 */
Undefined_Handler:ldr r0, =Undefined_Handlerbx r0/* SVC中断 */
SVC_Handler:ldr r0, =SVC_Handlerbx r0/* 预取终止中断 */
PrefAbort_Handler:ldr r0, =PrefAbort_Handler bx r0/* 数据终止中断 */
DataAbort_Handler:ldr r0, =DataAbort_Handlerbx r0/* 未使用的中断 */
NotUsed_Handler:ldr r0, =NotUsed_Handlerbx r0/* IRQ中断!重点!!!!! */
IRQ_Handler:push {lr} /* 保存lr地址 */push {r0-r3, r12} /* 保存r0-r3,r12寄存器 */mrs r0, spsr /* 读取spsr寄存器 */push {r0} /* 保存spsr寄存器 */mrc p15, 4, r1, c15, c0, 0 /* 从CP15的C0寄存器内的值到R1寄存器中* 参考文档ARM Cortex-A(armV7)编程手册V4.0.pdf P49* Cortex-A7 Technical ReferenceManua.pdf P68 P138*/ add r1, r1, #0X2000 /* GIC基地址加0X2000,也就是GIC的CPU接口端基地址 */ldr r0, [r1, #0XC] /* GIC的CPU接口端基地址加0X0C就是GICC_IAR寄存器,* GICC_IAR寄存器保存这当前发生中断的中断号,我们要根据* 这个中断号来绝对调用哪个中断服务函数*/push {r0, r1} /* 保存r0,r1 */cps #0x13 /* 进入SVC模式,允许其他中断再次进去 */push {lr} /* 保存SVC模式的lr寄存器 */ldr r2, =system_irqhandler /* 加载C语言中断处理函数到r2寄存器中*/blx r2 /* 运行C语言中断处理函数,带有一个参数,保存在R0寄存器中 */pop {lr} /* 执行完C语言中断服务函数,lr出栈 */cps #0x12 /* 进入IRQ模式 */pop {r0, r1} str r0, [r1, #0X10] /* 中断执行完成,写EOIR */pop {r0} msr spsr_cxsf, r0 /* 恢复spsr */pop {r0-r3, r12} /* r0-r3,r12出栈 */pop {lr} /* lr出栈 */subs pc, lr, #4 /* 将lr-4赋给pc *//* FIQ中断 */
FIQ_Handler:ldr r0, =FIQ_Handler bx r0
//Makefile
CROSS_COMPILE ?= arm-linux-gnueabihf-
TARGET ?= lcdCC := $(CROSS_COMPILE)gcc
LD := $(CROSS_COMPILE)ld
OBJCOPY := $(CROSS_COMPILE)objcopy
OBJDUMP := $(CROSS_COMPILE)objdumpLIBPATH := -lgcc -L /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/lib/gcc/arm-linux-gnueabihf/4.9.4INCDIRS := imx6ul \stdio/include \bsp/clk \bsp/led \bsp/delay \bsp/beep \bsp/gpio \bsp/key \bsp/exit \bsp/int \bsp/epittimer \bsp/keyfilter \bsp/uart \bsp/lcdSRCDIRS := project \stdio/lib \bsp/clk \bsp/led \bsp/delay \bsp/beep \bsp/gpio \bsp/key \bsp/exit \bsp/int \bsp/epittimer \bsp/keyfilter \bsp/uart \bsp/lcdINCLUDE := $(patsubst %, -I %, $(INCDIRS))SFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.S))
CFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c))SFILENDIR := $(notdir $(SFILES))
CFILENDIR := $(notdir $(CFILES))SOBJS := $(patsubst %, obj/%, $(SFILENDIR:.S=.o))
COBJS := $(patsubst %, obj/%, $(CFILENDIR:.c=.o))
OBJS := $(SOBJS) $(COBJS)VPATH := $(SRCDIRS).PHONY: clean$(TARGET).bin : $(OBJS)$(LD) -Timx6ul.lds -o $(TARGET).elf $^ $(LIBPATH)$(OBJCOPY) -O binary -S $(TARGET).elf $@$(OBJDUMP) -D -m arm $(TARGET).elf > $(TARGET).dis$(SOBJS) : obj/%.o : %.S$(CC) -Wall -nostdlib -fno-builtin -c -O2 $(INCLUDE) -o $@ $<$(COBJS) : obj/%.o : %.c$(CC) -Wall -Wa,-mimplicit-it=thumb -nostdlib -fno-builtin -c -O2 $(INCLUDE) -o $@ $<clean:rm -rf $(TARGET).elf $(TARGET).dis $(TARGET).bin $(COBJS) $(SOBJS)
相关文章:
37. RGBLCD实验
一、RGBLCD显示原理简介 1、像素点 于一个“小灯“,不管是液晶屏,还是手机,平板,RGBLCD屏幕他都是有由一个个的彩色小灯构成的。彩色点阵屏每个像素点有三个小灯,红色、绿色和蓝色,也叫做RGB。RGB就是光的…...
反馈驱动、上下文学习、多语言检索增强等 | Big Model Weekly 第55期
点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入! 01 A Bayesian Approach to Harnessing the Power of LLMs in Authorship Attribution 传统方法严重依赖手动特征,无法捕捉长距离相关性,限制了其有效性。最近的研究利用预训练语言模型的…...
【深度分析】微软全球裁员计划不影响印度地区,将继续增加当地就业机会
当微软的裁员刀锋掠过全球办公室时,班加罗尔的键盘声却愈发密集——这场资本迁徙背后,藏着数字殖民时代最锋利的生存法则。 表面是跨国公司的区域战略调整,实则是全球人才市场的地壳运动。微软一边在硅谷裁撤年薪20万美金的高级工程师&#x…...
H. Mad City
题目链接:Problem - H - Codeforces 题目大意:给定一个带环的图, 以及a, b两点 判断再图上不断的移动, b想不与a相遇, a想捉到b, 并且二者只能移动一步。 若b跑不掉 NO 否则YES. 具体题目看链接 输入: …...
【C++】类与对象(下)
🦄 个人主页: 小米里的大麦-CSDN博客 🎏 所属专栏: 小米里的大麦——C专栏_CSDN博客 🎁 代码托管: 小米里的大麦的Gitee仓库 ⚙️ 操作环境: Visual Studio 2022 文章目录 1. 再谈构造函数1.1 构造函数体赋值1.2 初始化列表1.3 explicit 关键…...
AJAX案例——图片上传个人信息操作
黑马程序员视频地址: AJAX-Day02-11.图片上传https://www.bilibili.com/video/BV1MN411y7pw?vd_source0a2d366696f87e241adc64419bf12cab&spm_id_from333.788.videopod.episodes&p26 图片上传 <!-- 文件选择元素 --><input type"file"…...
Redis-布隆过滤器
文章目录 布隆过滤器的特点:实践布隆过滤器应用 布隆过滤器的特点: 就可以把布隆过滤器理解为一个set集合,我们可以通过add往里面添加元素,通过contains来判断是否包含某个元素。 布隆过滤器是一个很长的二进制向量和一系列随机映射函数。 可以用来检索…...
OpenCV 图像旋转
在学习 OpenCV 和 Matplotlib 处理图像时,遇到了一些关于 cv2.imread()、cv2.getRotationMatrix2D()、plt.imshow() 的问题: import cv2 import numpy as np import matplotlib.pyplot as pltimg cv2.imread(img2.png, 1) # 读取彩色图像(…...
联想Y7000+RTX4060+i7+Ubuntu22.04运行DeepSeek开源多模态大模型Janus-Pro-1B+本地部署
直接上手搓了: conda create -n myenv python3.10 -ygit clone https://github.com/deepseek-ai/Janus.gitcd Januspip install -e .pip install webencodings beautifulsoup4 tinycss2pip install -e .[gradio]pip install pexpect>4.3python demo/app_januspr…...
在线知识库创建与维护提升企业效率与知识共享能力
内容概要 在当今数字化快速发展的背景下,在线知识库逐渐成为企业管理信息的重要工具。其核心在于将知识进行系统化、结构化的整理和存储,便于员工获取和分享。这不仅提高了信息的访问效率,还促进了团队之间的协作。在线知识库的建立可以有效…...
C语言指针专题二 -- 字符指针与字符串
目录 1. 字符指针与字符串的核心原理 字符串的本质 字符串的存储 字符指针的特性 字符指针的操作 2. 编程实例 3. 常见陷阱与注意事项 4. 总结 1. 字符指针与字符串的核心原理 字符串的本质 C语言中没有独立的字符串类型,字符串本质是 以\0(空…...
玄武计划--干中学,知行合一
作为开发者转型安全领域有一定优势,但需要系统学习网络安全知识。以下是针对你的情况(Java背景 + 快速入门)的实战导向学习路径,分为基础、工具、漏洞利用和进阶四个阶段: 一、基础准备(1-2周) 网络协议与渗透基础 重点协议:深入理解 TCP/IP、HTTP/HTTPS、DNS、SMTP,用…...
处理 .gitignore 未忽略文件夹问题
本地删除缓存 例如 .idea 文件夹被其他同事误提交,那么他本地执行以下代码 git rm -r --cached .idea对应本地再提交即可...
实验七 JSP内置对象II
实验七 JSP内置对象II 目的: 1、掌握JSP内置对象的使用。 2、理解JSP的作用域 3、掌握session,application对象的使用 实验要求: 1、完成实验题目 2、要求提交实验报告,将代码和实验结果页面截图放入报告中 实验过程:…...
【Leetcode 每日一题 - 补卡】219. 存在重复元素 II
问题背景 给你一个整数数组 n u m s nums nums 和一个整数 k k k,判断数组中是否存在两个 不同的索引 i i i 和 j j j,满足 n u m s [ i ] n u m s [ j ] nums[i] nums[j] nums[i]nums[j] 且 ∣ i − j ∣ < k |i - j| < k ∣i−j∣<…...
Flask数据的增删改查(CRUD)_flask删除数据自动更新
查询年龄小于17的学生信息 Student.query.filter(Student.s_age < 17) students Student.query.filter(Student.s_age.__lt__(17))模糊查询,使用like,查询姓名中第二位为花的学生信息 like ‘_花%’,_代表必须有一个数据,%任何数据 st…...
web自动化——前端知识
<iframe> 是 HTML 中的一个元素,用于在当前网页中嵌入另一个网页或文档。它就像一个“窗口”,可以在页面中显示其他内容。 主要特点: 嵌入外部内容:可以在网页中嵌入其他网页、视频、地图等。独立上下文:嵌入的…...
计算机网络一点事(22)
地址解析协议ARP ARP:查询Mac地址 ARP表(ARP缓存):记录映射关系,一个数据结构,定期更新ARP表 过程:请求分组,响应分组 动态主机配置协议DHCP 分配IP地址,配置默认网关…...
SG算法解析
Savitzky-Golay 滤波器的核心代码主要集中在计算投影矩阵B并使用这个矩阵对输入信号进行滤波。这部分核心代码包括计算B矩阵、处理边界效应和进行实际滤波操作。以下是对核心代码的一点解释: ① 计算 Savitzky-Golay 投影矩阵B B sgolay(order, framelen, weight…...
Ubuntu Server连接wifi
背景 家里服务器放在客厅太吵了, 准备挪到阳台, 所以买了TP wifi接收器, 因此需要配置wifi连接. 刚开始买了Tenda Ax300, 结果不支持服务器系统, 买前还是得和客服交流交流. 准备 驱动安装 对于windows系统来说, 这款接收器是免驱的, 但在linux上需要安装相应型号驱动 安装…...
Linux 4.19内核中的内存管理:x86_64架构下的实现与源码解析
在现代操作系统中,内存管理是核心功能之一,它直接影响系统的性能、稳定性和多任务处理能力。Linux 内核在 x86_64 架构下,通过复杂的机制实现了高效的内存管理,涵盖了虚拟内存、分页机制、内存分配、内存映射、内存保护、缓存管理等多个方面。本文将深入探讨这些机制,并结…...
L30.【LeetCode笔记】设计链表
1.题目 707. 设计链表 - 力扣(LeetCode) 你可以选择使用单链表或者双链表,设计并实现自己的链表。 单链表中的节点应该具备两个属性:val 和 next 。val 是当前节点的值,next 是指向下一个节点的指针/引用。 如果是双向…...
使用Pygame制作“Flappy Bird”游戏
1. 前言 Flappy Bird 是一款“点击上浮、松手下落”的横向卷轴游戏: 场景中持续出现上下成对的管道,玩家需要让小鸟在管道之间穿行;每穿过一对管道记 1 分;若小鸟碰到管道或掉到地面,则游戏结束;一旦上手…...
PHP中配置 variables_order详解
variables_order 是 PHP 配置文件 php.ini 中的一项配置指令,决定了 PHP 在处理请求时,哪些类型的变量将被注册到全局变量空间(如 $GLOBALS)中,以及这些变量的顺序。理解和正确配置 variables_order 对于开发和维护安全…...
Go学习:运算符总结
在 Go语言中,一元运算符拥有最高的优先级,二元运算符的运算方向均是从左至右。 下表列出了所有运算符以及它们的优先级,由上至下代表优先级由高到低:...
JS面相对象小案例:自定义安全数组
在JS中,数组不像其他语言(java、python)中那样安全,它具有动态性和弱类型性,切越界访问没有具体的报错,而是返回空,为提升数组的安全性,我们可以自行定义一个安全数组。 一、增加报…...
将markdown文件转为word文件
通义千问等大模型生成的回答多数是markdown类型的,需要将他们转为Word文件 一 pypandoc 介绍 1. 项目介绍 pypandoc 是一个用于 pandoc 的轻量级 Python 包装器。pandoc 是一个通用的文档转换工具,支持多种格式的文档转换,如 Markdown、HTM…...
Unet 改进:在encoder和decoder间加入TransformerBlock
目录 1. TransformerBlock 2. Unet 改进 3. 完整代码 Tips:融入模块后的网络经过测试,可以直接使用,设置好输入和输出的图片维度即可 1. TransformerBlock TransformerBlock是Transformer模型架构的基本组件,广泛应用于机器翻译、文本摘要和情感分析等自然语言处理任务…...
LeetCode题练习与总结:两个列表的最小索引总和--599
一、题目描述 假设 Andy 和 Doris 想在晚餐时选择一家餐厅,并且他们都有一个表示最喜爱餐厅的列表,每个餐厅的名字用字符串表示。 你需要帮助他们用最少的索引和找出他们共同喜爱的餐厅。 如果答案不止一个,则输出所有答案并且不考虑顺序。…...
IBM数据与人工智能系列 安装 IBM 编程助手
登录CPD环境 ${CPDM_OC_LOGIN} 安装编程助手 cpd-cli manage apply-olm \ --release${VERSION} \ --cpd_operator_ns${PROJECT_CPD_INST_OPERATORS} \ --componentswca cpd-cli manage apply-cr \ --componentswca \ --release${VERSION} \ --cpd_instance_ns${PROJECT_CPD…...
细说机器学习算法之ROC曲线用于模型评估
系列文章目录 第一章:Pyhton机器学习算法之KNN 第二章:Pyhton机器学习算法之K—Means 第三章:Pyhton机器学习算法之随机森林 第四章:Pyhton机器学习算法之线性回归 第五章:Pyhton机器学习算法之有监督学习与无监督…...
unity学习25:用 transform 进行旋转和移动,简单的太阳地球月亮模型,以及父子级关系
目录 备注内容 1游戏物体的父子级关系 1.1 父子物体 1.2 坐标关系 1.3 父子物体实际是用 每个gameobject的tranform来关联的 2 获取gameObject的静态数据 2.1 具体命令 2.2 具体代码 2.3 输出结果 3 获取gameObject 的方向 3.1 游戏里默认的3个方向 3.2 获取方向代…...
如何利用天赋实现最大化的价值输出
这种文章,以我现在的实力很难写出来。所以需要引用一些视频。 上92高校容易吗 如果基于天赋努力,非常容易。 如果不是这样,非常非常难。 高考失败人生完蛋?复读考上交大,进入社会才发现学历只是一张纸,98…...
使用 postman 测试思源笔记接口
思源笔记 API 权鉴 官方文档-中文:https://github.com/siyuan-note/siyuan/blob/master/API_zh_CN.md 权鉴相关介绍截图: 对应的xxx,在软件中查看 如上图:在每次发送 API 请求时,需要在 Header 中添加 以下键值对&a…...
代码随想录33
目录 leetcode738.单调递增的字符串 优化过的算法: 困难模式:968.监控二叉树 leetcode738.单调递增的字符串 当且仅当每个相邻位数上的数字 x 和 y 满足 x < y 时,我们称这个整数是单调递增的。 给定一个整数 n ,返回 小于…...
解决Oracle SQL语句性能问题(10.5)——常用Hint及语法(7)(其他Hint)
10.5.3. 常用hint 10.5.3.7. 其他Hint 1)cardinality:显式的指示优化器为SQL语句的某个行源指定势。该Hint具体语法如下所示。 SQL> select /*+ cardinality([@qb] [table] card ) */ ...; --注: 1)这里,第一个参数(@qb)为可选参数,指定查询语句块名;第二个参数…...
FFmpeg(7.1版本)的基本组成
1. 前言 FFmpeg 是一个非常流行的开源项目,它提供了处理音频、视频以及其他多媒体内容的强大工具。FFmpeg 包含了大量的库,可以用来解码、编码、转码、处理和播放几乎所有类型的多媒体文件。它广泛用于视频和音频的录制、转换、流媒体传输等领域。 2. FFmpeg的组成 1. FFmp…...
Hypium+python鸿蒙原生自动化安装配置
Hypiumpython自动化搭建 文章目录 Python安装pip源配置HDC安装Hypium安装DevEco Testing Hypium插件安装及使用方法插件安装工程创建区域 Python安装 推荐从官网获取3.10版本,其他版本可能出现兼容性问题 Python下载地址 下载64/32bitwindows安装文件&am…...
文明的基因:在传承中破茧重生
敦煌莫高窟的壁画历经千年风雨,至今仍在向世界讲述着东方美学的密码。那些斑驳的壁画上,既有北魏时期的天竺梵音,也留存着盛唐气象的长安余韵。文明的基因从未停止生长,就像莫高窟的壁画师们在临摹前朝壁画时,总会在衣…...
因果推断与机器学习—用机器学习解决因果推断问题
Judea Pearl 将当前备受瞩目的机器学习研究戏谑地称为“仅限于曲线拟合”,然而,曲线拟合的实现绝非易事。机器学习模型在图像识别、语音识别、自然语言处理、蛋白质分子结构预测以及搜索推荐等多个领域均展现出显著的应用效果。 在因果推断任务中,在完成因果效应识别之后,需…...
笔试-二进制
应用题 将符合区间[l,r]内的十进制整数转换为二进制表示,请问不包含“101”的整数个数是多少? 实现 l int(input("请输入下限l,其值大于等于1:")) r int(input("请输入上限r,其值大于等于l&#x…...
Day52:range()函数
在 Python 中,range() 是一个内置函数,用于生成一系列数字,通常用于循环结构中。它非常适合用于生成指定范围内的整数序列,并且支持步长控制,常用于 for 循环中。 今天我们将学习如何使用 range() 函数,并…...
数据结构:栈篇
ps: 本文所有图均为博主亲手所画,本文所有代码基于vs2022实现 系列文章目录 数据结构初探: 顺序表 数据结构初探:链表之单链表篇 数据结构初探:链表之双向链表篇 链表特别篇:链表经典算法问题 文章目录 系列文章目录前言一.栈的概念及其结构1.1概念1.2结构 二.准备工作1.Stack…...
药店药品销售管理系统的设计与实现
标题:药店药品销售管理系统的设计与实现 内容:1.摘要 摘要:本文介绍了药店药品销售管理系统的设计与实现。该系统旨在提高药店的运营效率和管理水平,通过信息化手段实现药品销售、库存管理、财务管理等功能。本文详细阐述了系统的需求分析、设计思路、技…...
【AI论文】VideoAuteur:迈向长叙事视频
摘要:近期的视频生成模型在制作持续数秒的高质量视频片段方面已展现出令人鼓舞的成果。然而,这些模型在生成能传达清晰且富有信息量的长序列时面临挑战,限制了它们支持连贯叙事的能力。在本文中,我们提出了一个大规模烹饪视频数据…...
pytorch基于FastText实现词嵌入
FastText 是 Facebook AI Research 提出的 改进版 Word2Vec,可以: ✅ 利用 n-grams 处理未登录词 比 Word2Vec 更快、更准确 适用于中文等形态丰富的语言 完整的 PyTorch FastText 代码(基于中文语料),包含࿱…...
PyTorch API 详细中文文档,基于PyTorch2.5
PyTorch API 详细中文文档 按模块分类,涵盖核心函数与用法示例 目录 张量操作 (Tensor Operations)数学运算 (Math Operations)自动求导 (Autograd)神经网络模块 (torch.nn)优化器 (torch.optim)数据加载与处理 (torch.utils.data)设备管理 (Device Management)模…...
leetcode 2300. 咒语和药水的成功对数
题目如下 数据范围 示例 注意到n和m的长度最长达到10的5次方所以时间复杂度为n方的必然超时。 因为题目要求我们返回每个位置的spell对应的有效对数所以我们只需要找到第一个有效的药水就行,这里可以先对potions排序随后使用二分查找把时间复杂度压到nlogn就不会…...
C# 实现 “Hello World” 教程
.NET学习资料 .NET学习资料 .NET学习资料 C# 作为一种广泛应用于.NET 开发的编程语言,以其简洁、高效和类型安全等特性,深受开发者喜爱。在踏入 C# 编程领域时,编写经典的 “Hello World” 程序是重要的起点,它能帮助我们快速熟…...
Elasticsearch——Elasticsearch性能优化实战
摘要 本文主要介绍了 Elasticsearch 性能优化的实战方法,从硬件配置优化、索引优化设置、查询方面优化、数据结构优化以及集群架构设计等五个方面进行了详细阐述,旨在帮助读者提升 Elasticsearch 的性能表现。 1. 硬件配置优化 升级硬件设备配置一直都…...