嵌入式Linux驱动开发日记

主机硬件环境
开发机:虚拟机Ubuntu12.04
内存: 1G
硬盘:80GB

目标板硬件环境
CPU: SP5V210 (开发板:QT210)
SDRAM: 512M  (4片K4T1G164Q )
Nand flash: 512M (K9F4G08)
以太网芯片: SMSC LAN9220

工具介绍
仿真器: 暂无
电缆: 串口线,USB线

Windows 操作系统软件环境
ADS编译工具: 暂无
仿真器软件:暂无
调试软件: 终端(ADB)、eclipse

Linux操作系统软件环境
GNU交叉编译工具: arm-linux-gcc 4.4.1、JDK1.6、git 1.7、gcc 4.5、python 2.7


Section ONE:最简单的驱动程序:hello world


首先我们写一个最简单的模块。编辑hello_module.c

#include<linux/init.h>    //module_init(),module_exit()
#include<linux/module.h> //MODULE_AUTHOR(),MODULE_LICENSE()
#include<linux/kernel.h> //KERN_EMERG static int hello_init(void){
printk(KERN_EMERG "hello world enter\n");
return 0;
} void hello_exit(void){
printk(KERN_EMERG "hello world exit\n");
} module_init(hello_init);
module_exit(hello_exit); MODULE_AUTHOR("CHSRY");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("A simple Hello World Module");
MODULE_ALIAS("a simplest module");
编写Makefile 
obj-m := hello.o
all:
make -C /lib/modules/$(shell uname -r)/build SUBDIRS=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build SUBDIRS=$(PWD) clean

运行#make

生成hello.ko,然后使用insmod 命令存入模块:insmod hello.ko

使用lsmod 就能看到你新插入的模块: lsmod | grep hello

使用rmmod移除模块:rmmod hello

最简单的驱动就完成了。

由于Linux内核的级别控制,导致printk打印的内容不一定都能从控制台正常输出

最好的办法是打开另外的一个终端,用一个终端不停地监视并且打印输出当前系统的日志信息:

在终端下输入:

while true
do
sudo dmesg -c
sleep 1
done

这样这个终端就会每1秒查看当前系统的日志并清空。


Section TWO:LED驱动程序


思维导图设计

2.1 QT210 开发板 LED驱动程序和测试程序

驱动文件:hello.c

/************************************************
LED的驱动,在Real210A开发板上做测试 维护记录: 2011-10-31 V1.0 linux内核:2.6.35.7 驱动用法:
设备名称:Real210-led
点亮一个灯:LED_ON
熄灭一个灯:LED_OFF
点亮所有灯:ALL_LED_ON
熄灭所有灯:ALL_LED_OFF
*************************************************/
#include<linux/init.h>
#include<linux/module.h> #include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <asm/irq.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/device.h>
#include <linux/gpio.h> #define DEVICE_NAME "Real210-led" /* 设备名称 */
static int LED_Major = 0; /* 主设备号 ,系统自动分配*/ #define LED_OFF 0
#define LED_ON 1
#define ALL_LED_OFF 3
#define ALL_LED_ON 4 /* 用来指定LED所用的GPIO引脚 */
static unsigned long led_table [] =
{
//S5PV210_GPH0(_nr);
//在头文件“~/kernel/arch/arm/mach-s5pv210/include/mach/” S5PV210_GPH0(6),
S5PV210_GPH0(7),
S5PV210_GPH0(4),
S5PV210_GPH0(5),
}; static int Real210_led_open(struct inode *inode, struct file *file)
{
// MOD_INC_USE_COUNT;
printk("Real210-LED Driver Open Called!\n");
return 0;
} static int Real210_led_release(struct inode *inode, struct file *file)
{
// MOD_DEC_USE_COUNT;
printk("Real210-LED Driver Release Called!\n");
return 0;
} static int Real210_led_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
int i;
if (arg > 4)
{
return -EINVAL;
}
switch(cmd)
{
case LED_ON: //set the pin
gpio_set_value (led_table[arg], 0);
break; case LED_OFF: //clr the pin
gpio_set_value (led_table[arg], 1);
break; case ALL_LED_ON: //set all pin
for (i = 0; i < 4; i++)
gpio_set_value (led_table[i], 0);
break; case ALL_LED_OFF: //clr all pin
for (i = 0; i < 4; i++)
gpio_set_value (led_table[i], 1);
break; default:
return -EINVAL;
}
} static struct file_operations Real210_led_fops =
{
.owner = THIS_MODULE,
.open = Real210_led_open,
.release = Real210_led_release,
.ioctl = Real210_led_ioctl,
}; static struct class *led_class; static int __init Real210_led_init(void)
{ printk("Real210 LED DRIVER MODULE INIT\n"); LED_Major = register_chrdev(0, DEVICE_NAME, &Real210_led_fops);
if (LED_Major < 0)
{
printk(DEVICE_NAME " can't register major number\n");
return LED_Major;
}
printk("register Real210-LED Driver OK! Major = %d\n", LED_Major); led_class = class_create(THIS_MODULE, DEVICE_NAME);
if(IS_ERR(led_class))
{
printk("Err: failed in Real210-LED class. \n");
return -1;
} device_create(led_class, NULL, MKDEV(LED_Major, 0), NULL, DEVICE_NAME); //IO初始化 //IO方向配置
gpio_direction_output (S5PV210_GPH0(6), 1);
gpio_direction_output (S5PV210_GPH0(7), 1);
gpio_direction_output (S5PV210_GPH0(4), 1);
gpio_direction_output (S5PV210_GPH0(5), 1);
//IO初始化
gpio_set_value (S5PV210_GPH0(6), 1);
gpio_set_value (S5PV210_GPH0(7), 0); printk(DEVICE_NAME " initialized\n");
return 0;
} static void __exit Real210_led_exit(void)
{
printk("Real210 LED DRIVER MODULE EXIT\n");
unregister_chrdev(LED_Major, DEVICE_NAME);
device_destroy(led_class, MKDEV(LED_Major, 0));
class_destroy(led_class);
} module_init(Real210_led_init);
module_exit(Real210_led_exit); //MODULE_LICENSE("Dual BSD/GP"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("wzl");
MODULE_DESCRIPTION("This is an example of hello drivers");
MODULE_ALIAS("A simplest module.");

Makefile文件:

obj-m := hello.o
KDIR := /home/work/QT210/qt210_ics_kernel3.0.8
all:
make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-eabi-
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symvers

测试文件:led.c

 #include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include <sys/ioctl.h> int main(int argc, char **argv)
{
unsigned int on;
unsigned int led_num;
int fd;
printf("Enter the test led !\n");
fd = open("/dev/Real210-led", 0);
if (fd < 0)
{
perror("open device led");
exit(1);
} ioctl(fd, 1, 0); //可修改本句代码 close(fd);
return 0;
}

Makefile文件:

all: led
led:led.c
arm-none-linux-gnueabi-gcc -o led led.c -static
arm-none-linux-gnueabi-strip led
clean:
@rm -vf led *.o *~

下面是调试信息:

adb shell
#mkdir mydev
#exit
adb push d:\android_led.ko /mydev
adb shell
#cd mydev
#chmod 777 android_led.ko
#insmod android_led.ko
#lsmod //查看是否加载上了。卸载命令 rmmod android_led 不要加.ko
# cat /proc/devices //也可以查看设备号和设备名。
#ls -l /dev/myled //同样。
此时myled 权限需要修改。
#chmod 777 /dev/myled
 

2.2 QT210 开发板 LED流水灯 驱动程序

water_led.c的代码

#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/workqueue.h> static struct delayed_work my_work; //static int watercount=0;
volatile unsigned long *gph0con = NULL;
volatile unsigned long *gph0dat = NULL;
static void waterfun(void)
{
static int watercount=0;
*gph0dat = 0x1 << ((watercount++)%4);//流水灯
//printk("waterfun:watercount:%d\n",watercount);
schedule_delayed_work(&my_work,msecs_to_jiffies(1000));
} static int __init waterinit(void)
{ int ret;
gph0con = (volatile unsigned long *)ioremap(0xE0200c00, 16);
gph0dat = gph0con + 1;
*gph0con |=0x1111 ;
*gph0con &=~0xf;
INIT_DELAYED_WORK(&my_work,waterfun);
ret = schedule_delayed_work(&my_work,msecs_to_jiffies(1000));
printk("water init:ret:%d\n",ret); return 0; }
static void __exit waterexit(void)
{
cancel_delayed_work(&my_work);
//destroy_wor(my_work);
//_work(&my_work);
iounmap(gph0con); } module_init(waterinit);
module_exit(waterexit);
MODULE_LICENSE("GPL");

Makefile的代码:

obj-m :=water_led.o

#KDIR :=/home/kernal_driver/linux-tiny6410/
KDIR :=/home/work/QT210/qt210_ics_kernel3.0.8
PWD :=$(shell pwd)
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
rm -f *.o *.bak *.order *.symvers

可以看到开发板子的 D6 D7 D8呈现流水灯(D5无法控制),证明驱动成功了。

2.3 QT210 开发板 LED驱动程序和android应用程序

目的: 编写一个android应用程序来控制开发板上led灯的亮与灭.

编译环境: Ubuntu12.04

Android系统: android4.0 (linux3.0.8)

一.驱动

1. 查看原理图,QT210开发板上led D5, D6, D7, D8 对应引脚为EINT0, EINT1, EINT2, EINT3.

2. 根据底板上的EINT引脚,在核心板上找到与之相对应的引脚,最终对应到了GPIO的GPH0_0, GPH0_1, GPH0_2, GPH0_3

3.  接下来在三星 S5PV210芯片手册上找到相应寄存器.控制led灯实际就是控制相应寄存器.

S5PV210_EVT1_Usermanual_20100218.pdf

4.  编写驱动文件led.c

#include <linux/module.h>
#include <linux/kernel.h>
//#include <linux/io.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/miscdevice.h>
#include <linux/pci.h>
#include <linux/ioctl.h>
#include <linux/init.h>
#include <linux/delay.h> #define DEVICE_NAME "leds" //设备名(/dev/leds)
#define LED_MAJOR 240 unsigned long *gph0con = NULL;
unsigned long *gph0dat = NULL; int major; static int led_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
printk(KERN_ALERT"\ncmd = %d arg = %d \n", cmd, arg);
switch(cmd)
{
case 0:
printk(KERN_ALERT"led%d off\n", arg);
switch(arg)
{
case 0:
*gph0dat &= ~0x01;
break;
case 1:
*gph0dat &= ~0x02;
break;
case 2:
*gph0dat &= ~0x04;
break;
case 3:
*gph0dat &= ~0x08;
break;
default:
break;
}
break;
case 1:
printk(KERN_ALERT"led%d on\n", arg);
switch(arg)
{
case 0:
*gph0dat |= 0x01;
break;
case 1:
*gph0dat |= 0x02;
break;
case 2:
*gph0dat |= 0x04;
break;
case 3:
*gph0dat |= 0x08;
break;
default:
break;
} break;
case 11:
printk(KERN_ALERT"led all on\n");
*gph0dat |= 0xf;
break;
case 10:
printk(KERN_ALERT"led all off\n");
*gph0dat &= ~0xf;
break;
default:
break;
} return 0;
} struct file_operations led_fops={
.owner = THIS_MODULE,
.unlocked_ioctl = led_ioctl,
}; static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR, //动态设备号
.name = DEVICE_NAME,
.fops = &led_fops,
}; static int __init led_init(void)
{
int rc;
gph0con = (unsigned long *)ioremap(0xE0200C00, 16);
gph0dat = (unsigned long *)ioremap(0xE0200C04, 8); *gph0con &= ~0xffff;
*gph0con |= 0x1111; *gph0dat &= ~0xf; rc = misc_register(&misc); if(rc<0)
{
printk(KERN_ALERT"register %s char dev error\n","leds");
return -1;
}
else
printk(KERN_ALERT" lcd module OK!\n"); return 0;
} static void __exit led_exit(void)
{
unregister_chrdev(LED_MAJOR, "leds");
printk(KERN_ALERT"module exit\n");
} module_init(led_init);
module_exit(led_exit); MODULE_LICENSE("GPL");
MODULE_AUTHOR("cw");

5. 编写led.c的Makefile. 这里将led驱动编译成模块的方式.(注意: 编写Makefile时,行的开头只能用Tab,不能用空格.)

KERNELDIR :=/home/share/210/android4.0/4.0/qt210_ics_kernel3.0.8
PWD :=$(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
obj-m:=led.o
clean:
rm -rf *.o *~core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers

6. 编译

编译成功后生成led.ko模块.

7. 将led.ko 拷贝到开发板上,半加载.加载之后会在/dev/目录下生成leds这个设备.

二. Android应用程序

1.  新建一个Android应用程序

2. 打开 src/LedActivity.java, 添加public static native int led_ioctl(int i, int j);

添加一个接口是为了利用java来生成jni的头文件.       src/LedActivity.java:

package com.example.led;  

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu; public class LedActivity extends Activity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_led);
} @Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.led, menu);
return true;
} public static native int led_ioctl(int i, int j); }

3. 编译整个android项目,将整个Led项目文件拷贝到ubuntu上.

新建一个jni目录

4. 利用java文件自动生成jni头文件.

javah -classpath bin/classes -d jni com.example.led.LedActivity

5. jni目录下编写led.c 即led测试程序led.c.

Led/jni/led.c:

#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <android/log.h> #define LOG_TAG "LED" //android logcat
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__ )
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS_ _) //int main(int argc, char **argv)
jint JNICALL Java_com_example_led_LedActivity_led_1ioctl(JNIEnv *env, jclass thiz, jint led_nu, jint on)
{
int fd; fd = open("/dev/leds", O_RDWR);
if(fd < 0)
printf("Can't open /dev/leds!\n"); ioctl(fd, on, led_nu);
LOGI("led_nu=%d,state=%d\n", led_nu, on);
close(fd); return 0;
}

6.  jni目录下编写Android.mk

Led/jni/Android.mk

LOCAL_PATH := $(call my-dir)  

include $(CLEAR_VARS)
LOCAL_MODULE := Led_ctrl
LOCAL_SRC_FILES := led.c
LOCAL_LDLIBS := -llog
LOCAL_C_INCLUDES := $(MY_ANDROID_SOURCE)/frameworks/base/core/jni/android/graphics \
$(MY_ANDROID_SOURCE)/external/skia/include/core \
$(MY_ANDROID_SOURCE)/external/skia/include/images \
$(MY_ANDROID_SOURCE)/frameworks/base/include \
$(MY_ANDROID_SOURCE)/system/core/include
include $(BUILD_SHARED_LIBRARY)

7.  Led目录下运行ndk-bluild, 将led.c文件编译成so库文件.

前提是你已经安装了android-ndk 工具(http://blog.csdn.net/colwer/article/details/8944166)

8.  将生成的libLed_ctrl.so拷贝到eclipse下Led应用程序中的libs/armeabi目录(如果没有armeabi目录需手动创建一个)

9. 在应用程序布局文件中加入4个开关按钮,对应四个led开关,也可以再添加一个总开关来同时控制四个led.

res/layout/activity_led.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".LedActivity" > <ToggleButton
android:id="@+id/btn1"
android:layout_width="140dip"
android:layout_height="wrap_content"
android:textOn="led1 on"
android:textOff="led1 off"
android:layout_gravity="center_horizontal"
/>
<ToggleButton
android:id="@+id/btn2"
android:layout_width="140dip"
android:layout_height="wrap_content"
android:textOn="led2 on"
android:textOff="led2 off"
android:layout_gravity="center_horizontal"
/>
<ToggleButton
android:id="@+id/btn3"
android:layout_width="140dip"
android:layout_height="wrap_content"
android:textOn="led3 on"
android:textOff="led3 off"
android:layout_gravity="center_horizontal"
/>
<ToggleButton
android:id="@+id/btn4"
android:layout_width="140dip"
android:layout_height="wrap_content"
android:textOn="led4 on"
android:textOff="led4 off"
android:layout_gravity="center_horizontal"
/> </LinearLayout>

10.  编写java文件.

package com.example.led;  

import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.ToggleButton; public class LedActivity extends Activity { private static final String TAG = "LED";
private ToggleButton button1;
private ToggleButton button2;
private ToggleButton button3;
private ToggleButton button4; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_led); button1 = (ToggleButton)findViewById(R.id.btn1);
button2 = (ToggleButton)findViewById(R.id.btn2);
button3 = (ToggleButton)findViewById(R.id.btn3);
button4 = (ToggleButton)findViewById(R.id.btn4); button1.setOnClickListener(new Button.OnClickListener()
{
public void onClick(View v)
{
if (button1.isChecked())
led_ioctl(0, 1); //led1 on
else
led_ioctl(0, 0); //led1 off
}
}); button2.setOnClickListener(new Button.OnClickListener()
{
public void onClick(View v)
{
if (button2.isChecked())
led_ioctl(1, 1); //led2 on
else
led_ioctl(1, 0); //led2 off
}
}); button3.setOnClickListener(new Button.OnClickListener()
{
public void onClick(View v)
{
if (button3.isChecked())
led_ioctl(2, 1); //led3 on
else
led_ioctl(2, 0); //led3 off
}
}); button4.setOnClickListener(new Button.OnClickListener()
{
public void onClick(View v)
{
if (button4.isChecked())
led_ioctl(3, 1); //led4 on
else
led_ioctl(3, 0); //led4 off
}
});
} @Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.led, menu);
return true;
} public static native int led_ioctl(int i, int j); static
{
System.loadLibrary("Led_ctrl"); // libs/armeabi/libLed_ctrl.so } }

编译生成Led.apk,并安装到开发板上.

至此,整个工作已经完成,开发板上打开应用程序就可以控制led了.但有几点需要注意

1. 开发板上D5这个灯已经被占用了,所以led1不能控制D5了.

2. 记住运行应用程序前确保内核中led.ko已被加载,并修改 /dev/leds的权限,否则led灯不受控制.

代码下载地址:http://download.csdn.net/detail/colwer/5403281

嵌入式Linux驱动开发日记的更多相关文章

  1. 嵌入式linux驱动开发之点亮led(驱动编程思想之初体验)

    这节我们就开始开始进行实战啦!这里顺便说一下啊,出来做开发的基础很重要啊,基础不好,迟早是要恶补的.个人深刻觉得像这种嵌入式的开发对C语言和微机接口与原理是非常依赖的,必须要有深厚的基础才能hold的 ...

  2. 驱动编程思想之初体验 --------------- 嵌入式linux驱动开发之点亮LED

    这节我们就开始开始进行实战啦!这里顺便说一下啊,出来做开发的基础很重要啊,基础不好,迟早是要恶补的.个人深刻觉得像这种嵌入式的开发对C语言和微机接口与原理是非常依赖的,必须要有深厚的基础才能hold的 ...

  3. 书籍--嵌入式Linux驱动开发

    <UNIX环境高级编程>(第2版),史蒂文斯著 <深入理解 Linux 内核>(第三版) ,博韦等著 Linux设备驱动开发详解:基于最新的Linux 4.0内核    宋宝华

  4. 嵌入式linux驱动开发 笔记

    @ 目录 首个驱动hellodrv 1.编写源码 2.编译模块 3.加载驱动 首个驱动hellodrv 3.如果下载不到,就自己编写,并编译驱动. 1.编写源码 2.编译模块 1.先写makefile ...

  5. linux驱动开发流程

    嵌入式linux驱动开发流程嵌入式系统中,操作系统是通过各种驱动程序来驾驭硬件设备的.设备驱动程序是操作系统内核和硬件设备之间的接口,它为应用程序屏蔽了硬件的细节,这样在应用程序看来,硬件设备只是一个 ...

  6. 驱动开发学习笔记. 0.06 嵌入式linux视频开发之预备知识

    驱动开发读书笔记. 0.06  嵌入式linux视频开发之预备知识 由于毕业设计选择了嵌入式linux视频开发相关的项目,于是找了相关的资料,下面是一下预备知识 UVC : UVC,全称为:USB v ...

  7. linux驱动开发重点关注内容--摘自《嵌入式Linux驱动模板精讲与项目实践》

    本文摘自本人拙著 <嵌入式Linux驱动模板精讲与项目实践> 初步看起来Linux设备驱动开发涉及内容非常多,而须要实现驱动的设备千差万别.事实上做一段时间驱动之后回首看来主要就是下面几点 ...

  8. 嵌入式linux应用开发完全手册学习笔记一

    2015.3.25星期三 晴 有两个星期没写学习日记了,找个时间把这段时间做的电子词典和ARM小项目总结一下. 下面的知识点总结,U-BOOT:参考PDF文档:嵌入式linux应用开发完全手册 当虚拟 ...

  9. 嵌入式linux驱动开发之给linux系统添加温度传感器模块

    忙了几天,终于可以让ds18b20在自己的开发板的linux系统上跑了!虽然ds18b20不是什么新鲜玩意,但是想想知己可以给linux系统添加模块了还是有点小鸡冻呢! 虽然说现在硬件的资源非常丰富而 ...

随机推荐

  1. sql2012还原sql2008备份文件语句

    --sql2012还原sql2008语句 --选择master数据库,新建查询 输入下面sql语句 --选择兼容模式(sql 2008)创建数据库db RESTORE DATABASE db FROM ...

  2. 优秀工具推荐:两款很棒的 HTML5 游戏开发工具

    HTML5 众多强大特性让我们不需要多么高深技术就能创建好玩的网页游戏,同时证明了开放的 Web 技术能与任何其他在游戏开发中使用的技术竞争.正如标题所说,这篇文章推荐的几款很棒 HTML5 游戏开发 ...

  3. Node创建应用

    github地址:https://github.com/lily1010/Node_learn/tree/master/test 一 使用node的意义 使用 Node.js 时,我们不仅仅 在实现一 ...

  4. SharePoint Server 2016 Update

    Today’s post was written by Seth Patton, senior director of product management for the SharePoint te ...

  5. 我理解的OAuth 1.0a 的验证过程

    故事梗概: 淘宝店主糖糖在京郊仓库存了一批大白兔奶糖,为了防止仓库钥匙被偷把仓库的钥匙交给了专业的钥匙保管员公司. 糖糖卖了一斤大白兔需要快递公司的小迪送货.快递员小迪找钥匙保管公司借钥匙,然后去京郊 ...

  6. php服务器版本更新工具up2server

    为什么要做这个工具 之前做php 开发的时候,每次版本更新,要把修改的文件同步到服务器,都要小心翼翼,如果漏掉了文件,那就完蛋了,KPI,奖金什么的都没了. 所以写了这个工具.代码在github  h ...

  7. 【数据库】MySQL的安装与简单使用

    首先我们要下载Mysql的安装包,大家可以到http://mysql.com官网中根据自己的电脑系统版本下载 也可以点击 MySQL资源 下载 密码:btuu 建议下载5.7以上的版本,因为省掉了许多 ...

  8. 安卓--selector简单使用

    selector ---选择器 在App的使用中经常能看到selector的身影 如:一个按键看上去白色或者其它颜色,可能是一张图片 按下去又显示其它的颜色或者另外一张图片 这里使用shape配合使用 ...

  9. IOS 杂笔-1(为什么不继承类簇?)

    答:首先,类簇是可以继承的,并不是不可以.例如,我们可以选择继承NSSting,但是此时你用你自己设定的类去调用NSSting的一些方法时,会存在无法实现的问题,这是为什么呢. 1.类簇里有很多私有的 ...

  10. python 判断学期与学年

    9,10,11,12,1 第一学期 2,3,4,5,6,7 第二学期 其中8月份放假,暂且放入第一学期.因为大部分学校都选在8月底开学 import datetime def getXNandXQ() ...