在ARM Linux下使用GPIO模拟SPI时序详解

Author:杨正  Data2016.1.1  Mailyz2012ww@gmail.com

一、       概述

SPI是英文SerialPeripheral Interface的缩写,顾名思义就是串行外围设备接口。SPI是一种高速、全双工、同步通信总线,标准的SPI有4个引脚,常用于单片机和EEPROM、FLASH、实时时钟、数字信号处理等器件的通信。SPI通信原理要比I2C简单,它主要是主从方式通信,这种通信方式通常只有一个主机和一个或多个从机,标准的SPI是4根线,分别是SSEL(片选)、SCLK(时钟,也写作SCK)、MOSI(主机输入,从机输出)和MISO(主机输入,从机输出)。

SSEL:从设备片选使能信号。譬如从设备是低电平使能的话,当拉低这个引脚,从设备就会被选中,主机和这个被选中的从设备通信。

SCLK:时钟信号,即主机产生。

MOSI:主机给从机发送指令或者数据的通道。

MISO:主机读取从机的状态或者数据的通道。

 

在某些情况下,也可以用3根或者2根线的SPI进行通信。譬如,主机只给从机发送指令,从机不需要回复数据的时候,MISO就可以不要;而主机只读从机的数据,不需要给从机发送数据的时候,MOSI就可以不要;当一个主机与一个从机通信时,从机的片选有时可以固定为有效电平而一直处于使能状态,那么SSEL可以不要,此时如果主机只给从机发数据,那么SSEL和MISO都可以不要;如果主机只读取从机发送来的数据,那么SSEL和MOSI都可以不要。当然一般情况下说的SPI都指的是标准的SPI,有4根线进行通信。

 

 

二、  时序分析

众所周知,SPI时序有4种模式,在讲解4种模式之前先学习两个单词,即PolarityPhase,这两个单词分别是SPI的时钟极性(Polarity)和相位(Phase),最常见的写法CPOLCPHA,也有其它的一些写法,如:

(1) CKPOL (Clock Polarity) = CPOL = POL = Polarity =(时钟)极性
(2) CKPHA (Clock Phase)   = CPHA = PHA = Phase =
(时钟)相位

 

那么时钟极性是什么概念呢?SPI通信过程分为空闲状态和通信状态,空闲状态是指SCLK在数据发送之前和发送完之后的状态,通信状态当然就是指发送数据的状态。CPOL=1,那么空闲状态SCLK为高电平,反之,CPOL=0,则空闲状态SCLK为低电平。

 

SPI是一个环形的总线结构,主要是在SCLK的控制下,两个双向移位寄存器进行数据交换。那么主机和从机在进行交换数据的时候就设计到一个问题,即主机在什么时刻输出到MOSI上而从机在什么时刻采样这个数据,或者从机什么时刻输出到MISO上而主机什么时刻采样这个数据。同步通信的一个特点就是所有数据的变化和采样都是伴随着时钟沿进行的,也就是说数据总是在时钟的边沿附近变化或被采样,而一个完整的时钟周期必定包含了一个上升沿和一个下降沿,这是周期的定义所决定的,只是这两个沿的先后并无规定。又因为数据从产生到它稳定是需要一定的时间,那么如果主机在上升沿输出数据到MOSI,从机就只能在下降沿去采样这个数据了。反之,如果一方在下降沿输出数据,那么另一方就必须在上升沿采样这个数据。那么由谁来决定上升沿采样还是下降沿采样,上升沿输出还是下降沿输出呢?

 

CPHA=1时,表示数据的输出在一个时钟周期的第一个沿上,至于这个沿是上升沿还是下降沿,就得由CPOL来决定。CPOL=1那就是下降沿,反之就是上升沿。那么数据采样自然就是第二个沿上了。

CPHA=0时,表示数据采样在一个时钟周期的第一个沿上,至于这个沿是上升沿还是下降沿,就得由CPOL来决定。CPOL=1那就是下降沿,反之就是上升沿。那么数据输出自然就是第二个沿上了。

 

通过以上的学习,SPI的4中模式其实已经浮现出来了,下面对此做一总结:

Mode0

CPOL=0CPHA=0

Mode1

CPOL=0CPHA=1

Mode2

CPOL=1CPHA=0

Mode3

CPOL=1CPHA=1

 

图形比文字更容易看懂,所以SPI4种模式的时序图如下:


再进一步说明模式1SPI处于使能状态,而且发送FIFO内有有效数据时,设置SSEL信号为低,表示开始传输数据。来自Slave的数据立刻发送到Master的接收数据线MISO。半个SCLK时钟周期之后,有效的Master数据传输到MOSI。此时MasterSlave数据都已经有效,SCLK管脚在接下来的半个SCLK时钟周期之后变为高电平。数据在SCLK时钟的上升沿被捕获(采样),在时钟的下降沿被传送(输出),传输完成后SSEL恢复为高电平。

 

再进一步说明模式2。当SPI为使能状态,而且发送FIFO内有有效数据时,设置SSEL信号为低表示开始传输数据。半个SCLK时钟周期之后,MasterSlave的有效数据分别在各自的传输线上有效。同时,SCLK从第一个上升沿开始有效。数据在SCLK时钟的下降沿被捕获,在时钟的上升沿被传送,传输完成后SSEL恢复为高电平。

 

再进一步的说明模式3。当SPI为使能状态,而且发送FIFO内有有效数据时,设置SSEL信号为低表示开始传输数据。此时Slave的数据立刻发送到Master的接收数据线MISO。半个SCLK周期之后,Master的有效数据传送到MOSI。再过半个SCLK时钟周期之后,SCLK管脚设置为低。这表示数据在SCLK时钟的下降沿被捕获,在SCLK时钟的上升沿被传送,传输完成后SSEL恢复为高电平。

 

再进一步的说明模式4。当SPI为使能状态,而且发送FIFO内有有效数据时,设置SSEL信号为低表示开始传输数据。半个SCLK时钟周期后,MasterSlave数据在各自的传输线上有效。同时,时钟SCLK1个下降沿开始有效。数据在SCLK时钟的上升沿被捕获,在时钟的下降沿被传送,传输完成后SSEL恢复为高电平。

 

 

 

三、  SPI访问寄存器模式

 

常见的SPI访问寄存器模式有3种,分别是SingleAccess(单次访问)、Burst Access(突发访问)、FIFO Access(FIFO访问)。

 

SingleAccess:通过写访问发送一个地址字节后跟一个数据字节,或者发送一个地址字节,再通过读访问接收一个数据字节。发送帧时SSEL为低,发送完最后一个字节后SSEL变为高。如下图,将0x0A写到寄存器0x02上,再从该寄存器上读其值。


W + addr. 0x02 Data: 0x0A                      R + addr. 0x02 Data:

注意:SSEL第一次为低电平使能时,MISO变为高电平,然后立即变为低电平,这表示从设备芯片已经装备好(Thefirst time CSn goes low, MISO goes high and then low again immediately,indicating that the chip is ready.)。


Single Byte Access (Write and Read)

 

 

BurstAccess:一个地址字节后跟多个数据字节。在每个数据字节之间地址字节会在内部自动增加,并且片选信号SSEL在发送帧时为低电平,在每个数据字节之间也保持低电平,当发送完最后一个字节后变为高电平。如:

BYTE xdata regValues[] = {1,2,3};

halSpiWriteBurstReg(0x00, regValues,sizeof(regValues));

halSpiReadReg(0x00);

halSpiReadReg(0x01);

halSpiReadReg(0x02);


BurstWrite Followed by Single Read

 

 

FIFO Access:如果地址字节对应的是FIFO地址,那么随后的数据字节将针对FIFO。该地址字节没有自动递增而被存储,并且不需要在每个数据字节之间发送该地址。片选信号SSEL在发送帧时为低电平,在每个数据字节之间也保持低电平,当发送完最后一个字节后变为高电平。

 

特别说明不同的SPI从设备地址字节的内容不一定相同,需要查看相关手册,才能知道地址字节的构成是什么样的。例如:RFM69H这个模块SPI的地址字节的组成如下:

The first byteis the address byte. It is made of:

wnr bit, whichis 1 for write access and 0 for read access

7 bits of address, MSB first

 

又如CCXX00的地址字节组成如下:

The R/W bit in the address header controlsif the register should be written or read, and the burst bit controls if it

is a single access or a burst access.

R/W

Burst

A5

A4

A3

A2

A1

A0

:其实地址位只有5位,最高位为读写位,1为读,0为写;后面一位是burstAccess的使能位,当为1时使能。

 

 

四、  例程解析

特别注意:在主设备这边配置SPI接口时钟的时候一定要弄清楚从设备的时钟要求,因为主设备这边的时钟极性和相位都是以从设备为基准的。因此在时钟极性的配置上一定要搞清楚从设备是在时钟的上升沿还是下降沿接收数据,是在时钟的下降沿还是上升沿输出数据。但要注意的是,由于主设备的SDO连接从设备的SDI,从设备的SDO连接主设备的SDI,从设备SDI接收的数据是主设备的SDO发送过来的,主设备SDI接收的数据是从设备SDO发送过来的,所以主设备这边SPI时钟极性的配置(即SDO的配置)跟从设备的SDI接收数据的极性是相反的,跟从设备SDO发送数据的极性是相同的。

 

通过手册得知(MOSI is generated by the master on the falling edge ofSCK and is sampled by the slave (i.e. this SPI interface) on the rising edge ofSCK. MISO is generated by the slave on the falling edge of SCK.A transferalways starts by the NSS pin going low. MISO is high impedance when NSS ishigh.),本例程使用的从设备的SPI工作在Mode1,即CPOL= 0 and CPHA = 0,且SSEL低电平使能,当SSEL为高电平时,MISO为高。故主机的MOSI在空闲状态时为高。

/*********************************************************************************
*     Copyright:  (C) 2015 YangZheng<yz2012ww@gmail.com> 
*                  All rights reserved.
*
*      Filename:  dev_rfm69h.c
*   Description:  This file
*                
*       Version:  1.0.0(12/28/2015~)
*        Author:  Yang Zheng<yz2012ww@gmail.com>
*     ChangeLog:  1, Release initialversion on "12/28/2015 07:46:07 PM"
*                
********************************************************************************/
#include<linux/kernel.h>
#include<linux/version.h>
#include<linux/module.h>
#include<linux/types.h>
#include<linux/errno.h>
#include<linux/fcntl.h>
#include<linux/mm.h>
#include<linux/proc_fs.h>
#include<linux/fs.h>
#include<linux/slab.h>
#include<linux/init.h>
#include<asm/uaccess.h>
#include<asm/io.h>
#include <asm/system.h>
#include<linux/miscdevice.h>
#include<linux/delay.h>
#include<linux/sched.h>
#include<linux/proc_fs.h>
#include<linux/poll.h>
#include<asm/bitops.h>
#include<asm/uaccess.h>
#include<asm/irq.h>
#include<linux/moduleparam.h>
#include <linux/ioport.h>
#include<linux/interrupt.h>
#include<linux/cdev.h>
#include<linux/semaphore.h>
#include<linux/wait.h>
#define IOCONFIG4_4                                 IO_ADDRESS(0x200f0000+ 0x054)          //复用管脚gpio4_4
#define IOCONFIG4_5                                 IO_ADDRESS(0x200f0000+ 0x050)          //复用管脚gpio4_5
#define IOCONFIG4_6                                 IO_ADDRESS(0x200f0000+ 0x04c)          //复用管脚gpio4_6
#define IOCONFIG4_7                                 IO_ADDRESS(0x200f0000+ 0x048)          //复用管脚gpio4_7
#define GPIO4_BASE                                    0x20180000                        //gpio基地址
#define GPIO4_SIZE                                     0x10000             // 64KB
#define GPIO4_DIR                                      IO_ADDRESS(GPIO4_BASE + 0x400)     //gpio4方向寄存器
#defineGPIO_SPI_CS_REG                         IO_ADDRESS(GPIO4_BASE+ 0x40)          //gpio4_4数据寄存器
#defineGPIO4_SPI_SCK_REG                    IO_ADDRESS(GPIO4_BASE + 0x80)          //gpio4_5数据寄存器
#defineGPIO4_SPI_MOSI_REG                 IO_ADDRESS(GPIO4_BASE+ 0x100)     //gpio4_6数据寄存器
#defineGPIO4_SPI_MISO_REG                 IO_ADDRESS(GPIO4_BASE+ 0x200)     //gpio4_7数据寄存器
#define GPIO4_4                                           (1<< 4)   //gpio4_4
#define GPIO4_5                                           (1<< 5)   //gpio4_5
#define GPIO4_6                                           (1<< 6)   //gpio4_6
#define GPIO4_7                                           (1<< 7)   //gpio4_7
#define DATA_LENGTH                                21
#define DRV_AUTHOR                                "Yang Zheng<yz2012ww@gmail.com>"
#define DRV_DESC                                       "spi driver"                                                                                
#define DRV_VERSION                                "v0.0.1"
#if 0
#defineDBG(x...)   printk(x)
#define DBG_PRINT
#else
#defineDBG(x...)   do {} while (0)
#endif
staticDECLARE_WAIT_QUEUE_HEAD(spi_waitq);
unsigned char                                       read_tmp_data[DATA_LENGTH] = {0};
void __iomem                                       *reg_ssp_base_va;
typedef unsignedchar                       byte;
typedef unsignedshort                      word;
static int                                                read_flag = 0;
/******************************************************************************
**函数名称:Set_nCS
**函数功能:禁用片选
**输入参数:无
**输出参数:无
**注意:   高电平为禁用片选,低电平为使能片选
******************************************************************************/
void Set_nCS(void)
{
unsigned char regvalue;
writel(0, IOCONFIG4_4);   //gpio模式
regvalue = readl(GPIO4_DIR);  //设置gpio输出
regvalue |= GPIO4_4;
writel(regvalue, GPIO4_DIR);
regvalue = readl(GPIO_SPI_CS_REG); 
regvalue |= GPIO4_4;
writel(regvalue, GPIO_SPI_CS_REG);  //禁用片选
}
/******************************************************************************
**函数名称:Clr_nCS
**函数功能:使能片选
**输入参数:无
**输出参数:无
**注意:   高电平为禁用片选,低电平为使能片选
******************************************************************************/
void Clr_nCS(void)
{
unsigned char regvalue;
writel(0, IOCONFIG4_4);   //gpio模式
regvalue = readl(GPIO4_DIR);  //设置gpio输出
regvalue |= GPIO4_4;
writel(regvalue, GPIO4_DIR);
regvalue = readl(GPIO_SPI_CS_REG); 
regvalue &= ~GPIO4_4;
writel(0, GPIO_SPI_CS_REG);  //使能片选
}
/******************************************************************************
**函数名称:Set_SCK
**函数功能:SCK为高电平
**输入参数:无
**输出参数:无
**注意:    
******************************************************************************/
void Set_SCK(void)
{
unsigned char regvalue;
writel(0, IOCONFIG4_5);   //gpio模式
regvalue = readl(GPIO4_DIR);  //设置gpio输出
regvalue |= GPIO4_5;
writel(regvalue, GPIO4_DIR);
regvalue =readl(GPIO4_SPI_SCK_REG);  //设置gpio输出高电平
regvalue |= GPIO4_5;
writel(regvalue, GPIO4_SPI_SCK_REG);
}
/******************************************************************************
**函数名称:Set_SCK
**函数功能:SCK为高电平
**输入参数:无
**输出参数:无
**注意:    
******************************************************************************/
void Clr_SCK(void)
{
unsigned char regvalue;
writel(0, IOCONFIG4_5);   //gpio模式
regvalue = readl(GPIO4_DIR);  //设置gpio输出
regvalue |= GPIO4_5;
writel(regvalue, GPIO4_DIR);
regvalue =readl(GPIO4_SPI_SCK_REG);  //设置gpio输出低电平
regvalue &= ~GPIO4_5;
writel(regvalue,GPIO4_SPI_SCK_REG); 
}
/******************************************************************************
**函数名称:Set_MOSI
**函数功能:MOSI为高电平
**输入参数:无
**输出参数:无
**注意:    
******************************************************************************/
void Set_MOSI(void)
{
unsigned char regvalue;
writel(0, IOCONFIG4_6);   //gpio模式
regvalue = readl(GPIO4_DIR);  //设置gpio输出
regvalue |= GPIO4_6;
writel(regvalue, GPIO4_DIR);
regvalue = readl(GPIO4_DIR);  //设置gpio输出高电平
regvalue |= GPIO4_6;
writel(regvalue, GPIO4_SPI_MOSI_REG);
}
/******************************************************************************
**函数名称:Set_MOSI
**函数功能:MOSI为低电平
**输入参数:无
**输出参数:无
**注意:    
******************************************************************************/
void Clr_MOSI(void)
{
unsigned char regvalue;
writel(0, IOCONFIG4_6);   //gpio模式
regvalue = readl(GPIO4_DIR);  //设置gpio输出
regvalue |= GPIO4_6;
writel(regvalue, GPIO4_DIR);
regvalue = readl(GPIO4_DIR);  //设置gpio输出低电平
regvalue &= ~GPIO4_6;
writel(regvalue, GPIO4_SPI_MOSI_REG);
}
/******************************************************************************
**函数名称:MISO_H
**函数功能:读取MISO_H的值
**输入参数:无
**输出参数:无
**注意:    
******************************************************************************/
unsigned charMISO_H(void)
{
unsigned char regvalue;
writel(0, IOCONFIG4_7);   //gpio模式
regvalue = readl(GPIO4_DIR);  //设置gpio输入
regvalue &= ~GPIO4_7;
writel(regvalue, GPIO4_DIR);
regvalue =readl(GPIO4_SPI_MISO_REG);  //读取输入值
//DBG("regvalue = %x\n",regvalue);
return regvalue;
}
/******************************************************************************
**函数名称:SPICmd8bit
**函数功能:SPI写入参数8bit
**输入参数:WrPara
**输出参数:无
**注意:   保留nCS输出Low
******************************************************************************/
voidSPICmd8bit(byte WrPara)
{
byte bitcnt;     
Clr_nCS();
Clr_SCK();
for(bitcnt = 8; bitcnt != 0; bitcnt--)
{
Clr_SCK();
if(WrPara&0x80)
{
Set_MOSI();
}
else
{
Clr_MOSI();
}
Set_SCK();
WrPara <<= 1;
}
Clr_SCK();
Set_MOSI();
//Set_nCS();            //*此处不关闭nCS,使用连续模式*
}
/******************************************************************************
**函数名称:SPIRead8bitt
**函数功能:SPI读取参数8bit
**输入参数:读取8bit数据——RdPara
**输出参数:无
**注意:   保留nCS输出Low
******************************************************************************/
byte SPIRead8bit(void)
{
byte RdPara = 0;
byte bitcnt;
Clr_nCS();
Set_MOSI();               //读FIFO,维持SDI为H 
for(bitcnt=8; bitcnt!=0; bitcnt--)
{
Clr_SCK();
RdPara <<= 1;
Set_SCK();
if(MISO_H())
{
RdPara |= 0x01;
}
else
{
;
}
}
Clr_SCK();
//Set_nCS();               //*此处不关闭nCS,使用连续模式*
//DBG("RdPara = %x\n",RdPara);
return(RdPara);
}
/******************************************************************************
**函数名称:SPIRead
**函数功能:SPI读取一个地址数据
**输入参数:adr
**输出参数:无
******************************************************************************/
byte SPIRead(byteadr)
{
byte tmp;         
SPICmd8bit(adr);               //发送要读取的地址
tmp = SPIRead8bit();    //读取数据    
Set_nCS();
return(tmp);
}
/******************************************************************************
**函数名称:SPIWrite
**函数功能:SPI写入一个16数据(高8位地址,低8位数据)
**输入参数:WrPara
**输出参数:无
******************************************************************************/
void SPIWrite(wordWrPara)                                                                    
{                                                      
byte bitcnt;   
Clr_SCK();                           //注意SCK先清0,保持低
Clr_nCS();
WrPara |= 0x8000;           //写数据高位置1
for(bitcnt=16; bitcnt!=0; bitcnt--)
{
Clr_SCK();
if(WrPara&0x8000)
{
Set_MOSI();
}
else
{
Clr_MOSI();
}
Set_SCK();
WrPara <<= 1;
}
Clr_SCK();
Set_MOSI();
Set_nCS();
}         
/******************************************************************************
**函数名称:SPIBurstRead
**函数功能:SPI连续读取模式
**输入参数:adr——读取地址
**          ptr——存储数据指针
**          length 读取长度
**输出参数:无,数据存在ptr中
******************************************************************************/
voidSPIBurstRead(byte adr, byte *ptr, byte length)
{
byte i;
if(length<=1)                       //读取长度必须大于1
{
return;
}
else
{
Clr_SCK();                          //注意SCK先清0,保持低
Clr_nCS();
SPICmd8bit(adr);               //读取地址
for(i=0;i<length;i++)
{
ptr[i]= SPIRead8bit();
}
Set_nCS();        
}
}
/******************************************************************************
**函数名称:SPIBurstWrite
**函数功能:SPI连续写入模式
**输入参数:adr——写入地址
**          ptr——存储数据指针
**          length 写入长度
**输出参数:无
******************************************************************************/
voidBurstWrite(byte adr, byte *ptr, byte length)
{
byte i;
if(length<=1)                       //读取长度不为0或1
{
return;
}
else 
{      
Clr_SCK();                           //注意SCK先清0,保持低
Clr_nCS();                                             
SPICmd8bit(adr|0x80);    //连续写
for(i=0;i<length;i++)
{
SPICmd8bit(ptr[i]);
}
Set_nCS();        
}
}
longspi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
……
switch(cmd)
{
case SSP_READ_ALT:
…...
val = *(unsigned int*)arg;
addr = (unsignedchar)(val&0xff);
data =SPIRead(addr);
……
*(unsigned int *)arg= (unsigned int)(data&0x0000ff);
break;
case SSP_READ_BURST:
{
unsignedchar          addr = 0x00;
……
/*读取数据 */
SPIBurstRead(addr,read_tmp_data, DATA_LENGTH);
…...
break;
}
case SSP_WRITE_ALT:
data = 0;
val  = *(unsigned int *)arg;
tmp = (unsignedshort)((val&0xff0000)>>8);      
tmp |= (unsignedshort)((val&0x0000ff)>>0);
……
SPIWrite(tmp);
break; 
case SSP_WRITE_BURST:
res =copy_from_user(tmp_str, (unsigned char *)arg, sizeof(tmp_str));
if (res != 0)
{
printk("copydata from the user space error\n");
}
……
BurstWrite(addr,data, DATA_LENGTH);
break;
default:
{
printk("Nosuch spi command %#x!\n", cmd);
return -1;
}
}
return 0;
}
int spi_open(structinode * inode, struct file * file)
{
……
return 0;
}
intspi_close(struct inode * inode, struct file * file)
{
return 0;
}
static structfile_operations spi_fops = {
.owner          =THIS_MODULE,
.unlocked_ioctl        = spi_ioctl,
.open           =spi_open,
.release           =spi_close
};
static structmiscdevice spi_dev = {
.minor                =MISC_DYNAMIC_MINOR,                                                                                      
.name               =DEV_NAME,
.fops                           =&spi_fops,
};
static int __initspi_gpio_init(void)
{
int ret;
ret = misc_register(&spi_dev);
if (ret < 0)
{
printk("registerspi_gpio device failed!\n");
return -1;
}
printk("SPI driver initializesuccessful! .\n");
return 0;
}
static void __exitspi_gpio_exit(void)
{
misc_deregister(&spi_dev);
printk("SPI driver exit!\n");
}
module_init(spi_gpio_init);
module_exit(spi_gpio_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR(DRV_AUTHOR);
MODULE_DESCRIPTION(DRV_DESC);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/252956.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

git clone时出现 error:inflate:data stream error(incorrect data check)

git clone时出现 error:inflate:data stream error(incorrect data check) fatal:serrious inflate inconsistency fatal:index-pack failed 经了解&#xff0c;此问题是遗留问题&#xff0c;之前是因为公司对gitlab服务器进行数据迁移而引起这种git clone失败的原因&#xff0…

CentOS 7.5 使用 yum 安装 Kubernetes 集群(二)

一、安装方式介绍 1、yum 安装 目前CentOS官方已经把Kubernetes源放入到自己的默认 extras 仓库里面&#xff0c;使用 yum 安装&#xff0c;好处是简单&#xff0c;坏处也很明显&#xff0c;需要官方更新 yum 源才能获得最新版本的软件&#xff0c;而所有软件的依赖又不能自己指…

zbb20171108 tomcat 性能优化

原文地址http://www.cnblogs.com/NiceTime/p/6665416.html 1)内存优化(调整配置堆的大小&#xff0c;修改文件&#xff1a;catalina.sh) JAVA_OPTS"-Djava.awt.headlesstrue -Dfile.encodingUTF-8 -server -XX:MinHeapFreeRatio80 -XX:MaxHeapFreeRatio80 -XX:ThreadStack…

深入理解pthread_cond_wait、pthread_cond_signal

man pthread_cond_wait的解释 LINUX环境下多线程编程肯定会遇到需要条件变量的情况&#xff0c;此时必然要使用pthread_cond_wait()函数。但这个函数的执行过程比较难于理解。 pthread_cond_wait()的工作流程如下&#xff08;以MAN中的EXAMPLE为例&#xff09;&#xff1a;…

LeetCode算法题-Factorial Trailing Zeroes(Java实现)

这是悦乐书的第183次更新&#xff0c;第185篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第42题&#xff08;顺位题号是172&#xff09;。给定一个整数n&#xff0c;返回n&#xff01;中的尾随零数。例如&#xff1a; 输入&#xff1a;3 输出&#xff1a;0 说明…

JavaWeb基础—JS学习小结

JavaScript是一种运行在浏览器中的解释型的编程语言 推荐&#xff1a;菜鸟教程一、简介js:javascript是基于对象【哪些基本对象呢】和和事件驱动【哪些主要事件呢】的语言&#xff0c;应用在客户端&#xff08;注意与面向对象的区分&#xff09; js的三大特点&#xff1a;  交…

Asp.Net 设计模式 之 “简单工厂”模式

主要思想&#xff1a;public static Operation CreateFactory(string ope) { //实例化空父类&#xff0c;让父类指向子类 Operation op null; switch (ope) { case "": op …

UBuntu国内镜像地址下载

http://www.oschina.net/p/ubuntu http://releases.ubuntu.com/ http://mirrors.163.com/ubuntu-releases/14.04/

Effective_STL 学习笔记(十九) 了解相等和等价的区别

find 算法和 set 的 insert 成员函数是很多必须判断两个值是否相同的函数代表&#xff0c; find 对 “相同” 的定义是相等&#xff0c;基于 operator &#xff0c; set::insert 对 “相同” 的定义是等价&#xff0c;通常基于 operator< 。 操作上来说&#xff0c;相等的概…

判断是否获取到手机相机权限

实际运用场景&#xff1a; 上传图片&#xff0c;查看相机设备&#xff0c;使用相机 在做这些操作的时候先调用这段话 AVAuthorizationStatus authStatus [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]; if (authStatus AVAuthorizationStatusRestric…

事物笔记

什么是事务&#xff1a; 一件事情有N个组成单元&#xff0c;执行之后要么同时成功&#xff0c;要么同时失败。 MySQL是一条默认的事务&#xff0c;一条sql语句就是一条事务。------------------------------------------------------------MySQL事务&#xff1a; 1、开启一个事…

Python Socket通信黏包问题分析及解决方法

参考&#xff1a;http://www.cnblogs.com/Eva-J/articles/8244551.html#_label5 1.黏包的表现(以客户端远程操作服务端命令为例) 注&#xff1a;只有在TCP协议通信的情况下&#xff0c;才会产生黏包问题 基于TCP协议实现的黏包 #!/usr/bin/env python # -*- coding: utf-8 -*- …

Django 路由

定义&#xff1a; URL配置(URLconf)就像Django 所支撑网站的目录。它的本质是URL与要为该URL调用的视图函数之间的映射表&#xff1b;你就是以这种方式告诉Django&#xff0c;对于这个URL调用这段代码&#xff0c;对于那个URL调用那段代码。 URL配置格式&#xff1a; urlpatter…

Ubuntu默认不进入图形界面

修改 /etc/X11/default-display-manager如果值为/usr/sbin/gdm&#xff0c;(ubuntu12.04 为/usr/sbin/lightdm)则进入图形界面 如果值为false&#xff0c;则进入控制台&#xff08;命令行方式&#xff09;。如果想从控制台进入图形界面&#xff0c;可以在控制台上输入命令 sudo…

读《构建之法》的心得体会

前段时间&#xff0c;我看了《构建之法》的一些内容&#xff0c;有了一些心得体会。 软件工程所讨论的是代码量巨大、涉及人数众多、项目需求多变时所要解决的问题。而在校学生根本就没有这样的环境。而邹欣老师的《构建之法》是我读过的书中最浅显易懂的软件工程书。 在绪论中…

2440内存管理

title: 2440内存管理 tags: ARM date: 2018-10-17 19:08:49 --- 2440内存管理 特性 大/小端&#xff08;通过软件选择&#xff09;地址空间&#xff1a;每个 Bank 有 128M 字节(总共 1G/8 个 Bank)除了 BANK0&#xff08;16/32 位&#xff09;之外【引导ROM&#xff0c;其总线宽…

C#设计模式之十二代理模式(Proxy Pattern)【结构型】

一、引言 今天我们要讲【结构型】设计模式的第七个模式&#xff0c;也是“结构型”设计模式中的最后一个模式&#xff0c;该模式是【代理模式】&#xff0c;英文名称是&#xff1a;Proxy Pattern。还是老套路&#xff0c;先从名字上来看看。“代理”可以理解为“代替”&#…

IPv6检测

1&#xff09;判断服务器是否支持IPv6 &#xff1a; http://ipv6-test.com/validate.php 2&#xff09;检测当前设备打开网站的连接方式是IPv4还是IPv6&#xff1a; http://ipv6.sjtu.edu.cn/ 转载于:https://www.cnblogs.com/superbobo/p/6687605.html

百度首席科学家吴恩达宣布将从百度离职

海外网3月22日电 据媒体消息&#xff0c;百度首席科学家吴恩达&#xff08;Andrew Ng&#xff09;在英文自媒体平台Medium及微博、Twitter等个人社交平台发布公开信&#xff0c;宣布自己将从百度离职&#xff0c;开启自己在人工智能领域的新篇章。 吴恩达是人工智能和机器学习…

CentOS7.5 使用二进制程序部署Kubernetes1.12.2(三)

一、安装方式介绍 1、yum 安装 目前CentOS官方已经把Kubernetes源放入到自己的默认 extras 仓库里面&#xff0c;使用 yum 安装&#xff0c;好处是简单&#xff0c;坏处也很明显&#xff0c;需要官方更新 yum 源才能获得最新版本的软件&#xff0c;而所有软件的依赖又不能自己指…