SPI 读取不同长度 寄存器_SPI协议,MCP2515裸机驱动详解

be203e32-e60f-eb11-8da9-e4434bdf6706.png

SPI概述

Serial Peripheral interface 通用串行外围设备接口

是Motorola首先在其MC68HCXX系列处理器上定义的。SPI接口主要应用在 EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。

SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间。

SPI特点

采用主-从模式(Master-Slave) 的控制方式

SPI 规定了两个 SPI 设备之间通信必须由主设备 (Master) 来控制次设备 (Slave). 一个 Master 设备可以通过提供 Clock 以及对 Slave 设备进行片选 (Slave Select) 来控制多个 Slave 设备, SPI 协议还规定 Slave 设备的 Clock 由 Master 设备通过 SCK 管脚提供给 Slave 设备, Slave 设备本身不能产生或控制 Clock, 没有 Clock 则 Slave 设备不能正常工作。

而这里的SPI中的时钟和相位,指的就是SCLk时钟的特性,即保证主从设备两者的时钟的特性一致了,以保证两者可以正常实现SPI通讯。

采用同步方式(Synchronous)传输数据

Master 设备会根据将要交换的数据来产生相应的时钟脉冲(Clock Pulse), 时钟脉冲组成了时钟信号(Clock Signal) , 时钟信号通过时钟极性 (CPOL) 和 时钟相位 (CPHA) 控制着两个 SPI 设备间何时数据交换以及何时对接收到的数据进行采样, 来保证数据在两个设备之间是同步传输的.

c0203e32-e60f-eb11-8da9-e4434bdf6706.png

工作机制

概述

首先看下SPI Data Transfer模块图。

c3203e32-e60f-eb11-8da9-e4434bdf6706.png

上图只是对 SPI 设备间通信的一个简单的描述, 下面详细解释一下图中所示的几个组件(Module):

SSPBUF

Synchronous Serial Port Buffer, 泛指 SPI 设备里面的内部缓冲区, 一般在物理上是以 FIFO 的形式, 保存传输过程中的临时数据;

c5203e32-e60f-eb11-8da9-e4434bdf6706.png

我们知道, 在每个时钟周期内, Master 与 Slave 之间交换的数据其实都是 SPI 内部移位寄存器从 SSPBUF 里面拷贝的. 我们可以通过往 SSPBUF 对应的寄存器 (Tx-Data / Rx-Data register) 里读写数据, 间接地操控 SPI 设备内部的 SSPBUF。

例如, 在发送数据之前, 我们应该先往 Master 的 Tx-Data 寄存器写入将要发送出去的数据, 这些数据会被 Master-SSPSR 移位寄存器根据 Bus-Width 自动移入 Master-SSPBUF 里, 然后这些数据又会被 Master-SSPSR 根据 Channel-Width 从 Master-SSPBUF 中移出, 通过 Master-SDO 管脚传给 Slave-SDI 管脚, Slave-SSPSR 则把从 Slave-SDI 接收到的数据移入 Slave-SSPBUF 里. 与此同时, Slave-SSPBUF 里面的数据根据每次接收数据的大小(Channel-Width), 通过 Slave-SDO 发往 Master-SDI, Master-SSPSR 再把从 Master-SDI 接收的数据移入 Master-SSPBUF.在单次数据传输完成之后, 用户程序可以通过从 Master 设备的 Rx-Data 寄存器读取 Master 设备数据交换得到的数据。

SSPSR

Synchronous Serial Port Register, 泛指 SPI 设备里面的移位寄存器(Shift Regitser), 它的作用是根据设置好的数据位宽(bit-width) 把数据移入或者移出 SSPBUF;

c8203e32-e60f-eb11-8da9-e4434bdf6706.png

SSPSR 是 SPI 设备内部的移位寄存器(Shift Register). 它的主要作用是根据 SPI 时钟信号状态, 往 SSPBUF 里移入或者移出数据, 每次移动的数据大小由 Bus-Width 以及 Channel-Width 所决定。 Bus-Width 的作用是指定地址总线到 Master 设备之间数据传输的单位. 例如, 我们想要往 Master 设备里面的 SSPBUF 写入 16 Byte 大小的数据: 首先, 给 Master 设备的配置寄存器设置 Bus-Width 为 Byte; 然后往 Master 设备的 Tx-Data 移位寄存器在地址总线的入口写入数据, 每次写入 1 Byte 大小的数据(使用 writeb 函数); 写完 1 Byte 数据之后, Master 设备里面的 Tx-Data 移位寄存器会自动把从地址总线传来的1 Byte 数据移入 SSPBUF 里; 上述动作一共需要重复执行 16 次。

Channel-Width 的作用是指定 Master 设备与 Slave 设备之间数据传输的单位. 与 Bus-Width 相似, Master 设备内部的移位寄存器会依据 Channel-Width 自动地把数据从 Master-SSPBUF 里通过 Master-SDO 管脚搬运到 Slave 设备里的 Slave-SDI 引脚, Slave-SSPSR 再把每次接收的数据移入 Slave-SSPBUF里.通常情况下, Bus-Width 总是会大于或等于 Channel-Width, 这样能保证不会出现因 Master 与 Slave 之间数据交换的频率比地址总线与 Master 之间的数据交换频率要快, 导致 SSPBUF 里面存放的数据为无效数据这样的情况

Controller

泛指 SPI 设备里面的控制寄存器, 可以通过配置它们来设置 SPI 总线的传输模式。 通常情况下, 我们只需要对上图所描述的四个管脚(pin) 进行编程即可控制整个 SPI 设备之间的数据通信。

cc203e32-e60f-eb11-8da9-e4434bdf6706.png

Master 设备里面的 Controller 主要通过时钟信号(Clock Signal)以及片选信号(Slave Select Signal)来控制 Slave 设备. Slave 设备会一直等待, 直到接收到 Master 设备发过来的片选信号, 然后根据时钟信号来工作。

Master 设备的片选操作必须由程序所实现. 例如: 由程序把 SS/CS 管脚的时钟信号拉低电平, 完成 SPI 设备数据通信的前期工作; 当程序想让 SPI 设备结束数据通信时, 再把 SS/CS 管脚上的时钟信号拉高电平.

SCK

Serial Clock, 主要的作用是 Master 设备往 Slave 设备传输时钟信号, 控制数据交换的时机以及速率;

SS/CS

Slave Select/Chip Select, 用于 Master 设备片选 Slave 设备, 使被选中的 Slave 设备能够被 Master 设备所访问。

SDO/MOSI

Serial Data Output/Master Out Slave In, 在 Master 上面也被称为 Tx-Channel, 作为数据的出口, 主要用于 SPI 设备发送数据。

SDI/MISO

Serial Data Input/Master In Slave Out, 在 Master 上面也被称为 Rx-Channel, 作为数据的入口, 主要用于SPI 设备接收数据。

SPI 设备在进行通信的过程中, Master 设备和 Slave 设备之间会产生一个数据链路回环(Data Loop), 就像上图所画的那样, 通过 SDO 和 SDI 管脚, SSPSR 控制数据移入移出 SSPBUF, Controller 确定 SPI 总线的通信模式, SCK 传输时钟信号。

极性和相位

要想搞清楚SPI的数据传输,首先要搞清楚相位和极性的概念,即SPI的极性Polarity和相位Phase。

最常见的写法是CPOL和CPHA,不过也有一些其他写法,简单总结如下:

  • (1) CKPOL (Clock Polarity) = CPOL = POL = Polarity = (时钟)极性
  • (2) CKPHA (Clock Phase) = CPHA = PHA = Phase = (时钟)相位
  • (3) SCK=SCLK=SPI的时钟
  • (4) Edge=边沿,即时钟电平变化的时刻,即上升沿(rising edge)或者下降沿(falling edge)

对于一个时钟周期内,有两个edge,分别称为:

  • (1)Leading edge=前一个边沿=第一个边沿,对于开始电压是1, 那么就是1变成0的时候,对于开始电压是0,那么就是0变成1的时候;
  • (2)Trailing edge=后一个边沿=第二个边沿,对于开始电压是1, 那么就是0变成1的时候(即在第一次1变成0之后,才可能有后面的0变成1), 对于开始电压是0,那么就是1变成0的时候;

本博文采用如下用法:

  1. 极性=CPOL
  2. 相位=CPHA
  3. SCLK=时钟
  4. 第一个边沿和第二个边沿

CPOL和CPHA,分别都可以是0或时1,对应的四种组合就是:

ble data-draft-node="block" data-draft-type="table" data-size="normal" data-row-style="normal">

d0203e32-e60f-eb11-8da9-e4434bdf6706.png

CPOL=0,CPHA=0

脉冲传输前和完成后都保持在低电平状态,所以 CPOL=0,即低电平是空闲时的电平。在第一个边沿(上升沿)采样数据,第二个边沿(下降沿)输出数据,对应着CPHA=0。

d3203e32-e60f-eb11-8da9-e4434bdf6706.png

CPOL=0,CPHA=1

脉冲传输前和完成后都保持在低电平状态,所以 CPOL=0,即低电平是空闲时的电平。在第二个边沿(下降沿)采样数据,第一个边沿(上升沿)输出数据,对应着CPHA=1。

d4203e32-e60f-eb11-8da9-e4434bdf6706.png

CPOL=1,CPHA=0

脉冲传输前和完成后都保持在高电平状态,所以 CPOL=1,即高电平是空闲时的电平。在第一个边沿(下降沿)采样数据,第二个边沿(上升沿)输出数据,对应着CPHA=0。

d6203e32-e60f-eb11-8da9-e4434bdf6706.png

CPOL=1,CPHA=1

脉冲传输前和完成后都保持在高电平状态,所以 CPOL=1,即高电平是空闲时的电平。在第二个边沿(上升沿)采样数据,第一个边沿(下降沿)输出数据,对应着CPHA=1。

da203e32-e60f-eb11-8da9-e4434bdf6706.png

软件中如何设置SPI的极性和相位

SPI分主设备和从设备,两者通过SPI协议通讯。 而设置SPI的模式,是从设备的模式,决定了主设备的模式。 所以要先去搞懂从设备的SPI是何种模式,然后再将主设备的SPI的模式,设置和从设备相同的模式,即可正常通讯。

对于从设备的SPI是什么模式,有两种:

  • (1)固定的,有SPI从设备硬件决定的 SPI从设备,具体是什么模式,相关的datasheet中会有描述,需要自己去datasheet中找到相关的描述,即: 关于SPI从设备,在空闲的时候,是高电平还是低电平,即决定了CPOL是0还是1; 然后再找到关于设备是在上升沿还是下降沿去采样数据,这样就是,在定了CPOL的值的前提下,对应着可以推算出CPHA是0还是1了。
  • (2)可配置的,由软件自己设定 从设备也是一个SPI控制器,4种模式都支持,此时只要自己设置为某种模式即可。 然后知道了从设备的模式后,再去将SPI主设备的模式,设置为和从设备模式一样即可。 对于如何配置SPI的CPOL和CPHA的话,不多细说,多数都是直接去写对应的SPI控制器中对应寄存器中的CPOL和CPHA那两位,写0或写1即可。

数据交换(Data Exchanges)

SPI只有主模式和从模式之分,没有读和写的说法,因为实质上每次SPI是主从设备在交换数据。也就是说,你发一个数据必然会收到一个数据;你要收一个数据必须也要先发一个数据。

SPI 设备间的数据传输之所以又被称为数据交换, 是因为 SPI 协议规定一个 SPI 设备不能在数据通信过程中仅仅只充当一个 "发送者(Transmitter)" 或者 "接收者(Receiver)"。 在每个 Clock 周期内, SPI 设备都会发送并接收一个 bit 大小的数据, 相当于该设备有一个 bit 大小的数据被交换了。

一个 Slave 设备要想能够接收到 Master 发过来的控制信号, 必须在此之前能够被 Master 设备进行访问 (Access)。 所以, Master 设备必须首先通过 SS/CS pin 对 Slave 设备进行片选, 把想要访问的 Slave 设备选上。 在数据传输的过程中, 每次接收到的数据必须在下一次数据传输之前被采样. 如果之前接收到的数据没有被读取, 那么这些已经接收完成的数据将有可能会被丢弃, 导致 SPI 物理模块最终失效。

因此, 在程序中一般都会在 SPI 传输完数据后, 去读取 SPI 设备里的数据, 即使这些数据(Dummy Data)在我们的程序里是无用的。

SPI举例

下面举一个例子帮助大家理解。

SPI是一个环形总线结构,由ss(cs)、sck、sdi、sdo构成,其时序其实很简单,主要是在sck的控制下,两个双向移位寄存器进行数据交换。

假设下面的8位寄存器装的是待发送的数据10101010,上升沿发送、下降沿接收、高位先发送。 那么第一个上升沿来的时候 数据将会是sdo=1;寄存器=0101010x。下降沿到来的时候,sdi上的电平将所存到寄存器中去,那么这时寄存器=0101010sdi,这样在 8个时钟脉冲以后,两个寄存器的内容互相交换一次。这样就完成里一个spi时序。

举例: 假设主机和从机初始化就绪:并且主机的sbuff=0xaa,从机的sbuff=0x55,下面将分步对spi的8个时钟周期的数据情况演示一遍:假设上升沿发送数据

dd203e32-e60f-eb11-8da9-e4434bdf6706.png

这样就完成了两个寄存器8位的交换,上面的上表示上升沿、下表示下降沿,sdi、sdo相对于主机而言的。

下一步就是把 上面的过程转为动画

e0203e32-e60f-eb11-8da9-e4434bdf6706.png

e3203e32-e60f-eb11-8da9-e4434bdf6706.png

e6203e32-e60f-eb11-8da9-e4434bdf6706.png

eb203e32-e60f-eb11-8da9-e4434bdf6706.png

请仔细比较下交换后的bit顺序。

了解了SPI协议说明之后,下面我们基于Cortex-A9架构的exynos-4412,讲解SPI控制器的使用。

Cortex-A9 SPI控制器

硬件设计

本例是基于FS4412开发板,SPI控制器外接了MCP2515,MCP2515与exynos-4412的硬件连接图如下图所示。

ed203e32-e60f-eb11-8da9-e4434bdf6706.png

ef203e32-e60f-eb11-8da9-e4434bdf6706.png

f3203e32-e60f-eb11-8da9-e4434bdf6706.png

管脚连接说明

由上图可知SPI个引脚与SOC的pin连接关系:

  • CS <---------> BUF_BK_LED <---------> GPC1_2
  • SO <---------> BUF_I2C_SDA6 <---------> GPC1_3
  • SI <---------> BUF_I2C_SCL6 <---------> GPC1_4
  • SCK <---------> BUF_GPC1_1 <---------> GPC1_1
  • INT <-------------------------------------------> BUF_GPX0_0
  • MCP2515芯片连接在4412芯片的SPI2上。
  • 中断连接在GPX0_0上; CS、SO、SI、SCK复用了GPIO引脚GPC1的引脚。

MCP2515输出连接SN65HVD230 CAN总线收发器,SN65HVD230是德州仪器公司生产的3.3V CAN收发器。为了节省功耗,缩小电路体积,MCP2515 CAN总线控制器的逻辑电平采用LVTTL,SN65HVD230就是与其配套的收发器。

Cortex-A9 SPI控制器

exynos4412 scp中的串行外设接口(SPI)通过各种外设来传输串行数据。SPI包括两个8、16和32位移位寄存器,用于传输和接收数据。在SPI传输过程中,它同时传输(串行移出)和接收(串行移位)数据。

特性

  • 全双工
  • 用于Tx/Rx的8/16/32位移位寄存器
  • 支持8位/16位/32位总线接口
  • 支持摩托罗拉SPI协议和National Semiconductor Microwire
  • 两个独立的32位宽的发送和接收FIFO:端口0的深度为64,端口1和2中的深度为16
  • 主模式和从模式
  • 接收而不发送操作
  • 发送/接收最高频率为50 MHz

SPI的操作

SPI在Exynos 4412 SCP和外部设备之间传输1位串行数据。 Exynos 4412 SCP中的SPI支持CPU或DMA分别同时发送或接收FIFO和双向传输数据。 SPI有两个信道,即Tx信道和Rx信道。Tx信道有来自Tx的路径

FIFO到外部设备。Rx通道有从外部设备到Rx FIFO的路径。

CPU(或DMA)必须将数据写入寄存器SPI_TX_DATA,才能将数据写入FIFO。寄存器上的数据会自动移动到Tx FIFO。要从Rx FIFO读取数据,CPU(或DMA)必须访问寄存器SPI_RX_DATA,数据会自动发送到SPI_RX_DATA寄存器。

CMU寄存器可以控制SPI的工作频率。

操作模式

SPI有两种模式,即主模式和从模式。 在主模式下,生成SPICLK并将其传输到外部设备。XspiCS#是选择从机的信号,它指示在设置XspiCS时数据有效低水平。在发送或接收数据包之前,必须将XspiCS设置为低。

FIFO存取

SPI支持对fifo的CPU访问和DMA访问。 对fifo的CPU访问和DMA访问的数据大小从8位、16位或32位数据中选择。当它选择8位数据大小时,有效位是0到7比特。用户可以定义触发阈值来引发CPU中断。端口0中每个FIFO的触发电平由从0到252字节的步进为4个字节,端口1中每个FIFO的字节从0到63字节按1个字节的步长设置。 SPI_MODE_CFG寄存器的TxDMAOn或RxDMAOn位必须设置为使用DMA访问。DMA访问支持只有单次传输和4突发传输。在Tx FIFO中,DMA请求信号是高的,直到Tx FIFO满为止。在Rx FIFO中,如果FIFO不为空,DMA请求信号高。

片选控制

芯片选择XspiCS是激活的低信号。换句话说,当XspiCS输入为0时,选择芯片。 您可以自动或手动控制XspiCS。不需要改变。 手动模式 当您使用手动控制模式时,您应清除AUTO_N_MANUAL(默认值为0)。NSSOUT位控制XspiCS级别。 自动模式 使用自动控制模式时,必须将AUTO_N_MANUAL设置为1。XspiCS在数据包和自动打包。NCS_TIME_COUNT 控制XspiCS的非激活期。NSSOUT在此时不可用。

SPI寄存器说明

配置寄存器CH_CFGn

f4203e32-e60f-eb11-8da9-e4434bdf6706.png

【bit:5】 软件复位的时候必须先将此位设置为1,给一个延时后再设置为0; 【bit:4】 设置SPI端口是主机还是从机,0:主机,1:从机; 【bit:2-3】设置相位和极性; 【bit:1】接收数据的通道使能位; 【bit:0】发送数据的通道使能位。

数据宽度寄存器MODE_CFGn

设置总线数据宽度,一般设置为1个字节。

f7203e32-e60f-eb11-8da9-e4434bdf6706.png

片选寄存器CS_REGn

只有NSSOUT 拉低,才会进行数据的传输

f8203e32-e60f-eb11-8da9-e4434bdf6706.png

移位寄存器状态寄存器SPI_STATUSn

发送操作开始,如果移位寄存器空了,该值置1,通过该值判断数据是否发送出去。

fa203e32-e60f-eb11-8da9-e4434bdf6706.png

发送缓冲寄存器SPI_TX_DATA

fb203e32-e60f-eb11-8da9-e4434bdf6706.png

接收缓冲寄存器SPI_RX_DATA

fd203e32-e60f-eb11-8da9-e4434bdf6706.png

SPI初始化流程

  1. 设置GPIO引脚为SPI模式;
  2. 设置clock;
  3. 软件复位;
  4. 设置CPOL CPHA 为 00 模式,并设置为主机模式;
  5. 设置数据位;
  6. 片选。

1. 设置GPIO引脚为SPI模式

因为CS、SO、SI、SCK复用了GPIO引脚GPC1的引脚。首先需要设置GPIO引脚为SPI模式。

01213e32-e60f-eb11-8da9-e4434bdf6706.png

如上所示,该寄存器设置方式如下:

GPC1.CON = (GPC1.CON & ~0xffff0) | 0x55550;//设置IO引脚为SPI模式

Step 1 设置CPOL CPHA 为 00 模式

08213e32-e60f-eb11-8da9-e4434bdf6706.png

SPI2.CH_CFG&=~((0x1<< 4)|(0x1<<3)|(0x1<< 2)|0x3);

//master mode, CPOL = 0, CPHA = 0 (Format A)

2 设置clock

时钟的设置需要依赖锁相环(PLL)时钟产生器。

0b213e32-e60f-eb11-8da9-e4434bdf6706.png

从30.2.1节可知,时钟配置需要参考CMU这一章。

10213e32-e60f-eb11-8da9-e4434bdf6706.png

14213e32-e60f-eb11-8da9-e4434bdf6706.png

由上图可知SPI 的clock源是SCLK_SPI。

搜索SCLK_SPI

17213e32-e60f-eb11-8da9-e4434bdf6706.png

从第七章搜所有的SPI

18213e32-e60f-eb11-8da9-e4434bdf6706.png

继续搜索

69213e32-e60f-eb11-8da9-e4434bdf6706.png

由此可知SPI0~2的之中受CLKMPLL_USER_T 控制,继续搜索。 而此时钟位于寄存器CLK_SRC_PERIL1的bit[27:24]。

6c213e32-e60f-eb11-8da9-e4434bdf6706.png

继续搜索SPI2。

76213e32-e60f-eb11-8da9-e4434bdf6706.png

79213e32-e60f-eb11-8da9-e4434bdf6706.png

搜索到CLK_SRC_MASK_PERIL1、CLK_DIV_PERIL2。 可知寄存器CLK_SRC_MASK_PERIL1默认是打开的,所以不用设置。 CLK_DIV_PERIL2用来设置SPI2分频的,于是寄存器设置如下:

CLK_SRC_PERIL1 = (CLK_SRC_PERIL1 & ~(0xF<<24)) | 6<<24;
// 0x6: 0110 = SCLKMPLL_USER_T 800Mhz
CLK_DIV_PERIL2 = 19 <<8 | 3;//SPI_CLK = 800/(19+1)/(3+1)

3. 软件复位

7d213e32-e60f-eb11-8da9-e4434bdf6706.png
void soft_reset(void)
{ SPI2.CH_CFG |= 0x1 << 5;delay(1);                     //延时SPI2.CH_CFG &= ~(0x1 << 5);
}

4. 设置CPOL CPHA 为 00 模式,并设置为主机模式

SPI2.CH_CFG &= ~( (0x1 << 4) | (0x1 << 3) | (0x1 << 2) | 0x3);

5. 设置数据位MODE_CFG

82213e32-e60f-eb11-8da9-e4434bdf6706.png
SPI2.MODE_CFG &= ~((0x3 << 17) | (0x3 << 29));//BUS_WIDTH=8bit,CH_WIDTH=8bit 

6. 片选

SPI2.CS_REG &= ~(0x1 << 1);        //选择手动选择芯片

初始化搞定后,下面我们来看如何利用SPI收发数据。

收发数据流程

收发数据流程如下:

  1. spi复位
  2. 片选从机
  3. 收发数据
  4. 取消片选

【注意】一下代码为设置每次只读写1个byte数据,每次读写1个byte数据都要按照上述步骤操作。

1 spi复位

void soft_reset(void)
{ SPI2.CH_CFG |= 0x1 << 5;delay(1);                     //延时SPI2.CH_CFG &= ~(0x1 << 5);
}

2 片选从机

void slave_enable(void)
{SPI2.CS_REG &= ~0x1; //enable salvedelay(3);
}

3.1 发送数据

void send_byte(unsigned char data)
{SPI2.CH_CFG |= 0x1; // enable Tx Channeldelay(1);SPI2.SPI_TX_DATA = data;while( !(SPI2.SPI_STATUS & (0x1 << 25)) );SPI2.CH_CFG &= ~0x1; // disable Tx Channel
}

3.2 接收数据

unsigned char recv_byte()
{unsigned char data;SPI2.CH_CFG |= 0x1 << 1; // enable Rx Channeldelay(1);data = SPI2.SPI_RX_DATA;delay(1);SPI2.CH_CFG &= ~(0x1 << 1); //disable Rx Channelreturn  data;
}

取消片选

void slave_disable(void)
{SPI2.CS_REG |= 0x1; //disable salvedelay(1);
}

OK,到底为止,如何通过SPI收发数据,我们已经可以实现了,但是SPI往往外部回接各种各样的从设备。下面我们来看SPI如何操作从设备。

上面我们说了,fs4412开发板的SPI2外设外接了MCP2515,现在我们来分析一下MCP2515。

MCP2515

MCP2515详细资料,大家自行搜索 MCP2515 datasheet 《带有 SPI 接口的独立 CAN 控制器》。

简介

MCP2515是一种独立的CAN总线通信控制器,是Microchip公司首批独立CAN解决方案的升级器件,其传输能力较Microchip公司原有CAN控制器(MCP2510)高两倍,高通信速率可达到1Mbps。MCP2515能够接收和发送标准数据帧和扩展数据帧以及远程帧,通过两个接收屏蔽寄存器和六个接收过滤寄存器滤除无关报文,从而减轻CPU负担。

特性

MCP2515主要功能参数及电气特性如下:

  • (1)支持CAN技术规范2.0A/B, 高传输速率达到1Mbps;
  • (2)支持标准数据帧、扩展数据帧和远程帧,每帧数据域长度可为0~8个字节;
  • (3)内含两个的接收缓冲器和三个发送缓冲器,并且可编程设定优先级;
  • (4)内含六个29位(bit)的接收过滤寄存器和两个29位(bit)的接收屏蔽寄存器;
  • (5)高速SPI接口,支持SPI 0,0和1,1模式;
  • (6)一次性模式可确保报文被一次性传输;
  • (7)具有可编程时钟脉冲输出引脚,可作为其他芯片时钟信号源;
  • (8) 帧起始(SOF)信号输出功能可被用于在确定的系统中(如时间触发CAN-TTCAN)执行时隙功能,或在CAN总线诊断中决定早期总线出级;
  • (9) 采用低功耗CMOS技术,工作电压:2.7V~5.5V, 工作电流:5mA(待机状态1μA);
  • (10)工作温度范围:(I)-40℃到+85℃,(E)-40℃到+125℃。

结构框图

88213e32-e60f-eb11-8da9-e4434bdf6706.png

CAN模块

MCP2515 是一款独立 CAN 控制器, 可简化需要与 CAN总线连接的应用。如上图 简要显示了 MCP2515 的结构框图。该器件主要由三个部分组成:

  1. CAN 模块,包括 CAN 协议引擎、验收滤波寄存 器、验收屏蔽寄存器、发送和接收缓冲器。
  2. 用于配置该器件及其运行的控制逻辑和寄存器。
  3. SPI 协议模块。

CAN 模块的功能是处理所有 CAN 总线上的报文接收和发送。报文发送时,首先将报文装载到正确的报文缓冲器和控制寄存器中。通过 SPI 接口设置控制寄存器中的相应位或使用发送使能引脚均可启动发送操作。通过读取相应的寄存器可以检查通讯状态和错误。 会对在 CAN总线上检测到的任何报文进行错误检查,然后与用户定义的滤波器进行匹配,以确定是否将报文移到两个接收缓冲器中的一个。

SPI 协议模块

MCU通过SPI接口与该器件连接。使用标准的SPI读/写指令以及专门的 SPI 命令来读 / 写所有的寄存器。 MCP2515 设计可与许多单片机的串行外设接口( SPI)直接相连,支持 0,0 和 1,1 运行模式。外部数据和命令通过 SI 引脚传送到器件中,且数据在 SCK 时钟信号的上升沿传送进去。 MCP2515 在 SCK 的下降沿通过 SO引脚传送出去。在进行任何操作时, CS 引脚都必须保持为低电平。

与MCP2515通信

SPI指令集

我们要想操作MCP2515,只能用过SPI总线向MCP2515发送一些数据,根据规定,发送不同的数据就代表不同的操作,于是就形成了对应的指令集。

89213e32-e60f-eb11-8da9-e4434bdf6706.png

如上图所示,比如我们要执行复位操作,那么我只需要通过SPI总线写入11000000,即0xC0即可。

下面我们来详细分析如何向MCP2515发送复位命令,如何读写数据。

复位

因为复位只需要发送0XC0即可,并不需要其他额外操作,所以我们只需要根据我们之前章节所讲的SPI发送数据流程操作接口。

void reset_2515()
{soft_reset();      //复位spi控制器slave_enable() ;   //片选从机send_byte(0xc0);   //发送复位命令slave_disable() ;  //取消片选}

读取数据

8d213e32-e60f-eb11-8da9-e4434bdf6706.png

由上图可知,读取数据流程如下:

  1. 片选从机
  2. 通过SPI发送指令0x03
  3. 发送地址
  4. 读取数据
  5. 取消片选
unsigned char read_byte_2515(unsigned char Addr)
{unsigned char ret;slave_enable();send_byte(0x03);send_byte(Addr);ret = recv_byte();slave_disable();return(ret);
}

发送数据

90213e32-e60f-eb11-8da9-e4434bdf6706.png

由上图可知,发送数据流程如下:

  1. 片选从机
  2. 通过SPI发送指令0x02
  3. 发送地址
  4. 发送数据
  5. 取消片选
void write_byte_2515(unsigned char addr,unsigned char data)
{slave_enable();send_byte(0x02);send_byte(addr);send_byte(data);slave_disable();
}

读RX缓冲器

93213e32-e60f-eb11-8da9-e4434bdf6706.png

装载TX缓冲器

96213e32-e60f-eb11-8da9-e4434bdf6706.png

请求发送(RTS)指令

9b213e32-e60f-eb11-8da9-e4434bdf6706.png

位修改指令

a6213e32-e60f-eb11-8da9-e4434bdf6706.png

有些寄存器要修改对应的bit,必须先发送该指令,发送屏蔽字节,然后才可以修改屏蔽字节中对应位为1的值,后面会有例子给出。

CAN

知道该如何和CAN通信,下面我们来看如何初始化CAN。

CAN初始化

CAN的初始化步骤如下:

  1. MCP2515复位
  2. 设置MCP2515为配置模式
  3. 位定时配置,有配置寄存器CNF1,CNF2,CNF3控制
  4. 中断使能
  5. 接收缓冲器配置
  6. 引脚控制寄存器和状态寄存器

此外为方便测试,我们再加一步: 7. 回环模式,用于测试

1. MCP2515复位

上一节已经实现。

void reset_2515()

2. 设置MCP2515为配置模式

ab213e32-e60f-eb11-8da9-e4434bdf6706.png

由上图所示,只需要向地址0X0F写入数据0x80即可。

 write_byte_2515(0x0f, 0x80);    //CANCTRL寄存器--进入配置模式 中文DATASHEET 58页

3. 位定时配置,有配置寄存器CNF1,CNF2,CNF3控制

CAN总线上的所有节点都必须具有相同的标称比特率。CAN 协议采用不归零( Non Return to Zero, NRZ)编码方式,在数据流中不对时钟信号进行编码。因此,接收时钟信号必须由接收节点恢复并与发送器的时钟同步。

由于不同节点的振荡器频率和传输时间不同,接收器应具有某种能与数据传输边沿同步的锁相环( Phase Lock Loop, PLL)来同步时钟并保持这种同步。

鉴于数据采用 NRZ 编码,有必要进行位填充以确保至少每 6 位时间发生一次边沿,使数字锁相环 ( Digital Phase LockLoop, DPLL)同步。MCP2515 通过 DPLL 实现位定时。 DPLL 被配置成同输入数据同步,并为发送数据提供标称定时。 DPLL 将每一 个 位 时 间 分 割 为 由 最 小 单 位 为 时 间 份 额 ( Time Quanta, TQ)所组成的多个时间段。

在位时间帧中执行的总线定时功能,例如与本地振荡器同步、网络传输延迟补偿和采样点定位等,都是由DPLL 的可编程位定时逻辑来规定的。

CNF1 BRP<5:0> 控制波特率预分频比的设置。这些位根据OSC1 输入频率设置 TQ 的时间长度。当 BRP<5:0> =‘b000000’, TQ 最小值取 2 TOSC。通过 SJW<1:0> 选择以 TQ 计的同步跳转宽度。

CNF2 PRSEG<2:0> 位设定以 TQ 计的传播段时间长度。PHSEG1<2:0>位设定以TQ计的相位缓冲段PS1的时间长度。

CNF3 如果 CNF2.BTLMODE 位为 1,则相位缓冲段 PS2 的时间长度将由 PHSEG2<2:0> 位设定,以 TQ 计。如果BTLMODE 位为 0,则 PHSEG2<2:0> 位不起作用。

b0213e32-e60f-eb11-8da9-e4434bdf6706.png

b7213e32-e60f-eb11-8da9-e4434bdf6706.png

bd213e32-e60f-eb11-8da9-e4434bdf6706.png

MCP2515 波特率配置以16M晶振为例, SJW 段数(1+PRSEG+PRSEG1+PRSEG2)

#define CNF1_20K     0xd3        //4   20(1+4+8+7) 
#define CNF2_20K     0xfb          
#define CNF3_20K     0x46           //可以设置的波特率 5K 10K 15K 20K 25K 40K 50K 80K 100K 125K 200K 400K 500K 667K 800K 1M
write_byte_2515(0x2A, CNF1_20K); //CNF1位定时配置寄器  
write_byte_2515(0x29, CNF2_20K); //CNF2位定时配置寄器 
write_byte_2515(0x28, CNF3_20K); //CNF3位定时配置寄器 

4. 中断使能

MCP2515 有八个中断源。 CANINTE 寄存器包含了使能各中断源的中断使能位。 CANINTF 寄存器包含了各中断源的中断标志位。当发生中断时, INT 引脚将被MCP2515 拉为低电平, 并保持低电平状态直至 MCU 清除中断。中断只有在引起相应中断的条件消失后,才会被清除。 建议在对 CANINTF 寄存器中的标志位进行复位操作时,采用位修改命令而不要使用一般的写操作。这是为了避免在写命令执行过程中无意间修改了标志位,进而导致中断丢失。 应该注意的是, CANINTF 中的中断标志位是可读写位,因此在相关 CANINTE 中断使能位置 1 的前提下,对上述任一位置 1 均可使 MCU 产生中断请求。

bf213e32-e60f-eb11-8da9-e4434bdf6706.png
write_byte_2515(0x2B, 0x1f);     //CANINTE中断使能寄存器  

5. 接收缓冲器配置

MCP2515 具有两个全接收缓冲器。每个接收缓冲器配备 有多 个 验 收滤 波 器。除 上述 专 用 接收 缓 冲 器外,MCP2515 还具有单独的报文集成缓冲器 ( Message Assembly Buffer, MAB) ,可作为第三个接收缓冲器。

c3213e32-e60f-eb11-8da9-e4434bdf6706.png

bit5:6设置为1,其余位暂时不用,设置为0.

 write_byte_2515(0x60, 0x60);   //RXB0CTRL接收缓冲器0 控制寄存器 

6. 引脚控制寄存器和状态寄存器

当引脚配置为数字输出引脚时,相应的接收缓冲器中的BFPCTRL.BxBFM位应被清零, 而BFPCTRL.BnBFE位应被置 1。在这种工作模式下,引脚的状态由 BFPCTRL.BnBFS位控制。 BnBFS位写入1时,将使相应的缓冲器满中断引脚输出高电平,写入 0 将使该引脚输出低电平。当引脚处于这种模式时,该引脚的状态只应通过位修改 SPI 命令来修改,以避免任何缓冲器满中断引脚出现干扰。

c8213e32-e60f-eb11-8da9-e4434bdf6706.png
void bit_modify_2515(unsigned char addr, unsigned char mask, unsigned char data)
{
//    CS_SPI = 0 ;slave_enable() ;send_byte(0x05) ;send_byte(addr) ;send_byte(mask) ;send_byte(data) ;slave_disable() ;
//    CS_SPI = 1 ;
}
bit_modify_2515(0x0C, 0x0f, 0x0f); //BFPCTRL_RXnBF 引脚控制寄存器和状态寄存器 中文DATASHEET 29 页

7. 回环模式,用于测试

write_byte_2515(0x0f, 0x40);   //CAN控制寄存器--回环模式,用于测试

can缓冲区数据收发

MCP2515 采用三个发送缓冲器。每个发送缓冲器占用14 字节的 SRAM,并映射到器件存储器中。 其中第一个字节 TXBnCTRL 是与报文缓冲器相关的控制寄存器。该寄存器中的信息决定了报文在何种条件下发送,并在报文发送时指示其状态 。

用 5 个字节来装载标准和扩展标识符以及其他报文仲裁信息(见寄存器 3-3 到寄存器 3-7) 。最后 8 个字节用于装载等待发送报文的 8 个可能的数据字节 。

至少须将 TXBnSIDH、 TXBnSIDL 和 TXBnDLC 寄存器装载数据。如果报文包含数据字节,还需要对 TXBnDm寄存器进行装载。若报文采用扩展标识符,应对 TXBnEIDm 寄存器进行装载,并将 TXBnSIDL.EXIDE 位置1。

下面我们看如何向CAN的缓冲区0发送和接收数据。

数据发送

can缓冲区0数据发送流程如下:

  1. 设置为发送最高优先级
  2. 设置发送缓冲器0标准标识符高位
  3. 设置发送缓冲器0标准标识符低位
  4. 设置发送缓冲器0数据长度码8字节
  5. 向缓冲区写入数据,地址从0x36起
  6. 发送请求命令0x81,发送数据

1. 设置为发送最高优先级

ca213e32-e60f-eb11-8da9-e4434bdf6706.png
write_byte_2515(0x30, 0x03); //设置为发送最高优先级

2. 设置发送缓冲器0标准标识符高位

cf213e32-e60f-eb11-8da9-e4434bdf6706.png
write_byte_2515(0x31, 0xff); //发送缓冲器0标准标识符高位

3. 设置发送缓冲器0标准标识符低位

d2213e32-e60f-eb11-8da9-e4434bdf6706.png
write_byte_2515(0x32, 0x00); //发送缓冲器0标准标识符低位

4. 设置发送缓冲器0数据长度码8字节

d6213e32-e60f-eb11-8da9-e4434bdf6706.png
write_byte_2515(0x35, 0x08);  //发送缓冲器0数据长度码8字节

5. 向缓冲区写入数据,地址从0x36起

d8213e32-e60f-eb11-8da9-e4434bdf6706.png
write_byte_2515(0x36+i ,tx_buff[i]); //向txb缓冲器中写入8个字节

6. 发送请求命令0x81,发送数据

void send_req_2515()
{//   CS_SPI = 0; //复位soft_reset();      //复位spi控制器slave_enable() ;   //片选从机send_byte(0x81);   //发送请求命令slave_disable() ;  //取消片选
// CS_SPI=1;
}

Can数据的接收

从CAN缓冲区读取数据流程如下:

  1. 读取中断标志寄存器0x2c的value,判断bit0是否为1
  2. 从接收缓冲区读走数据,地址从0X66开始
  3. 软复位
  4. 向中断标志寄存器0x2c写入位掩码
  5. 向中断标志寄存器0x2c,写入数据0,清终端

1. 读取中断标志寄存器0x2c的value,判断bit0是否为1

当报文传送至某一接收缓冲器时,与该接收缓冲器对应的 CANINTF.RXnIF 位将置 1。一旦缓冲器中的报文处理完毕, MCU 就必须将该位清零以接收下一条报文。该控制位提供的锁定功能确保 MCU 尚未处理完上一条报文前, MCP2515 不会将新的报文载入接收缓冲器。

如果 CANINTE.RXnIE 位被置 1,器件会在 INT 引脚产生一个中断,显示接收到报文有效。另外,如果被配置为接收缓冲器满中断引脚,与之相应的 RXnBF 引脚会被拉低。

MCP2515 有八个中断源。 CANINTE 寄存器包含了使能各中断源的中断使能位。 CANINTF 寄存器包含了各中断源的中断标志位。当发生中断时, INT 引脚将被MCP2515 拉为低电平, 并保持低电平状态直至 MCU 清除中断。中断只有在引起相应中断的条件消失后,才会被清除。

建议在对 CANINTF 寄存器中的标志位进行复位操作时,采用位修改命令而不要使用一般的写操作。这是为了避免在写命令执行过程中无意间修改了标志位,进而导致中断丢失。

应该注意的是, CANINTF 中的中断标志位是可读写位,因此在相关 CANINTE 中断使能位置 1 的前提下,对上述任一位置 1 均可使 MCU 产生中断请求。

da213e32-e60f-eb11-8da9-e4434bdf6706.png

2. 从接收缓冲区读走数据

rx_buff[i]= read_byte_2515(0x66+i);

3. 软复位

soft_reset();

4. 向中断标志寄存器0x2c写入位掩码

bit_modify_2515(0x2c,0x01,0x00);//修改bit 0

5.清中断

write_byte_2515(0x2c, 0x00);

最终操作代码如下

节省篇幅,重复函数不贴了。

#define CNF1_20K     0xd3        //4   20(1+4+8+7) 
#define CNF2_20K     0xfb          
#define CNF3_20K     0x46  void  Init_can(void)
{reset_2515(); //复位write_byte_2515(0x0f, 0x80); //CANCTRL寄存器--进入配置模式 中文DATASHEET 58页//可以设置的波特率 5K 10K 15K 20K 25K 40K 50K 80K 100K 125K 200K 400K 500K 667K 800K 1Mwrite_byte_2515(0x2A, CNF1_20K); //CNF1位定时配置寄器   中文DATASHEET 41-42页write_byte_2515(0x29, CNF2_20K); //CNF2位定时配置寄器   中文DATASHEET 41-42页write_byte_2515(0x28, CNF3_20K); //CNF3位定时配置寄器   中文DATASHEET 41-43页write_byte_2515(0x2B, 0x1f);     //CANINTE中断使能寄存器  中文DATASHEET 50 页write_byte_2515(0x60, 0x60);     //RXB0CTRL接收缓冲器0 控制寄存器 中文DATASHEET 27 页//write_byte_2515(0x70, 0x20);   //接收缓冲器1控制寄存器bit_modify_2515(0x0C, 0x0f, 0x0f); //BFPCTRL_RXnBF 引脚控制寄存器和状态寄存器 中文DATASHEET 29 页write_byte_2515(0x0f, 0x40);   //CAN控制寄存器--回环模式,用于测试
}
void send_byte(unsigned char data)
{SPI2.CH_CFG |= 0x1; // enable Tx Channeldelay(1);SPI2.SPI_TX_DATA = data;while( !(SPI2.SPI_STATUS & (0x1 << 25)) );SPI2.CH_CFG &= ~0x1; // disable Tx Channel
}
unsigned char recv_byte()
{unsigned char data;SPI2.CH_CFG |= 0x1 << 1; // enable Rx Channeldelay(1);data = SPI2.SPI_RX_DATA;delay(1);SPI2.CH_CFG &= ~(0x1 << 1); //disable Rx Channelreturn  data;
}
void bit_modify_2515(unsigned char addr, unsigned char mask, unsigned char data)
{
//    CS_SPI = 0 ;slave_enable() ;send_byte(0x05) ;send_byte(addr) ;send_byte(mask) ;send_byte(data) ;slave_disable() ;
//    CS_SPI = 1 ;
}
void Can_send(unsigned char *tx_buff)
{unsigned char i;write_byte_2515(0x30, 0x03); //设置为发送最高优先级write_byte_2515(0x31, 0xff); //发送缓冲器0标准标识符高位write_byte_2515(0x32, 0x00); //发送缓冲器0标准标识符低位write_byte_2515(0x35, 0x08);  //发送缓冲器0数据长度码8字节for(i = 0; i < 8; i++){write_byte_2515(0x36+i ,tx_buff[i]); //向txb缓冲器中写入8个字节
//  printf("%x ",tx_buff[i]);}send_req_2515();}unsigned char Can_receive(unsigned char *rx_buff)
{unsigned char i,flag;flag = read_byte_2515(0x2c); //CANINTF——中断标志寄存器printf("flag=%xn",flag);//  printf(" SPI2.SPI_STATUS =%xn", SPI2.SPI_STATUS );//   soft_reset();if (flag&0x1)                //接收缓冲器0满中断标志位{for(i = 0; i < 16; i++){rx_buff[i]= read_byte_2515(0x66+i);//  printf("%x ",rx_buff[i]);//  printf(" SPI2.SPI_STATUS =%xn", SPI2.SPI_STATUS );soft_reset();}bit_modify_2515(0x2c,0x01,0x00);write_byte_2515(0x2c, 0x00);if (!(rx_buff[1]&0x08)) return(1);   //接收标准数据帧}return(0);
}
int main(void)
{GPX2.CON = 0x1 << 28;uart_init();unsigned char ID[4],buff[8];                 //状态字unsigned char key;unsigned char ret;//,j,k,ret0,ret1,ret2,ret3,ret4,ret5,ret6,ret7,ret8,ret9;unsigned int rx_counter;volatile int i=0;GPC1.CON = (GPC1.CON & ~0xffff0) | 0x55550;//设置IO引脚为SPI模式/*spi clock config*/CLK_SRC_PERIL1 = (CLK_SRC_PERIL1 & ~(0xF<<24)) | 6<<24;// 0x6: 0110 = SCLKMPLL_USER_T 800MhzCLK_DIV_PERIL2 = 19 <<8 | 3;//SPI_CLK = 800/(19+1)/(3+1)soft_reset();                    // 软复位SPI控制器SPI2.CH_CFG &= ~( (0x1 << 4) | (0x1 << 3) | (0x1 << 2) | 0x3);//master mode, CPOL = 0, CPHA = 0 (Format A)SPI2.MODE_CFG &= ~((0x3 << 17) | (0x3 << 29));   //BUS_WIDTH=8bit,CH_WIDTH=8bitSPI2.CS_REG &= ~(0x1 << 1);        //选择手动选择芯片mydelay_ms(10);    //延时Init_can();   //初始化MCP2515printf("n************ SPI CAN test!! ************n");while(1){//Turn on ledGPX2.DAT = GPX2.DAT | 0x1 << 7;mydelay_ms(50);printf("nplease input 8 bytesn");for(i=0;i<8;i++){src[i] = getchar();putc(src[i]);}printf("n");Can_send(src); //发送标准帧mydelay_ms(100);ret = Can_receive(dst); //接收CAN总线数据printf("ret=%xn",ret);printf("src=");for(i=0;i<8;i++) printf(" %x", src[i]);//将CAN总线上收到的数据发到串行口printf("n");printf("dst=");for(i=0;i<8;i++) printf(" %x",dst[6+i]); //将CAN总线上收到的数据发到串行口printf("n");//Turn offGPX2.DAT = GPX2.DAT & ~(0x1 << 7);mydelay_ms(100);} //while(1)return 0;
} //main

问题

1 什么是feddback 时钟?

2 Can的缓冲寄存器组 原理 更多信息,请关注 公号 一口Linux

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

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

相关文章

20162314 《Program Design Data Structures》Learning Summary Of The First Week

20162314 2017-2018-1 《Program Design & Data Structures》Learning Summary Of The First Week Summary of teaching materials Algorithm analysis is the basic project of the computer science.Increasing function prove that the utilization of the time and spa…

高并发解决方法

2019独角兽企业重金招聘Python工程师标准>>> 高并发来说&#xff0c;要从实际项目的每一个过程去考虑&#xff0c;页面&#xff0c;访问过程&#xff0c;服务器处理&#xff0c;数据库访问每个过程都可以处理。&#xff08;前端-宽带-后端-DB&#xff09; 集群&…

MySQL 之 存储过程

一、初识存储过程 1、什么是存储过程 存储过程是在大型数据库系统中一组为了完成特定功能的SQL语句集&#xff0c;存储在数据库中。存储过程经过第一次编译后&#xff0c;再次调用不需要编译&#xff0c;用户可以通过指定的存储过程名和给出一些存储过程定义的参数来使用它。…

如何root安卓手机_安卓Root+卡开机画面救砖教程丨以一加手机为例

一加手机买到手已经用了1个多月了&#xff0c;还有很多朋友在问我怎么Root、怎么替换Recovery、怎么安装Magisk、有时候刷Magisk模块变砖怎么解救。小编统一整理一下&#xff0c;其他安卓手机也可以参考&#xff0c;很多思路都是通用的。一加手机刷入TWRP并RootTWRP大概是现在安…

unity消息队列判断字符串相等有错误_Python3十大经典错误及解决办法

◆ ◆ ◆ ◆ ◆接触了很多Python爱好者&#xff0c;有初学者&#xff0c;亦有转行人。不论大家学习Python的目的是什么&#xff0c;总之&#xff0c;学习Python前期写出来的代码不报错就是极好的。下面&#xff0c;严小样儿为大家罗列出Python3十大经典错误及解决办法&#xf…

php qmqp 没有方法,CentOS7 php 安装 amqp扩展

继续安装完 rabbitmq后&#xff0c;安装phpqmqp扩展1.安装rabbitmq-c安装最新版wget -c https://github.com/alanxz/rabbitmq-c/releases/download/v0.8.0/rabbitmq-c-0.8.0.tar.gztar zxf rabbitmq-c-0.8.0.tar.gzcd rabbitmq-c-0.8.0./configure --prefix/usr/local/rabbitmq…

CentOS 7镜像下载

方式一 官网下载 官网链接&#xff1a;http://isoredirect.centos.org/centos/7/isos/x86_64/ Actual Country 国内资源 Nearby Countries 周边国家资源 方式二 阿里云下载 阿里云站点&#xff1a;http://mirrors.aliyun.com/centos/7/isos/x86_64/ 各个版本的ISO镜像文件…

Docker Dirty Cow逃逸

2019独角兽企业重金招聘Python工程师标准>>> 在Linux中&#xff0c;有一个功能&#xff1a;VDSO(virtual dvnamic shared object),这是一个小型共享库&#xff0c;能将内核自动映射到所有用户程序的地址空间。 Docker逃逸利用Dirty Cow漏洞&#xff0c;将Payload写到…

创建office一直转圈_Windows写字板出现广告条幅:推荐用户使用在线版Office

自Windows 95开始&#xff0c;写字板(Wordpad)应用就一直预装在Windows操作系统中。它是一款非常简单的文本编辑器&#xff0c;在功能方面介于记事本和Word之间。近日Rafael Rivera发现微软正在为这款古老的写字板添加新功能--在应用中添加广告横幅。这个广告横幅就是推荐那些写…

2017软件工程实践第二次作业

1、 项目地址&#xff1a;https://github.com/one-piece-zero/sudoku 2、PSP表格记录的估计耗时 3、解题思路&#xff1a; 在拿到这个题目的时候&#xff0c;我最早想到的是大一下学期做的程序语言综合设计实践中的N皇后问题&#xff0c;这两个题目之间有许多的类似之处&#x…

CentOS7 安装或迁移 wordpress(完整迁移)

一、安装Apache web服务器 安装Apache web服务器&#xff1a; yum install -y httpd # 使用yum安装 systemctl start httpd # 启动Apache服务器 systemctl enable httpd # Apache服务器开机后自动启动 使用浏览器打开http://127.0.0.1检查Apache安装是否成功。成功后…

WinForm部署问题

WinForm部署问题 1、解决&#xff1a;This implementation is not part of the Windows Platform 问题&#xff1f; 一&#xff1a;单击 开始 &#xff0c;单击 运行 &#xff0c;键入 gpedit.msc &#xff0c;然后单击 确定 。    二&#xff1a;依次展开 计算机配置 &…

signal软件如何退出账号_超好用的手机视频剪辑软件Videoleap内购分享

注意事项【必读】&#xff1a;1.必须按照下面的教程操作&#xff0c;教程讲的很详细。2.如果遇到帐号密码错误&#xff0c;先看本页面新密码再登陆&#xff0c;别乱试密码。3.如果手机上有你购买的这个软件&#xff0c;请先卸载&#xff0c;再用我们的苹果id登陆下载&#xff0…

python之eval函数,map函数,zip函数

eval(str)函数很强大&#xff0c;官方解释为&#xff1a;将字符串str当成有效的表达式来求值并返回计算结果。所以&#xff0c;结合math当成一个计算器很好用。 eval()函数常见作用有&#xff1a; 1、计算字符串中有效的表达式&#xff0c;并返回结果 >>> eval(pow(2,…

第一个servlet小程序

第一个servlet小程序 com.fry.servlet.HelloServlet 1 package com.fry.servlet;2 3 import javax.servlet.ServletException;4 import javax.servlet.http.HttpServlet;5 import javax.servlet.http.HttpServletRequest;6 import javax.servlet.http.HttpServletResponse;7 im…

win10开启oracle服务器配置,Windows环境(Win10)下安装、配置服务器类Oracle Database 11g Release 2...

该篇为服务器类Oracle Database 11gRelease 2的安装、配置&#xff0c;若需安装、配置桌面类(通常是选择桌面类&#xff0c;如果是将本机作为服务器来使用&#xff0c;则选择服务器类)&#xff0c;可参考“Windows环境(Win10)下安装、配置桌面类Oracle Database 11g Release 2”…

简单的机器学习程序_人体动作识别小程序【机器学习 人工智能】

人体动作识别(Human activity recognition)是健康领域一个热点问题&#xff0c;它通过加速度计&#xff0c;陀螺仪等传感器记录人体运动数据&#xff0c;对人体动作进行识别。最近用微信小程序做了一个动作识别的项目&#xff0c;同时尝试部署了单片机。首先奉上b站的视频链接&…

CSS布局说——可能是最全的

前言 现在&#xff0c;我们被称为前端工程师。然而&#xff0c;早年给我们的称呼却是页面仔。或许是职责越来越大&#xff0c;整体的前端井喷式的发展&#xff0c;使我们只关注了js&#xff0c;而疏远了css和html。 其实&#xff0c;我们可能经常在聊组件化&#xff0c;咋地咋地…

php dingo和jwt,dingo配合laravel、JWT使用

介绍&#xff1a;dingo api包是给laravel和lumen提供的Restful的工具包&#xff0c;它可以与jwt组件一起配合快速的完成用户认证&#xff0c;同时对于数据和运行过程中所产生的异常能够捕获到并且可以做出对应的响应。dingo文档地址&#xff1a;https://github.com/dingo/api/w…

二三星缩水软件手机版_还在抱怨三星手机不好用?用这些软件立马解决

S10系列上市让三星在国内的销量有所回暖&#xff0c;但是很多小伙伴拿到手机后都在吐槽三星的软件工程师不行&#xff0c;比如手势操作太难用了&#xff0c;不如小米人性化。其实这只是你没找到秘诀而已&#xff0c;三星手机原来还可以这样使用&#xff1f;三星有一个官方软件&…