以前做过的一个演示项目,一款判断人体进出的语言播报方案,通过LwM2M 协议连接 OneNET :
硬件平台:M5311 + STM32F103
云平台:中国移动 OneNET
语音芯片:WT(唯创知音) WT588D
传感器探头:  SHARP(夏普)  GP2Y0A21YK0F
文章意在于对本次项目做个笔记,方便以后再次用到。

目录

  • 前言
  • 一、硬件部分
    • 1.1 M5311芯片部分
    • 1.2 SIM 卡部分
    • 1.3 控制与指示部分
    • 1.4 STM32部分
    • 1.5 WT588D部分
    • 1.6 功放部分
    • 1.7 电源部分
  • 二、对接流程
    • 2.1 整理流程图
    • 2.2 注册码
    • 2.3 OneNeT 指令集接入汇总
      • 2.3.1 资源说明
  • 三、软件部分
    • 3.1 基本定义
    • 3.2 AT命令发送函数
    • 3.3 M5311初始化函数
  • 四、云平台部分
    • 4.1 创建添加产品
    • 4.2 添加设备

前言

本文是个人笔记,文章只讲基本流程,不讲细节,因为时间太久了,也不太记得了= =!只是个人笔记……

最后所有的资料原理图和程序都会上传至资源。

一、硬件部分

整个项目硬件本相对来说是最简单的,硬件设计可以参考《M5311硬件设计手册》,下面上一下各部分原理图,因为本文主要记录的是 M5311 的使用,STM32我就当大家都很熟悉了,上个最小系统,然后语音模块WT588D 芯片:

1.1 M5311芯片部分

1.2 SIM 卡部分

1.3 控制与指示部分

1.4 STM32部分

1.5 WT588D部分

1.6 功放部分

1.7 电源部分


其他的细节图这里就不上了,只要把主要的这几个地方设计好,其他的地方是很简单的。

二、对接流程

一般来说,对于开发者,这种对接流程是整个工程中相对比较复杂的。

但是中移动官方已经给我们提供了详细的说明文档:《M531X_OneNET参考手册》,因为模块是中移动的,云平台也是中移动的,所以对接资料还是很到位的,这里我只做个简单总结:

2.1 整理流程图

2.2 注册码

一般来说都是对接重庆的平台,M5311直接使用这个码就可以:

/*设置模组侧设备注册码*/
char* Onenet_key = "AT+MIPLCREATE=56,130038F10003F2002A04001100000000000010196E\
62696F7462742E6865636C6F7564732E636F6D3A35363833000131F300080000000000,0,56,0\r\n";//设置模组侧设备注册码

2.3 OneNeT 指令集接入汇总

说明部分截取文档中的说明:

2.3.1 资源说明

对于上面的 Object 3200 资源对应关系,有一个表格(下面只列出了部分),在上传资源《资源表》文档有完整的说明:

如果设备超过了保活时间就会离线,此时无法发送消息,需要重新上线,但是不需要再进行注册码登记了,直接发送资源配置与登录即可,保活时间单位为s

三、软件部分

本项目的重点就在于 M5311 的驱动部分,解决了 M5311 的驱动,其他基本没有问题。

3.1 基本定义

M5311 的驱动需要根据文档的说明来,首先我们得根据自己的需求做一个初始的定义:

3.2 AT命令发送函数

其次实现 AT 指令发送的函数:

3.3 M5311初始化函数

初始化函数中除了对模块的复位操作,还有重要的地方就是获取 SIM 卡的 IMEI 和 IMSI,这个在后面平台添加设备的时候需要填写 SIM 卡的这两个参数。

初始化函数如下图:

其他的地方直接看下面源代码把。

虽然所有资料我会上传至资料,但是还要积分下载,这里我把本项目核心的 M5311 驱动部分代码直接贴上,需要的小伙伴直接看这个就行了

/******
*
正常程序中等待返回指令,不能死等,如果设备没有插卡或者卡不正常,就永远启动不了,
进入不了正常的门禁程序
每个步骤使用函数定义,每个步骤规定尝试次数,使用if判断 即便失败,也能够进入正常程序2020/2/18
模组侧 OneNET 数据收发流程
序列  命令  描述
1   AT+MIPLNOTIFY=0,0,3200,0,5750,1,4,"abcd",0,0,147    数据上传
2   AT+MIPLREADRSP=0,32705,1,3200,0,5750,1,4,"abcd",0,0  Read 操作回复
3   AT+MIPLWRITERSP=0,25845,2                            Write 操作回复
4   AT+MIPLEXECUTERSP=0,18166,2                          Execute 操作回复data type
1 string  2 opaque  3  integer  4 float   5 bool+MIPLNOTIFY Example
AT+MIPLNOTIFY=0,1477,3202,0,5600,4,3,"1.2",0,0,35
OK
+MIPLEVENT:0,26,35
AT+MIPLNOTIFY=0,1478,3202,2,5600,4,5,"-0.08",2,1
OK
AT+MIPLNOTIFY=0,1478,3202,2,5601,4,3,"-0.08",1,2
OK
AT+MIPLNOTIFY=0,1478,3202,2,5602,4,5,"-0.08",0,0
OK
4.6.9. AT+MIPLREADRSP+MIPLREADRSP Example
+MIPLREAD:0,289,3200,0,5750
AT+MIPLREADRSP=0,289,1,3202,0,5750,1,5,"-0.08",0,0    //"-0.08前面是长度",5    再前面2个是数据类型  1
OK示例
+MIPLREAD:<ref>,<mid>,<objid>,<insid>,<resid>
参数说明
<ref>
OneNET 设备实例 ID。
<mid>
消息 ID。
<objid>
Object ID。
<insid>
Instance ID,如果为-1,需要读取该 object 下的所有资源。
<resid>
Resource ID,如果为-1,需要读取该 instance 下的所有资源。+MIPLREAD:0,18172,3200,0,5750
AT+MIPLREADRSP=0,18172,11       //错误读取
OK
+MIPLREAD:0,18172,3200,0,-1
AT+MIPLREADRSP=0,18172,1,3200,0,5500,5,1,"0",2,1        //最后一个1,第一条报文
OK
AT+MIPLREADRSP=0,18172,1,3200,0,5501,3,3,"-12",1,2      //最后一个为2,中间报文
OK
AT+MIPLREADRSP=0,18172,1,3200,0,5750,1,4,"test",0,0     //最后一个为0,最后一条报文
OK+MIPLWRITERSP Example
+MIPLWRITE:0,321,3200,0,5750,1,3,123,0
AT+MIPLWRITERSP=0,321,2
OK2020/2/19
AT+MIPLDISCOVERRSP
该命令用于设置指定 object 的所需资源列表。
举例:
/
查表可得:此处设定 数字输入 3个资源列表:1、数字输入状态  2、数字输入计数器  3、应用类型
/
AT+MIPLDISCOVERRSP=0,3200,1,14,”5500;5501;5750”
OK说明:设备注册时间例程为 3000S,时间范围为 有符号的 4字节整形  [-2147483648, 2147483647];
建议设置为一两天,快到时间更新
:
模组侧设备存活时间更新流程
序列  命令  描述
AT+MIPLUPDATE=0,3000,0       //存活时间更新流程,继续存活3000S******/
#include"common.h"// typedef enum
// {//  //! Waiting for the synchronisation  +MIPLxxxx
//  GET_SYNC_STATE=0,
//  //!
//  GET_ref_STATE,
//  //!
//  GET_mid_STATE,
//  //!
//  GET_objid_STATE,
//     //!
//     GET_insid_STATE,
//     GET_resid_STATE
// } STATES_GET_PACKET; char* AT = "AT";
char* AT_RST = "AT+CMRB";
char* IMEI = "AT+GSN";
char* IMSI = "AT+CIMI";
char* Open_led = "AT+CMSYSCTRL=0,2";
char* Close_sleep = "AT+SM=LOCK_FOREVER";
// char* RSSI = "AT+CSQ";
// char* CEREG = "AT+CEREG?";
char RSSI[] = "AT+CSQ";
char CEREG[] = "AT+CEREG?";
/*设置模组侧设备注册码*/
char* Onenet_key = "AT+MIPLCREATE=56,130038F10003F2002A04001100000000000010196E\
62696F7462742E6865636C6F7564732E636F6D3A35363833000131F300080000000000,0,56,0\r\n";//设置模组侧设备注册码
char* LWM_object_T = "AT+MIPLADDOBJ=0,3303,1,\"1\",0,1";  //订阅 Object 3303 资源设置
char* LWM_Resource_T = "AT+MIPLDISCOVERRSP=0,3303,1,4,\"5700\"";//订阅 Resource 5700 资源设置
char* LWM_object_H = "AT+MIPLADDOBJ=0,3304,1,\"1\",0,1";//订阅 Object 3304 资源设置
char* LWM_Resource_H = "AT+MIPLDISCOVERRSP=0,3304,1,4,\"5700\""; //订阅 Resource 5700 资源设置
char* Onenet_connect = "AT+MIPLOPEN=0,65000,30"; //设备登录到 OneNET 平台,一天为86400秒,16位 65535 ,定时65000S,到64500时间更新
char LWM_object_Pir[] = "AT+MIPLADDOBJ=0,3300,1,\"1\",0,0";         //3300通用传感器
char LWM_Resource_Pir[] = "AT+MIPLDISCOVERRSP=0,3303,1,4,\"5502\"";//订阅 Resource 5502 资源设置 ,bool类型,分别对应进出char* Time_refresh = "AT+MIPLUPDATE=0,65000,0"; //平台时间更新
char* T_begin= "AT+MIPLNOTIFY=0,0,3303,0,5700,4,4,\"";
char* T_end = "\",0,0";void T_Send_Test(u8 t_data){char Send_onenet_T[50] = ""; sprintf(Send_onenet_T,"AT+MIPLNOTIFY=0,0,3303,0,5700,4,4,\"%d\",0,0",t_data); Iot_SendCmd(Send_onenet_T,"OK",1000);
}/*******************************************************************************发送字符串  并解析返回值是否正确cmd为传入值  reply 为校验返回值 wait 为延时
*******************************************************************************/
int Iot_SendCmd(char* cmd, char* reply, int wait)
{u8 i;memset(&struct_usart3.USART_BUFF, 0, sizeof(struct_usart3.USART_BUFF)); //先清空缓冲区struct_usart3.USART_Length = 0;printf("[NBiot_SendCmd] %s\r\n 等待时间 %d ms\r\n", cmd,wait);delay_ms(100);uart3_send_buff((u8*)cmd,strlen(cmd));if (wait >= 1000){for (i = 0; i < (wait / 1000); i++){delay_ms(1000);}}else delay_ms(wait);if(strcmp(reply , "") == 0) return 0 ; // 返回值为空if (struct_usart3.USART_Length != 0){if (strstr((char*)struct_usart3.USART_BUFF, reply)){printf("\r\n%s\r\n", struct_usart3.USART_BUFF);return 1;}else if (strstr((char*)struct_usart3.USART_BUFF, "ERROR")){printf("ERROR...\r\n");return 0;}else{printf("\r\n%s\r\n", struct_usart3.USART_BUFF);return 0;}}return 0 ;
}void Iot_SendNOCheck(char* cmd)
{uart3_send_buff((u8*)cmd,strlen(cmd));
}void m5311_on(void)
{//硬件复位GPIO_SetBits(GPIOB,GPIO_Pin_7);delay_ms(1200);GPIO_ResetBits(GPIOB,GPIO_Pin_7);delay_ms(200);
}/*************** 重启模块*************//*************** 重启模块,如果失败,尝试3次*************/
int Rst_mode()
{int res = 0 ;int i = 0;for(i=0;i<4;i++){res = Iot_SendCmd(AT_RST,"READY",3000);if(res == 1) return res;}  return res ;
}/*************** AT,如果失败,尝试3次*************/
int AT_OK()
{int res = 0 ;int i = 0;for(i=0;i<4;i++){res = Iot_SendCmd(AT,"OK",1000);if(res == 1) return res;} return res ;
}/*************** 关闭睡眠,如果失败,尝试3次*************/
int Closesleep_mode()
{int res = 0 ;int i = 0;for(i=0;i<4;i++){res = Iot_SendCmd(Close_sleep,"OK",1000);if(res == 1) return res;}    return res ;
}int Check_CEREG()
{int res = 0 ;int i = 0;for(i=0;i<6;i++){res = Iot_SendCmd(CEREG,"1",1500);if(res == 1) return res;}   return res ;
}/*************** Onenet注册码 ,如果失败,尝试3次*************/
int Onenet_create()
{int res = 0 ;int i = 0;for(i=0;i<4;i++){res = Iot_SendCmd(Onenet_key,"+MIP",1500);if(res == 1) return res;}  return res ;
}/*
订阅Object,LWM2M协议标准
*/
int Lwm2m_object_Pir()
{int res = 0 ;int i = 0;for(i=0;i<4;i++){res = Iot_SendCmd(LWM_object_Pir,"OK",1000);if(res == 1) return res;} return res ;
}int Lwm2m_object_T()
{int res = 0 ;int i = 0;for(i=0;i<4;i++){res = Iot_SendCmd(LWM_object_T,"OK",1000);if(res == 1) return res;}   return res ;
}int Lwm2m_object_H()
{int res = 0 ;int i = 0;for(i=0;i<4;i++){res = Iot_SendCmd(LWM_object_H,"OK",1000);if(res == 1) return res;}   return res ;
}/*
订阅Resource
*/int Lwm2m_resource_Pir()
{int res = 0 ;int i = 0;for(i=0;i<4;i++){res = Iot_SendCmd(LWM_Resource_Pir,"OK",1000);if(res == 1) return res;}   return res ;
}int Lwm2m_resource_T()
{int res = 0 ;int i = 0;for(i=0;i<4;i++){res = Iot_SendCmd(LWM_Resource_T,"OK",1000);if(res == 1) return res;} return res ;
}int Lwm2m_resource_H()
{int res = 0 ;int i = 0;for(i=0;i<4;i++){res = Iot_SendCmd(LWM_Resource_H,"OK",1000);if(res == 1) return res;} return res ;
}/*************** Onenet登录 ,如果失败,尝试3次*************/
int Onenet_sign_in()
{int res = 0 ;int i = 0;for(i=0;i<4;i++){res = Iot_SendCmd(Onenet_connect,"OK",1000); //测试查看返回结果再确定如何使用if(res == 1) return res;}   return res ;
}int Onenet_time_refresh()
{int res = 0 ;int i = 0;for(i=0;i<4;i++){res = Iot_SendCmd(Time_refresh,"OK",1000); //测试查看返回结果再确定如何使用if(res == 1) return res;} return res ;
}/*
采用这种逻辑,产品不会因为NB网络问题导致,正常的门禁播报不能实现
*/
#ifdef TTEST
void m5311_init(void)
{m5311_on();
}
#else
void m5311_init(void)
{m5311_on();printf("等待软复位……\r\n");if(Rst_mode()){if(AT_OK()){printf("复位成功……,AT指令测试成功,打开LED指示灯\r\n");Iot_SendCmd(Open_led, "OK", 1000);//打开LED指示灯,正常程序不需要if(Closesleep_mode()){printf("关闭睡眠模式,查询NB卡的IMEI和IMSI\r\n");Iot_SendCmd(IMEI,"OK", 1000);  //获取IMEIIot_SendCmd(IMSI,"OK", 1000);  //获取IMSI printf("查看信号质量\r\n");if(Check_CEREG()){printf("信号正常,一切准备就绪\r\n");  }  }}}
}
#endif
/*****onenet 连接while (!Send_NBIOT(Onenet_key, "+MIP", 500));   //这个消息经常返回出错,原因不明。while (!Send_NBIOT(LWM_object_T, "OK", 1000));while (!Send_NBIOT(LWM_Resource_T, "OK", 1000));while (!Send_NBIOT(LWM_object_H, "OK", 1000));while (!Send_NBIOT(LWM_Resource_H, "OK", 1000));while (!Send_NBIOT(Onenet_connect, "OK", 1000));Serial.println("Connect_onenet!!!");*******/
#ifdef TTEST
void onenet_init(void)
{printf("开始测试……,请手动输入指令\r\n");
}
#else
void onenet_init()
{printf("开始创建设备,如果创建过,返回错误也没关系,直接跳过这一步\r\n");Onenet_create(); Lwm2m_object_Pir();Lwm2m_resource_Pir();if(Onenet_sign_in()){printf("ONENET 登录成功!\r\n");   }else;Onenet_ON = TRUE;  //这里不好判断是不是真的连接上了,所以初始化以后目前都认为是连接上了
}
#endif/*数据处理缓存数据处理判断先测试一下,空闲标志位 = 1时候处理,再测试 长度 部位0 情况处理。有一个问题,就是缓存什么时候清空,应该是判断完了以后就清空,要不人随时可能来数据,冲乱数据位void T_Send_Test(u8 t_data){char Send_onenet_T[50] = ""; sprintf(Send_onenet_T,"AT+MIPLNOTIFY=0,0,3303,0,5700,4,4,\"%d\",0,0",t_data); Iot_SendCmd(Send_onenet_T,"OK",1000);
}*/
void EXECUTER_back(char *cmd)
{char Send_EXECUTER_back[50] = "";  sprintf(Send_EXECUTER_back,"AT+MIPLEXECUTERSP=0,%s,2",cmd); Iot_SendNOCheck(Send_EXECUTER_back); printf("%s\r\n",Send_EXECUTER_back);
}void call_back()
{u8 i = 0;u8 j = 0;u8 u8Count  =0;char msg[10] = {0};if(struct_usart3.flag == 1){printf("收到服务器数据:%s \r\n",struct_usart3.USART_BUFF);       if (strstr((char*)struct_usart3.USART_BUFF, "+MIPLEXECUTE")){printf("指令数据……\r\n");if(strstr((char*)struct_usart3.USART_BUFF, "chone")){command_on = TRUE;command = 1;}else if(strstr((char*)struct_usart3.USART_BUFF, "chtwo")){command_on = TRUE;command = 2;}else if(strstr((char*)struct_usart3.USART_BUFF, "chthree")){command_on = TRUE;command = 3;}else if(strstr((char*)struct_usart3.USART_BUFF, "chfour")){command_on = TRUE;command = 4;}else if(strstr((char*)struct_usart3.USART_BUFF, "chfive")){command_on = TRUE;command = 5;}else if(strstr((char*)struct_usart3.USART_BUFF, "chsix")){command_on = TRUE;command = 6;} else if(strstr((char*)struct_usart3.USART_BUFF, "chseven")){command_on = TRUE;command = 7;}else if(strstr((char*)struct_usart3.USART_BUFF, "cheight")){command_on = TRUE;command = 8;}else if(strstr((char*)struct_usart3.USART_BUFF, "chnine")){command_on = TRUE;command = 9;}else if(strstr((char*)struct_usart3.USART_BUFF, "chten")){command_on = TRUE;command = 10;}else;//+MIPLREAD:0,289,3200,0,5750  //AT+MIPLREADRSP=0,32705,1,3200,0,5750,1,4,"abcd",0,0  Read 操作回复,//+MIPLEXECUTE:0,51638,3301,0,5601,4,"ping"//AT+MIPLEXECUTERSP=<ref>,<msgid>,<result>//AT+MIPLEXECUTERSP=0,51638,2for(i=0;i<strlen(struct_usart3.USART_BUFF);i++){if((char)struct_usart3.USART_BUFF[i] == ':') break;             }i++;//0i++;//,i++;//数字第一位,这里如果不继续加一位,下面的for会直接跳出,因为第一个if就是','u8Count =i;for(;i<(strlen(struct_usart3.USART_BUFF)-u8Count);i++){if((char)struct_usart3.USART_BUFF[i] != ','){msg[j++] = struct_usart3.USART_BUFF[i];}else break;} printf("指令回复……\r\n");    EXECUTER_back(msg);printf("指令回复完毕……\r\n"); }else if(strstr((char*)struct_usart3.USART_BUFF, "+MIPLWRITE")){printf("写数据……\r\n");}else if(strstr((char*)struct_usart3.USART_BUFF, "+MIPLREAD")){printf("读数据……\r\n");}else printf("不需要的数据\r\n");printf("清楚缓存……\r\n");struct_usart3.flag = 0;struct_usart3.USART_Length = 0;memset(&struct_usart3.USART_BUFF, 0, sizeof(struct_usart3.USART_BUFF)); //清空缓冲区    }
}

四、云平台部分

云平台设置部分,使用截图演示一遍。

4.1 创建添加产品

在 OneNET 主界面右上角 进入控制台 界面,选择NB-IoT物联网套件,如图:

进入NB-IoT物联网套件页面以后,如果以前有产品会有产品列表:

这里我们点击添加产品:

4.2 添加设备

点击需要添加设备的产品进行添加设备,按如下操作:

这里填写的 IMEI 和 IMSI 是根据上文 3.3 M5311初始化函数获取到的,新的 SIM卡添加设备需要在 第一次上电的时候查看一下这两个参数:

这里我就不添加了,直接用以前的设备做个展示:


添加好了设备以后模块通过我们的正常流程就能与 OneNET 交互信息了,里面的一些详情和资源可以自己研究查看一下,比如资源属性:

这个5502是和 2.3.1 资源说明 一样的,属性意义在《资源表》文档中有说明:

本片记录就到这里,需要全部资源的小伙伴可以去下载,或者直接找我要也可以!

资源链接:STM32+ M5311连接OneNET方案原理图,源码,参考资料

STM32+M5311对接 OneNET 项目记录相关推荐

  1. STM32对接涂鸦wifi模块项目记录(智能插座完善版本)

    应项目需求,客户需要对接涂鸦平台,从了解平台到样品实际落地,还是挺方便的, 做过的一个项目,人体感应智能插座项目,对接涂鸦云 : 硬件平台:STM32F103 WIFI模块: 涂鸦WiFi(型号见文章 ...

  2. stm32 m5311上传gps数据上onenet云平台实现地图定位

    新手,第一次写博客,如有不足请大家见谅并指出.下面开始正文. 本文是帮一个朋友做一个NB_Iot的小东西这个过程的学习记录吧. NB模块是M5311,然后还有一个stm32f103的最小系统开发板,后 ...

  3. M5311模组对接OneNet平台—AT指令基本操作流程(LwM2M协议)

    目录 概述 一.开机驻网流程 二.注册onenet平台 概述 下面将介绍M5311模组对接OneNet平台-AT指令基本操作流程(LwM2M协议),已在项目中使用. 一.开机驻网流程 1.AT+SM= ...

  4. stm32代码_ME3616 NB-IoT模组对接OneNET教程以及STM32代码

    前言 本文讲解所有采用MT2625设计的NB-IoT模组ME3616对接OneNET,适用所有所有采用MT2625设计的NB-IoT模组. MT2625内置OneNET SDK,采用CoAP+LwM2 ...

  5. ME3616 NBIOT模组对接OneNET教程以及STM32代码

    前言 本文讲解所有采用MT2625设计的NBIOT模组ME3616对接OneNET,适用所有所有采用MT2625设计的NBIOT模组.MT2625内置OneNET SDK,采用CoAP+LwM2M协议 ...

  6. 【毕业设计】基于云平台的火灾报警器 - stm32 物联网 单片机 OneNET云平台

    文章目录 0 简介 1 项目简介 2 开发环境 3 火焰传感器 4 连接OneNET云平台 5 演示效果 6 最后 0 简介 Hi,大家好,这里是丹成学长,今天向大家介绍一个 单片机项目 基于云平台的 ...

  7. 毕业设计 基于云平台的火灾报警系统设计与实现 - stm32 物联网 单片机 OneNET云平台

    文章目录 0 简介 1 项目简介 2 开发环境 3 火焰传感器 4 连接OneNET云平台 5 演示效果 6 最后 0 简介 Hi,大家好,学长今天向大家介绍一个 单片机项目 基于云平台的火灾报警器 ...

  8. RT-Thread学习的综合应用——使用AP6181 WiFi模组对接OneNET应用示例

    学习了RT-Thread的内核也有一段时间了,由于各种各样的琐事自己没有去做一个综合应用示例,刚最近有点时间,做了一个对接OneNET的历程,采用的是OneNET的EDP协议,关于OneNET的EDP ...

  9. ssm 项目记录用户操作日志和异常日志

    ssm 项目记录用户操作日志和异常日志 参考文章: (1)ssm 项目记录用户操作日志和异常日志 (2)https://www.cnblogs.com/mei-m/p/10231792.html (3 ...

最新文章

  1. [初级]深入理解乐观锁与悲观锁
  2. Java 爬虫--类似Python的requests库--HttpClient, HttpAsyncClient--Maven
  3. [LeetCode] Count Primes - 素数系列问题
  4. AssetBundle系列——共享资源打包/依赖资源打包
  5. leetcode 467. Unique Substrings in Wraparound String | 467. 环绕字符串中唯一的子字符串(动态规划)
  6. Git 版本对比 idea图形化版本
  7. elasticsearch-analysis-ik-1.10.0中文分词插件安装
  8. 通过css样式,控制文字显示...
  9. thinkphp框架环境部署
  10. [编程语言]C陷阱与缺陷
  11. iOS底层:PAGEZERO的作用
  12. echarts数据可视化系列:柱状图
  13. java 清理页面缓存数据_清除浏览器缓存的几种方法总结(必看)
  14. 金融量化?金融市场?股票? 来,告诉你这些都是什么
  15. 2016年12月当前世界经济形势分析--美国的加息计谋
  16. getch()使用和注意事项!
  17. 从零开始学习SVM(二)---松弛变量
  18. TCP原理,Socket与网络编程入门
  19. OpenCore-Legacy-Patcher 0.5.1正式版
  20. HTML5如何与老师剑指天涯【三】

热门文章

  1. MTK Android4.0.3 ICS 添加缅甸语Myanmar
  2. 软件开发过程一般有几个阶段?每个阶段的作
  3. python详细介绍
  4. 神舟十二号航天员名单确定,3名航天员本次上天将完成这些任务
  5. Android技术功底不够如何去面试,复习指南
  6. 树莓派 魔镜 magicmirror2
  7. PID算法控制平衡小车速度
  8. 提升网站访问速度--Yslow优化
  9. WinRAR安装、破解与去除弹窗广告(亲测有效)
  10. 企业采用电子招投标的优势