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

久安网络微信网站建设沈阳网站建设公司哪家好

久安网络微信网站建设,沈阳网站建设公司哪家好,济南做网站的高端品牌,流程图在线制作免费前言#xff1a; 本实验的目的主要是通过上位机通过UART来控制ESP32端的LED的点亮以及熄灭#xff0c;整个项目逻辑比较简单#xff0c;整体架构如下#xff1a; 上位机(PC)主要是跑在PC端的一个软件#xff0c;主要作用包含#xff1a; 1#xff09;串口相关配置 本实验的目的主要是通过上位机通过UART来控制ESP32端的LED的点亮以及熄灭整个项目逻辑比较简单整体架构如下 上位机(PC)主要是跑在PC端的一个软件主要作用包含 1串口相关配置串口号波特率等配置串口动态识别打开关闭串口等 2发送json指令来控制ESP32 LED等点亮跟熄灭 3显示ESP32吐出来的log 下位机(ESP32)主要就是ESP32开发板主要包含作用如下 1LED灯的驱动 2UART select监听上位机发送的指令从而来控制LED灯的点亮/熄灭 3发送log到上位机 整个工程链接esp32_study/2_peripheral/4_pc_control_led at main · sj15712795029/esp32_study · GitHub 一. ESP32下位机端 1. LED、UART select方式 LED驱动我们在前面已经介绍链接如下一灯大师点亮ESP32的LED_esp32点亮led-CSDN博客 UART select方式我们在前面已经介绍链接如下 详解ESP32使用select函数来监听串口数据-CSDN博客 2. json基础 JSONJavaScript Object Notation是一种轻量级的数据交换格式易于人阅读和编写同时也易于机器解析和生成。它基于JavaScript的一个子集但独立于语言广泛用于Web应用中的数据交换。 a. JSON的基本结构 JSON数据由键值对组成主要有两种结构 对象Object 用花括号 {} 包裹表示一个无序的键值对集合。键值对之间用逗号 , 分隔。键和值之间用冒号 : 分隔。键必须是字符串值可以是字符串、数字、布尔值、数组、对象或 null。 示例 {name: Alice,age: 25,isStudent: false,address: {city: Beijing,postalCode: 100000},hobbies: [reading, traveling] } 数组Array 用方括号 [] 包裹表示一个有序的值集合。值之间用逗号 , 分隔。值可以是字符串、数字、布尔值、数组、对象或 null。 示例 [{name: Alice,age: 25},{name: Bob,age: 30} ] b. JSON的数据类型 JSON支持以下几种数据类型 字符串String用双引号 包裹的文本。数字Number整数或浮点数。布尔值Booleantrue 或 false。数组Array有序的值集合。对象Object无序的键值对集合。null表示空值。 c. JSON的示例 以下是一个包含多种数据类型的JSON示例 {name: Alice,age: 25,isStudent: false,scores: [95, 89, 78],contact: {email: aliceexample.com,phone: 123-456-7890},graduated: null } d. JSON的特点 简洁JSON格式简洁易于阅读和编写。跨语言JSON独立于编程语言几乎所有主流语言都支持JSON的解析和生成。轻量级JSON数据格式比XML更轻量适合网络传输。 e. JSON的使用场景 Web APIJSON常用于Web API的数据交换格式。配置文件许多应用程序使用JSON格式来存储配置信息。数据存储NoSQL数据库如MongoDB使用JSON格式存储数据。 3. json编程 在了解了json的基础后(其实很简单哈就是格式)我们首先要做的第一件事情就是约定下上位机跟下位机的通讯格式我自己定出来一个哈·如下 以LED_ON为例发送的格式如下 {FUNC:HW,OPERATE:LED_ON,PARAM1:null,PARAM2:null,PARAM3:null,PARAM4:null,PARAM5:null,PARAM6:null} 后面的PARAM是为了其他硬件功能的扩展我们在LED灯中没有用到 在ESP IDF中已经集成了json的库就是cJson只需要引用这个头文件即可以使用其中的API #include cJSON.h 我们先来看下核心代码 /* 解析上位机的json格式 */cJSON* parse_json cJSON_Parse((const char *)shell_string);if(!parse_json){ESP_LOGE(TAG, Not specific json format:%s\n,shell_string);goto exit;}uint8_t* func_value (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,FUNC))-valuestring;uint8_t* operate_value (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,OPERATE))-valuestring;uint8_t* para1 (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,PARAM1))-valuestring;uint8_t* para2 (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,PARAM2))-valuestring;uint8_t* para3 (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,PARAM3))-valuestring;uint8_t* para4 (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,PARAM4))-valuestring;uint8_t* para5 (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,PARAM5))-valuestring;uint8_t* para6 (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,PARAM6))-valuestring;ESP_UNUSED(para1);ESP_UNUSED(para2);ESP_UNUSED(para3);ESP_UNUSED(para4);ESP_UNUSED(para5);ESP_UNUSED(para6);if(!func_value || !operate_value){ESP_LOGE(TAG, Not specific json format:%s\n,shell_string);goto exit;}if(strcmp((const char *)func_value,HW) 0){if(strcmp((const char *)operate_value,LED_ON) 0){ESP_LOGD(TAG, UART PARSE DEBUG:operate LED_ON\n);LED_ON;goto exit;}if(strcmp((const char *)operate_value,LED_OFF) 0){ESP_LOGD(TAG, UART PARSE DEBUG:operate LED_OFF\n);LED_OFF;goto exit;}} 这里的核心作用就是解析了json格式来控制了LED灯的点亮系列其中部分API的使用如下 cJSON 是一个轻量级的C语言库用于解析和生成JSON数据。它提供了一系列函数来操作JSON对象和数组。以下是你代码中使用到的 cJSON 函数及其作用的详细介绍 cJSON_Parse cJSON* cJSON_Parse(const char *value); 作用将JSON格式的字符串解析为 cJSON 对象。参数 value要解析的JSON字符串。 返回值 成功时返回一个指向 cJSON 对象的指针。失败时返回 NULL。 cJSON_GetObjectItem cJSON* cJSON_GetObjectItem(const cJSON *object, const char *string); 作用从 cJSON 对象中获取指定键对应的值。参数 object要查找的 cJSON 对象。string要查找的键名。 返回值 成功时返回一个指向 cJSON 对象的指针。如果键不存在或对象不是JSON对象返回 NULL。 cJSON 结构体 cJSON 结构体用于表示JSON数据。常用的字段包括 valuestring如果 cJSON 对象表示一个字符串该字段存储字符串的值。valueint如果 cJSON 对象表示一个整数该字段存储整数的值。valuedouble如果 cJSON 对象表示一个浮点数该字段存储浮点数的值。type表示 cJSON 对象的类型如字符串、数字、对象、数组等。 cJSON_Delete void cJSON_Delete(cJSON *item); 作用释放 cJSON 对象及其所有子对象的内存。参数 item要释放的 cJSON 对象。 代码解析 你的代码片段展示了如何使用 cJSON 库解析JSON字符串并提取其中的值。以下是代码的详细解析 解析JSON字符串 cJSON* parse_json cJSON_Parse((const char *)shell_string); 将 shell_string 解析为 cJSON 对象 parse_json。 提取JSON对象中的值 uint8_t* func_value (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,FUNC))-valuestring; uint8_t* operate_value (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,OPERATE))-valuestring; uint8_t* para1 (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,PARAM1))-valuestring; uint8_t* para2 (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,PARAM2))-valuestring; uint8_t* para3 (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,PARAM3))-valuestring; uint8_t* para4 (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,PARAM4))-valuestring; uint8_t* para5 (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,PARAM5))-valuestring; uint8_t* para6 (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,PARAM6))-valuestring; 使用 cJSON_GetObjectItem 从 parse_json 中提取键为 FUNC、OPERATE、PARAM1 到 PARAM6 的值并将其转换为 uint8_t* 类型。 示例JSON 假设 shell_string 包含以下JSON字符串 {FUNC: start,OPERATE: run,PARAM1: value1,PARAM2: value2,PARAM3: value3,PARAM4: value4,PARAM5: value5,PARAM6: value6 } 解析后func_value 将指向 startoperate_value 将指向 runpara1 到 para6 将分别指向 value1 到 value6。 所有代码如下(包含LED灯的控制UART的select解析) /* UART Select ExampleThis example code is in the Public Domain (or CC0 licensed, at your option.)Unless required by applicable law or agreed to in writing, thissoftware is distributed on an AS IS BASIS, WITHOUT WARRANTIES ORCONDITIONS OF ANY KIND, either express or implied. */ #include stdio.h #include string.h #include sys/fcntl.h #include sys/errno.h #include sys/unistd.h #include sys/select.h #include freertos/FreeRTOS.h #include freertos/task.h #include esp_log.h #include driver/uart_vfs.h #include driver/uart.h #include driver/gpio.h #include cJSON.h#define LED_PIN 17 #define LED_PIN_SEL (1LED_PIN)/* Operate LED on/off */ #define LED_OFF gpio_set_level(LED_PIN, 1) #define LED_ON gpio_set_level(LED_PIN, 0)void bsp_led_init() {gpio_config_t io_conf;io_conf.intr_type GPIO_INTR_DISABLE;io_conf.mode GPIO_MODE_OUTPUT;io_conf.pin_bit_mask LED_PIN_SEL;io_conf.pull_down_en 0;io_conf.pull_up_en 0;gpio_config(io_conf); }static const char* TAG uart_select_example;#define UART_JSON_BUFFER_SIZE 512 char uart_json_buf[UART_JSON_BUFFER_SIZE] {0};void uart_receive_parse(uint8_t *shell_string) {cJSON* parse_json cJSON_Parse((const char *)shell_string);if(!parse_json){ESP_LOGE(TAG, Not specific json format:%s\n,shell_string);goto exit;}uint8_t* func_value (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,FUNC))-valuestring;uint8_t* operate_value (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,OPERATE))-valuestring;uint8_t* para1 (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,PARAM1))-valuestring;uint8_t* para2 (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,PARAM2))-valuestring;uint8_t* para3 (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,PARAM3))-valuestring;uint8_t* para4 (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,PARAM4))-valuestring;uint8_t* para5 (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,PARAM5))-valuestring;uint8_t* para6 (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,PARAM6))-valuestring;ESP_UNUSED(para1);ESP_UNUSED(para2);ESP_UNUSED(para3);ESP_UNUSED(para4);ESP_UNUSED(para5);ESP_UNUSED(para6);if(!func_value || !operate_value){ESP_LOGE(TAG, Not specific json format:%s\n,shell_string);goto exit;}if(strcmp((const char *)func_value,HW) 0){if(strcmp((const char *)operate_value,LED_ON) 0){ESP_LOGD(TAG, UART PARSE DEBUG:operate LED_ON\n);LED_ON;goto exit;}if(strcmp((const char *)operate_value,LED_OFF) 0){ESP_LOGD(TAG, UART PARSE DEBUG:operate LED_OFF\n);LED_OFF;goto exit;}}if(strcmp((const char *)shell_string,shop220811498.taobao.com) 0)ESP_LOGD(TAG, welcome to use our stm32f1 camera wifi board\n);elseESP_LOGD(TAG, UART PARSE ERR:HW_ERR_SHELL_NO_CMD\n);exit:cJSON_Delete(parse_json);return; }static void uart_select_task(void *arg) {if (uart_driver_install(UART_NUM_0, 2 * 1024, 0, 0, NULL, 0) ! ESP_OK) {ESP_LOGE(TAG, Driver installation failed);vTaskDelete(NULL);}uart_config_t uart_config {.baud_rate 115200,.data_bits UART_DATA_8_BITS,.parity UART_PARITY_DISABLE,.stop_bits UART_STOP_BITS_1,.flow_ctrl UART_HW_FLOWCTRL_DISABLE,.source_clk UART_SCLK_DEFAULT,};uart_param_config(UART_NUM_0, uart_config);while (1) {int fd;if ((fd open(/dev/uart/0, O_RDWR)) -1) {ESP_LOGE(TAG, Cannot open UART);vTaskDelay(5000 / portTICK_PERIOD_MS);continue;}// We have a driver now installed so set up the read/write functions to use driver also.uart_vfs_dev_use_driver(UART_NUM_0);while (1) {int s;fd_set rfds;struct timeval tv {.tv_sec 5,.tv_usec 0,};FD_ZERO(rfds);FD_SET(fd, rfds);s select(fd 1, rfds, NULL, NULL, tv);if (s 0) {ESP_LOGE(TAG, Select failed: errno %d (%s), errno, strerror(errno));break;} else if (s 0) {ESP_LOGI(TAG, Timeout has been reached and nothing has been received);} else {if (FD_ISSET(fd, rfds)) {memset(uart_json_buf,0,UART_JSON_BUFFER_SIZE);if (read(fd, uart_json_buf, UART_JSON_BUFFER_SIZE) 0) {// Note: Only one character was read even the buffer contains more. The other characters will// be read one-by-one by subsequent calls to select() which will then return immediately// without timeout.uart_receive_parse((uint8_t *)uart_json_buf);} else {ESP_LOGE(TAG, UART read error);break;}} else {ESP_LOGE(TAG, No FD has been set in select());break;}}}close(fd);}vTaskDelete(NULL); }void app_main(void) {bsp_led_init();xTaskCreate(uart_select_task, uart_select_task, 4 * 1024, NULL, 5, NULL); } 二.PC上位机端 1. 上位机介绍 整个上位机比较简单分为几个区 1串口配置区包括串口的参数串口的打开关闭以及UI上体现不出来的支持串口热插拔扫描等 2LED测试区主要是发送控制LED灯点亮/熄灭的功能 3串口调试区因为我们是通过串口来发送指令所以ESP32下位机的log也会通过这个串口吐出来所以要做一个类似其他串口工具的串口调试区用来输出log 上位机的概念知识我们就不在这里介绍了因为比较庞大我是用winform来编写的上位机有非常多的空间对于写这种搓搓的上位机已经够用了我们直接贴代码吧 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.IO.Ports; using Newtonsoft.Json;namespace led_control {public partial class Form1 : Form{string hw_func HW;string operate_led_on LED_ON;string operate_led_off LED_OFF;const int PRINTFING_LOG 0;const int PARSEING_JSON 1;int serial_recv_status PRINTFING_LOG;string recv_json_str;public const int WM_DEVICE_CHANGE 0x219;public const int DBT_DEVICEARRIVAL 0x8000;public const int DBT_DEVICE_REMOVE_COMPLETE 0x8004;public Form1(){InitializeComponent();System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls false;}private void Form1_Load(object sender, EventArgs e){search_add_serial_port();cb_serial_baudrate.SelectedIndex 0;}/* 串口搜索 */private void search_add_serial_port(){/* 更新串口按键状态 *//*------串口界面参数设置------*/int has_port 0;//检查是否含有串口string[] str SerialPort.GetPortNames();//添加串口foreach (string s in str){has_port;if (!cb_serial_port.Items.Contains(s))cb_serial_port.Items.Add(s);}if (has_port 0){return;}//设置默认串口选项cb_serial_port.SelectedIndex 0;}protected override void WndProc(ref Message m){if (m.Msg WM_DEVICE_CHANGE) // 捕获USB设备的拔出消息WM_DEVICECHANGE{switch (m.WParam.ToInt32()){case DBT_DEVICE_REMOVE_COMPLETE: // USB拔出 {b_serial_open.Enabled true;b_serial_close.Enabled false;}break;case DBT_DEVICEARRIVAL: // USB插入获取对应串口名称 {search_add_serial_port();}break;}}base.WndProc(ref m);}private void b_serial_send_Click(object sender, EventArgs e){if (t_data_send.Text )MessageBox.Show(发送内容为空, 错误提示);else{if (serialPort1.IsOpen)serialPort1.Write(t_data_send.Text);elseMessageBox.Show(先打开串口, 错误提示);}}private void b_serial_open_Click(object sender, EventArgs e){if (!serialPort1.IsOpen)//串口处于关闭状态{try{if (cb_serial_port.SelectedIndex -1){MessageBox.Show(Error: 无效的端口,请重新选择, Error);return;}string strSerialName cb_serial_port.SelectedItem.ToString();serialPort1.PortName strSerialName;//串口号serialPort1.BaudRate Convert.ToInt32(cb_serial_baudrate.SelectedItem.ToString());//波特率serialPort1.DataBits 8;//数据位serialPort1.StopBits StopBits.One;serialPort1.Parity Parity.None;//打开串口serialPort1.Open();b_serial_open.Enabled false;b_serial_close.Enabled true;}catch (System.Exception ex){MessageBox.Show(Error: ex.Message, Error);return;}}}private void b_serial_close_Click(object sender, EventArgs e){if (serialPort1.IsOpen)//串口处于关闭状态{serialPort1.Close();//关闭串口b_serial_open.Enabled true;b_serial_close.Enabled false;}}private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e){if (serialPort1.IsOpen){try{string recv_data_string;int recv_data_count serialPort1.BytesToRead;while (serialPort1.BytesToRead 0){recv_data_string serialPort1.ReadLine();if (recv_data_string.Contains({) || (serial_recv_status PARSEING_JSON)){serial_recv_status PARSEING_JSON;recv_json_str recv_data_string;if (recv_data_string.Contains(})){serial_recv_status PRINTFING_LOG; #if CONSOLE_DEBUGConsole.WriteLine(recv_json_str); #endifjson_status status JsonConvert.DeserializeObjectjson_status(recv_json_str);json_status_recv_parse(status);recv_json_str ;//return;}}else{t_data_recv.AppendText(recv_data_string \r \n);}}}catch (Exception ex){return;}}}private void b_led_on_Click(object sender, EventArgs e){json_construction_send(hw_func, operate_led_on, null, null, null, null, null, null);}private void b_led_off_Click(object sender, EventArgs e){json_construction_send(hw_func, operate_led_off, null, null, null, null, null, null);}private void json_construction_send(string func, string operate, string param1, string param2, string param3, string param4, string param5, string param6){json_commmand cmd new json_commmand();cmd.FUNC func;cmd.OPERATE operate;cmd.PARAM1 param1;cmd.PARAM2 param2;cmd.PARAM3 param3;cmd.PARAM4 param4;cmd.PARAM5 param5;cmd.PARAM6 param6;string json_cmd JsonConvert.SerializeObject(cmd); #if CONSOLE_DEBUGConsole.WriteLine(json_cmd); #endifif (serialPort1.IsOpen){serialPort1.WriteLine(json_cmd);}}private void json_status_recv_parse(json_status status){ #if CONSOLE_DEBUGConsole.WriteLine(----------json_status_recv_parse-------------);Console.WriteLine(json func: status.FUNC);Console.WriteLine(json operate: status.OPERATE);Console.WriteLine(json status: status.STATUS);Console.WriteLine(json param1: status.PARAM1);Console.WriteLine(json param2: status.PARAM2);Console.WriteLine(json param3: status.PARAM3);Console.WriteLine(json param4: status.PARAM4);Console.WriteLine(json param5: status.PARAM5);Console.WriteLine(----------json_status_recv_parse end--------); #endif}private void b_serial_send_Click_1(object sender, EventArgs e){if (t_data_send.Text )MessageBox.Show(发送内容为空, 错误提示);else{if (serialPort1.IsOpen)serialPort1.Write(t_data_send.Text);elseMessageBox.Show(先打开串口, 错误提示);}}}/* JSON定义 */public class json_commmand{public string FUNC { get; set; }public string OPERATE { get; set; }public string PARAM1 { get; set; }public string PARAM2 { get; set; }public string PARAM3 { get; set; }public string PARAM4 { get; set; }public string PARAM5 { get; set; }public string PARAM6 { get; set; }}public class json_status{public string FUNC { get; set; }public string OPERATE { get; set; }public string STATUS { get; set; }public string PARAM1 { get; set; }public string PARAM2 { get; set; }public string PARAM3 { get; set; }public string PARAM4 { get; set; }public string PARAM5 { get; set; }public string PARAM6 { get; set; }} }2. 发送json数据来控制LED灯 每个语言基本都有自己的json库我们c#用的是using Newtonsoft.Json; 点击LED ON(蓝色图标)触发的动作如下 string hw_func HW; string operate_led_on LED_ON;private void b_led_on_Click(object sender, EventArgs e) {json_construction_send(hw_func, operate_led_on, null, null, null, null, null, null); }点击LED OFF(红色图标)触发的动作如下 string hw_func HW; string operate_led_off LED_OFF;private void b_led_off_Click(object sender, EventArgs e) {json_construction_send(hw_func, operate_led_off, null, null, null, null, null, null); } 其中json_construction_send函数如下 private void json_construction_send(string func, string operate, string param1, string param2, string param3, string param4, string param5, string param6) {json_commmand cmd new json_commmand();cmd.FUNC func;cmd.OPERATE operate;cmd.PARAM1 param1;cmd.PARAM2 param2;cmd.PARAM3 param3;cmd.PARAM4 param4;cmd.PARAM5 param5;cmd.PARAM6 param6;string json_cmd JsonConvert.SerializeObject(cmd); #if CONSOLE_DEBUGConsole.WriteLine(json_cmd); #endifif (serialPort1.IsOpen){serialPort1.WriteLine(json_cmd);} }可以看到这个也是遵循我们指定的json格式上位机跟下位机的格式是一致的 我们就来看下这个函数非常简单 创建 JSON 命令对象: json_commmand cmd new json_commmand(); 这里创建了一个 json_commmand 类的实例 cmd。json_commmand 类应该是一个自定义类用于存储命令的各个部分。 设置命令属性 cmd.FUNC func; cmd.OPERATE operate; cmd.PARAM1 param1; cmd.PARAM2 param2; cmd.PARAM3 param3; cmd.PARAM4 param4; cmd.PARAM5 param5; cmd.PARAM6 param6; 将传入的参数赋值给 cmd 对象的相应属性。 将对象序列化为 JSON 字符串: string json_cmd JsonConvert.SerializeObject(cmd); 使用 JsonConvert.SerializeObject 方法将 cmd 对象序列化为 JSON 格式的字符串。JsonConvert 是 Newtonsoft.Json 库中的一个类用于处理 JSON 数据的序列化和反序列化。 通过串口发送 JSON 命令: if (serialPort1.IsOpen) {serialPort1.WriteLine(json_cmd); }
http://www.dnsts.com.cn/news/49345.html

相关文章:

  • 网站制作无锡如何查商标是否已被注册
  • 吉林智能建站系统价格wordpress编辑器增加按钮
  • 唐山网站制作案例字体+添加+wordpress
  • 哪些网站需要icp备案佛山用户网站建站
  • 网站买云服务哪家好网站开发维护花费
  • 百度网盘做自已网站wordpress常规选项
  • 网站开发 售后服务协议河北云网站建设
  • 网站开发用哪个软件方便怎么看一个网站是什么时候做的
  • wordpress主题 team talk花都网络推广seo公司
  • 织梦网站怎么把index.html去掉seoul是哪个城市
  • 外贸公司网站建设方案电脑手机一体网站
  • 高端网站建设公司名称八爪鱼网站建设
  • 企业网站推广的线上渠道有哪些怎么自己制作软件app
  • 网站未及时续费手机端网站动效类怎么做
  • 菏泽市城乡和建设局网站公司网站制作费计入会计什么科目
  • 南京汤山建设银行网站杭州老牌的网站建设
  • 网站设计制作的服务商登录html模板
  • 成都公司核名的网站脑白金网络营销方式
  • 为什么想做网站运营杭州电子商务网站建设
  • 永久开源的免费建站系统北京门户网站设计
  • 网站建设续约合同朋友圈广告
  • 沈阳哪里有教做网站的域名状态查询
  • 莒南建设局网站招聘网站开发设计文档
  • 怎么在赶集网上做招聘网站设计本质是什么
  • 河北省建设网站首页中山市住房建设局网站
  • html导航网站源码白水网站建设
  • 新手做自己的网站教程选择赣州网站建设
  • 一家专业做导购的网站定兴网站建设
  • psd 下载网站深圳宝协建设公司
  • 池州市建设厅官方网站wordpress 本地