STM32软件模拟SPI协议控制KS1092 EEG芯片

2024-08-21 13:52:17 浏览数 (2)

实不相瞒,我觉得这个芯片就有毛病设计的,寄存器也不多,数据输出也不是走数字接口,但是就要用SPI接口。尤其脑电这种东西两个芯片能够?真的裂开了。。。

2个KS1092挂在同一个SPI上面,然后使用不同的CS控制

KS1092 采用带通放大器。由于高通滤波特性的超低截止频率,信号可能需要几秒钟才能稳定下来。当电极首次连接时,此稳定时间可能会给用户带来不受欢迎的延迟。

为了解决这个问题,KS1092 的快速恢复引脚 (PIN8: FR) 可以由外部信号控制。通过将 PIN8: FR 设置为高状态,将激活快速恢复模式。

这个是STM32 上面的两个SPI接口

然后围绕下面的空余IO设置一下,完全使用IO模拟,不用硬件。

设置情况

大概就是这样

寄存器也就这样的

设计这样的函数,SPI单独的和封装的传感器读取写入,以及快速稳定

首先是初始化函数,按照数据手册的顺序开关对应的引脚,最后控制SPI

这个功能也简单,就是IO控制就行

还有关

因为是多个器件,所以写了这样的函数,来手动控制对应的器件

SPI(Serial Peripheral Interface,串行外围设备接口)是一种同步串行通信协议,广泛应用于微控制器与各种外围设备之间的数据传输。SPI协议包括四个主要信号:MOSI(主输出从输入),MISO(主输入从输出),SCLK(时钟),以及CS(片选)。

以下是SPI协议读写数据的基本步骤:

  1. 片选信号(CS):主设备将CS信号拉低,选择目标从设备进行通信。
  2. 数据传输:
    • 写数据:主设备将数据写入MOSI引脚,从设备在时钟信号(SCLK)的上升或下降沿读取数据。
    • 读数据:从设备将数据写入MISO引脚,主设备在时钟信号的上升或下降沿读取数据。
  3. 时钟信号(SCLK):时钟信号由主设备生成,用于同步数据传输。每个时钟周期对应传输一位数据。
  4. 数据有效性:SPI可以配置为在时钟上升沿或下降沿采样数据,根据不同的设备配置选择不同的模式。
代码语言:javascript复制
void KS1029_Write_One_Byte(uint8_t Bytein)
{
    uint8_t Byte = Bytein;
    uint8_t len = 0;
    HAL_GPIO_WritePin(KS1092_1_SCLK_GPIO_Port, KS1092_1_SCLK_Pin, GPIO_PIN_SET); // SCLK High
    for (len = 0; len < 8; len  )
    {
        if ((Byte & 0x80))
        {
            HAL_GPIO_WritePin(KS1092_1_SDI_GPIO_Port, KS1092_1_SDI_Pin, GPIO_PIN_SET); // SDI High
        }
        else
        {
            HAL_GPIO_WritePin(KS1092_1_SDI_GPIO_Port, KS1092_1_SDI_Pin, GPIO_PIN_RESET); // SDI Low
        }
        Byte = Byte << 1;
        Delay_us(5);
        HAL_GPIO_WritePin(KS1092_1_SCLK_GPIO_Port, KS1092_1_SCLK_Pin, GPIO_PIN_RESET); // SCLK Low
        Delay_us(5);
        HAL_GPIO_WritePin(KS1092_1_SCLK_GPIO_Port, KS1092_1_SCLK_Pin, GPIO_PIN_SET); // SCLK High
        Delay_us(5);
    }
}

函数控制时钟信号(SCLK)和数据输入引脚(SDI)来向KS1092写入一个字节的数据。每次循环发送一位数据,总共8次循环完成一个字节的发送。

  1. 设置SCLK高电平:表示准备开始传输数据。
  2. 检查当前字节的最高位:如果为1,则将SDI设置为高电平;否则,设置为低电平。
  3. 左移字节:将字节左移一位,为发送下一个数据位做准备。
  4. 延时:确保信号稳定。
  5. 设置SCLK低电平:表示数据位已被发送。
  6. 重复上述步骤:直至发送完一个字节的所有位。
代码语言:javascript复制
uint8_t SPI_ReadWriteByte(uint8_t byte)
{
    uint8_t receivedByte = 0;

    for (int i = 0; i < 8; i  )
    {
        // Generate clock rising edge for reading
        HAL_GPIO_WritePin(KS1092_1_SCLK_GPIO_Port, KS1092_1_SCLK_Pin, GPIO_PIN_SET);

        Delay_us(1);

        // Read MISO and store it in the lowest bit of the received byte
        receivedByte <<= 1;
        if (HAL_GPIO_ReadPin(KS1092_1_SDO_GPIO_Port, KS1092_1_SDO_Pin) == GPIO_PIN_SET)
        {
            receivedByte |= 0x01;
        }

        // Write data bit to MOSI
        if (byte & 0x80)
        {
            HAL_GPIO_WritePin(KS1092_1_SDI_GPIO_Port, KS1092_1_SDI_Pin, GPIO_PIN_SET);
        }
        else
        {
            HAL_GPIO_WritePin(KS1092_1_SDI_GPIO_Port, KS1092_1_SDI_Pin, GPIO_PIN_RESET);
        }

        byte <<= 1; // Prepare the next bit to send

        Delay_us(1);

        // Generate clock falling edge for writing
        HAL_GPIO_WritePin(KS1092_1_SCLK_GPIO_Port, KS1092_1_SCLK_Pin, GPIO_PIN_RESET);

        Delay_us(1);
    }

    return receivedByte;
}

函数实现SPI协议的读写操作。对于每一位数据:

  1. 设置SCLK高电平:准备读取数据。
  2. 读取MISO:将MISO上的数据位存储到接收字节的最低位。
  3. 写数据到MOSI:根据待发送字节的最高位,设置SDI的电平。
  4. 左移字节:将待发送字节左移一位,为发送下一个数据位做准备。
  5. 设置SCLK低电平:表示数据位已被发送和读取。
  6. 延时:确保信号稳定。 ----------------------------------------------------------------------

KS1029_Write_One_Byte函数实现了单字节的写操作

SPI_ReadWriteByte函数则实现了双向数据传输,既可以发送数据,也可以接收数据

----------------------------------------------------------------------

软件SPI vs. 硬件SPI

  • 软件SPI:通过软件控制GPIO引脚实现SPI通信,灵活性高,但效率较低。
  • 硬件SPI:使用微控制器内部的硬件SPI模块进行通信,效率高,速度快,但灵活性相对较低。
  • 在代码里面运行这个就行

为了应对上面的情况,我也设计了一个MSPM0L1106 KS1092的单独方案,使用一颗MCU,将SPI转换为IIC,做到多个传感器一次挂在一个接口上面,节省IO以外还可以扩展多通道检测通道。至于什么时候写,看我时间。

0 人点赞