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

无锡做网站6自己做一网站

无锡做网站6,自己做一网站,ci wordpress cms,WordPress mx 主题在内核空间编写SPI设备驱动的要点 在SPI总线控制器的设备树节点下增加SPI设备的设备树节点#xff0c;节点中必须包含 reg 属性、 compatible 属性、 spi-max-frequency 属性#xff0c; reg 属性用于描述片选索引#xff0c; compatible属性用于设备和驱动的匹配#xff…在内核空间编写SPI设备驱动的要点 在SPI总线控制器的设备树节点下增加SPI设备的设备树节点节点中必须包含 reg 属性、 compatible 属性、 spi-max-frequency 属性 reg 属性用于描述片选索引 compatible属性用于设备和驱动的匹配 spi-max-frequency 用于描述设备可支持的最大 SPI 总线频率在注册SPI总线控制器会解析其中的子节点并注册成SPI设备。创建并初始化struct spi_driver对象其中重点关注of_match_table、probe、removeof_match_table用于设备树和驱动匹配probe在设备驱动匹配成功时执行remove在设备或驱动卸载时执行。在模块初始化函数中使用int spi_register_driver(struct spi_driver *sdrv)注册SPI设备驱动使用void spi_message_init(struct spi_message *m)和void spi_message_add_tail(struct spi_transfer *t, struct spi_message *m)组织数据包然后使用int spi_sync(struct spi_device *spi, struct spi_message *message)或int spi_async(struct spi_device *spi, struct spi_message *message)传输数据包在模块卸载函数中使用void spi_unregister_driver(struct spi_driver *sdrv)注销SPI设备驱动 SPI OLED驱动编写 OLED模块原理图 模块一共由7个引脚采用SPI模式时引脚定义如下 GND电源地 VCC2.2V~5.5V SCL(D0)CLK 时钟 高电平 2.2V~5.5V SDA(D1)MOSI 数据高电平 2.2V~5.5V RST复位高电平 2.2V~5.5V D/C数据/命令高电平 2.2V~5.5V CSSPI片选 注意没有MISO引脚因为主控只能向OLED写数据不能读取OLED的数据 与主控的连接示意图 要操作OLED只需使用SPI接口发送数据并不需要使用SPI接口读取数据。除此之外还需要控制D/C引脚 当DC引脚是低电平时是命令比如复位、打开显示、设置地址当DC引脚是高电平时是数据写入要显示的数据 显存和像素 OLED上有128*64个像素128列64行每个像素只有2种状态亮、灭。 OLED内部有一块显存GDDRAM(Graphic Display Data RAM)显存中每位对应一个像素入下图所示 byte0对应屏幕左上角竖向排列的8个像素即COL0第0~第7行的8个像素byte1对应COL1列第0~第7行的8个像素……byte127对应COL127列第0~第7行的8个像素byte128对应COL0那列第8~第15行的8个像素…… 显存寻址模式 显存被分为8页、128列要写某个字节时需要先指定地址哪页、哪列然后写入1字节的数据。 OLED有三种寻址模式 页地址模式(Page addressing mode)每写入1个字节行地址不变列地址增1列地址达到127后会从0开始 水平地址模式(Horizontal addressing mode)每写入1个字节行地址不变列地址增1列地址达到127后从0开始行地址指向下一页列地址达到127、行地址达到7时列地址和行地址都被复位为0指向左上角在此驱动中初始化时将地址设置为此模式 垂直地址模式(Vertical addressing mode) 每写入1个字节行地址增1列地址不变行地址达到7后从0开始列地址指向下一列 列地址达到127、行地址达到7时列地址和行地址都被复位为0指向左上角 编写OLED设备树 在 stm32mp15-pinctrl.dtsi 的 pinctrl_z 节点中修改 SPI 的引脚配置为如下内容 spi1_pins_a: spi1-0 {pins1 {pinmux STM32_PINMUX(Z, 0, AF5), /* SPI1_SCK */STM32_PINMUX(Z, 2, AF5); /* SPI1_MOSI */bias-disable;drive-push-pull;slew-rate 3;};pins2 {pinmux STM32_PINMUX(Z, 1, AF5); /* SPI1_MISO */bias-disable;drive-push-pull;slew-rate 3;};};spi1_sleep_pins_a: spi1-sleep-0 {pins {pinmux STM32_PINMUX(Z, 0, ANALOG), /* SPI1_SCK */STM32_PINMUX(Z, 1, ANALOG), /* SPI1_MISO */STM32_PINMUX(Z, 2, ANALOG); /* SPI1_MOSI */};};在顶层设备树中引用spi1节点并加入如下内容 spi1 {pinctrl-names default, sleep;pinctrl-0 spi1_pins_a;pinctrl-1 spi1_sleep_pins_a;cs-gpios gpioz 3 GPIO_ACTIVE_LOW, gpioa 14 GPIO_ACTIVE_LOW;status okay;/* OLED屏幕 */oled1 {compatible atk,oled;reg 1; /* CS #1 */spi-max-frequency 1000000;dc-gpios gpioi 3 GPIO_ACTIVE_LOW;rst-gpios gpioi 11 GPIO_ACTIVE_LOW;}; };用make ARCHarm CROSS_COMPILEarm-none-linux-gnueabihf- dtbs -j8编译设备树并用新的.dtb文件启动系统 使能SPI控制器驱动 内核中使能 SPI 控制器驱动 ST 默认将SPI控制器驱动编译为模块使能步骤如下 执行命令make ARCHarm CROSS_COMPILEarm-none-linux-gnueabihf- menuconfig打开内核配置菜单进行如下配置 Device DriversSPI support (SPI [y])* STMicroelectronics STM32 SPI controller //编译进内核使用命令make ARCHarm CROSS_COMPILEarm-none-linux-gnueabihf- all LOADADDR0XC2000040 -j16编译内核使用命令make ARCHarm CROSS_COMPILEarm-none-linux-gnueabihf- uImage dtbs LOADADDR0XC2000040 -j16生成uImage 驱动代码编写 OLED驱动程序基于SPI总线驱动框架和缓冲帧驱动框架编写有关缓冲帧的内容参考8.1缓冲帧(Framebuffer)驱动框架和8.2LCD-TFT显示控制器驱动 (LCD驱动)部分驱动代码主要包括以下几个部分 注册/注销SPI设备驱动注册/注销缓冲帧驱动OLED初始化OLED显示更新 驱动代码的完成内容如下所示 #include linux/init.h #include linux/kernel.h #include linux/module.h #include linux/fs.h #include linux/cdev.h #include linux/slab.h #include linux/device.h #include linux/uaccess.h #include linux/io.h #include linux/ioport.h #include linux/poll.h #include linux/platform_device.h #include linux/of.h #include linux/of_gpio.h #include linux/interrupt.h #include linux/of_irq.h #include linux/kthread.h #include linux/delay.h #include linux/input.h #include linux/spi/spi.h #include linux/vmalloc.h #include linux/mm.h #include linux/fb.h #include linux/dma-mapping.h#define OLED_DISPLAY_RAM_SIZE (8*128)struct oled_handle{struct spi_device *spi; //oled所属spi设备int rst_gpio; //复位引脚int dc_gpio; //数据命令选择引脚struct task_struct *kthread; //用于将显存内容更新到OLED的内核线程uint8_t (*oled_buffer)[128]; //oled buffer将缓冲帧中的数据转换为OLED格式后在通过SPI总线发送到OLEDstruct fb_info *fb; //缓冲帧句柄unsigned int pseudo_palette[16]; //调色板uint8_t (*fb_buffer)[16]; //缓冲帧dma_addr_t phy_addr; //缓冲帧物理地址uint8_t (*old_fb_buffer)[16]; //缓冲帧上一次更新时的状态 };//初始化OLED的复位引脚和数据命令选择引脚 static int devm_pin_init(struct oled_handle *oled) {int result;//获取RST GPIO号oled-rst_gpio of_get_named_gpio(oled-spi-dev.of_node, rst-gpios, 0);if(oled-rst_gpio 0){printk(get rst_gpio failed\r\n);return oled-rst_gpio;}//申请RST GPIOresult devm_gpio_request(oled-spi-dev, oled-rst_gpio, oled,rst_gpio);if(result 0){printk(request rst_gpio failed\r\n);return result;}//设置复位引脚输出高电平gpio_direction_output(oled-rst_gpio, 1);//获取DC GPIO号oled-dc_gpio of_get_named_gpio(oled-spi-dev.of_node, dc-gpios, 0);if(oled-dc_gpio 0){printk(get dc_gpio failed\r\n);return oled-dc_gpio;}//申请DC GPIOresult devm_gpio_request(oled-spi-dev, oled-dc_gpio, oled,dc_gpio);if(result 0){printk(request dc_gpio failed\r\n);return result;}//设置数据/命令选择引脚输出高电平gpio_direction_output(oled-dc_gpio, 1);return 0; }//数据命令选择引脚拉高表示发送数据 static void dc_high(struct oled_handle *oled) {gpio_direction_output(oled-dc_gpio, 1); }//数据命令选择引脚拉低表示发送命令 static void dc_low(struct oled_handle *oled) {gpio_direction_output(oled-dc_gpio, 0); }//复位引脚拉高 static void rst_high(struct oled_handle *oled) {gpio_direction_output(oled-rst_gpio, 1); }//复位引脚拉低 static void rst_low(struct oled_handle *oled) {gpio_direction_output(oled-rst_gpio, 0); }//复位OLED屏幕 static void oled_reset(struct oled_handle *oled) {//暂时拉高复位引脚rst_high(oled);msleep_interruptible(200);//拉低复位引脚进行复位rst_low(oled);msleep_interruptible(200);//拉高复位引脚复位结束rst_high(oled);msleep_interruptible(200); }//通过SPI总线向OLED设备发送数据 static int oled_write(struct oled_handle *oled, const uint8_t *data, uint32_t lenght) {int result;uint8_t *buffer;struct spi_message message;struct spi_transfer transfer;//分配发送缓存buffer kzalloc(lenght, GFP_KERNEL);if(!buffer)return -ENOMEM;//将数据拷贝到buffer中memcpy(buffer, data, lenght);//初始化spi_messagespi_message_init(message);//复位spi_transfermemset(transfer, 0, sizeof(transfer));//发送缓存transfer.tx_buf buffer;//接收缓存transfer.rx_buf NULL;//传输的长度transfer.len lenght;//将spi_transfer添加到spi_message队列spi_message_add_tail(transfer, message);//同步传输result spi_sync(oled-spi, message);//释放发送缓存kfree(buffer);return result; }//向OLED屏幕发送命令 static int oled_write_cmd(struct oled_handle *oled, uint8_t *command, uint32_t lenght) {//拉低数据命令选择引脚表示发送命令dc_low(oled);//通过SPI发送数据return oled_write(oled, command, lenght); }//向OLED屏幕发送数据 static int oled_write_data(struct oled_handle *oled, uint8_t *data, uint32_t lenght) {//拉高数据命令选择引脚表示发送数据dc_high(oled);//通过SPI发送数据return oled_write(oled, data, lenght); }//将oled_buffer中的数据显示在OLED屏幕上 static int oled_update(struct oled_handle *oled) {int result;uint8_t command[3];//设置地址command[0] 0xB0 0; //设置页地址command[1] 0x10 0; //设置显示位置—列高地址高4位command[2] 0x00 0; //设置显示位置—列低地址低4位result oled_write_cmd(oled, command, 3);if(result ! 0)return result;//发送显示数据result oled_write_data(oled, oled-oled_buffer[0], 128*8);if(result ! 0)return result;return 0; }//初始化OLED屏幕 static int oled_init(struct oled_handle *oled) {int result;uint8_t command[28];//复位OLEDoled_reset(oled);//发送初始化命令command[0 ] 0xAE; //--turn off oled panelcommand[1 ] 0x00; //---set low column addresscommand[2 ] 0x10; //---set high column addresscommand[3 ] 0x40; //--set start line address Set Mapping RAM Display Start Line (0x00~0x3F)command[4 ] 0x81; //--set contrast control registercommand[5 ] 0xCF; // Set SEG Output Current Brightnesscommand[6 ] 0xA1; //--Set SEG/Column Mapping 0xa0左右反置 0xa1正常command[7 ] 0xC8; //Set COM/Row Scan Direction 0xc0上下反置 0xc8正常command[8 ] 0xA6; //--set normal displaycommand[9 ] 0xA8; //--set multiplex ratio(1 to 64)command[10] 0x3F; //--1/64 dutycommand[11] 0xD3; //-set display offset Shift Mapping RAM Counter (0x00~0x3F)command[12] 0x00; //-not offsetcommand[13] 0xD5; //--set display clock divide ratio/oscillator frequencycommand[14] 0x80; //--set divide ratio, Set Clock as 100 Frames/Seccommand[15] 0xD9; //--set pre-charge periodcommand[16] 0xF1; //Set Pre-Charge as 15 Clocks Discharge as 1 Clockcommand[17] 0xDA; //--set com pins hardware configurationcommand[18] 0x12; command[19] 0xDB; //--set vcomhcommand[20] 0x40; //Set VCOM Deselect Levelcommand[21] 0x20; //-Set Addressing Mode (0x00/0x01/0x02)command[22] 0x00; //command[23] 0x8D; //--set Charge Pump enable/disablecommand[24] 0x14; //--set(0x10) disablecommand[25] 0xA4; // Disable Entire Display On (0xa4/0xa5)command[26] 0xA6; // Disable Inverse Display On (0xa6/a7) command[27] 0xAF; //--turn on oled panel result oled_write_cmd(oled, command, 28);if(result ! 0)return result;//更新OLED显示return oled_update(oled); }//将缓冲帧中的像素转换成OLED格式 static void convert_fb_to_oled(struct oled_handle *oled) {int i, j, k;//一共8*8行其中每8行1bytefor(i0; i8; i) {//一个128列for(j0; j16; j) {for(k0; k8; k) {oled-oled_buffer[i][j*8k] (((oled-fb_buffer[i*80][j] k) 0x01) 0) |(((oled-fb_buffer[i*81][j] k) 0x01) 1) |(((oled-fb_buffer[i*82][j] k) 0x01) 2) |(((oled-fb_buffer[i*83][j] k) 0x01) 3) |(((oled-fb_buffer[i*84][j] k) 0x01) 4) |(((oled-fb_buffer[i*85][j] k) 0x01) 5) |(((oled-fb_buffer[i*86][j] k) 0x01) 6) |(((oled-fb_buffer[i*87][j] k) 0x01) 7);}}} }//内核线程用于周期性刷新OLED显示屏 static int oled_thread(void *arg) {struct oled_handle *oled;oled (struct oled_handle*)arg;while(!kthread_should_stop()){//缓冲帧内容改变才刷新OLEDif(memcmp(oled-old_fb_buffer, oled-fb_buffer, OLED_DISPLAY_RAM_SIZE)){//应用层可能正在进行写操作这里延时休眠600~700us等待应用层写完usleep_range(600, 700);//显存格式转换convert_fb_to_oled(oled);//记录缓冲帧状态memcpy(oled-old_fb_buffer, oled-fb_buffer, OLED_DISPLAY_RAM_SIZE);//更新显示oled_update(oled);}else{//休眠msleep_interruptible(2);}}return 0; }static inline unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf) {chan 0xffff;chan 16 - bf-length;return chan bf-offset; }static int oled_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info) {unsigned int val;unsigned int *pseudo_palette;if (regno 16)return -EINVAL;val chan_to_field(red, info-var.red);val | chan_to_field(green, info-var.green);val | chan_to_field(blue, info-var.blue);pseudo_palette info-pseudo_palette;pseudo_palette[regno] val;return 0; }//缓冲帧操作函数集合 static struct fb_ops oled_ops {.owner THIS_MODULE,.fb_setcolreg oled_setcolreg,.fb_fillrect cfb_fillrect,.fb_copyarea cfb_copyarea,.fb_imageblit cfb_imageblit, };static int oled_probe(struct spi_device *spi) {int result;struct oled_handle *oled;printk(%s\r\n, __FUNCTION__);//设置SPI设备的DMA寻址范围不然dma_alloc会执行失败spi-dev.coherent_dma_mask DMA_BIT_MASK(32);//分配OLED句柄oled devm_kmalloc(spi-dev, sizeof(struct oled_handle), GFP_KERNEL);if(!oled){printk(alloc oled_buffer failed\r\n);return -ENOMEM;}memset(oled, 0x00, sizeof(struct oled_handle));//分配oled缓存缓冲帧中的数据经过格式转换后拷贝到oled_buffer中然后在显示到屏幕oled-oled_buffer devm_kmalloc(spi-dev, OLED_DISPLAY_RAM_SIZE, GFP_KERNEL);if(!oled-oled_buffer){printk(alloc oled_buffer failed\r\n);return -ENOMEM;}memset(oled-oled_buffer, 0x00, OLED_DISPLAY_RAM_SIZE);//分配old_fb缓存用于存储上一次更新显示器时缓冲帧中的状态oled-old_fb_buffer devm_kmalloc(spi-dev, OLED_DISPLAY_RAM_SIZE, GFP_KERNEL);if(!oled-old_fb_buffer){printk(alloc old_fb_buffer failed\r\n);return -ENOMEM;}memset(oled-old_fb_buffer, 0x00, OLED_DISPLAY_RAM_SIZE);//分配缓冲帧oled-fb_buffer dma_alloc_wc(spi-dev, OLED_DISPLAY_RAM_SIZE, oled-phy_addr, GFP_KERNEL);if(!oled-fb_buffer){printk(alloc fb_buffer failed\r\n);return -ENOMEM;}memset(oled-fb_buffer, 0x00, OLED_DISPLAY_RAM_SIZE);//设置SPI设备的驱动私有数据spi-dev.driver_data (void*)oled;//给oled句柄绑定SPI设备oled-spi spi;//设置SPI模式也可以在设备树中进行配置/*MODE3CPOL1CPHA1*/oled-spi-mode SPI_MODE_3;spi_setup(oled-spi);//初始化OLED的GPIOresult devm_pin_init(oled);if(result 0){dma_free_wc(spi-dev, OLED_DISPLAY_RAM_SIZE, oled-fb_buffer, oled-phy_addr);printk(init gpio failed\r\n);return result;}//初始化OLED屏幕result oled_init(oled);if(result 0){dma_free_wc(spi-dev, OLED_DISPLAY_RAM_SIZE, oled-fb_buffer, oled-phy_addr);printk(oled_init failed\r\n);return result;}//分配缓冲帧句柄oled-fb framebuffer_alloc(0, spi-dev);if(!oled-fb){dma_free_wc(spi-dev, OLED_DISPLAY_RAM_SIZE, oled-fb_buffer, oled-phy_addr);printk(alloc fb failed\r\n);return -ENOMEM;}//设置fb//显存虚拟地址和大小oled-fb-screen_base (char*)oled-fb_buffer;oled-fb-screen_size OLED_DISPLAY_RAM_SIZE;//LCD分辨率、颜色格式oled-fb-var.xres 128;oled-fb-var.yres 64;oled-fb-var.xres_virtual 128;oled-fb-var.yres_virtual 64;oled-fb-var.bits_per_pixel 1;//IDstrcpy(oled-fb-fix.id, atk,oled);//显存大小和物理地址oled-fb-fix.smem_len OLED_DISPLAY_RAM_SIZE;oled-fb-fix.smem_start oled-phy_addr;//一行的显存长度oled-fb-fix.line_length 16;//显示器类型oled-fb-fix.type FB_TYPE_PACKED_PIXELS;//像素格式oled-fb-fix.visual FB_VISUAL_MONO10;//底层操作函数集合oled-fb-fbops oled_ops;//颜色表oled-fb-pseudo_palette oled-pseudo_palette;//注册缓冲帧驱动result register_framebuffer(oled-fb);if(result 0){framebuffer_release(oled-fb);dma_free_wc(spi-dev, OLED_DISPLAY_RAM_SIZE, oled-fb_buffer, oled-phy_addr);printk(register fb failed\r\n);return result;}//创建内核线程更新OLEDoled-kthread kthread_create(oled_thread, (void*)oled, oled_thread%d,%d, oled-spi-controller-bus_num, oled-spi-chip_select);if(IS_ERR(oled-kthread)){unregister_framebuffer(oled-fb);framebuffer_release(oled-fb);dma_free_wc(spi-dev, OLED_DISPLAY_RAM_SIZE, oled-fb_buffer, oled-phy_addr);printk(create oled_thread failed\r\n);return PTR_ERR(oled-kthread);}wake_up_process(oled-kthread);return 0; }//设备或驱动卸载时执行 static int oled_remove(struct spi_device *spi) {struct oled_handle *oled;printk(%s\r\n, __FUNCTION__);oled (struct oled_handle*)spi-dev.driver_data;if(!oled){printk(verification failed\r\n);return -EINVAL;}//停止内核线程kthread_stop(oled-kthread);//注销缓冲帧驱动unregister_framebuffer(oled-fb);//释放缓冲帧句柄framebuffer_release(oled-fb);//释放缓冲帧dma_free_wc(spi-dev, OLED_DISPLAY_RAM_SIZE, oled-fb_buffer, oled-phy_addr);return 0; }//匹配列表用于设备树和平台驱动匹配 static const struct of_device_id oled_of_match[] {{.compatible atk,oled},{ /* Sentinel */} }; //传统匹配方式ID列表 static const struct spi_device_id oled_id[] {{} }; //SPI驱动 static struct spi_driver oled_drv {.driver {.name oled,.owner THIS_MODULE,.pm NULL,.of_match_table oled_of_match,},.id_table oled_id,.probe oled_probe,.remove oled_remove, }; static int __init oled_drv_init(void) {int result 0;printk(%s\r\n, __FUNCTION__);//注册SPI设备驱动result spi_register_driver(oled_drv);if(result 0){printk(add cdev failed\r\n);return result;}return 0; }static void __exit oled_drv_exit(void) {printk(%s\r\n, __FUNCTION__);//注销SPI驱动spi_unregister_driver(oled_drv); }module_init(oled_drv_init); module_exit(oled_drv_exit);MODULE_LICENSE(GPL); MODULE_AUTHOR(CSDN); MODULE_DESCRIPTION(oled_dev);编写驱动测试程序 OLED应用程序开发步骤如下 打开缓冲帧设备获取屏幕参数主要包括屏幕x、y像素个数以及每个像素的bit数然后计算出显存的大小通过mmap函数映射显存地址到用户空间通过向映射到用户空间的显存写入数据以控制在OLED上的显示内容使用完成后取消mmap的映射。关闭设备 如下是OLED测试程序的主函数其中oled_lib对OLED的常用功能进行了封装比如初始化、反初始化、画线、画方块、读写像素点等初始化完成的内容包括上面的1~3步反初始化完成的上面的第5步其他接口均是读写显存。 #include unistd.h #include oled_lib.hint main(int argc, char *argv[]) {if(argc 2){printf(Error Usage!\r\n);return -1;}oled_init(argv[1]);while(1){oled_clear();usleep(100*1000);display_line(0, 0, 127, 63);usleep(100*1000);display_line(0, 63, 127, 31);usleep(100*1000);display_rect(55, 5, 50, 20);sleep(1);}return 0; }上机测试 修改设备树设备树需要结合硬件进行修改然后编译设备树并用新的设备树启动从这里下载代码并进行编译然后拷贝到目标板根文件系统的root目录执行命令insmod oled.ko加载OLED驱动加载完成后在/dev目录增加了一个以fb开通的缓冲帧设备文件 执行命令./oled_app.out /dev/fb0运行测试命令/dev/fb0是OLED的缓冲帧设备可以看到屏幕上显示相应的测试图像终端也会打印屏幕的参数。
http://www.pierceye.com/news/56518/

相关文章:

  • 网站建设的公司联系方式电商培训班
  • 电商网站开发面试题各大网站搜索引擎入口
  • 成都建设二维码网站手机网站 微信网站 区别
  • 网站登录模板下载软件工程四大方向
  • 廊坊模板建站代理2017建站之星怎么样
  • 公司网站建设企划书蚌埠网络科技有限公司
  • 文学类网站怎么做泰兴网站制作
  • WordPress去掉由开发沧州快速关键词排名优化
  • 电力网站建设网站 方案
  • 襄樊网站网站建设网站子网页设计
  • 做母婴网站中国证券登记结算有限公司官网
  • 不限空间的免费网站江西宜春市建设局网站
  • 杭州市网站seo闵行手机网站建设
  • 网站域名解析时间网页设计的版式有哪些
  • php网站开发和部署做网站做什么公司好
  • 网站建设征求意见稿免费建站网站一级
  • 什么是网站建设有哪些具体内容网络营销创意方案
  • 莆田外贸网站建设有哪些wordpress实战教程 pdf
  • 安全联盟可信任网站认证 网站网站优化怎么样
  • 网站建设的安全技术中国建筑招聘网官网
  • 学生账号登录平台登录入口seo分析案例
  • 建设银行人力资源系统网站可以做水果的团购网站有哪些
  • 有网站公司源码可以重建网站吗自己做的网站买域名多少钱
  • 天涯网站怎么做外链网站照片上传不了怎么办
  • 17做网站 一件代发网站构成三要素
  • 自己做的网站360显示过期ps网页设计尺寸
  • 互联网站备案信息查询wordpress别名 文章id
  • 大英做网站如何查看网站开发者
  • 凯里市网站建设网站怎么做防360拦截
  • 设计网站官网入口2003建网站