目录
一.背景
- CPOL:规定了时钟信号线在空闲时的状态,CPOL=0表示时钟信号线在空闲时为低电平;CPOL=1表示时钟信号线在空闲是为高电平;
- CPHA:与I2C不同,SPI的数据接收方并不是在时钟高或者低电平时采样的,而是在时钟信号处于沿时,至于是在上升沿还是下降沿取决于CPHA。CPHA=0表示是在时钟信号变化的第一个沿时采样
SPI四种工作模式
CPOL= 1,CPHA=1:空闲时SCLK为高电平,SPI在上升沿采样
CPOL=0, CPHA=0:空闲时SCLK为低电平,SPI在上升沿采样
CPOL=0, CPHA=1:空闲时SCLK为低电平,SPI在下降沿采样
三种协议对比
| UART | I2C | SPI |
|---|---|---|
| 全双工、异步、串行 | 半双工、同步、串行 | 全双工、同步、串行 |
| 两根线 TXD RXD | 两根线 SCL SDA | 四根线 SCLK MOSI MISO CS |
| < 5MHZ | 100KHZ - 3.4MHZ | 1M - 100MHZ |
| 点对点 | 多主多从 | 一主多从 |
| 低位先行 | 高位先行 | 高位先行 |
ADXL345传感器
测量X,Y,Z三轴的重力加速度


写时寄存器地址最高位为低电平,读时为高电平。
INT1/2中断引脚,里面有寄存器可以设置XYZ三轴的阈值,当超过阈值触发中断
SDO->MISO
SDA->MOSI
CS->片选

CS接17号,SCL接18号,MISO/SDO接19号,MOSI/SDA接20号引脚
二.寄存器
con


将60MHZ分频为1MHZ

四位,将哪一位置1就是将该通道设置为主机模式

三种启动方式:
1.切换通道
2.片选线拉低
3.SMC位,向发送缓冲区写数据自动开启
EN:在配置其他寄存器之前,将此位置1
config

SCLK_CTL置1,默认高电平

SS_POL:片选极性,(极性即默认电平的高低),上面引脚接线图将CS接到GPIO引脚,所以可通过GPIO设置,此处默认即可。

SS_CTL:置0对应上面reg寄存器的发送数据就开始通信,置1说明片选线拉低才通信。
SCLK_POL:表示空闲时为高还是低电平。
SCLK_PHA即CPHA,表示第几个沿发送数据,时钟极性和相位都应置1.
start

RR:置1表示超过一位字节数据在接收缓冲区
TE同理。
三.实现
1.初始化
// spi3_channel0初始化
void spi3_channel0_init(void)
{
// 1. spi引脚复用功能
IOMUXC_SetPinMux(IOMUXC_UART2_TX_DATA_GPIO1_IO20, 0); // CS
IOMUXC_SetPinMux(IOMUXC_UART2_RX_DATA_ECSPI3_SCLK, 0); // SCLK
IOMUXC_SetPinMux(IOMUXC_UART2_RTS_B_ECSPI3_MISO, 0); // MISO
IOMUXC_SetPinMux(IOMUXC_UART2_CTS_B_ECSPI3_MOSI, 0); // MOSI
// 2. spi引脚电气属性
IOMUXC_SetPinConfig(IOMUXC_UART2_TX_DATA_GPIO1_IO20, 0x10B1);
IOMUXC_SetPinConfig(IOMUXC_UART2_RX_DATA_ECSPI3_SCLK, 0x10B1);
IOMUXC_SetPinConfig(IOMUXC_UART2_RTS_B_ECSPI3_MISO, 0x10B1);
IOMUXC_SetPinConfig(IOMUXC_UART2_CTS_B_ECSPI3_MOSI, 0x10B1);
// 3. 通信前,将CS拉高
GPIO_Type_t t =
{
.direction = gpio_output,
.default_value = 1
};
gpio_init(GPIO1, 20, &t);
// 4. SPI寄存器
ECSPI3->CONREG = 0;
ECSPI3->CONREG |= (7 << 20) | (0x0E << 12) | (2 << 8) | (1 << 4) | (1 << 3) | (1 << 0);
ECSPI3->CONFIGREG = 0;
ECSPI3->CONFIGREG |= (1 << 20) | (1 << 4) | (1 << 0);
};
电气属性更改高压摆率即可,其余和点灯功能相同。
2.读写
原理

SPI是全双工移位通信:主从两侧各有一个移位寄存器。每个时钟沿到来时,主机通过 MOSI 往外“移出”1位,同时从 MISO “移入”1位。也就是——每“写”一位的同时必然“读”到一位。
写即是读:你往总线“写”一个字节(移出8位),同一过程里也会“读”回从机在MISO上的8(可能是无效/占位字节)。
读即是写:你想从从机“读”数据,必须提供时钟,所以主机必须同时“写”出一个占位字节(通常是0xFF或0x00),用这些时钟把从机的数据“移入”。
// spi读写
unsigned char spi3_read_write(unsigned char data)
{
while ((ECSPI3->STATREG & (1 << 0)) == 0);
ECSPI3->TXDATA = data;
while ((ECSPI3->STATREG & (1 << 3)) == 0);
return ECSPI3->RXDATA;
}
ADC调用
// adxl345写
void adxl345_write(unsigned char reg_addr, unsigned char data)
{
// 拉低CS
gpio_set_value(GPIO1, 20, 0);
// 发送寄存器地址
spi3_read_write(reg_addr);//发完会回复一个字节,无用不管
// 发送数据
spi3_read_write(data);
// 拉高CS
gpio_set_value(GPIO1, 20, 1);
}
// adxl345读
unsigned char adxl345_read(unsigned char reg_addr)
{
unsigned char ret = 0;
// 拉低CS
gpio_set_value(GPIO1, 20, 0);
// 发送寄存器地址
spi3_read_write(reg_addr | 0x80);
// 发送Dummy
ret = spi3_read_write(0xFF);
// 拉高CS
gpio_set_value(GPIO1, 20, 1);
return ret;
}


struct ADXL345_Data
{
short x;
short y;
short z;
float xg;
float yg;
float zg;
};
// adxl345初始化
void adxl345_init(void)
{
// 关闭中断
adxl345_write(0x2E, 0x08);
// 设置满分辨率 + 设置满量程
adxl345_write(0x31, 0x0B);
// 低功耗模式 + 速率
adxl345_write(0x2C, 0x08);
// 配置测量模式 + 唤醒模式
adxl345_write(0x2D, 0x0B);
}
// 获得adxl345三轴加速度
struct ADXL345_Data adxl345_collect(void)
{
struct ADXL345_Data ret;
// 读取x轴数据
ret.x = adxl345_read(0x32);
ret.x |= adxl345_read(0x33) << 8;
// 读取y轴数据
ret.y = adxl345_read(0x34);
ret.y |= adxl345_read(0x35) << 8;
// 读取z轴数据
ret.z = adxl345_read(0x36);
ret.z |= adxl345_read(0x37) << 8;
// 获得x y z三轴加速度
ret.xg = ret.x * 0.0039;
ret.yg = ret.y * 0.0039;
ret.zg = ret.z * 0.0039;
return ret;
}
423



被折叠的 条评论
为什么被折叠?



