嵌入式第五十七天(SPI(adxl345))
问题1:什么是SPI?四线SPI的四根信号线各自作用是什么?

- SPI定义:SPI(Serial Peripheral Interface,串行外设接口)是一种高速的、全双工的、同步的串行通信总线,常用于短距离设备间(如微控制器与传感器、存储芯片、显示模块等)的通信。
- 四线SPI信号线作用
- SCLK(Serial Clock):串行时钟线,由主设备产生,用于同步主从设备之间的数据传输。
- MOSI(Master Out Slave In):主设备输出、从设备输入线,主设备通过该线向从设备发送数据。
- MISO(Master In Slave Out):主设备输入、从设备输出线,从设备通过该线向主设备发送数据。
- NSS(Slave Select,也称为CS - Chip Select):从设备选择线,由主设备控制,用于选择要通信的从设备(低电平有效,通常一个从设备对应一个NSS引脚)。

问题2:什么是时钟极性,什么是时钟相位?
- 时钟极性(CPOL,Clock Polarity):指SPI通信中时钟信号的空闲状态电平。
- CPOL=0时,时钟空闲状态为低电平;
- CPOL=1时,时钟空闲状态为高电平。
- 时钟相位(CPHA,Clock Phase):指数据采样是在时钟的上升沿还是下降沿。
- CPHA=0时,在时钟的第一个跳变沿(若CPOL=0则为上升沿,若CPOL=1则为下降沿)采样数据;
- CPHA=1时,在时钟的第二个跳变沿(若CPOL=0则为下降沿,若CPOL=1则为上升沿)采样数据。

问题3:为什么说SPI的时序分四种模式?
SPI(Serial Peripheral Interface)的四种模式由时钟极性(CPOL)和时钟相位(CPHA)两个参数的组合决定。CPOL定义时钟空闲时的电平状态,CPHA定义数据采样的边沿。四种模式分别对应不同的数据采样和稳定的时序要求。
模式0(CPOL=0, CPHA=0)
- 时钟极性(CPOL):空闲时为低电平。
- 时钟相位(CPHA):数据在时钟的第一个边沿(上升沿)采样,第二个边沿(下降沿)切换。
- 典型应用:常见于大多数SPI设备,如传感器和存储器。
模式1(CPOL=0, CPHA=1)
- 时钟极性(CPOL):空闲时为低电平。
- 时钟相位(CPHA):数据在时钟的第二个边沿(下降沿)采样,第一个边沿(上升沿)切换。
- 典型应用:某些特定外设,如部分ADC或通信模块。
模式2(CPOL=1, CPHA=0)
- 时钟极性(CPOL):空闲时为高电平。
- 时钟相位(CPHA):数据在时钟的第一个边沿(下降沿)采样,第二个边沿(上升沿)切换。
- 典型应用:较少见,需根据设备手册配置。
模式3(CPOL=1, CPHA=1)
- 时钟极性(CPOL):空闲时为高电平。
- 时钟相位(CPHA):数据在时钟的第二个边沿(上升沿)采样,第一个边沿(下降沿)切换。
- 典型应用:部分特殊设备或高速通信场景。
模式选择的关键点
- 设备兼容性:主从设备的模式必须一致,否则无法通信。
- 时序稳定性:模式影响数据建立和保持时间,需根据硬件特性选择。
- 信号完整性:高频场景下,模式可能影响抗干扰能力。

问题四:为什么说SPI读既是写,写既是读
SPI是全双工移位通信:主从两侧各有一个移位寄存器。每个时钟沿到来时,主机通过 MOSI 往外“移出”1位,同时从 MISO “移入”1位。也就是——每“写”一位的同时必然“读”到一位。
写即是读:你往总线“写”一个字节(移出8位),同一过程里也会“读”回从机在MISO上的8位(可能是无效/占位字节)。
读即是写:你想从从机“读”数据,必须提供时钟,所以主机必须同时“写”出一个占位字节(通常是0xFF或0x00),用这些时钟把从机的数据“移入”。
部分相关代码:
#include "spi.h"
#include "MCIMX6Y2.h"
#include "fsl_iomuxc.h"
#include "gpio.h"
void init_spi3(void)
{
IOMUXC_SetPinMux(IOMUXC_UART2_RX_DATA_ECSPI3_SCLK,0);
IOMUXC_SetPinMux(IOMUXC_UART2_CTS_B_ECSPI3_MOSI,0);
IOMUXC_SetPinMux(IOMUXC_UART2_RTS_B_ECSPI3_MISO,0);
IOMUXC_SetPinMux(IOMUXC_UART2_TX_DATA_GPIO1_IO20,0);
IOMUXC_SetPinConfig(IOMUXC_UART2_RX_DATA_ECSPI3_SCLK,0x10B1);
IOMUXC_SetPinConfig(IOMUXC_UART2_CTS_B_ECSPI3_MOSI,0x10B1);
IOMUXC_SetPinConfig(IOMUXC_UART2_RTS_B_ECSPI3_MISO,0x10B1);
IOMUXC_SetPinConfig(IOMUXC_UART2_TX_DATA_GPIO1_IO20,0x10B1);
struct GPIO_Type_t t =
{
.direction = gpio_output,
.defalut_value = 1
};
init_gpio(GPIO1,20,&t);
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);
//ECSPI3->CONREG |= (1<<0);
}
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;
}
#include "spi.h"
#include "gpio.h"
#include "adxl345.h"
void adxl345_write(unsigned char reg_address,unsigned char data)
{
write_gpio(GPIO1,20,0);
spi3_read_write(reg_address);
spi3_read_write(data);
write_gpio(GPIO1,20,1);
}
unsigned char adxl345_read(unsigned char reg_address)
{
unsigned char ret;
write_gpio(GPIO1,20,0);
spi3_read_write(reg_address | 0x80);
ret = spi3_read_write(0xFF);
write_gpio(GPIO1,20,1);
return ret;
}
void init_adxl345(void)
{
adxl345_write(0x2E,0x08);
adxl345_write(0x31,0x0B);
adxl345_write(0x2C,0x08);
adxl345_write(0x2D,0x0B);
}
struct ADXL345_Data adxl345_work(void)
{
struct ADXL345_Data ret;
ret.x = adxl345_read(0x32);
ret.x |= adxl345_read(0x33)<<8;
ret.y = adxl345_read(0x34);
ret.y |= adxl345_read(0x35)<<8;
ret.z = adxl345_read(0x36);
ret.z |= adxl345_read(0x37)<<8;
ret.xg = ret.x * 0.0039;
ret.yg = ret.y * 0.0039;
ret.zg = ret.z * 0.0039;
return ret;
}
#include <stdio.h>
#include "beep.h"
#include "led.h"
#include "key.h"
#include "gpio.h"
#include "interrupt.h"
#include "clock.h"
#include "epit.h"
#include "gpt.h"
#include "delay.h"
#include "uart.h"
#include "i2c.h"
#include "string.h"
#include "im75.h"
#include "adc.h"
#include "spi.h"
#include "adxl345.h"
int main(void)
{
init_clocks();
system_interrupt_init();
init_led();
init_beep();
//init_key();
//init_epit();
init_gpt1();
init_uart1();
init_i2c1();
init_spi3();
init_adc1_channle1();
while(1)
{
struct ADXL345_Data t;
t = adxl345_work();
//printf("x = %d,y = %d,z = %d\n",t.x,t.y,t.z);
int i,j,k;
i = t.xg * 10;
j = t.yg * 10;
k = t.zg * 10;
printf("x = %d.%d,y = %d.%d,z = %d.%d\n",i/10,i%10,j/10,j%10,k/10,k%10);
}
return 0;
}
更多推荐

所有评论(0)