前言

在调试之前看这个数据手册一脸懵,特别是MQTT部分还是独立的,这个和前接触到的上海合宙的模块多少有点出处。另外就是那个AT命令的传入参数也是一脸懵,后来发现BC26的模块好像把MQTT部分单独的做成了支持阿里云服务器的功能。接触过阿里云的设备对接相比都知道,阿里云要求的是一机一密或者一型一密,这个在对于简单的成本低廉的MCU来说无疑是一个很大的考验。而BC26这块还是做的非常友好的,在MQTT部分只需要传入产品对应设备下的三元组即可,无需经过哈希算法计算密钥。

先上图:

连接及上传部分:

数据下载部分:

基本上通信也是非常稳定的,不过我这个地方信号贼差,以模块满格31来算,这里测试才有9,10的样子。

整体的应用层思路是这样的:

1、单片机控制模块自检

2、单片机控制模块连接阿里云

3、单片机控制模块定时发送数据并接收下发数据

看上面三个步骤虽然简洁明了,单是要做好单片机的应用底层也不是那么简单,为此我专门谢了一个对应BC26传输机制的地层代码,可以检测BC26模块的状态,连接状态,断线重连、超时复位等机制。详细请看下文代码:

BC26底层驱动部分:

C文件:

#include "fy_bc26.h"
static void ResetModule(void);
static void CheckModule(void);
static void SetCFUN(void);
static void CheckCIMI(void);
static void ActivateNetwork(void);
static void CheckNetwork(void);
static void CheckCSQ(void);
static void QMTCFG(char* PK, char* DN, char* DS);
static void QMTOPEN(void);
static void QMTCONN( char* DN );
static void QMTSUB( char* TOPIC );
static void CheckPubTopic(void);
_typdef_bc26 _bc26;static void ClearFIFO(void) {memset(_bc26.rxbuf,0,256);*(_bc26.rxlen) = 0;
}
void BC26_Configuration(u8 *prx,u16 *rxlen)
{_bc26.rxbuf = prx;*(_bc26.rxlen) = *rxlen;_bc26.timeOver=0;_bc26.csq = 0;_bc26.sta = 0;GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd( BC26_RST_RCC,ENABLE);GPIO_InitStructure.GPIO_Pin = BC26_RST_PIN;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_Init(BC26_RST_PORT, &GPIO_InitStructure);GPIO_ResetBits(BC26_RST_PORT,BC26_RST_PIN);}
static void CheckPubTopic(void) {if(strstr((char *)_bc26.rxbuf,"+QMTPUB: 0,1,0") != NULL) {_bc26.sta = 11;}
}//每300ms执行一次
void BC26_IRQHandler(void) {switch(_bc26.sta) {case 0:ResetModule();break;          //复位模块case 1:CheckModule();break;           //检查模块case 2:SetCFUN();break;               //设置全功能case 3:CheckCIMI();break;                //检查卡case 4:ActivateNetwork();break;        //激活网络case 5:CheckNetwork();break;          //检查网络case 6:CheckCSQ();break;              //检查信号强度case 7:QMTCFG(ProductKey,DeviceName,DeviceSecret);break;        //配置MQTT参数case 8:QMTOPEN();break;               //打开TCP连接case 9:QMTCONN(DeviceName);break;              //登录MQTT服务器case 10:QMTSUB(SubTopic);break;              //订阅主题case 11:break;case 12:CheckPubTopic();                //发布消息状态检测default:break;                            //正常运行状态}
}/*** 功能:复位BC26模组* 参数:None* 返回值:*        0 :正常*      其他: 异常*/
static void ResetModule(void) {if(_bc26.timeOver==0) {_bc26.timeOver = 66;   //20sGPIO_SetBits(BC26_RST_PORT,BC26_RST_PIN);}else {--_bc26.timeOver;if(_bc26.timeOver == 63){GPIO_ResetBits(BC26_RST_PORT,BC26_RST_PIN);}else if(_bc26.timeOver == 60){BC26_SendString("AT+QRST=1\r\n");LOG("AT+QRST=1\r\n");}else if(_bc26.timeOver == 4) {BC26_SendString("ATE0\r\n");  //关闭回显LOG("ATE0\r\n");    //关闭回显}else if(_bc26.timeOver==0) {_bc26.timeOver = 0;       _bc26.sta = 1;ClearFIFO();}}
}/*** 功能:检查BC26模组是否正常* 参数:None* 返回值:*        0 :正常*      其他: 异常*/
static void CheckModule(void) {if(strstr((char*)_bc26.rxbuf,"OK") == NULL) {if(_bc26.timeOver==0) {ClearFIFO();BC26_SendString("AT\r\n");LOG("AT\r\n");_bc26.timeOver = 3;}else {--_bc26.timeOver;if(_bc26.timeOver==0) {_bc26.sta = 0;ClearFIFO();}}}else {_bc26.timeOver = 0;      _bc26.sta=2;ClearFIFO();}
}/*** 功能:设置BC26的CFUN功能(默认打开全功能)* 参数:None* 返回值:*        0 :正常*      其他: 异常*/
static void SetCFUN(void) {if(strstr((char*)_bc26.rxbuf,"OK") == NULL) {if(_bc26.timeOver==0) {ClearFIFO();BC26_SendString("AT+CFUN=1\r\n");LOG("AT+CFUN=1\r\n");_bc26.timeOver = 3;}else {--_bc26.timeOver;if(_bc26.timeOver==0) {_bc26.sta = 0;ClearFIFO();}}}else {_bc26.timeOver = 0;      _bc26.sta=3;ClearFIFO();}
}/*** 功能:检查BC26的SIM卡是否正常* 参数:None* 返回值:*        0 :正常*      其他: 异常*/
static void CheckCIMI(void) {if(strstr((char*)_bc26.rxbuf,"460") == NULL) {if(_bc26.timeOver==0) {ClearFIFO();BC26_SendString("AT+CIMI\r\n");LOG("AT+CIMI\r\n");_bc26.timeOver = 3;}else {--_bc26.timeOver;if(_bc26.timeOver==0) {_bc26.sta = 0;ClearFIFO();}}}else {_bc26.timeOver = 0;     _bc26.sta=4;ClearFIFO();}
}/*** 功能:设置(激活)网络* 参数:None* 返回值:*        0 :正常*      其他: 异常*/
static void ActivateNetwork(void) {if(strstr((char*)_bc26.rxbuf,"OK") == NULL) {if(_bc26.timeOver==0) {ClearFIFO();BC26_SendString("AT+CGATT=1\r\n");LOG("AT+CGATT=1\r\n");_bc26.timeOver = 3;}else {--_bc26.timeOver;if(_bc26.timeOver==0) {_bc26.sta = 0;ClearFIFO();}}}else {_bc26.timeOver = 0;      _bc26.sta=5;ClearFIFO();}
}/*** 功能:检查网络激活状态* 参数:None* 返回值:*        0 :正常*      其他: 异常*/
static void CheckNetwork(void) {if(strstr((char*)_bc26.rxbuf,"+CGATT: 1") == NULL) {if(_bc26.timeOver==0) {ClearFIFO();BC26_SendString("AT+CGATT?\r\n");LOG("AT+CGATT?\r\n");_bc26.timeOver = 3;}else {--_bc26.timeOver;if(_bc26.timeOver==0) {_bc26.sta = 0;ClearFIFO();}}}else {_bc26.timeOver = 0;     _bc26.sta=6;ClearFIFO();}
}/*** 功能:查看获取CSQ值* 参数:None* 返回值:RSSI信号强度*/
static void CheckCSQ(void) {_bc26.csq = _bc26.rxbuf[6]-'0';_bc26.csq *= 10;_bc26.csq += _bc26.rxbuf[7]-'0';if(_bc26.csq == 0 || _bc26.csq == 99) {ClearFIFO();if(_bc26.timeOver==0) {BC26_SendString("AT+CSQ\r\n");LOG("AT+CSQ\r\n");_bc26.timeOver = 3;}else {--_bc26.timeOver;if(_bc26.timeOver==0) {_bc26.sta = 0;ClearFIFO();}}}else {_bc26.timeOver = 0;      _bc26.sta=7;ClearFIFO();}
}static void QMTCFG(char* PK, char* DN, char* DS) {if(strstr((char*)_bc26.rxbuf,"OK") == NULL) {if(_bc26.timeOver==0) {char temp[200];memset( temp, 0, sizeof( temp ) );  //清空 temp,避免隐藏错误strcat( temp, "AT+QMTCFG=\"aliauth\",0,\"" ); //AT+MQTCFG="aliauth",0,"strcat( temp, PK );                       //AT+MQTCFG="aliauth",0,"PKstrcat( temp, "\",\"" );                        //AT+MQTCFG="aliauth",0,"PK","strcat( temp, DN );                    //AT+MQTCFG="aliauth",0,"PK","DNstrcat( temp, "\",\"" );                     //AT+MQTCFG="aliauth",0,"PK","DN","strcat( temp, DS );                 //AT+MQTCFG="aliauth",0,"PK","DN","DSstrcat( temp, "\"\r\n" );                      //AT+MQTCFG="aliauth",0,"PK","DN","DS"\r\nClearFIFO();BC26_SendString(temp);LOG("%s",temp);_bc26.timeOver = 3;}else {--_bc26.timeOver;if(_bc26.timeOver==0) {_bc26.sta = 0;ClearFIFO();}}}else {_bc26.timeOver = 0;       _bc26.sta=8;ClearFIFO();}
}
//TCP连接阿里云 注意,连接过程时间是比较长的,在连接过程重复发送连接命令会造成错误
static void QMTOPEN(void) {if(strstr((char*)_bc26.rxbuf,"+QMTOPEN: 0,0") == NULL) {ClearFIFO();if(_bc26.timeOver == 0) {BC26_SendString("AT+QMTOPEN=0,\"iot-as-mqtt.cn-shanghai.aliyuncs.com\",1883\r\n");LOG("AT+QMTOPEN=0,\"iot-as-mqtt.cn-shanghai.aliyuncs.com\",1883\r\n");_bc26.timeOver = 66;    //TCP连接加入检测机制 20s时间}else {_bc26.timeOver--;if(_bc26.timeOver == 0) {_bc26.sta=0;}}}else {_bc26.timeOver = 0;_bc26.sta=9;ClearFIFO();}
}//登录阿里云MQTT 注意,连接过程时间是比较长的,在连接过程重复发送连接命令会造成错误
static void QMTCONN( char* DN )
{if(strstr((char*)_bc26.rxbuf,"+QMTCONN: 0,0,0") == NULL) {if(_bc26.timeOver == 0) {char temp[200];memset( temp, 0, sizeof( temp ) );    //清空 temp,避免隐藏错误strcat( temp, "AT+QMTCONN=0,\"" );  //AT+QMTCONN=0,"strcat( temp, DN );          //AT+QMTCONN=0,"DNstrcat( temp, "\"\r\n" );           //AT+QMTCONN=0,"DN"\r\nClearFIFO();BC26_SendString( temp );LOG( "%s",temp );_bc26.timeOver = 66;             //MQTT登录连接加入检测机制 20s时间}else {_bc26.timeOver--;if(_bc26.timeOver == 0) {_bc26.sta=0;}}}else {_bc26.sta=10;_bc26.timeOver = 0;ClearFIFO();}
}void QMTSUB( char* TOPIC )
{if(strstr((char*)_bc26.rxbuf,"+QMTSUB: 0,1,0,1") == NULL) {if(_bc26.timeOver == 0) {char temp[200];memset( temp, 0, sizeof( temp ) );   //清空 temp,避免隐藏错误strcat( temp, "AT+QMTSUB=0,1,\"" ); //AT+QMTSUB=0,1,"strcat( temp, TOPIC );          //AT+QMTSUB=0,1,"TOPICstrcat( temp, "\",0\r\n" );         //AT+QMTSUB=0,1,"TOPIC",0\r\nClearFIFO();BC26_SendString( temp );LOG( "%s",temp );_bc26.timeOver = 66;           //20s}else {_bc26.timeOver--;if(_bc26.timeOver == 0) {_bc26.sta=8;}}}else {_bc26.timeOver = 0;    _bc26.sta=11;ClearFIFO();}
}/* 此处的KeyWord 是阿里云“功能定义”->“添加功能”->所选功能的标识符号*/
void BC26_PubTopic( char* Topic,char *KeyWord,char* value )
{if(_bc26.sta == 11) {    //空闲状态可以发布消息char temp[200];memset( temp, 0, sizeof( temp ) );                       //清空 temp,避免隐藏错误strcat( temp, "AT+QMTPUB=0,1,1,0,\"" );                 //AT+QMTPUB=0,0,0,0,"strcat( temp, Topic );                              //AT+QMTPUB=0,0,0,0,"Topicstrcat( temp, "\",\"{params:{" );                      //AT+QMTPUB=0,0,0,0,"Topic","{params:{strcat( temp, KeyWord );                                 //AT+QMTPUB=0,0,0,0,"Topic","{params:{KeyWordstrcat( temp, ":" );                                    //AT+QMTPUB=0,0,0,0,"Topic","{params:{KeyWord:strcat( temp, value );                                   //AT+QMTPUB=0,0,0,0,"Topic","{params:{KeyWord:valuestrcat( temp, "}}\"" );                                  //AT+QMTPUB=0,0,0,0,"Topic","{params:{KeyWord:value}}"strcat( temp, "\r\n" );                                   //AT+QMTPUB=0,0,0,0,"Topic","{params:{KeyWord:value}}"ClearFIFO();BC26_SendString( temp );LOG( "%s",temp );_bc26.timeOver = 33;                                    //10s}else if(_bc26.sta == 12) {if(_bc26.timeOver) {--_bc26.timeOver;if(_bc26.timeOver == 0) {printf("Topic Error!\r\n");_bc26.sta = 11;}}}
}/*********************************************END OF FILE********************************************/

H文件:

#ifndef __FY_BC26_H
#define __FY_BC26_H#include "fy_includes.h"#define BC26_RST_RCC    RCC_APB2Periph_GPIOB
#define BC26_RST_PORT   GPIOB
#define BC26_RST_PIN    GPIO_Pin_3#define BC26_SendString       Usart2_SendString
#define BC26_SendBuf        Usart2_SendBuf/*阿里云服务器地址(华东2):*.iot-as-mqtt.cn-shanghai.aliyuncs.com:1883                          *ProductKeyhmacsha1加密在线计算网站:http://encode.chahuo.com/客户端ID:   *|securemode=3,signmethod=hmacsha1|                                                   *设备名称用户名    :    *&#                                                                                 *设备名称 #ProductKey密码 :    用DeviceSecret作为密钥对clientId*deviceName*productKey#进行hmacsha1加密后的结果       *设备名称 #ProductKey*/
域名(华东2)
//#define DomainName        "%s.iot-as-mqtt.cn-shanghai.aliyuncs.com" //ProductKey
端口
//#define Port          1883//设备三元组 根据自己的填写就好
#define ProductKey      "xxx"
#define DeviceName      "xxx"
#define DeviceSecret    "xxx"//MQTT   发布主题
#define PubTopic        "/sys/xxx/xxx/thing/event/property/post"          //ProductKey    DeviceName
//MQTT  订阅主题
#define SubTopic        "/sys/xxx/xxx/thing/service/property/set"         //ProductKey    DeviceName#define CurrentTemperature        "CurrentTemperature"
#define CurrentHumidity         "CurrentHumidity"
#define TPSet                   "TPSet"typedef struct {u8 *rxbuf;u16 *rxlen;u16 timeOver;u8 csq;u8 sta;
} _typdef_bc26;extern _typdef_bc26 _bc26;void BC26_Configuration(u8 *rxbuf,u16 *rxlen);
void BC26_IRQHandler(void);
void BC26_PubTopic( char* Topic,char *KeyWord,char* value );#endif/*********************************************END OF FILE********************************************/

上述代码主要的功能实现在于BC26的IRQHandler函数,这个函数在主程序中是每300ms执行一次,为什么是300ms?这个数据手册给出了定义:

可以看到几乎每条AT指令的响应时间最大都是300ms,所以这里索性就300ms。

然后再来看看主程序部分:

#include "fy_includes.h"
#include "hmac_sha1.h"//实验17
//BC26-MQTT-ALIYUN
//技术交流群:733945348
//作者:Urien @MARS
//日期:2020/1/3u8 u2_rxbuf[256];
u16 u2_rxlen=0;
u8 u2_rxok=0;
u16 cnt300ms=0;
u16 cnt5s=0;
int main(void)
{float tempvalue;char tempstr[20];NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4 SysClock_Configuration(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9);RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);     //开启AFIO时钟GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);  //禁止JTAG保留SWDSystick_Configuration();Led_Configuration();Usart1_Configuration(115200);Usart2_Configuration(115200);printf("this is aliyun test!\n\n");BC26_Configuration(u2_rxbuf,&u2_rxlen);while(1){if(cnt300ms>=300 || u2_rxok){Led_Tog();if(u2_rxok){Usart1_SendBuf(u2_rxbuf,u2_rxlen);}cnt300ms = 0;u2_rxok = 0;BC26_IRQHandler();u2_rxlen=0;}Led_Tog();if(cnt5s == 5000){srand(SysTick->VAL);tempvalue = 0.1*(rand()%1200);sprintf(tempstr,"%.1f",tempvalue);BC26_PubTopic(PubTopic,CurrentTemperature,tempstr);}else if(cnt5s == 10000){srand(SysTick->VAL);tempvalue = 0.1*(rand()%1000);sprintf(tempstr,"%.1f",tempvalue);BC26_PubTopic(PubTopic,CurrentHumidity,tempstr);}else if(cnt5s == 15000){cnt5s=0;srand(SysTick->VAL);tempvalue = (rand()%200);sprintf(tempstr,"%d",(u8)tempvalue);BC26_PubTopic(PubTopic,TPSet,tempstr);}}
}u8 rx_buf[256];
u8 rx_len=0;
//USART1串口中断函数
void USART1_IRQHandler(void)
{if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET){rx_buf[rx_len++] = USART1->DR;}if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET){u8 clear = USART1->DR;//读DR和SR有效清除中断clear = USART1->SR;u2_rxok=1;}
}//USART1串口中断函数
void USART2_IRQHandler(void)
{if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET){u2_rxbuf[u2_rxlen++] = USART2->DR;u2_rxlen%=256;}if(USART_GetITStatus(USART2, USART_IT_IDLE) != RESET){u8 clear = USART2->DR;//读DR和SR有效清除中断clear = USART2->SR;u2_rxok=1;}
}

主程序比较简单,使用系统滴答的1ms时基定时中断用来简单计时,然后就是每300ms执行BC26的IRQHandler函数,每500ms上传一次数据。注意这里因为简单测试,上传我只是把单一的数据点一个个分时上传,为了提高效率,完全可以上传多个或者所有的数据点。

再有就是串口部分,串口部分用到了2个,串口1用来打印调试信息,串口2才是对接BC26模组的,两个串口都用到了串口的接收中断和空闲中断。空闲中断不宜耗时太长,所以我这里只是立了一个flag变量,放在while里面去处理。

最后要说明一下,关于BC26的底层部分,如果是参考上述代码的话建议多啃啃,难就难在传输机制上面,举一个简单的例子,TCP连接上如果AT发送了TCP连接后,模组并不是马上或者就很快能连上服务器的,各种原因都有,网络延迟啦,信号不好啦等等,那么这个时候再次发送连接命令是会报错的,即使连接成功也一样。MQTT的登录也一样。再有就是BC26的复位,建议是软件复位和硬件复位都接上。

By Urien 2020年1月8日 18:44:04

【单片机笔记】上海移远公司NB-IOT模组 BC26 使用STM32 AT命令实现连接阿里云数据上传和下载相关推荐

  1. QUECTEL上海移远4G通讯CAT4模组EC20CEFAG模块串口调试指南之02【EC20模组硬件供电和开关机复位操作】

    QUECTEL上海移远4G通讯CAT4模组EC20CEFAG模块串口调试指南之02[EC20模组硬件供电和开关机复位操作] 一.模组硬件知识 1.背景知识:网络制式 2.模组的供电 3.模组的开机 4 ...

  2. QUECTEL上海移远4G通讯CAT4模组EC20CEFAG模块串口调试指南之03【EC20模组基础串口指令说明】

    QUECTEL上海移远4G通讯CAT4模组EC20CEFAG模块串口调试指南之03[EC20模组基础串口指令说明] 一.准备工作 二.硬件环境的搭建 三.基础AT指令的说明和测试 STM32F103学 ...

  3. QUECTEL上海移远4G通讯CAT4模组EC20CEFAG模块串口调试指南之04【EC20模组SIM卡和驻网模组指令说明】

    QUECTEL上海移远4G通讯CAT4模组EC20CEFAG模块串口调试指南之04[EC20模组SIM卡和驻网模组指令说明] 一.准备工作 二.硬件环境的搭建 三.基础AT指令的说明和测试 关于SIM ...

  4. QUECTEL上海移远4G通讯CAT4模组EC20CEFAG模块串口调试指南之05【EC20模组TCP/IP模块AT指令说明】

    QUECTEL上海移远4G通讯CAT4模组EC20CEFAG模块串口调试指南之05[EC20模组TCP/IP模块AT指令说明] Socket长连接 一.准备工作 二.针对TCP/IP协议 关于TCP/ ...

  5. QUECTEL上海移远4G通讯CAT4模组EC20CEFAG模块串口调试指南之01物联网模组简介

    本系列博文将系统性讲解物联网模组系列的实际使用和调试指南,以移远4G模组EC20为例(其他厂家模组的调试方法大同小异),加快嵌入式软硬件工程师对物联网模组调试和使用的上手速度,让你们的项目进度尽可能快 ...

  6. QUECTEL上海移远4G通讯CAT4模组EC20CEFAG模块串口调试指南之02EC20模组硬件供电和开关机复位操作

    本系列博文将系统性讲解物联网模组系列的实际使用和调试指南,以移远4G模组EC20为例(其他厂家模组的调试方法大同小异),加快嵌入式软.硬件工程师对物联网模组调试和使用的上手速度. 一.模组硬件知识 1 ...

  7. QUECTEL上海移远4G通讯CAT4模组EC20CEFAG模块串口调试指南之03EC20模组基础串口指令说明

    本系列博文将系统性讲解物联网模组系列的实际使用和调试指南,以移远4G模组EC20为例(其他厂家模组的调试方法大同小异),加快嵌入式软.硬件工程师对物联网模组调试和使用的上手速度. 一.准备工作 1.软 ...

  8. QUECTEL上海移远4G通讯CAT4模组EC20CEFAG模块串口调试指南之【05EC20模组TCP/IP模块AT指令说明】

    本系列博文将系统性讲解物联网模组系列的实际使用和调试指南,以移远4G模组EC20为例(其他厂家模组的调试方法大同小异),加快嵌入式软.硬件工程师对物联网模组调试和使用的上手速度. 一.准备工作 1.软 ...

  9. QUECTEL上海移远4G通讯CAT4模组EC20CEFAG模块串口调试指南之04EC20模组SIM卡和驻网模组指令说明

    本系列博文将系统性讲解物联网模组系列的实际使用和调试指南,以移远4G模组EC20为例(其他厂家模组的调试方法大同小异),加快嵌入式软.硬件工程师对物联网模组调试和使用的上手速度. 一.准备工作 1.软 ...

最新文章

  1. The following module was built either with optimizations enabled or without debug information - winz
  2. 鲲鹏服务器的作用,眼见为实,华为鲲鹏架构服务器生态大揭秘
  3. eclipse 下编写java code 比较好的设置和快捷键
  4. API文档和代码片段管理器:​​​​Dash
  5. 通过tomcat配置solr 4.10.3
  6. MThings:ModbusTCP通讯调试调测工具助手
  7. 游程编码用matlab实现代码_二值图像游程编码算法的Matlab实现 -
  8. 计算机cpu后面字母代表什么意思,英特尔CPU型号中最后的字母什么意思?如有不懂欢迎驻足停留...
  9. android 验证手机、邮箱格式
  10. 谁说大象不能跳舞读后感
  11. 图像处理与计算机视觉:基础,经典以及最近发展(转)
  12. gtk之G_LIKELY(expr)和G_UNLIKELY(expr)
  13. kettle 9.x 版本连接资源库,资源库灰色
  14. 将Opera默认搜索引擎改为百度
  15. 简单易懂的P2P通信原理
  16. 【论文摘要】一种基于NSPD-DCT域变参数混沌映射的零水印新方案
  17. HTML罕见的冷门标签
  18. Laravel Debugbar
  19. 那些职场高手,都是怎么解决问题的?
  20. 00软考 中级 信息安全工程师考试介绍

热门文章

  1. The Path to Learning WR Python FPE.16
  2. word 2013无法执行撤销操作
  3. 单片机(AT89C51)按钮控制LED灯实现流水灯,闪烁流水灯
  4. 金蝶云计算的产品和解决方案
  5. 拼多多,能再创商业奇迹吗?
  6. 强软弱虚---强引用、软引用、弱引用、虚引用
  7. 2022四川最新建筑八大员(资料员)模拟考试试题及答案解析
  8. AT97SC3205 安全芯片介绍
  9. 快速开发智能硬件,阿里云AIoT首期云端一体训练营开麦了
  10. AI —— Bayes Rule