最近闲着无聊,买了个树莓派Zero,准备在上面跑.Net Core,来驱动各种传感器

  就是上面这货。之前手上已经有一个树莓派3B+,但是介于3B+已经被我挂在路由器旁边当做服务器用,不是很方便拿来研究接口,于是就挑了一个便宜的Zero玩玩,事实证明,我想太天真了,我以为只要是Linux系统,就能安装.net Core,实际上呢,我整了一个晚上才不得不认识到一个事实:即便是.net Core也是认CPU架构的,Pi Zero用的ARMv6就是不支持,哎早知道在买之前多做做功课了,买一个树莓派4也是个不错的选择啊。

幸好苍天不负有心人,我找到了 另外一个能在Linux上面运行.net的途径,那就是在Linux上面安装一个Mono,然后.net通过Mono当做虚拟机运行,其实在原理上和.net core是差不多的,可是Mono在性能上比原生的.net core差了很多便是,不过我们只是用来跑外部模块,也不是很需要多高性能便是了。

好了,唠嗑正式结束,让我们开始正题吧

首先,我们需要在Linux上面配置Mono的程序,讲人话就是安装Mono,不过在安装之前,我们还需要更改源,毕竟树莓派自带的源别指望在国内有好的下载体验

sudo sed -i 's#://raspbian.raspberrypi.org#s://mirrors.tuna.tsinghua.edu.cn/raspbian#g' /etc/apt/sources.list
sudo sed -i 's#://archive.raspberrypi.org/debian#s://mirrors.tuna.tsinghua.edu.cn/raspberrypi#g' /etc/apt/sources.list.d/raspi.list

运行上述两条指令,把树莓派自带的源替换成清华源,这样安装Mono会快很多

sudo apt-get install mono-devel mono-complete mono-dbg

运行上面指令后,在树莓派Zero上就会自动安装配置完毕Mono环境了。

对了,为了方便调试,我们还需要配置SSH的远程root连接

sudo nano /etc/ssh/sshd_config

运行上述指令后

找到这一条,然后改成上图这样子后(其实也就去掉#,后面的参数改成yes罢了)

完事以后,按Ctrl+X,退出编辑并覆盖保存就行。

sudo service ssh --full-restart

最后我们运行上述指令重启SSH服务以后就能够以root权限登录树莓派了。

以上是树莓派的系统的配置过程。

接下来我们需要配置Visual Studio

首先我们新建一个项目,由于最新的Mono支持.net core,所以我们直接建立.net core 3框架的项目就行,而且甚至不需要拖家带口带上.net core那么多运行库就能直接在Mono虚拟机下跑,简直了...

然后,我们需要有一个扩展能够直接在PC上远程调试树莓派上的程序,因此

搜索Mono的调试插件,有很多个,功能都差不多,挑一个顺手的就行

安装好Mono调试插件以后

需要配置下Mono调试插件的设置

其实主要的无非就是这么几个,新建一个配置,输入IP、端口、用户名和密码,避免麻烦最好直接上root权限,反正自己用

然后每次调试的时候,点击通过SSH生成和调试

就能获得和本地调试一样的体验,不得不说,这个体验实在是太好了。

接下来是项目的

其实也就一点,在Nuget上面找一个第三方的库来调用GPIO接口就行,没别的了

Nuget下搜索Raspberry,下面的库基本上都是关于调用树莓派gpio的,随便挑一个便是

我这边选择了文档最为齐全的Unosquare.Raspberry.IO

下面两个是依赖项,尤其是WiringPi,是直接管理接口的主要库

好,以上是准备工作,下面的是具体实现

上面这张图,对应的就是树莓派Zero上,一共40个针脚的定义,其中,两个5V的接口可以直接当做电源输入或者输出用,GND是接地这个没啥好说的,我们主要看GPIO,这里有很多很多GPIO接口,这些接口才是负责信号输入以及输出使用,我们控制的主要也是这些接口。

然后我们这次的主角也上场了

注意看接线的颜色,其中CLK和DIO代表时钟信号和数据信号,虽说是时钟信号,其实是类似于发送命令的接口,因此都接GPIO,VCC是电源,这个没啥好说的,就是输入电源(注意看传感器的电压,如果电压过高会烧毁传感器,所以树莓派预留了两个3.3V的电压接口),GND是接地,随便找个接地的接口插上去就行。

根据照片所示,我使用了4,14,16,18号接口,其中16口接了时钟信号,18口接了数据信号

好了,线也接好了,环境也配置好了,我们正式开始编程阶段

Pi.Init<BootstrapWiringPi>();//初始化通信接口,分配内存空间等
var clkPin = Pi.Gpio[BcmPin.Gpio23];//引用16接口
var dataPin = Pi.Gpio[BcmPin.Gpio24];//引用18接口
clkPin.PinMode = GpioPinDriveMode.Output;//设置16接口模式为输出
dataPin.PinMode = GpioPinDriveMode.Output;//设置18接口模式为输出

上面代码是初始化阶段,反正刚开头照这个姿势填就行了,值得注意的是接口引用部分

你看,我明明CLK接口插的是树莓派16号物理接口,为啥这里引用的却是GPIO23呢,其实这个是编码方式的不同导致的,主要有以下两种

  • BCM

编号侧重CPU寄存器,根据BCM2835的GPIO寄存器编号。

  • wiringPi

编号侧重实现逻辑,把扩展GPIO端口从0开始编号,这种编号方便编程。

具体使用哪一种,需要看调用库用的哪一套,因为我用的这个库使用的是Bcm(引用的时候已经写明了BcmPin)所以查表得知,16接口对应的GPIO23,18接口对应的GPIO24

接口配置完毕以后我们就可以正式开始驱动四位数码管了

驱动数码管实际上是操控TM1637芯片,我们的操作规程需要满足TM1637芯片的特性,

其中最主要的特性是

//数据输入开始
void startDisp()
{
clkPin.Write(GpioPinValue.High);//CLK拉为高电平
dataPin.Write(GpioPinValue.High);//DIO拉为高电平
dataPin.Write(GpioPinValue.Low);//和上面那句指令一起就是DIO由高变低
clkPin.Write(GpioPinValue.Low);//然后CLK上的时钟信号拉低,DIO接口的数据允许改变,代表开始写入数据
}

上面这四句执行完后,就表示告诉TM1637芯片,我要开始写数据了,后面DIO接口的任何电位变化,都是我要写的数据,下面就是写数据的过程

//开始写入数据
void writeByte(byte input)
{
for (int i = ; i < ; i++)//每次写入一个byte,一共8bit
{
  clkPin.Write(GpioPinValue.Low);//确保无误输入前再拉低一次时钟 ,代表开始写入数据
  if ((input & 0x01) == )//判断每一位的高低电平
  {
    dataPin.Write(GpioPinValue.High);
  }
  else
  {
    dataPin.Write(GpioPinValue.Low);
  }
  input >>= ;//每写入完毕一次,移动一位
  clkPin.Write(GpioPinValue.High);//每次输入完一位,就拉高一次时钟
}
//应答信号ACK,这里本来是用来判断DIO脚是否被自动拉低,代表上面写入的数据TM1637已经接受到了
//但是我这里闲麻烦,直接将CLK信号低高低的拉,让芯片直接执行下一步操作
clkPin.Write(GpioPinValue.Low);//先拉低
clkPin.Write(GpioPinValue.High);//需要判断D是否为低电平此期间C一直拉高
clkPin.Write(GpioPinValue.Low);//应答完毕以后拉低C
}

上面执行完以后,我们就已经向芯片发送了一个字节,也就是8位的数据,写完以后,我们还需要告知芯片,数据传输完毕了

//结束条件是CLK为高时,DIO由低电平变为高电平
void stopDisp()
{
clkPin.Write(GpioPinValue.Low);//先拉低CLK,代表允许DIO改变数据
dataPin.Write(GpioPinValue.Low);//拉低DIO
clkPin.Write(GpioPinValue.High);//CLK拉高,满足结束条件前半部分
dataPin.Write(GpioPinValue.High);//DIO由低变高,代表数据输入结束
}

好了,上面三段代码一起执行完毕,就表示一个完整的,信号从准备输入,开始输入,结束输入的过程,每次要输入1字节,都需要经过以上三个过程,因此我们将上面三个过程分别写成各自的方法,毕竟是需要经常调用的东西,而且基本上都不会变。以上的代码实现,都是基于TM1637规格书,就是上面的接口说明实现的。

下面开始介绍该怎么在数码管上显示出东西来

在开始之前,我们先仔细看看数码管是怎么一个样子的

  //      A
  // ---
  // F | | B
  // -G-
  // E | | C
  // ---
  // D
 XGFEDCBA
  00111111, // 0 //0x3f
  00000110, // 1 //0x06
  01011011, // 2 //0x5b
  01001111, // 3 //0x4f
  01100110, // 4 //0x66
  01101101, // 5 //0x6d
  01111101, // 6 //0x7d
  00000111, // 7 //0x07
  01111111, // 8 //0x7f
  01101111, // 9 //0x6f
  01110111, // A //0x77
  01111100, // b //0x7C
  00111001, // C //0X39
  01011110, // d //0X5E
  01111001, // E //0X79
  01110001 // F //0X71

上图展示了数码管,一个字样的显示方式,跟我们写汉字一样,一共准备了7个笔画,我们想让哪个笔画亮起来,就让那个笔画的电平拉高就行,总的来说还是挺直观的,因为我们只有7个笔画,但是一个比特有8位,所有还有一位空置为低电平,如果有其他用处的话,可以补上()。于是我们把这些二进制,通过计算器换算成16进制的话就变成了0x3F样式的字节码

static byte[] Characters = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//0~9,A,b,C,d,E,F            

当然,也可以自己任意根据上面的描述,编写想要的走线图案,不一定非要按照0到9的数字或者字母定式来写。

//设置基本参数
startDisp();//开始写入指令
writeByte(0x40);//指定功能参数
stopDisp();//结束写入指令 //设置显示地址以及显示内容
startDisp();
writeByte(0xC0);//设置首地址,指向第一个字符
var Date = DateTime.Now.ToString("hhmm").ToCharArray();//获得当前日期,并表示为小时分钟
byte[] Characters = { 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71 };//0~9,A,b,C,d,E,F
for (int i = ; i <4; i++)//循环更改四个字符的显示,想更改数码管的显示,只要更改循环体内的操作就行
{
  if (i != ) writeByte(Characters[Date[i] - ]);//从Characters数组根据索引获得字符显示的编码
  else writeByte((byte)(Characters[Date[] - ] + 0x80));//第二个字符带有冒号,因此将第一位空置拉高
}
stopDisp(); //开始写入亮度
startDisp();
writeByte(0x8f);
stopDisp();

以上代码便是驱动数码管显示的完整代码,循环运行上述代码就能不断驱动数码管显示当前的时间,同时更改循环体内的writeByte()方法参数,就能实现不同字符的显示。startDisp();stopDisp(); writeByte();方法体,都在上面有完全的展示。

除去上述三个方法,

writeByte(0x40);//指定功能参数
writeByte(0xC0);//设置首地址,指向第一个字符
writeByte((byte)(Characters[Date[1] - 48] + 0x80));//显示 :符号,这三个参数需要单独讲一下。
writeByte(0x8f);//指定亮度

首先,上述代码的先后顺序不能变,一定是先指定功能参数,后指定显示位置,然后指定显示内容,最后指定显示亮度

而功能参数0x40写入进去有啥用呢

我们查阅TM1637的规格书可知

0x40翻译成二进制便是

0 | 1  | 0 | 0 |  0 | 0 | 0 |  0
B7|B6|B5|B4|B3|B2|B1|B0

根据上述表格我们可以知道01000000(0X40)所代表的的意思就是

1:数据写到显示寄存器,也就是功能是显示

2:地址的增加模式是自+1

3:测试模式为普通模式

在此介绍一下前两种的区别

第一条的意思就是,这个芯片是支持按键响应和屏幕输出的,也就是说,如果B1置1则芯片功能是读取按钮 (虽然数位管上并没有任何按键),B1置0就是显示输出模式

第二条的意思就是,

for (int i = ; i <; i++)//循环更改四个字符的显示,想更改数码管的显示,只要更改循环体内的操作就行
{
  writeByte(Characters[Date[i] - ]);//从Characters数组根据索引获得字符显示的编码
}

如果B2置0,功能为自动地址增加模式,那么循环体内每次循环写入一个字符以后,下一次循环光标位置就会移到下一个字符的位置,就和我们打字类似

那么如果B2置1,功能为固定地址模式的话,顾名思义,就是哪个位置显示什么字符串由我们决定。

那么显示代码就变成了

  startDisp();
  writeByte(0xC0);//第一个字符
  writeByte(Characters[Date[] - ]);
  stopDisp();   startDisp();
  writeByte(0xC1);//第二个字符
  writeByte(Characters[Date[] - ]);
  stopDisp();   startDisp();
  writeByte(0xC2);//第三个字符
  writeByte(Characters[Date[] - ]);
  stopDisp();   startDisp();
  writeByte(0xC3);//第四个字符
  writeByte(Characters[Date[] - ]);
  stopDisp();

那么这个0xC0,0xC1,0xC2,0xC3哪里来的呢,同样查阅规格书可知

就是11000000,11000001,11000010,11000011,上述几个二进制转换成16进制便是C0,C1,C2,C3,当然,该芯片最多可支持显示6个字符

对了,中间这个  : 的符号,并不占用一个字符显示,这个符号归类到0xC1地址内,被当成了一个标点使用

   XGFEDCBA
  , // 0 //0x3f

还记得上面那张图吧,A~G,分别表示7个笔画,但是多了一位闲置的在这里就派上用场了,只要把0xC1,也就是第二个字符的位置最高位置1,变成10111111,那么这个符号变会显示出来

writeByte((byte)(Characters[Date[] - ] + 0x80));

代码上就是在原先的基础上加上0x80就可以了。

上面的步奏全部完成以后,其实只是把需要显示的数据存到芯片里面而已,芯片还没有输出任何数据给数码管,因为我们还什么都看不到

所以我们还需要再输入一次命令

writeByte(0x8f);//指定亮度并显示

那这个 0x8f又是哪里来的呢

这里同样有一张表格,B3表示开关,B0~B2表示脉冲宽带pwm,脉冲宽度越长,代表输出给数码管的时间越长,也就越亮,参照之前的方法,把对应的8位二进制转换成16进制填入进去就行,我想都看到这里了,应该没啥疑问的。

好,上述就是完整的教程,下面贴完整代码

        private static void Main(string[] args)
{
Pi.Init<BootstrapWiringPi>();//初始化通信接口,分配内存空间等
var clkPin = Pi.Gpio[BcmPin.Gpio23];//引用16接口
var dataPin = Pi.Gpio[BcmPin.Gpio24];//引用18接口
clkPin.PinMode = GpioPinDriveMode.Output;//设置16接口模式为输出
dataPin.PinMode = GpioPinDriveMode.Output;//设置18接口模式为输出
clkPin.Write(GpioPinValue.Low);//初始化电平为低,可不加
dataPin.Write(GpioPinValue.Low);//初始化电平为低,可不加 void startDisp()
{
//数据输入开始
clkPin.Write(GpioPinValue.High);//CLK拉为高电平
dataPin.Write(GpioPinValue.High);//DIO拉为高电平
dataPin.Write(GpioPinValue.Low);//和上面那句指令一起就是DIO由高变低
clkPin.Write(GpioPinValue.Low);//然后CLK上的时钟信号拉低,DIO接口的数据允许改变,代表开始写入数据
}
void stopDisp()
{
//结束条件是CLK为高时,DIO由低电平变为高电平
clkPin.Write(GpioPinValue.Low);//先拉低CLK,代表允许DIO改变数据
dataPin.Write(GpioPinValue.Low);//拉低DIO
clkPin.Write(GpioPinValue.High);//CLK拉高,满足结束条件前半部分
dataPin.Write(GpioPinValue.High);//DIO由低变高,代表数据输入结束
}
void writeByte(byte input)
{
//开始写入数据
for (int i = ; i < ; i++)//每次写入一个byte,一共8bit
{
clkPin.Write(GpioPinValue.Low);//确保无误输入前再拉低一次时钟 ,代表开始写入数据
if ((input & 0x01) == )//判断每一位的高低电平
{
dataPin.Write(GpioPinValue.High);
}
else
{
dataPin.Write(GpioPinValue.Low);
}
input >>= ;//每写入完毕一次,移动一位
clkPin.Write(GpioPinValue.High);//每次输入完一位,就拉高一次时钟
}
//应答信号ACK,这里本来是用来判断DIO脚是否被自动拉低,代表上面写入的数据TM1637已经接受到了,
//但是我们这里闲麻烦,直接将CLK信号低高低的拉,让芯片直接执行下一步操作
clkPin.Write(GpioPinValue.Low);//先拉低
clkPin.Write(GpioPinValue.High);//需要判断D是否为低电平此期间C一直拉高
clkPin.Write(GpioPinValue.Low);//应答完毕以后拉低C
}
void Show()
{
//设置基本参数
startDisp();//开始写入指令
writeByte(0x40);//指定功能参数为自动增加
stopDisp();//结束写入指令 //设置显示地址以及显示内容
startDisp();
writeByte(0xC0);//设置首地址,指向第一个字符
var Date = DateTime.Now.ToString("hhmm").ToCharArray();//获得当前日期,并表示为小时分钟
byte[] Characters = { 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71 };//0~9,A,b,C,d,E,F
for (int i = ; i < Date.Length; i++)
{
if (i != ) writeByte(Characters[Date[i] - ]);//从Characters数组根据索引获得字符显示的编码
else writeByte((byte)(Characters[Date[] - ] + 0x80));//第二个字符带有冒号,因此将第一位空置拉高
} //开始写入亮度
startDisp();
writeByte(0x8f);
stopDisp();
}
while (true)
{
Show();
}
}

以上是字符地址自增加的代码

        private static void Main(string[] args)
{
Pi.Init<BootstrapWiringPi>();//初始化通信接口,分配内存空间等
var clkPin = Pi.Gpio[BcmPin.Gpio23];//引用16接口
var dataPin = Pi.Gpio[BcmPin.Gpio24];//引用18接口
clkPin.PinMode = GpioPinDriveMode.Output;//设置16接口模式为输出
dataPin.PinMode = GpioPinDriveMode.Output;//设置18接口模式为输出
clkPin.Write(GpioPinValue.Low);//初始化电平为低,可不加
dataPin.Write(GpioPinValue.Low);//初始化电平为低,可不加 void startDisp()
{
//数据输入开始
clkPin.Write(GpioPinValue.High);//CLK拉为高电平
dataPin.Write(GpioPinValue.High);//DIO拉为高电平
dataPin.Write(GpioPinValue.Low);//和上面那句指令一起就是DIO由高变低
clkPin.Write(GpioPinValue.Low);//然后CLK上的时钟信号拉低,DIO接口的数据允许改变,代表开始写入数据
}
void stopDisp()
{
//结束条件是CLK为高时,DIO由低电平变为高电平
clkPin.Write(GpioPinValue.Low);//先拉低CLK,代表允许DIO改变数据
dataPin.Write(GpioPinValue.Low);//拉低DIO
clkPin.Write(GpioPinValue.High);//CLK拉高,满足结束条件前半部分
dataPin.Write(GpioPinValue.High);//DIO由低变高,代表数据输入结束
}
void writeByte(byte input)
{
//开始写入数据
for (int i = ; i < ; i++)//每次写入一个byte,一共8bit
{
clkPin.Write(GpioPinValue.Low);//确保无误输入前再拉低一次时钟 ,代表开始写入数据
if ((input & 0x01) == )//判断每一位的高低电平
{
dataPin.Write(GpioPinValue.High);
}
else
{
dataPin.Write(GpioPinValue.Low);
}
input >>= ;//每写入完毕一次,移动一位
clkPin.Write(GpioPinValue.High);//每次输入完一位,就拉高一次时钟
}
//应答信号ACK,这里本来是用来判断DIO脚是否被自动拉低,代表上面写入的数据TM1637已经接受到了,
//但是我们这里闲麻烦,直接将CLK信号低高低的拉,让芯片直接执行下一步操作
clkPin.Write(GpioPinValue.Low);//先拉低
clkPin.Write(GpioPinValue.High);//需要判断D是否为低电平此期间C一直拉高
clkPin.Write(GpioPinValue.Low);//应答完毕以后拉低C
}
void Show()
{
//设置基本参数
startDisp();//开始写入指令
writeByte(0x44);//指定功能参数为固定地址显示
stopDisp();//结束写入指令 var Date = DateTime.Now.ToString("hhmm").ToCharArray();//获得当前日期,并表示为小时分钟
byte[] Characters = { 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71 };//0~9,A,b,C,d,E,F
//设置显示地址以及显示内容
startDisp();
writeByte(0xC0);//第一个字符
writeByte(Characters[Date[] - ]);
stopDisp(); startDisp();
writeByte(0xC1);//第二个字符
writeByte((byte)(Characters[Date[] - ] + 0x80));//第二个字符带有冒号,因此将第一位空置拉高
stopDisp(); startDisp();
writeByte(0xC2);//第三个字符
writeByte(Characters[Date[] - ]);
stopDisp(); startDisp();
writeByte(0xC3);//第四个字符
writeByte(Characters[Date[] - ]);
stopDisp(); //开始写入亮度
startDisp();
writeByte(0x8f);
stopDisp();
}
while (true)
{
Show();
}
}

以上是固定字符显示代码

对于.net core的项目来说,如果想使用Mono运行,那么命令是

执行mono xxxx.dll的方式,如果是普通的.net4.0框架的程序才是mono xxxx.exe的方式

在树莓派Zero上使用C#+Mono驱动TM1637四位数码管的更多相关文章

  1. sruts2:单个文件上传,多个文件上传(属性驱动)

    文件上传功能在Struts2中得到了很好的封装,主要使用fileUpload上传组件. 1. 单个文件上传 1.1 创建上传单个文件的JSP页面.显示提交结果的JSP页面 uploadTest1.js ...

  2. Raspberry Pi(树莓派)上从零开始构建Linux系统(简称PiLFS)(一)

    一. 准备工作 1. 装有Linux宿主系统的树莓派主板,可参考 Raspberry Pi(树莓派)上安装Raspbian(无路由器,无显示器) 2. 参考网址:Linux From Scratch ...

  3. 在树莓派2上安装 Windows 10

    微软在2015年4月29日发布了树莓派玩家期待已久的 Windows 10 物联网核心预览版(Windows 10 IoT Core Insider Preview Image for Raspber ...

  4. 在树莓派3B上安装node.js

    本文主讲如何在树莓派3B上安装node.js 环境描述1. 树莓派安装了`2016-11-25-raspbian-jessie-lite`(PS:在此版本的镜像中,默认禁用了ssh,在烧录好镜像之后, ...

  5. 2019 年在 Raspberry Pi 「树莓派」上运行的 10 个操作系统推荐

    原文:2019 年在 Raspberry Pi 「树莓派」上运行的 10 个操作系统推荐 image Raspberry Pi** 是一款基于 ARM 的单板计算机,默认运行一款称为 Raspbian ...

  6. 【Linux开发】【CUDA开发】Ubuntu上安装NVIDIA显卡驱动

    机型为戴尔Vostro3900  显卡型号为GTX 745  对于Nvidia显卡的驱动,如今很多Linux发行版会默认使用名为nouveau的驱动程序.Nouveau是由第三方为Nvidia开发的一 ...

  7. [七月挑选]树莓派Raspberrypi上配置Git

    title: 树莓派Raspberrypi上配置Git 树莓派Raspberrypi上配置Git. 开始 首先你得有一树莓派!!! 过程 查看自己树莓派的版本 pi@raspberrypi:~ $ u ...

  8. 在香蕉派的树莓派系统上配置 Syncthing 自启动

    在香蕉派的树莓派系统上配置 Syncthing 自启动 —— 魏刘宏 2020 年 1 月 19 日 首先做个名词解释,” 香蕉派” 是国内一款山寨树莓派的硬件产品,” 树莓派系统” 指的是”rasp ...

  9. raspberrypi(树莓派)上安装mono和jexus,运行asp.net程序

    参考网址: http://www.linuxdot.net/ http://www.cnblogs.com/mayswind/p/3279380.html http://www.raspberrypi ...

随机推荐

  1. vue小故事之父子(上下级)通信之父传子props

    vue小故事之父子(上下级)通信之父传子props vue 父子(上下级)通信 props  或许你对父子通信有点迷糊,为什么这样那样父子之间就可以通信了,以下通过一个小故事来进行解说,故事模型或许有 ...

  2. Cas服务器以及客户端搭建

    一.搭建cas服务器 官网:http://jasig.github.io/cas/ Cas Server 下载:http://developer.jasig.org/cas/ Cas Client 下 ...

  3. 解决ssh链接慢问题

    1,ssh -v root@ip 2,查看哪里卡住了 一般情况就是卡在debug1: SSH2_MSG_SERVICE_ACCEPT received 3,如果是上面卡住了 修改/etc/ssh/ss ...

  4. 【3】火狐中: radio被点击以后,重刷页面,不会选择默认的radio

    1.问题:火狐中radio (单选框)点击以后,重新刷新页面,不会选择默认的radio 解决:form表单中添加:autocomplete="off" autocomplete 属 ...

  5. redis cluster 集群 安装 配置 详解

    redis cluster 集群 安装 配置 详解 张映 发表于 2015-05-01 分类目录: nosql 标签:cluster, redis, 安装, 配置, 集群 Redis 集群是一个提供在 ...

  6. Selenium 2自动化测试实战11(键盘事件)

    一.键盘事件 1.Keys()类提供了键盘上几乎所有按键的方法,如下实例: #coding:utf-8 from selenium.webdriver.common.keys import Keys ...

  7. Linux(Debian)发行版中文输入法

    Linux发行版下有两大输入法框架:ibus 和fcitx,其中fcitx 的体验要比ibus 好,因此选择 fcitx 框架,并安装中文输入法. 中文输入法中你可以选择fcitx-pinyin or ...

  8. C#学习笔记二 (资源托管,泛型,数组和元组,运算符和类型强制转换)

     托管和非托管资源 1.托管资源是指GC管理的内存空间,非托管资源是指文件句柄,网络连接,数据库连接等. 2.方法中临时申请的变量,被存放在栈中.栈存储非对象成员的值数据.例如在方法中有B b=new ...

  9. ${pagecontext.request.contextpath}绝对路径理解

    ${pageContext.request.contextPath}是JSP取得绝对路径的方法,等价于<%=request.getContextPath()%> .也就是取出部署的应用程序 ...

  10. k8s-kubernetes-configmap存储

    存储 configMap configMap描述信息 ConfigMap功能在Kubernetes1.2版本中引入,许多应用程序会从配置文件.命令行参数或环境变量中读取配置信息. ConfigMap ...