• MSP430F149用模拟SPI和FM25CL640通信


    最近因为用到了MSP430F149这个芯片,其中硬件已经设计好了,串口1和SPI1都要用,但大家都知道MSP430F149的这两个外设共用一些寄存器,两个同时用就很麻烦,所以这里我们模拟一个SPI来用,
    先简单讲一下FM25CL640,
    在这里插入图片描述
    在这里插入图片描述FM25CL640支持SPI模式0和3,我们这里用的模式3,详细FM25CL640资料大家可以再去百度一下。

    首先是SPI引脚的初始化:

    在这里插入图片描述

    void Master_SPI_Init(void)
    { 
     
          P5DIR |= BIT0+BIT1+BIT3;//SC+MOSI+SCLK
          P5DIR &=~BIT2;//MISO      
          P5OUT |= BIT0+BIT1+BIT3;//默认输出高   
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里用芯片的SPI1的接口(用其他IO一样的),MSP430F149,IO的方向是通过寄存器PxDIR来配置的,0是是输入,1是输出;
    一组IO口有8个 P5.0到P5.7对应0到第7位。这里:
    P5.0CS是片选信号,方向输出
    P5.1MOSI,这个口是主机输出,从机输入,放向输出
    P5.2MISO,这个口是主机输入,从机输出,放向输入
    P5.3SCK,这个口是时钟信号,方向输出,
    同时为了方便我们这里需要做一些定义:

    #define SPI_SC_H  (P5OUT |=BIT0)
    #define SPI_SC_L  (P5OUT &=~BIT0)
    #define SPI_CLK_H  (P5OUT |=BIT3) 
    #define SPI_CLK_L  (P5OUT &=~BIT3)
    #define SPI_MOSI_H (P5OUT |=BIT1)
    #define SPI_MOSI_L (P5OUT &=~BIT1)
    #define SPI_MISO   (P5IN&0X04)
    #define uchar unsigned char 
    #define uint unsigned int 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    MSP430F149,IO口的输出寄存器是PxOUT,输入寄存器是PxIN,比如说将P5.0输出高电平,那么就把P5OUT的第0位置1,还有比如要读P5.3输入的电平,那么就去查看P5IN的第3位,上面的BIT0是为了方便使用将数字封装了下,是官方头文件里面提供的,
    在这里插入图片描述
    接下来我们先写发送一字节的函数,

    void Spisend(uchar dataR)
    { 
    	for (int i=0; i<8; ++i)//一个字节8位,我们从高到低依次送出
    	{
    		SPI_CLK_L;        //先拉低时钟信号
    		if (dataR & 0x80)//逻辑与,判断当前最高位为1还是0,是1就将MOSI拉高,0就拉低
    		{
                      SPI_MOSI_H ;    //待将数据1发送出去		
    		}
    		else
    		{
    		   SPI_MOSI_L ;    //待将数据0发送出去
    		}
    
    		SPI_CLK_H;	    //将时钟型号拉高,同时将数据左移一位,开始送下一位
            dataR<<=1;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    接下来写往指定的地址写指定长度的数据

    void SPI_write_FM25CL64(uint address,uchar * buffer, uchar len)
    {
     uchar addr_tempH,addr_tempL;
     addr_tempH=(address&0xff00)>>8;//获取高8位地址
     addr_tempL=address&0x00ff;//获取低8位地址
    
        SPI_SC_L ;//片选使能,
       Spisend(FM25CL64Wren_CMD);//FM25CL640写使能
        SPI_SC_H ;//注意这一步
      SPI_SC_L ;
       Spisend(FM25CL64Write_CMD);//FM25CL640写命令
     Spisend(addr_tempH);//发送高8位地址
     Spisend(addr_tempL);//发送低8位地址
     
       for( uchar i = 0; i < len; i++ )
    	{
                Spisend(buffer[i]);//发送一个字节的数据到SPI芯片		 
    	}
     SPI_SC_H ;
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    这里需要注意FM25CL64在写之前需要使能一下,其命令码如下:

     #define FM25CL64Read_CMD 0x03        //读25LC640命令0000 0011
    #define FM25CL64Write_CMD 0x02      //写25LC640命令0000 0010
    #define FM25CL64Wren_CMD 0x06       //写25LC640使能命令0000 0110
    #define FM25CL64Wrdi_CMD 0x04      //复位 写25LC640使能命令0000 0100(禁止写操作)
    #define FM25CL64Rdsr_CMD 0x05       //读25LC640状态寄存器命令0000 0101(读状态,看有没有读取结束)
    #define FM25CL64Wrsr_CMD 0x01       //写25LC640状态寄存器命令0000 0001(写状态,看有没有写结束)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    需要注意的这里先将片选拉低使能,然后发送写使能,发完后需要先将片选拉高,然后再次拉低开始下面的内容,我起先是一开始拉低片选直到操作完所有在拉高,结果弄了半天没写进去。操作完写使能,再次拉低片选,发写命令,然后发送地址,先发高8位再发低8位,然后写数据,我们这里用一个for循环,地址会自己递增我们不用管。写完将片选拉高就行。
    接下来是读数据,先写读一个字节的

    uchar Spireceive(void)
    {
    	
    	uchar data = 0x00;        //		
         
    	for (int i=0; i<8; ++i) //我们需要一位一位的读,
    	{
              SPI_CLK_L;        //时钟拉低
              if(SPI_MISO)//这个我们在上面定义过#define SPI_MISO   (P5IN&0X04)读取P5.2的电平
              {
              	data<<=1;//将数据左移一位然后加一,
                data +=1;//                    
              }
              else
              {
               data<<=1;//0的话直接左移,等下一位
              }
               SPI_CLK_H;        //
    	}
    	return (data);      //返回接收到的data						  		  
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    接下来写从指定的地址读取指定长度的数据

    uchar SPI_read_FM25CL64(uint address,uchar * buffer ,uchar len)
    {
     uchar data_temp,addr_tempH,addr_tempL;
     addr_tempH=(address&0xff00)>>8;//获取高8位地址
     addr_tempL=address&0x00ff;//获取低8位地址
      SPI_SC_L ;//使能片选
    Spisend(FM25CL64Read_CMD);//FM25CL640读命令
     Spisend(addr_tempH);//发送高8位地址
     Spisend(addr_tempL);//发送低8位地址
         for( uchar i = 0; i < len; i++ )
         {
          buffer[ i ] = Spireceive();//接收一个字节的数据;    
         }
    
       SPI_SC_H ;
     return data_temp;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    这里读不需要使能,直接发读命令然后地址(先高8位在低8位),然后循环读数据,同样地址不用管会自己递增。
    这样我们的收发就写好了,然后去试试,

    unsigned char TestBuff1[]={0X01,0X02,'3','4','5','6','A','B','C','D'};
    unsigned char TestBuff[]={0,0,0,0,0,0,0,0,0,0};
    void main(void)
    {    
    /*下面六行程序关闭所有的IO口*/    
        P1DIR = 0X00;P1OUT = 0X00;
        P2DIR = 0X00;P2OUT = 0X00;
        P3DIR = 0X00;P3OUT = 0x00;
        P4DIR = 0X00;P4OUT = 0X00;
        P5DIR = 0X00;P5OUT = 0X00;
        P6DIR = 0X00;P6OUT = 0X00;
        
        WDTCTL = WDTPW + WDTHOLD;                 // 关闭看门狗
        BCSCTL1 &= ~XT2OFF;                       // XT2on
        do
        {
            IFG1 &= ~OFIFG;                 //清除晶振失败标志
            for (z = 0xFF; z > 0; z--);     //等待8MHz晶体起振
        }
        while ((IFG1 & OFIFG));             //晶振失效标志仍然存在?
        BCSCTL2 |= SELM_2 + SELS;                 // MCLK= SMCLK= XT2 (safe)
        Master_SPI_Init();
    		
    
      SPI_write_FM25CL64( 0x0001,  TestBuff1, 10);
      SPI_read_FM25CL64( 0x0001, TestBuff, 10 );
    while(1)
    {
    
    }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    我们将TestBuff1数组的内容写进去,然后读出来放到TestBuff,运行后:
    在这里插入图片描述

  • 相关阅读:
    Unity中国成立,以应对国内日益严格的数据处理法规
    云原生技术盛会KubeCon即将召开!亚马逊云科技作为钻石赞助商参会
    零基础学Linux内核之设备驱动篇(8)_设备模型_概念篇
    XSS详解及复现gallerycms字符长度限制短域名绕过
    BI行业分析思维框架 - 环保行业分析(二)
    Unity中的静态合批、动态合批、GPU Instance 以及SRP Batching
    【golang】多个defer的执行顺序以及器相关练习
    牛客网:链表分割
    Python函数进阶:实现自定义的装饰器
    力扣511. 游戏玩法分析 I
  • 原文地址:https://blog.csdn.net/qq_23127707/article/details/126756263