单片机控制气压海拔模块BMP180之模块化编程(持续更新中)
这里将我写的STC12C5A60S2单片机控制气压海拔测量模块BMP180的程序共享一下,是为了让前辈给予斧正。
更新:
2015/05/05 08:30 完善了温度值的类型及其运算(没有进行实物验证)
2014/04/17 10:22
(也可以用官网封装好的函数BMP180_API :http://www.general-files.org/download/gs64624bfeh32i0/bmp180_api.zip.html)
(补充:只需要修改bmp180.h文件中含有 “选择” 字样的部分,就可以达到复用的效果,只需注意中文注释部分)
对于lcd2004部分,请参考《单片机控制2004A液晶屏之模块化编程》点击进入
模块:
检测到BMP180的存在:
未检测到BMP180的存在:
测试程序:
#include <reg52.h>
#include <string.h>
#include "lcd2004.h"
#include "bmp180.h"UB8 *table0 = "Module :BMP180" ;
UB8 *table1 = "Temperature:" ;
UB8 *table2 = "Pressure :" ;
UB8 *table3 = "Altitude :" ;void display(BMP180_info temp) ;void main()
{ BMP180_info temp ;lcd2004Init(); lcd2004WriteCommand(0x0c) ;/*为了显示效果更佳明显,暂时取消光标显示和闪烁,也可以在LCD2004模块内部修改*/lcd2004AddressWriteString(LCD2004_ROW0,0,table0) ;lcd2004AddressWriteString(LCD2004_ROW1,0,table1) ;lcd2004AddressWriteString(LCD2004_ROW2,0,table2) ;lcd2004AddressWriteString(LCD2004_ROW3,0,table3) ;BMP180Init(&temp); while(1) { if(temp.ExistFlag == BMP180_EXISTENCE) //存在{BMP180Convert(&temp);display(temp) ;}else //不存在{lcd2004CleanAll() ;lcd2004AddressWriteString(LCD2004_ROW0,0,"Error") ;while(1);}}
} void display(BMP180_info temp)
{// 温度lcd2004AddressWriteByte(LCD2004_ROW1,strlen(table1),((UL32)temp.Temperature)%1000/100+'0') ;lcd2004AddressWriteByte(LCD2004_ROW1,strlen(table1)+1,((UL32)temp.Temperature)%100/10+'0') ;lcd2004AddressWriteByte(LCD2004_ROW1,strlen(table1)+2,((UL32)temp.Temperature)%10+'0') ;lcd2004AddressWriteByte(LCD2004_ROW1,strlen(table1)+3,'.') ;lcd2004AddressWriteByte(LCD2004_ROW1,strlen(table1)+4,((UL32)(temp.Temperature*10))%10+'0') ;lcd2004AddressWriteByte(LCD2004_ROW1,strlen(table1)+5,0xdf) ;lcd2004AddressWriteByte(LCD2004_ROW1,strlen(table1)+6,'C') ;//气压lcd2004AddressWriteByte(LCD2004_ROW2,strlen(table2),temp.GasPress%1000000/100000+'0') ;lcd2004AddressWriteByte(LCD2004_ROW2,strlen(table2)+1,temp.GasPress%100000/10000+'0') ;lcd2004AddressWriteByte(LCD2004_ROW2,strlen(table2)+2,temp.GasPress%10000/1000+'0') ;lcd2004AddressWriteByte(LCD2004_ROW2,strlen(table2)+3,'.') ;lcd2004AddressWriteByte(LCD2004_ROW2,strlen(table2)+4,temp.GasPress%1000/100+'0') ;//数据没有全部显示出来lcd2004AddressWriteByte(LCD2004_ROW2,strlen(table2)+5,'K') ;lcd2004AddressWriteByte(LCD2004_ROW2,strlen(table2)+6,'p') ;lcd2004AddressWriteByte(LCD2004_ROW2,strlen(table2)+7,'a') ;//海拔lcd2004AddressWriteByte(LCD2004_ROW3,strlen(table3),(UL32)temp.Altitude%10000/1000+'0') ;lcd2004AddressWriteByte(LCD2004_ROW3,strlen(table3)+1,(UL32)temp.Altitude%1000/100+'0') ;lcd2004AddressWriteByte(LCD2004_ROW3,strlen(table3)+2,(UL32)temp.Altitude%100/10+'0') ;lcd2004AddressWriteByte(LCD2004_ROW3,strlen(table3)+3,(UL32)temp.Altitude%10+'0') ;lcd2004AddressWriteByte(LCD2004_ROW3,strlen(table3)+4,'.') ;lcd2004AddressWriteByte(LCD2004_ROW3,strlen(table3)+5,(UL32)(temp.Altitude*10)%10+'0') ;lcd2004AddressWriteByte(LCD2004_ROW3,strlen(table3)+6,'m') ;
}
/*################BMP180.h start################*/
#ifndef __BMP180_H__
#define __BMP180_H__#include <reg52.h>
#include "common.h"sbit BMP180_sclk_bit = P3^6 ; /*根据硬件连接选择*/
sbit BMP180_sda_bit = P3^7 ; /*根据硬件连接选择*///BMP180校正参数(calibration param)
typedef struct {SW16 AC1 ;SW16 AC2 ;SW16 AC3 ;UW16 AC4 ;UW16 AC5 ;UW16 AC6 ;SW16 B1 ;SW16 B2 ;SW16 MB ;SW16 MC ;SW16 MD ;
}BMP180_cal_param;typedef struct {UB8 ExistFlag ; //存在标志BMP180_cal_param cal_param;//修正系数UB8 Version ; //版本SL32 UnsetTemperature ; //未校正的温度值SL32 UnsetGasPress ; //未校正的气压值float Temperature ; /*校正后的温度值*/SL32 GasPress ; /*校正后的气压值*/float Altitude ; /*海拔*/}BMP180_info ;#define BMP180_NOT_EXISTENCE 0 /*不存在*/
#define BMP180_EXISTENCE 1 /*存在*/#define OSS 2 //范围(0~3)#define BMP180_READ 0x01
#define BMP180_WRITE (0x01 &(~(0x01<<0))) #define BMP180_DEVICE_ADDRESS_BASE_VALUE 0xee /*器件地址基值*/
//#define BMP180_CONTROL_REGISTER_ADDRESS_BASE_VALUE 0xf4 /*控制寄存器地址*/
#define BMP180_ID_REGISTER_ADDRESS 0xd0 /*ID编号寄存器(0x55固定)*/
#define BMP180_VERSION_REGISTER_ADDRESS 0XD1 /*版本编号*/
//#define BMP180_SOFT_RESET_REGISTER_BASE_VALUE 0xe0 /*软件复位寄存器,只写,设置0xb6*///control register
//#define BMP180_CONTROL_REGISTER_SCO_BIT (0X01<<5)//id register
#define BMP180_ID_FIXED_VALUE 0x55 /*id固定编号(0x55)*//*****************内部函数******************/
//初始化
extern void BMP180Init(BMP180_info *p); //转换,修正温度、气压,计算海拔
extern void BMP180Convert(BMP180_info *temp) ; /*下面两个函数一般不在外部使用,也可以直接声明为BMP180.c的内部函数*/
//地址写数据
extern void BMP180AddressWrite(UB8 addresss,UB8 dataCode) ;//地址读数据
extern UB8 BMP180AddressReadByte(UB8 address) ;
/**********************************************/#endif /*__BMP180_H__*/
/*################BMP180.h start################*/
/*################BMP180.c start################*/
/***************************************************************************
Module :BMP180.cPurpose :Implementation of BMP180 module.Version :0.01 2014/02/03 12:00(OK)Complier:Keil 8051 C complier V9.01MCU :STC12C5A60S2Author :yangruiQQ :279729201Email :yangrui90s@163.comModification:
=================2015/05/05 09:06Reason:1.在BMP180.h中的结构体BMP180_info中修改SL32 Temperature ; //校正后的温度值为float Temperature ; //校正后的温度值因为BMP180内部通过校正得到的温度值为的单位是0.1摄氏度,比如校正后得到280,表示28摄氏度 。 之前的程序是在其他地方修改注意一下,但是这样做不是太好。这里完善一下。2.将函数BMP180Convert(BMP180_info *temp)里面的:temp->Temperature= ((B5 + 8) >> 4;修改为:temp->Temperature= (((B5 + 8) >> 4)*0.1;
==================================2014/04/16 23:06Reason:1.在BMP180.h中的结构体BMP180_info中添加了器件存在标志位。2.在初始化函数BMP180Init(...)中添加了器件存在检测功能。==================================2014/04/16 15:39Reason:1.完成=================***************************************************************************/
#include <reg52.h>
#include <intrins.h>
#include <math.h>
#include "bmp180.h"/*外部接口函数在BMP180.h中声明*//*****************内部函数******************/
static void delay5msForBMP180(void) ;
static void BMP180StartSignal(void) ;
static void BMP180StopSignal(void) ;
static void BMP180Acknowledge(void) ;
static void BMP180WriteByte(UB8 dataCode) ;
static UB8 BMP180ReadByte(void) ;
static SL32 BMP180AddressRead2Byte(UB8 address) ;
static SL32 BMP180ReadUnsetTemperature(void) ;
static SL32 BMP180ReadUnsetPressure(void) ;
static void BMP180ReadCalibrateParam(BMP180_info *p) ;
/**********************************************//******************************************************
Function :delay5msForBMP180
Input :N/A
Output :N/A
Return :N/A
Description :N/A
Note :由STC-ISP V6.67软件针对相应MCU生成,若MCU不同最好也要修改此函数。
******************************************************/
static void delay5msForBMP180(void) //@11.0592MHZ
{unsigned char i, j;_nop_();_nop_();i = 54;j = 198;do{while (--j);} while (--i);}/******************************************************
Function :BMP180StartSignal
Input :N/A
Output :N/A
Return :N/A
Description :BMP180 start signal
Note :N/A
******************************************************/
static void BMP180StartSignal(void)
{BMP180_sda_bit = HIGH_LEVEL ;//_nop_() ;BMP180_sclk_bit = HIGH_LEVEL ;//_nop_() ;BMP180_sda_bit = LOW_LEVEL ;//_nop_();
}/******************************************************
Function :BMP180StopSignal
Input :N/A
Output :N/A
Return :N/A
Description :BMP180 stop signal
Note :N/A
******************************************************/
static void BMP180StopSignal(void)
{BMP180_sda_bit = LOW_LEVEL ;//_nop_() ;BMP180_sclk_bit = HIGH_LEVEL ;//_nop_() ;BMP180_sda_bit = HIGH_LEVEL ;/*BMP180 self timed write cycle (5ms max)*/delay5msForBMP180();
}/******************************************************
Function :BMP180Acknowledge
Input :N/A
Output :N/A
Return :N/A
Description :When BMP180 receive a data from mcu , BMP180 write the datato internal address, after completed write ,BMP180 send a zeroto mcu,then mcu can input data into BMP180.(Once the internally timed write cycle has started and the EEPROM inputs are disabled until write finished.)
Note :N/A
******************************************************/
static void BMP180Acknowledge(void)
{UB8 i=0 ;BMP180_sclk_bit = LOW_LEVEL ;//_nop_() ;BMP180_sclk_bit = HIGH_LEVEL ;//_nop_() ;while((BMP180_sda_bit) && (i<250)){i++;//暂时,具体见调试//经过测试,这里的250足够大了}BMP180_sclk_bit = LOW_LEVEL ;
}/******************************************************
Function :BMP180WriteByte
Input :the data which is ready to write to BMP180
Output :N/A
Return :N/A
Description :N/A
Note :N/A
******************************************************/
static void BMP180WriteByte(UB8 dataCode)
{UB8 i ;UB8 temp = dataCode ;for(i=0 ; i<8 ; i++){BMP180_sclk_bit = LOW_LEVEL ;//_nop_();//方法一BMP180_sda_bit = (bit)(temp & (0x80>>i)) ;//方法二//temp <<= 1 ;//BMP180_sda_bit = CY ;//_nop_();BMP180_sclk_bit = HIGH_LEVEL ;//_nop_();}
}/******************************************************
Function :BMP180AddressWrite
Input :address,data
Output :N/A
Return :N/A
Description :write 'dataCode' to 'address'
Note :N/A
******************************************************/
void BMP180AddressWrite(UB8 addresss,UB8 dataCode)
{BMP180StartSignal(); BMP180WriteByte(BMP180_DEVICE_ADDRESS_BASE_VALUE | BMP180_WRITE); BMP180Acknowledge() ;BMP180WriteByte(addresss); BMP180Acknowledge() ;BMP180WriteByte(dataCode); BMP180Acknowledge() ;BMP180StopSignal();
}/******************************************************
Function :BMP180ReadByte
Input :N/A
Output :N/A
Return :the byte-data which read from BMP180
Description :N/A
Note :N/A
******************************************************/
static UB8 BMP180ReadByte(void)
{UB8 i ;UB8 dataCode = 0x00 ;//Ready/*Data on sda pin may change during scl low timer period*/BMP180_sclk_bit = LOW_LEVEL ;//_nop_() ;BMP180_sda_bit = HIGH_LEVEL ;//ready to read//_nop_() ;for(i=0; i<8 ; i++){BMP180_sclk_bit = HIGH_LEVEL ;//_nop_() ;dataCode<<= 1;dataCode |= BMP180_sda_bit ;//_nop_() ;BMP180_sclk_bit = LOW_LEVEL ;//_nop_() ;}return dataCode ;
}/******************************************************
Function :BMP180AddressReadByte
Input :address
Output :N/A
Return :data which read from bmp180's address
Description :read byte-data from bmp180's address
Note :不需要应答.
******************************************************/
UB8 BMP180AddressReadByte(UB8 address)
{ UB8 dataCode;BMP180StartSignal(); BMP180WriteByte(BMP180_DEVICE_ADDRESS_BASE_VALUE | BMP180_WRITE); BMP180Acknowledge() ;BMP180WriteByte(address); BMP180Acknowledge() ;BMP180StartSignal(); BMP180WriteByte(BMP180_DEVICE_ADDRESS_BASE_VALUE | BMP180_READ); BMP180Acknowledge() ;dataCode=BMP180ReadByte(); BMP180StopSignal(); return dataCode;
}/******************************************************
Function :BMP180AddressRead2Byte
Input :address
Output :N/A
Return :long data
Description :从连续地址读取数据,并"组装"为long型数据
Note :N/A
******************************************************/
static SL32 BMP180AddressRead2Byte(UB8 address)
{UB8 msb , lsb ;msb = BMP180AddressReadByte(address) ;lsb = BMP180AddressReadByte(address+1) ;return ( ((SL32)msb) << 8 | lsb) ;
}/******************************************************
Function :BMP180ReadUnsetTemperature
Input :address
Output :N/A
Return :shour int byte-data
Description :读取未校正的温度值
Note :接收后面的一字节数据,主机不需要应答
******************************************************/
static SL32 BMP180ReadUnsetTemperature(void)
{BMP180AddressWrite(0xf4,0x2e) ;return (BMP180AddressRead2Byte(0xf6));
}/******************************************************
Function :BMP180ReadUnsetPressure
Input :N/A
Output :N/A
Return :未校正气压值
Description :读取未校正的气压值
Note :N/A
******************************************************/
static SL32 BMP180ReadUnsetPressure(void)
{SL32 pressure = 0;BMP180AddressWrite(0xf4,0x34 + (OSS<<6)) ;delay5msForBMP180();delay5msForBMP180();pressure = BMP180AddressRead2Byte(0xf6) ;pressure = (((SL32)pressure <<8) + BMP180AddressReadByte(0xf8)) >>(8-OSS) ;return pressure; }/******************************************************
Function :BMP180ReadCalibrateParam
Input :BMP180_info type point
Output :AC1,AC3,AC3,AC4,AC5,AC6,B1,B2,MB,MC,MD
Return :N/A
Description :读取校正参数
Note :N/A
******************************************************/
static void BMP180ReadCalibrateParam(BMP180_info *p)
{p->cal_param.AC1= BMP180AddressRead2Byte(0xAA);p->cal_param.AC2= BMP180AddressRead2Byte(0xAC);p->cal_param.AC3= BMP180AddressRead2Byte(0xAE);p->cal_param.AC4= BMP180AddressRead2Byte(0xB0);p->cal_param.AC5= BMP180AddressRead2Byte(0xB2);p->cal_param.AC6= BMP180AddressRead2Byte(0xB4);p->cal_param.B1= BMP180AddressRead2Byte(0xB6);p->cal_param.B2= BMP180AddressRead2Byte(0xB8);p->cal_param.MB= BMP180AddressRead2Byte(0xBA);p->cal_param.MC= BMP180AddressRead2Byte(0xBC);p->cal_param.MD= BMP180AddressRead2Byte(0xBE);
}/******************************************************
Function :Init_BMP180
Input :BMP180_info type point
Output :p->ExistFlag 存在标志位p->Version 版本号
Return :N/A
Description :初始化
Note :N/A
******************************************************/
void BMP180Init(BMP180_info *p)
{if(BMP180AddressReadByte(BMP180_ID_REGISTER_ADDRESS)== BMP180_ID_FIXED_VALUE){//存在p->ExistFlag = BMP180_EXISTENCE ;BMP180ReadCalibrateParam(p);p->Version = BMP180AddressReadByte(BMP180_VERSION_REGISTER_ADDRESS);}else{//不存在p->ExistFlag = BMP180_NOT_EXISTENCE ;}
}/******************************************************
Function :BMP180Convert
Input :BMP180_info type point
Output :temp->UnsetTemperature 未经过校正的温度值temp->UnsetGasPress 未经过校正的气压值temp->Temperature 校正后的温度值temp->GasPress 校正后的气压值temp->Altitude 海拔计算值
Return :N/A
Description :温度值、气压值的校正和海拔的计算
Note :N/A
******************************************************/
void BMP180Convert(BMP180_info *temp)
{ SL32 x1, x2, B5, B6, x3, B3, p;unsigned long b4, b7;//未校正的温度值temp->UnsetTemperature = BMP180ReadUnsetTemperature();//未校正的气压值temp->UnsetGasPress = BMP180ReadUnsetPressure();//温度校正x1 = ((temp->UnsetTemperature) - temp->cal_param.AC6) * (temp->cal_param.AC5) >> 15;x2 = ((SL32)(temp->cal_param.MC) << 11) / (x1 + temp->cal_param.MD);B5 = x1 + x2;temp->Temperature= ((B5 + 8) >> 4)*0.1;//气压校正B6 = B5- 4000;x1 = ((SL32)(temp->cal_param.B2) * (B6 * B6 >> 12)) >> 11;x2 = ((SL32)temp->cal_param.AC2) * B6 >> 11;x3 = x1 + x2;B3 = ((((SL32)(temp->cal_param.AC1) * 4 + x3)<<OSS) + 2)/4;x1 = ((SL32)temp->cal_param.AC3) * B6 >> 13;x2 = ((SL32)(temp->cal_param.B1) * (B6 * B6 >> 12)) >> 16;x3 = ((x1 + x2) + 2) >> 2;b4 = ((SL32)(temp->cal_param.AC4) * (unsigned long) (x3 + 32768)) >> 15;b7 = ((unsigned long)(temp->UnsetGasPress) - B3) * (50000 >> OSS);if( b7 < 0x80000000){p = (b7 * 2) / b4 ;}else{p = (b7 / b4) * 2;}x1 = (p >> 8) * (p >> 8);x1 = ((SL32)x1 * 3038) >> 16;x2 = (-7357 * p) >> 16;temp->GasPress= p + ((x1 + x2 + 3791) >> 4);//海拔计算temp->Altitude =(44330.0 * (1.0-pow((float)(temp->GasPress) / 101325.0, 1.0/5.255)) );
}
/*################BMP180.c start################*/
补充:common.h
#ifndef __COMMON_H__
#define __COMMON_H__typedef unsigned char UB8 ;
typedef unsigned short int UW16 ;
typedef unsigned long UL32 ;typedef char SB8;
typedef short int SW16 ;
typedef long SL32 ;#define HIGH_LEVEL 1
#define LOW_LEVEL 0#endif /*__COMMON_H__*/
单片机控制气压海拔模块BMP180之模块化编程(持续更新中)相关推荐
- 单片机控制数字光照强度传感模块GY-30(主芯片BH1750FVI)之模块化编程(持续更新中)
这里将我写的STC12C5A60S2单片机控制数字光照强度模块GY-30(主芯片BH1750FVI)的程序共享一下,是为了让前辈给予斧正. 更新: 2014/04/29 14:05 (补充:以下代码只 ...
- 单片机控制雷达测距模块HC-SR04测量距离(通过测试)
雷达测距模块在小车防撞中应用比较不错,在这篇文章中简单介绍下雷达测距模块HC-SR04的使用. 一.硬件介绍 引脚四个,分别为VCC.TRIG.ECHO.GND 单片机控制引脚TRIG:用于给出促发测 ...
- python模块化编程_什么是模块,Python模块化编程(入门必读)
Python 提供了强大的模块支持,主要体现在,不仅 Python 标准库中包含了大量的模块(称为标准模块),还有大量的第三方模块,开发者自己也可以开发自定义模块.通过这些强大的模块可以极大地提高开发 ...
- 什么是模块,Python模块化编程(入门必读)
Python 提供了强大的模块支持,主要体现在,不仅 Python 标准库中包含了大量的模块(称为标准模块),还有大量的第三方模块,开发者自己也可以开发自定义模块.通过这些强大的模块可以极大地提高开发 ...
- 11.1 什么是模块,Python模块化编程
Python提供了强大的模块支持,主要体现在,不仅 Python 标准库中包含了大量的模块(称为标准模块),还有大量的第三方模块,开发者自己也可以开发自定义模块.通过这些强大的模块可以极大地提高开发者 ...
- 单片机控制5v继电器模块
连接问题: 图中的这个要用杜邦线连接,3个排针左右可能是电源的正负端,中间是单片机的信号端.(图片不是很清晰,我也不能确定)这个板子上有三极管,所以不需要在另外加放大三极管了.蓝色有螺丝的是输出端,中 ...
- 【持续更新中...】《多旋翼飞行器设计与控制》- 北航可靠飞行控制研究组 ---- 学习笔记
<多旋翼飞行器设计与控制>- 北航可靠飞行控制研究组 ---- 学习笔记 学习内容出处 绪论 1.基本概念 常见飞行器分类 固定翼 直升机 多旋翼 多旋翼一般受力特点: 四旋翼和六旋翼分类 ...
- java 流程控制篇 2021/02/26持续更新中
1. 用户交互Scanner 1.1 简单的Scanner用法 首先,需要 import java.util.Scanner 其次,需要创建一个 Scanner 类的对象, Scanner s = n ...
- 单片机控制GSM模块实现短信收发的软件设计
摘要:借助系统模型,阐明GSM模块收发短信的基本概念以及串口控制SMS的基本原理.详细介绍单片机控制GSM模块工作的软件实现过程,对怎样用单片机控制GSM模块收发短信进行探讨,也对程序设计的主体思想作 ...
- ZigBee无线气压测量模块的实现
在集装箱运输中,对冷藏集装箱可靠性要求很高,除进行强度实验外,还需按要求完成热工性能实验.热工性能实验中需要测量集装箱的气密性,漏热性,制冷性等. 为提高测量的自动化程度,控制测量过程的人为因素,需要 ...
最新文章
- [小猫学NA]CCNA学习指南第二章笔记
- XSS漏洞自动化攻击工具XSSer
- 弱网环境测试-Charles学习
- 战神背光键盘如何关系_4000元学生办公游戏本该如何选择?
- 为什么余额宝要不断限制用户购买?
- signature=c0c1b69f720d190a4a817d6bf2ff57c3,Fungicidal substituted N-(1-iodopropargyl)thiazolidinones
- 魅族魅蓝max简单打开USB调试模式的经验
- 水箱建模最小二乘法_北师大版小学数学下册五年级第四单元长方体(二)整理复习电子课本练习同步教学视频...
- blob字段如何更新_Axure RP8 中继器:字段增删改
- Python数据分析师特训营84节
- 条件概率分布、联合概率分布和边缘概率分布
- 苹果手机微信声音小怎么调大声_怎么把手机声音变大,试试这种方法
- 通过 scrapy 爬取豆果美食热门数据, 使用 flask 搭建后端, 最后搭建一个简单的小程序
- Xilinx FPGA全局时钟和局部时钟
- 大数据和人工智能的关系,超全解析 1
- 区块链技术如何赋能公共资源招采管理服务?
- java 获取今天或者某一天是星期几/周几以及几号的方法
- 小强期中考试(考察1-9章)
- printf \a 响铃的流程(你想知道的C语言 1.9)
- hdu 2897 邂逅明下
热门文章
- OpenCV-绘制圆角矩形
- 获取少女资源.html,AI少女资源一般在哪获取比较好?AI少女全地图资源获取地址一览...
- 《Java编程思想》 第6章 访问权限控制
- 华为发展鸿蒙再出奇招,学习宝马推出官方认证二手手机
- 基于jQuery/express/socket.io实现的匿名聊天室
- 银行业务中台和阿里中台的异曲同工之妙
- python爬取bilibili弹幕_python 爬取bilibili 视频弹幕
- kotlin版贪吃蛇小游戏
- (MATLAB)错误使用 xlsread (line 260) 无法激活 Excel 工作表
- Overture五线谱打曲谱用得上的排版技巧