用GPIO模拟SPI,但不知道哪里出了问题- -

2019-07-20 05:09发布




主机程序spi.h

#ifndef _SPI_H
#define _SPI_H
#include "sys.h"


#define MOSI PHout(3)   //主机输出,从机输入
#define SCLK PHout(4)   //时钟引脚
#define MISO PBin(2)        //主机输入,从机输出
#define CS1  PAout(4)          //片选信号1
#define CS2  PAout(5)        //片选信号2

void SPI_Init(void);
u8 SPI_ReadWrite(u8 dat, u8 choice);

#endif


spi.c

#include "spi.h"
#include "delay.h"

////////////////////////////////////////////////////////////////////////////////
//我们标定CPOL和CPHA都为0
//CPOL=0:时钟空闲时电平为低;
//CPHA=0;时钟周期的上升沿发送数据,时钟周期的下降沿接收数据;

////////////////////////////////////////////////////////////////////////////////


//SPI IO初始化
void SPI_Init(void)
{
    GPIO_InitTypeDef GPIO_Initure;
    __HAL_RCC_GPIOB_CLK_ENABLE();           //开启GPIOB时钟
        __HAL_RCC_GPIOA_CLK_ENABLE();           //开启GPIOA时钟
        __HAL_RCC_GPIOH_CLK_ENABLE();                                                        //开启GPIOH时钟
    GPIO_Initure.Pin=GPIO_PIN_3|GPIO_PIN_4; //PH3,4
    GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;  //推挽输出
    GPIO_Initure.Pull=GPIO_PULLUP;          //上拉
    GPIO_Initure.Speed=GPIO_SPEED_HIGH;     //高速
    HAL_GPIO_Init(GPIOH,&GPIO_Initure);
       
        GPIO_Initure.Pin=GPIO_PIN_4|GPIO_PIN_5; //PA4,5
    GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;  //推挽输出
    GPIO_Initure.Pull=GPIO_PULLUP;          //上拉
    GPIO_Initure.Speed=GPIO_SPEED_HIGH;     //高速
    HAL_GPIO_Init(GPIOA,&GPIO_Initure);

    GPIO_Initure.Pin=GPIO_PIN_2;            //PB2
    GPIO_Initure.Mode=GPIO_MODE_INPUT;      //输入
    GPIO_Initure.Pull=GPIO_PULLUP;        //下拉
    GPIO_Initure.Speed=GPIO_SPEED_HIGH;     //高速
    HAL_GPIO_Init(GPIOB,&GPIO_Initure);
       
       
       
    HAL_GPIO_WritePin(GPIOH,GPIO_PIN_3,GPIO_PIN_SET);        //PH3置1
    HAL_GPIO_WritePin(GPIOH,GPIO_PIN_4,GPIO_PIN_SET);        //PH4置1  
               
        HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);        //PA4置1
    HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);        //PA5置1  
}

//延时函数封装:可以进行改变延时的大小
void Delay()
{
        delay_us(10);                //延时1ms
}

//spi实现读写函数
//dat:要发送的数据
//choice: 选择的spi器件
u8 SPI_ReadWrite(u8 dat, u8 choice)
{
        u8 temp;
        SCLK = 0;        //空闲时为低电平
        Delay();
       
        if (choice == 1)
        {
                CS1 = 0;        //置低
        }
        else
        {
                CS2 = 0;   //置低
        }
        Delay();

       
        for (int i = 0; i < 8; i++)
        {
                MOSI = dat & 0x01;        //低位在前
                dat >>= 1;
                SCLK = 1;        //数据在上升沿时,主机发送数据,从机读取数据
                Delay();
                temp >>= 1;                //下降沿时开始读取数据
                if (MISO)temp++;
                SCLK = 0;
                Delay();       
        }
       
        //片选关闭,不再选择
        CS1 = 1;
        CS2 = 1;
        Delay();
       
        return temp;
}



从机程序
spi.h
#ifndef _SPI_H
#define _SPI_H
#include "sys.h"


#define MOSI PHin(3)   //主机输出,从机输入
#define SCLK PHin(4)   //时钟引脚
#define MISO PBout(2)        //主机输入,从机输出
#define CS1  PAin(4)          //片选信号1

void SPI_Init(void);
u8 SPI_ReadWrite(u8 dat);

#endif


spi.c

#include "spi.h"
#include "delay.h"

////////////////////////////////////////////////////////////////////////////////
//我们标定CPOL和CPHA都为0
//CPOL=0:时钟空闲时电平为低;
//CPHA=0;时钟周期的上升沿采集数据,时钟周期的下降沿接收数据;

////////////////////////////////////////////////////////////////////////////////
//从机PB3输入,PB2,PH4输出

//SPI IO初始化
void SPI_Init(void)
{
       GPIO_InitTypeDef GPIO_Initure;
    __HAL_RCC_GPIOB_CLK_ENABLE();           //开启GPIOB时钟
                __HAL_RCC_GPIOA_CLK_ENABLE();           //开启GPIOA时钟
                __HAL_RCC_GPIOH_CLK_ENABLE();                                                        //开启GPIOH时钟
    GPIO_Initure.Pin=GPIO_PIN_3|GPIO_PIN_4; //PH3
    GPIO_Initure.Mode=GPIO_MODE_INPUT;  //推挽输入
    GPIO_Initure.Pull=GPIO_PULLUP;          //上拉
    GPIO_Initure.Speed=GPIO_SPEED_HIGH;     //高速
    HAL_GPIO_Init(GPIOH,&GPIO_Initure);
       
                GPIO_Initure.Pin=GPIO_PIN_4; //PA4
    GPIO_Initure.Mode=GPIO_MODE_INPUT;  //推挽输入
    GPIO_Initure.Pull=GPIO_PULLUP;          //上拉
    GPIO_Initure.Speed=GPIO_SPEED_HIGH;     //高速
    HAL_GPIO_Init(GPIOA,&GPIO_Initure);

    GPIO_Initure.Pin=GPIO_PIN_2;            //PB2
    GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;      //输出
    GPIO_Initure.Pull=GPIO_PULLUP;        //上拉
    GPIO_Initure.Speed=GPIO_SPEED_HIGH;     //高速
    HAL_GPIO_Init(GPIOB,&GPIO_Initure);
       

    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_SET);        //PB3   HIGH  

                HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);//PA4   LOW
}

//延时函数封装:可以进行改变延时的大小
void Delay()
{
        delay_us(10);                //延时1ms
}

//spi实现读写函数
//dat:要发送的数据

u8 SPI_ReadWrite(u8 dat)
{
        u8 temp=0;

        Delay();
       
               
        for (int i = 0; i < 8; i++)
        {
               
                //数据在上升沿读取,在下降沿发送
                if(SCLK==1)
                {
                       
                        Delay();
       
                        if (MOSI)temp++;       
                       
                        temp <<= 1;       
               
               
        }
                else if(SCLK==0)
                {
                        Delay();
                        if(dat&&0x80)MISO=1;
                        else MISO=0;
                        dat<<=1;
                       
                }
       
        }
               
        return temp;
}


友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
6条回答
chaojunchi
1楼-- · 2019-07-20 08:27
 精彩回答 2  元偷偷看……
szczyb1314
2楼-- · 2019-07-20 09:53
SPI没模拟过从机,帮顶
chaojunchi
3楼-- · 2019-07-20 15:49
本帖最后由 chaojunchi 于 2018-11-11 20:22 编辑

        for (int i = 0; i < 8; i++)
        {
                MOSI = dat & 0x01;        //低位在前
                dat >>= 1;
                SCLK = 1;        //数据在上升沿时,主机发送数据,从机读取数据
                Delay();
                temp >>= 1;                //下降沿时开始读取数据
                if (MISO)temp++;
                SCLK = 0;
                Delay();        
        }
你这个temp应该是temp<<=1;否则只能返回0和1两个值,不会有其它值。这样先进的是高位。如果你想先读进的是低位,那程序得改一下了。
       temp = 0;
       for(int i = 0;i < 8;i++)
       {
              MOSI = dat & 0x01;
              dat >> 1;
              SCLK = 1;
              Delay();
              if(MISO)temp1 = 1 << i;else temp1 = 0;
              temp |= temp1;
              SCLK = 0;
              Delay();
        }
edmund1234
4楼-- · 2019-07-20 17:28
 精彩回答 2  元偷偷看……
aozima
5楼-- · 2019-07-20 22:06
 精彩回答 2  元偷偷看……
GILLGAMIE
6楼-- · 2019-07-21 00:32
chaojunchi 发表于 2018-11-11 20:33
细看你程序好像有很大问题啊,时钟同主机发送没错,从机要判断时钟上升沿和下降沿,而不是高电平和低电平 ...

多谢老哥指点,初学stm32,我自己再改改

一周热门 更多>