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

肥城做网站广西网站设计运营公司

肥城做网站,广西网站设计运营公司,商城网页制作,祁连网站建设公司目录前言一、建立工程二、编写和移植前期准备驱动部分修改三、使用和验证结论#xff08;2022年1月22日重制#xff09;本文主要是移植带简单图形库的程序#xff0c;如果只是实现DMA控制#xff0c;建议看【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动… 目录前言一、建立工程二、编写和移植前期准备驱动部分修改三、使用和验证结论2022年1月22日重制本文主要是移植带简单图形库的程序如果只是实现DMA控制建议看【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结 本文参考例程 提取码: sch3 前言 本文将介绍在STM32 HAL库下实现硬件IICDMA控制0.96寸 OLED屏以及OLED图形库的移植。 一、建立工程 平台野火指南者STM32F103VET6 STM32Cube MX Keil MDK 5 (示例) 1.选择所用MCU。 2.选择启用晶振 3.选择Debug方式 4.设置时钟树 5.选择合适的引脚开启I2C 6.加入I2Cx_TX的DMA 7.开启12Cx_event_interrupt 8.配置完后建立工程 二、编写和移植 本节主要介绍移植标准库编写的oledlib图形库过程。 oledlib库原作者:MjGame 原作例程开源地址:MjGame 的例程 本文使用的oledlib库修订者一只程序缘 本文所要移植库的开源地址:一只程序缘 的例程 git clone https://gitee.com/jiezhuonew/oledlib.git示例 前期准备 1.先导入所需的文件 所用Delay文件参考《无需另配定时器在STM32 HAL下实现微秒级延时(兼容FreeRTOS)》 2.将delay.h改为我们所用的Delay.h文件 修改u16为unsigned short或uint16_t 驱动部分修改 在oled_config.h中添加#include “main.h”并修改TRANSFER_METHOD 在oled_driver.h和oled_driver.c中注释掉标准库相关的东西 此时编译不再弹出错误。 在oled_driver.c修改I2C_WriteByte函数 /**brief I2C_WriteByte向OLED寄存器地址写一个byte的数据param addr寄存器地址data要写入的数据retval 无*/void I2C_WriteByte(uint8_t addr, uint8_t data){ // while (I2C_GetFlagStatus(I2CX, I2C_FLAG_BUSY));// I2C_GenerateSTART(I2CX, ENABLE);//开启I2C1 // while (!I2C_CheckEvent(I2CX, I2C_EVENT_MASTER_MODE_SELECT)); /*EV5,主模式*/// I2C_Send7bitAddress(I2CX, OLED_ADDRESS, I2C_Direction_Transmitter);//器件地址 -- 默认0x78 // while (!I2C_CheckEvent(I2CX, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));// I2C_SendData(I2CX, addr);//寄存器地址 // while (!I2C_CheckEvent(I2CX, I2C_EVENT_MASTER_BYTE_TRANSMITTED));// I2C_SendData(I2CX, data);//发送数据 // while (!I2C_CheckEvent(I2CX, I2C_EVENT_MASTER_BYTE_TRANSMITTED));// I2C_GenerateSTOP(I2CX, ENABLE);//关闭I2C1总线extern I2C_HandleTypeDef hi2c1;HAL_I2C_Mem_Write(hi2c1, OLED_ADDRESS, addr, I2C_MEMADD_SIZE_8BIT, data, 1, 10);}在oled_driver.c修改OLED_CLS函数 void OLED_CLS(void)//清屏 { // unsigned char m, n; // for (m 0; m 8; m) // { // WriteCmd(0xb0 m); //page0-page1 // WriteCmd(0x00); //low column start address // WriteCmd(0x10); //high column start address // for (n 0; n 128; n) // { // WriteDat(0x00); // } // }extern unsigned char ScreenBuffer[SCREEN_PAGE_NUM][SCREEN_COLUMN];uint16_t i;for (i 0; i SCREEN_PAGE_NUM * SCREEN_COLUMN; i){ScreenBuffer[0][i] 0;}OLED_FILL(ScreenBuffer[0]); }在oled_driver.c修改OLED_FILL函数 void OLED_FILL(unsigned char BMP[]) { // uint8_t i, j;unsigned char *p;p BMP;// for (i 0; i 8; i) // { // WriteCmd(0xb0 i); //page0-page1 // WriteCmd(0x00); //low column start address // WriteCmd(0x10);// for (j 0; j 128; j) // { // WriteDat(*p); // } // }extern I2C_HandleTypeDef hi2c1;while(hi2c1.State ! HAL_I2C_STATE_READY);HAL_I2C_Mem_Write_DMA(hi2c1, OLED_ADDRESS, 0x40, I2C_MEMADD_SIZE_8BIT, p, SCREEN_PAGE_NUM * SCREEN_PAGEDATA_NUM); }注意到 //请将此函数放入1ms中断里为图形提供时基 //系统时间基准主要用于FrameRateUpdateScreen()中固定帧率刷新屏幕 void OledTimeMsFunc(void) {if(OledTimeMs ! 0x00){ OledTimeMs--;} }故到stm32f1xx_it.c中声明并添加此函数 若未使用FreeRTOS则在滴答定时器中断中添加反之在对应定时器中断中添加: /*** brief This function handles System tick timer.*/ void SysTick_Handler(void) {/* USER CODE BEGIN SysTick_IRQn 0 *//* USER CODE END SysTick_IRQn 0 */HAL_IncTick();/* USER CODE BEGIN SysTick_IRQn 1 */OledTimeMsFunc();/* USER CODE END SysTick_IRQn 1 */ }修改OLED_Init函数 void OLED_Init(void) {WriteCmd(0xAE); //display offWriteCmd(0x20); //Set Memory Addressing Mode // WriteCmd(0x10); //00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,InvalidWriteCmd(0x00); //00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,InvalidWriteCmd(0xb0); //Set Page Start Address for Page Addressing Mode,0-7WriteCmd(0xc8); //Set COM Output Scan DirectionWriteCmd(0x00); //---set low column addressWriteCmd(0x10); //---set high column addressWriteCmd(0x40); //--set start line addressWriteCmd(0x81); //--set contrast control registerWriteCmd(0xff); //亮度调节 0x00~0xffWriteCmd(0xa1); //--set segment re-map 0 to 127WriteCmd(0xa6); //--set normal displayWriteCmd(0xa8); //--set multiplex ratio(1 to 64)WriteCmd(0x3F); //WriteCmd(0xa4); //0xa4,Output follows RAM content;0xa5,Output ignores RAM contentWriteCmd(0xd3); //-set display offsetWriteCmd(0x00); //-not offsetWriteCmd(0xd5); //--set display clock divide ratio/oscillator frequencyWriteCmd(0xf0); //--set divide ratioWriteCmd(0xd9); //--set pre-charge periodWriteCmd(0x22); //WriteCmd(0xda); //--set com pins hardware configurationWriteCmd(0x12);WriteCmd(0xdb); //--set vcomhWriteCmd(0x20); //0x20,0.77xVccWriteCmd(0x8d); //--set DC-DC enableWriteCmd(0x14); //WriteCmd(0xaf); //--turn on oled panelOLED_CLS(); }其中 WriteCmd(0x20); WriteCmd(0x00); 两句函数将SSD1306的寻址方式修改为了水平寻址能够一次性对OLED内部Graphic Display Data RAM (GDDRAM)整体更新。 见firestaradmin大佬的 《STM32 DMA-IIC刷新OLED屏(理论可达42帧率)》 和Coder_BCM大佬的 《基于STM32F407的 中景园0.96寸OLEDIIC的程序升级DMAIIC 显存Buffer》) 若发现行错位则修改 WriteCmd(0xd3); //-set display offsetWriteCmd(0x00 加或减 8的倍数); 三、使用和验证 添加test.c该文件源自原例程有修改。 需要注意的是调用OLED_ShowCHinese函数的文件和oled_font.c文件的编码格式需一致GBK。当一个为UTF-8一个为GBK时会显示不出汉字。 /*Copyright (c) [2019] [一只程序缘 jiezhuo][https://gitee.com/jiezhuonew/oledlib] is licensed under the Mulan PSL v1.You can use this software according to the terms and conditions of the Mulan PSL v1.You may obtain a copy of Mulan PSL v1 at:http://license.coscl.org.cn/MulanPSLTHIS SOFTWARE IS PROVIDED ON AN AS IS BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS ORIMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULARPURPOSE.See the Mulan PSL v1 for more details.此函数是oledlib图形库的综合测试函数 基本上使用到了里面的所有内容目前接线说明:仅仅使用到0.96寸7引脚oled 使用SPI通信方式(具体见oled_drive.c)D0 SCK - PA4 (屏幕批次不同丝印可能不同)D1 SDA - PA5RES RES - PA6DC DC - PA7CS SCS - PA8软件模块:oled spi驱动beep 蜂鸣器 提示或作为led表示运行状态timer3 中断1ms 可为图形库提供时间基准uart 可作为串口连接电脑打印调试xinxidelay 系统自带的时间设置与提供延时函数视频演示信息:单片机 --- STM32F103oled --- 采用4线SPI的7引脚0.96寸黑白双色oled图形库功能:在oledlib文件夹下作出多个c文件的分类 每个c文件的开头都有对该文件的简要说明包括打点 画线 矩形 三角形 圆 椭圆 圆角矩形 的边缘与填充还包括 字符显示 汉字显示 位图显示最后还有 oled模拟串口printf的debug字符显示:针对于字符有4种大小0-1-2-3 具体参见SetFontSize()基于大家的使用习惯0是一般大家习惯用的 此时y只能为0-7对应显示的7大行 注意:此时x为地基大行 y为第几列2 3都是基于1的等比例放大 此时y能为0-6x对应显示的每一小行 此时为正常坐标系 x为第几小行 y为第几列中文汉字显示:中文汉字的大小为16x16 此时y也只能为0-7对应显示的7大行 注意:此时x为地基大行 y为第几列取模说明:取模软件采用PCtoLCD2002字符 汉字 和 位图的取模方式和设置都在font.c和bmp.c中有注释用户调用函数:在draw_api.h中提供了所有函数的接口 可在其中查看所有函数的简要功能移植说明:1.移植图形库仅需要准备好底层驱动 在oled_driver.c中作出修改即可 在该c文件开头有说明2.若需要对test.c中的动画效果进行测试 还需要为函数OledTimeMsFunc()提供时间基准3.库函数使用的延时函数是DelayMs() 移植后由单片机型号补充调整DelayMs()图形库本质:该图形库本质为对一数组进行操作 然后刷新整个数组到屏幕中实现效果因此相似点阵屏(oled/TFT/大小尺寸/点阵/液晶)也可以使用 根据像素可参见oled_config.h详细的注释:如果是使用为用途 了解test.c和draw_api.c即可 做出花里胡哨的UI界面在本人阅读代码和注释的过程中 发现很多结构和函数都值得学习 仔细理解理解GUI和本图形库的关系:gui是一个以图形界面来进行人机交互的系统 gui是拥有窗口、菜单、控件、对话框等交互的图形接口这个只是一个图形库 类似于c上的easyx图形库 是没有图形接口的 只提供绘图和显示的功能图形库可以算是gui的一部分也可以自己以图形库继续封装为gui库代码容量:除去位图 Code26254 RO-data3754 RW-data100 ZI-data4108原作的话:为了做这个绘制图形库我参考了很多其他的算法,花了大量时间去做移植优化其中参考最多的是github中的arduboy游戏机大部分图形是移植它的现在是最初的初稿版本,还有很多地方需要优化改进。我想要将这个图形库做大后续会加入更多有趣的东西和模块代码都是用最简单的方式编写的都是开源的。后续也会加上注释说明让更多人以单片机和oled屏来入门硬件编程如果你使用了该库请标明出处。b站关注oximeterg可获取该库的最新版本和消息。注意绘制填充或实心的图形影响刷新效率待优化中 */// #include test.h #include draw_api.h #include ../Delay/Delay.h #include stdlib.h #include stdio.h #include math.hvoid ShowStars(void); void ShowWatch(void); void ShowPolygon(void); void ShowSnow(void);void demo(void) {int i,j;//demo演示ClearScreen();DrawBitmap(0,0,Panda,128,64);UpdateScreen();DelayMs(1000);//字符ClearScreen();SetFontSize(1);DrawString(0,0,test);UpdateScreen();DelayMs(1000);SetFontSize(2);DrawString(0,8,test);UpdateScreen();DelayMs(1000);SetFontSize(3);DrawString(0,24,test);UpdateScreen();DelayMs(1000);//汉字测试ClearScreen();OLED_ShowCHinese(0,0,一只程序缘);UpdateScreen();DelayMs(1000);OLED_ShowCHinese(2,0,一只程序缘一只程序缘一只程序缘一只程序缘);UpdateScreen();DelayMs(1000);//数字测试ClearScreen();for(i0; i300; i){SetFontSize(0);DrawNum(0,96,i,4);SetFontSize(1);DrawNum(0,16,i,4);SetFontSize(2);DrawNum(0,24,i,4);SetFontSize(3);DrawNum(0,40,i,4);UpdateScreen();}//串口debugDelayMs(100);ClearScreen();for(i0; i256; i){OledPrintf(num:%d cha:%c hex:%x\r\n,i,i,i);}DelayMs(100);//划线ClearScreen();for(i0; i20; i){DrawLine(0,0,i*10,63);UpdateScreen();}for(i0; i20; i){DrawLine(128,0,128-i*10,63);UpdateScreen();}DelayMs(100);//矩形for(j0; j2; j){if(j0)ClearScreen();for(i0; i31; i2){DrawRect2(i*2,i,128-i*4,64-2*i);//画矩形外框UpdateScreen();}if(j0)ClearScreen();DelayMs(100);for(i31; i0; i-2){DrawFillRect2(i*2,i,128-i*4,64-2*i);//画实心矩形UpdateScreen();}SetDrawColor(pix_black);//划线颜色SetFillcolor(pix_black);//填充颜色}SetDrawColor(pix_white);SetFillcolor(pix_white);//圆角矩形for(j0; j2; j){if(j0)ClearScreen();for(i0; i25; i2){DrawRoundRect(i*2,i,128-i*4,64-2*i,8);UpdateScreen();}if(j0)ClearScreen();DelayMs(100);for(i25; i2; i-2){DrawfillRoundRect(i*2,i,128-i*4,64-2*i,8);UpdateScreen();}SetDrawColor(pix_black);SetFillcolor(pix_black);}SetDrawColor(pix_white);SetFillcolor(pix_white);DelayMs(100);//椭圆ClearScreen();DrawEllipse(63,31,63,31);UpdateScreen();DelayMs(500);ClearScreen();DrawEllipse(63,31,16,31);UpdateScreen();DelayMs(500);ClearScreen();DrawFillEllipse(63,31,63,31);UpdateScreen();DelayMs(500);ClearScreen();DrawFillEllipse(63,31,16,31);UpdateScreen();DelayMs(500);//圆ClearScreen();DrawCircle(63,31,30);UpdateScreen();DelayMs(500);ClearScreen();DrawFillCircle(63,31,30);UpdateScreen();DelayMs(500);//三角形ClearScreen();DrawTriangle(5,10,100,30,60,50);UpdateScreen();DelayMs(500);ClearScreen();DrawFillTriangle(5,10,100,30,60,50);UpdateScreen();DelayMs(500);//绘制图形图片 位图ClearScreen();DrawBitmap(0,0,BmpTest1,16,16);UpdateScreen();DelayMs(500);DrawBitmap(16,0,BmpTest2,32,32);UpdateScreen();DelayMs(500);DrawBitmap(48,0,BmpTest3,64,64);UpdateScreen();DelayMs(500);//圆弧ClearScreen();for(i0; i360; i){DrawArc(63,31,30,0,i); //画圆弧UpdateScreen();DelayMs(25);ClearScreen();}DrawCircle(63,31,30); //画圆UpdateScreen();DelayMs(100);for(i0; i10; i){DrawFillCircle(63,31,i); //在中心填充圆DrawCircle(63,31,30);UpdateScreen();DelayMs(25);ClearScreen();}//绕点for(i0; i720; i) //转720度2圈{TypeXY temp;SetAngle(i); //设置角度SetRotateCenter(63,31); //设置圆心tempGetRotateXY(63,3130); //讲已知坐标旋转角度DrawFillCircle(temp.x,temp.y,5);//画出算出的位置DrawCircle(63,31,30); //画出轨迹DrawFillCircle(63,31,10); //填充中心UpdateScreen(); //更新屏幕ClearScreen();}//向右边平移for(i0; i95; i){TypeXY temp; //其实就是上面继续旋转SetAngle(720i); //画图的时候x偏移量SetRotateCenter(63i,31);tempGetRotateXY(63i,3130);DrawFillCircle(temp.x,temp.y,5);DrawCircle(63i,31,30);DrawFillCircle(63i,31,10);UpdateScreen();ClearScreen();}//动画ShowStars(); //星空动画ShowWatch(); //时钟动画ShowPolygon(); //多边形动画 // ShowSnow(); //下雪动画DelayMs(100);//结束ClearScreen();SetFontSize(2);DrawString(8,16, Show End ); //显示字符串UpdateScreen();DelayMs(1000);ClearScreen();DrawBitmap(0,10,Like,128,40); //三连图片UpdateScreen();DelayMs(1000); }/ //星空动画 void ShowStars(void) {int i;int count0;int fps60;typedef struct START{short x;short y;short speed;unsigned char speedcount;unsigned char isexist;} Star;Star star[128] {0};srand(2);for(i0; i128; i){if(star[i].isexist0){//设置128个()星星的初始信息star[i].xrand()%127; //随机生成初始x坐标star[i].yrand()%64; //随机生成y的坐标star[i].speedcount0;star[i].speedrand()%81; //1-8的数star[i].isexist1;}}while(1){if(FrameRateUpdateScreen(fps)1) //在此函数中定时刷新屏{count;if(countfps*10) //10秒钟时间到达之后跳出循环结束动画return;}//此段函数一直在运行//依次画出128个星星for(i0; i128; i){//如果这一个星星已经移动到退出屏幕界面//则在最左侧重新生成一颗新星星if(star[i].isexist0){star[i].x0;star[i].yrand()%64;star[i].speedrand()%61;star[i].speedcount0;star[i].isexist1;}else{star[i].speedcount;if(star[i].x124) //标记已经退出屏幕star[i].isexist0;//清除上一个时刻画的星星(的尾巴) 不管有没有操作 都进行清除操作SetDrawColor(pix_black);DrawLine(star[i].x,star[i].y,star[i].x,star[i].y);SetDrawColor(pix_white);if(star[i].speedcountstar[i].speed) //运行时间到了一定的长度{star[i].speedcount0; //复位运行时间并向右移一格star[i].x1; //总之星星的结束需要在这经历124次} //只不过有的更快 就能移动更快//从头到尾画出整条星星 不管星星是否已经变化DrawLine(star[i].x, star[i].y, star[i].x(6/star[i].speed)-1, star[i].y);}}} } //时钟动画 //钟 小时 分钟 秒 void RoundClock(int hours,int minute,int sec) {unsigned char i0;TypeXY hourspoint,minutepoint,secpoint,tmp1,tmp2;//时针SetRotateValue(63,31,hours*30(minute*30)/60,1);hourspointGetRotateXY(63-14,31);DrawLine(63,31,hourspoint.x,hourspoint.y);//分针SetRotateValue(63,31,minute*6(sec*6)/60,1);minutepointGetRotateXY(63-21,31);DrawLine(63,31,minutepoint.x,minutepoint.y);//秒针SetRotateValue(63,31,sec*6,1);secpointGetRotateXY(63-28,31);DrawLine(63,31,secpoint.x,secpoint.y);//表盘for(i0; i12; i){SetRotateValue(63,31,i*30,1);tmp1GetRotateXY(63-29,31);tmp2GetRotateXY(63-24,31);DrawLine(tmp1.x,tmp1.y,tmp2.x,tmp2.y);}DrawFillCircle(63,31,2);DrawCircle(63,31,30);UpdateScreen();DelayMs(25);ClearScreen(); }void ShowWatch(void) {int i,j,z;int count0;for(i0; i12; i)for(j0; j60; j)for(z0; z60; z){RoundClock(i,j,z);count;if(count800)return;} }/ //多边形动画 void ShowPolygon(void) {int x063,y031; //正多边形的外接圆的圆心unsigned char i 0,j;int n1,r31; //画正n边形 大小半径31int v1,count0; //每个相邻的多边形隔1 画count次后退出int x[30],y[30];while(1){ClearScreen();for(i0; in; i){x[i]r*cos(2*3.1415926*i/n)x0;y[i]r*sin(2*3.1415926*i/n)y0;}for(i0; in-2; i){for(ji1; jn-1; j)DrawLine(x[i],y[i],x[j],y[j]);}nv;if(n20||n0)v-v;UpdateScreen();DelayMs(25); //延时停顿100msif(count90){count0;return ;}} }//下雪的函数 和星空类似 void ShowSnow(void) {int a[66],i,num0;int count0;int fps60;struct Snow{short x;short y;short speed;} snow[100];srand(1);for(i0; i66; i)a[i](i-2)*10;ClearScreen();while(1){if(FrameRateUpdateScreen(fps)1) //在此函数中定时刷新屏{count;if(countfps*10) //10秒钟时间到达之后跳出循环结束动画return;}if(num!100){snow[num].speed1rand()%4;irand()%66;snow[num].xa[i];snow[num].y0;num;}for(i0; inum; i){snow[i].ysnow[i].speed;DrawPixel(snow[i].x,snow[i].y1);DrawPixel(snow[i].x1,snow[i].y);DrawPixel(snow[i].x,snow[i].y);DrawPixel(snow[i].x-1,snow[i].y);DrawPixel(snow[i].x,snow[i].y-1);if(snow[i].y63){snow[i].y0;}}UpdateScreen();DelayMs(25);ClearScreen();} } 在main.c文件中包含必要的头文件 //... #include main.h/* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include ../Delay/Delay.h #include ../oledlib/draw_api.h /* USER CODE END Includes */ //...添加初始化函数并测试demo //.../* USER CODE BEGIN 2 */delay_init();InitGraph();/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */void demo(void);demo();}/* USER CODE END 3 */ //...效果如下 结论 相比于普通的硬件IIC控制屏幕改用DMA驱动后刷新率得到了很大提升。其速度提升的原理为《STM32 DMA-IIC刷新OLED屏(理论可达42帧率)》
http://wiki.neutronadmin.com/news/115772/

相关文章:

  • 外贸网站在哪做外链wordpress 页面 插件
  • 瑞安做网站建设哪家好网页设计与网站开发pdf
  • 自学网站有哪些网站建设模型
  • 灵川建设局网站全球建筑设计公司排名
  • 一个ip做几个网站吗重庆seo哪个强
  • 创建网站英文四惠网站建设
  • 网站开发招聘名称长沙网站 建设推广世云网络
  • 网站推广效果的评价指标有高密网站制作
  • 个人做网站有什么好处大型综合门户网站开发
  • wordpress熊掌号文章提交成都seo网络优化公司
  • 郑州做网站加密的公司简述四大行业的网站推广方式
  • 什么是网站主机物流公司创建
  • 洪梅网站建设公司网站地图优化
  • 购物网站建设方案书程序员开源网站
  • seo网站营销推广网站换域名做301会有影响
  • seddog站长之家软件工程师薪资待遇
  • 有没有免费的资源可以在线观看做网站优化有用吗
  • 中国建设银行官方网站纪念币wordpress首页文章排序
  • 揭阳网站制作建设做网站百度还是阿里巴巴好
  • 企业黄页网站源码东莞如何建网站费用
  • 安康微网站建设服饰怎么做网站推广
  • 专业从事网站开发公司兰州seo排名
  • 蚌埠网站制作公司仿糗事百科wordpress
  • 怎么建设网站手机网站制作价格h5 网站开发
  • 有什么平台可以做网站河南省鹤壁市住房和城乡建设局网站
  • 北京建设信息港网站响应式网站开发软件
  • 重庆网站备案查询系统wordpress 图片阴影
  • 博客网站模板用discuz怎样做网站
  • 网站相互推广怎么做wordpress侧边栏实现
  • 5173网站源码婚恋咨询网站运营