STM32F407 SPI接口驱动MCP42100

STM32F407 通过SPI接口驱动MCP42100

MCP42100是具有两路数字电位器,两路数字电位器block diagram 如下
在这里插入图片描述
主机和MCP42100 通过SPI硬件接口进行通信.

MCP操作时序图.
在这里插入图片描述

问题描述

两路电位器连续写的时候会发现第二路写不成功的现象,但是单独一路操作是正常的,都可进行.连续使用SpiWriteUnitTest()函数分别给0 和1 电位器写的时候就会出现第二个电位器写不进去.
代码如下:
SPI初始化代码:


void SpiInit()
{
     uint32_t i;
    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB
                         | RCC_AHB1Periph_GPIOC
                         | RCC_AHB1Periph_GPIOD, ENABLE);// 时钟使能

    GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_SPI2);// PB13 复用为SPI2接口
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_SPI2);//同上

    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_13     // PB13 SCLK 
                                  | GPIO_Pin_15;    // PB15  MOSI
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
		
		SPI_InitTypeDef SPI_InitStruct;

		RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
		
		SPI_I2S_DeInit(SPI2);
		SPI_InitStruct.SPI_Direction         = SPI_Direction_1Line_Tx; //单向发送
		SPI_InitStruct.SPI_Mode              = SPI_Mode_Master;
		SPI_InitStruct.SPI_DataSize          = SPI_DataSize_16b;
		SPI_InitStruct.SPI_CPOL              = SPI_CPOL_High; // SPI_CPOL_Low
		SPI_InitStruct.SPI_CPHA              = SPI_CPHA_2Edge ;//SPI_CPHA_1Edge
		SPI_InitStruct.SPI_NSS               = SPI_NSS_Soft;
		SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128;//
		SPI_InitStruct.SPI_FirstBit          = SPI_FirstBit_MSB;
		SPI_InitStruct.SPI_CRCPolynomial     = 7;
		SPI_Init(SPI2, &SPI_InitStruct);

         SPI_Cmd(SPI2, ENABLE);//使能SPI2

}

SPIwrite data 代码:

 void SpiWriteUnitTest(uint8_t a_chan, uint8_t a_value)
 {

        
    GPIO_ResetBits(GPIOC, GPIO_Pin_12);//cs enable

     while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);

    if (0 == a_chan)
    {
        SPI_I2S_SendData(SPI2, 0x1100 | a_value);
    }
    else if (1 == a_chan)
    {
        SPI_I2S_SendData(SPI2, 0x1200 | a_value);
    }
    else if(2 == a_chan)
    {

      SPI_I2S_SendData(SPI2, 0x1300 | a_value);

    }

    while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == SET);

		
    SPI_I2S_ReceiveData(SPI2);  //need read ,otherwise continue write next  will fail,however  i don't kow why ~ ~
    while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == SET);
    GPIO_SetBits(GPIOC, GPIO_Pin_12);//cs disable

    return;

 }

此项目使用的是SPI只写,硬件仅需三根线,SCK,CS,MOSI,硬件未连接MISO信号线.


SPI四种模式

我们SPI通信有4种不同的模式,不同的从设备可能在出厂是就是配
置为某种模式,这是不能改变的;但我们的通信双方必须是工作在同一模式下,所以我们
可以对我们的主设备的SPI模式进行配置,通过CPOL(时钟极性)和CPHA(时钟相位)来
控制我们主设备的通信模式,具体如下:
Mode0:CPOL=0,CPHA=0
Mode1:CPOL=0,CPHA=1
Mode2:CPOL=1,CPHA=0
Mode3:CPOL=1,CPHA=1

时钟极性CPOL是用来配置SCLK的电平出于哪种状态时是空闲态或者有效态,时钟相位CPHA
是用来配置数据采样是在第几个边沿:
CPOL=0,表示当SCLK=0时处于空闲态,所以有效状态就是SCLK处于高电平时
CPOL=1,表示当SCLK=1时处于空闲态,所以有效状态就是SCLK处于低电平时
CPHA=0,表示数据采样是在第1个边沿,数据发送在第2个边沿
CPHA=1,表示数据采样是在第2个边沿,数据发送在第1个边沿

例如:
CPOL=0,CPHA=0:此时空闲态时,SCLK处于低电平,数据采样是在第1个边沿,也就是
SCLK由低电平到高电平的跳变,所以数据采样是在上升沿,数据发送是在下降沿。

CPOL=0,CPHA=1:此时空闲态时,SCLK处于低电平,数据发送是在第1个边沿,也就是
SCLK由低电平到高电平的跳变,所以数据采样是在下降沿,数据发送是在上升沿。

CPOL=1,CPHA=0:此时空闲态时,SCLK处于高电平,数据采集是在第1个边沿,也就是
SCLK由高电平到低电平的跳变,所以数据采集是在下降沿,数据发送是在上升沿。

CPOL=1,CPHA=1:此时空闲态时,SCLK处于高电平,数据发送是在第1个边沿,也就是
SCLK由高电平到低电平的跳变,所以数据采集是在上升沿,数据发送是在下降沿。

我们此项目使用的是Mode3这个根据MCP42100的时序可以看到Mode3符合MCP42100的时序.


解决方案:

如下是硬件电路图:
在这里插入图片描述

同时写两路的电位器的时候总是第二次写的电位器写不进去,当时思考两种方案

  1. 写两遍的做法,此方法可以正确写入两路,因此怀疑时许存在问题,
  2. 写完后实验主机进行读取一次操作.发现一次就可写成功.
    因此使用第二个做法在写完后调用读取函数进行读取操作. 执行如下代码即可成功进行操作.
     SPI_I2S_ReceiveData(SPI2);  //need read ,otherwise continue write next data will fail,however  i don't kow why ~ ~
    while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == SET);

总结

以上就是我在调试stm32 SPI接口和MCP402100数字电位器的过程中遇到的问题,在此作为借鉴,若有错误望大家指出.共同进步,成长为一名完美的嵌入式工程师是我们的终极目标,…

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值