[应用相关] STM32 SPI双机通信(主从全双工)

[复制链接]
3475|2
 楼主| dentsgot 发表于 2016-4-7 20:41 | 显示全部楼层 |阅读模式
个人心得:在做主从双机通信时,一定要理解好主机和从机的作用,做主机时会控制通信的时钟,从机是不能产生时钟的。如果从机要发送数据,那可以在主机发送数据 的时钟上发送数据。配置上差不多是一样的,就设计主从就得了。我这里接收都是用中断。
还有一点要注意的,做主机接收时,不能和发送共用一个函数。这个为什么我自己现在也没有清楚,只是在实验中测得。

纠错:从机的接收函数改成,这时因为我测试完成后有改动就压包,后来测试发现主机不能正常接收到数据
更正:我之前的两个时钟的理论是不合理的,因为全双工收发是可以共用时钟的,这个我在后面改进的主机程序中有体现。



欢迎大家测试

  1. u8 SPI1_ReadByte(u8 TxData)
  2. {  
  3. u8 retry=0;   
  4. // while((SPI1->SR&1<<1)==0)//等待发送区空
  5. // {
  6. //  retry++;
  7. //  if(retry>200)return 0;
  8. // }   
  9. // SPI1->DR=TxData;     //发送一个byte
  10. retry=0;
  11. while((SPI1->SR&1<<0)==0) //等待接收完一个byte
  12. {
  13.   retry++;
  14.   if(retry>200)return 0;
  15. }            
  16. return SPI1->DR;          //返回收到的数据      
  17. }
主机
  1. #include "sys.h" //系统子函数
  2. #include "usart.h"//串口子函数  
  3. #include "delay.h" //延时子函数
  4. // SPI总线速度设置
  5. #define SPI_SPEED_2   0
  6. #define SPI_SPEED_8   1
  7. #define SPI_SPEED_16  2
  8. #define SPI_SPEED_256 3

  9. u8 Master_Temp =0;
  10. void SPI1_Init(void);    //初始化SPI口
  11. void SPI1_SetSpeed(u8 SpeedSet); //设置SPI速度  
  12. u8 SPI1_ReadWriteByte(u8 TxData);//SPI总线读写一个字节

  13. int main(void)
  14. {
  15.    Stm32_Clock_Init(3); //系统时钟设置
  16.    delay_init(24);//延时函数初始化
  17.    uart_init(24,9600); //串口初始化
  18.    SPI1_Init(); //SPI1初始化
  19.    SPI1_SetSpeed(SPI_SPEED_256);//SPI速度两分频
  20.    while(1)
  21.    {
  22.        SPI1_ReadWriteByte(0x55);
  23.        SPI1_ReadWriteByte(0x66);
  24.        printf("Master_Temp  =%x\r\n",Master_Temp );
  25.       delay_ms(100);
  26.    }
  27. }

  28. //SPI口初始化
  29. //这里针是对SPI1的初始化
  30. void SPI1_Init(void)
  31. {
  32.          RCC->APB2ENR|=1<<0; //复用
  33.          RCC->APB2ENR|=1<<2;       //PORTA时钟使能  
  34.         RCC->APB2ENR|=1<<12;      //SPI1时钟使能
  35.    
  36.      //这里只针对SPI口初始化
  37.      GPIOA->CRL&=0X000FFFFF;
  38.      GPIOA->CRL|=0XBBB00000;//PA5.6.7复用     
  39.      GPIOA->ODR|=0X7<<5;    //PA5.6.7上拉

  40.   
  41.      SPI1->CR1|=0<<10;//全双工模式
  42.      SPI1->CR1|=1<<9; //软件nss管理
  43.      SPI1->CR1|=1<<8;

  44.      SPI1->CR1|=1<<2; //SPI主机
  45.      SPI1->CR1|=0<<11;//8bit数据格式
  46.      SPI1->CR1|=1<<1; //空闲模式下SCK为1 CPOL=1
  47.      SPI1->CR1|=1<<0; //数据采样从第二个时间边沿开始,CPHA=1
  48.      SPI1->CR1|=0<<3; //Fsck=Fcpu/256
  49.      SPI1->CR1|=0<<7; //MSBfirst

  50.      SPI1->CR2|=1<<6;      //接收缓冲区非空中断使能
  51.      MY_NVIC_Init(1,0,SPI1_IRQChannel,4);  
  52.   
  53.      SPI1->CR1|=1<<6; //SPI设备使能
  54.   
  55. }  
  56. //SPI 速度设置函数
  57. //SpeedSet:
  58. //SPI_SPEED_2   2分频   (SPI 12M    --sys 24M)
  59. //SPI_SPEED_8   8分频   (SPI 3M     --sys 24M)
  60. //SPI_SPEED_16  16分频  (SPI 1.5M    --sys 24M)
  61. //SPI_SPEED_256 256分频 (SPI  905.6K --sys 24M)
  62. void SPI1_SetSpeed(u8 SpeedSet)
  63. {
  64.          SPI1->CR1&=0XFFC7;//Fsck=Fcpu/256
  65.      if(SpeedSet==SPI_SPEED_2)//二分频
  66.      {
  67.           SPI1->CR1|=0<<3;//Fsck=Fpclk/2=36Mhz
  68.      }else if(SpeedSet==SPI_SPEED_8)//八分频
  69.      {
  70.           SPI1->CR1|=2<<3;//Fsck=Fpclk/8=9Mhz
  71.      }else if(SpeedSet==SPI_SPEED_16)//十六分频
  72.      {
  73.           SPI1->CR1|=3<<3;//Fsck=Fpclk/16=4.5Mhz
  74.      }

  75.     else      //256分频
  76.      {
  77.           SPI1->CR1|=7<<3; //Fsck=Fpclk/256=281.25Khz 低速模式
  78.      }
  79.      SPI1->CR1|=1<<6; //SPI设备使能  
  80. }
  81. //SPIx 读写一个字节
  82. //TxData:要写入的字节
  83. //返回值:读取到的字节
  84. u8 SPI1_ReadWriteByte(u8 TxData)
  85. {  
  86.      u8 retry=0;   
  87.      while((SPI1->SR&1<<1)==0)//等待发送区空
  88.      {
  89.           retry++;
  90.           if(retry>200)return 0;
  91.      }   
  92.      SPI1->DR=TxData;     //发送一个byte
  93.      retry=0;
  94.      while((SPI1->SR&1<<0)==0) //等待接收完一个byte
  95.      {
  96.           retry++;
  97.           if(retry>200)return 0;
  98.      }            
  99.      return SPI1->DR;          //返回收到的数据      
  100. }

  101. u8 SPI1_ReadByte(u8 TxData)
  102. {  
  103.      u8 retry=0;   

  104.       while((SPI1->SR&1<<0)==0) //等待接收完一个byte
  105.      {
  106.           retry++;
  107.           if(retry>200)return 0;
  108.      }            
  109.      return SPI1->DR;          //返回收到的数据      
  110. }


  111. void SPI1_IRQHandler(void)
  112. {
  113.      if((SPI1->SR&1<<0)==1)
  114.      {
  115.           Master_Temp = SPI1_ReadByte(0x00);
  116.      }  
  117. }





 楼主| dentsgot 发表于 2016-4-7 20:42 | 显示全部楼层
从机
  1. #include "sys.h" //系统子函数
  2. #include "usart.h"//串口子函数  
  3. #include "delay.h" //延时子函数
  4. // SPI总线速度设置
  5. #define SPI_SPEED_2   0
  6. #define SPI_SPEED_8   1
  7. #define SPI_SPEED_16  2
  8. #define SPI_SPEED_256 3

  9. u8 Slave_Temp=0;

  10. void SPI1_Init(void);    //初始化SPI口
  11. void SPI1_SetSpeed(u8 SpeedSet); //设置SPI速度  
  12. u8 SPI1_ReadWriteByte(u8 TxData);

  13. int main(void)
  14. {
  15.      Stm32_Clock_Init(3); //系统时钟设置
  16.      delay_init(24);//延时函数初始化
  17.      uart_init(24,9600); //串口初始化
  18.      SPI1_Init(); //SPI1初始化
  19.      SPI1_SetSpeed(SPI_SPEED_256);//SPI速度两分频
  20.      MY_NVIC_Init(0,0,SPI1_IRQChannel,4);   //设置抢占优先级为1,响应优先级为1,中断分组为4
  21.      while(1)
  22.      {
  23.             printf("Slave_Temp=%x\r\n",Slave_Temp);
  24.               delay_ms(100);
  25.         }
  26. }

  27. //SPI口初始化
  28. //这里针是对SPI1的初始化
  29. void SPI1_Init(void)
  30. {
  31.      RCC->APB2ENR|=1<<0; //复用
  32.      RCC->APB2ENR|=1<<2;       //PORTA时钟使能  
  33.      RCC->APB2ENR|=1<<12;      //SPI1时钟使能
  34.    
  35.      //这里只针对SPI口初始化
  36.      GPIOA->CRL&=0X000FFFFF;
  37.      GPIOA->CRL|=0XBBB00000;//PA5.6.7复用     
  38.      GPIOA->ODR|=0X7<<5;    //PA5.6.7上拉

  39.   
  40.      SPI1->CR1|=0<<10;//全双工模式
  41.      SPI1->CR1|=1<<9; //软件nss管理
  42.      SPI1->CR1|=0<<8;//ssi为0

  43.      SPI1->CR1|=0<<2; //SPI从机
  44.      SPI1->CR1|=0<<11;//8bit数据格式
  45.      SPI1->CR1|=1<<1; //空闲模式下SCK为1 CPOL=1
  46.      SPI1->CR1|=1<<0; //数据采样从第二个时间边沿开始,CPHA=1
  47.      SPI1->CR1|=0<<3; //Fsck=Fcpu/256
  48.      SPI1->CR1|=0<<7; //MSBfirst

  49.      SPI1->CR2|=1<<6;      //接收缓冲区非空中断使能
  50.      MY_NVIC_Init(1,0,SPI1_IRQChannel,4);   

  51.      SPI1->CR1|=1<<6; //SPI设备使能
  52. }  
  53. //SPI 速度设置函数
  54. //SpeedSet:
  55. //SPI_SPEED_2   2分频   (SPI 12M    --sys 24M)
  56. //SPI_SPEED_8   8分频   (SPI 3M     --sys 24M)
  57. //SPI_SPEED_16  16分频  (SPI 1.5M    --sys 24M)
  58. //SPI_SPEED_256 256分频 (SPI  905.6K --sys 24M)
  59. void SPI1_SetSpeed(u8 SpeedSet)
  60. {
  61.      SPI1->CR1&=0XFFC7;//Fsck=Fcpu/256
  62.      if(SpeedSet==SPI_SPEED_2)//二分频
  63.      {
  64.           SPI1->CR1|=0<<3;//Fsck=Fpclk/2=36Mhz
  65.      }
  66.      else if(SpeedSet==SPI_SPEED_8)//八分频
  67.      {
  68.           SPI1->CR1|=2<<3;//Fsck=Fpclk/8=9Mhz
  69.      }
  70.      else if(SpeedSet==SPI_SPEED_16)//十六分频
  71.      {
  72.           SPI1->CR1|=3<<3;//Fsck=Fpclk/16=4.5Mhz
  73.      }
  74.      else      //256分频
  75.      {
  76.           SPI1->CR1|=7<<3; //Fsck=Fpclk/256=281.25Khz 低速模式
  77.      }
  78.      SPI1->CR1|=1<<6; //SPI设备使能  
  79. }


  80. u8 SPI1_ReadWriteByte(u8 TxData)
  81. {  
  82.      u8 retry=0;   
  83.      while((SPI1->SR&1<<1)==0)//等待发送区空
  84.      {
  85.           retry++;
  86.           if(retry>200)return 0;
  87.      }   
  88.      SPI1->DR=TxData;     //发送一个byte
  89.      retry=0;
  90.      while((SPI1->SR&1<<0)==0) //等待接收完一个byte
  91.      {
  92.           retry++;
  93.           if(retry>200)return 0;
  94.      }            
  95.      return SPI1->DR;          //返回收到的数据      
  96. }

  97. u8 SPI1_ReadByte(u8 TxData)
  98. {  
  99.      u8 retry=0;   
  100. //   while((SPI1->SR&1<<1)==0)//等待发送区空
  101.   //   {
  102.    //       retry++;
  103.    //       if(retry>200)return 0;
  104.   //   }   
  105.    //  SPI1->DR=TxData;     //发送一个byte
  106.    //  retry=0;
  107.      while((SPI1->SR&1<<0)==0) //等待接收完一个byte
  108.      {
  109.           retry++;
  110.           if(retry>200)return 0;
  111.      }            
  112.      return SPI1->DR;          //返回收到的数据      
  113. }


  114. void SPI1_IRQHandler(void)
  115. {
  116.       if((SPI1->SR&1<<0)==1)
  117.      {     
  118.           Slave_Temp = SPI1_ReadByte(0x00);
  119.           SPI1_ReadWriteByte(0xaa);
  120.      }  
  121. }


 楼主| dentsgot 发表于 2016-4-7 20:43 | 显示全部楼层
改进:把主机改成查询接收也是可以的,这时只要一个发送,是真正意义上的全双工了。

主机:
  1. #include "sys.h" //系统子函数
  2. #include "usart.h"//串口子函数  
  3. #include "delay.h" //延时子函数
  4. #include "TIMER.h"

  5. // SPI总线速度设置
  6. #define SPI_SPEED_2   0
  7. #define SPI_SPEED_8   1
  8. #define SPI_SPEED_16  2
  9. #define SPI_SPEED_256 3

  10. u8 Master_Temp =0;
  11. void SPI1_Init(void);    //初始化SPI口
  12. void SPI1_SetSpeed(u8 SpeedSet); //设置SPI速度  
  13. void SPI1_WriteByte(u8 TxData);//SPI总线读写一个字节
  14. u8 SPI1_ReadByte(u8 TxData);

  15. int main(void)
  16. {
  17. Stm32_Clock_Init(3); //系统时钟设置
  18. delay_init(24);//延时函数初始化
  19. uart_init(24,9600); //串口初始化
  20. SPI1_Init(); //SPI1初始化
  21. SPI1_SetSpeed(SPI_SPEED_256);//SPI速度两分频


  22. while(1)
  23. {
  24.      SPI1_WriteByte(0x55);
  25.   Master_Temp = SPI1_ReadByte(0x00);
  26.   printf("Master_Temp =%x\r\n",Master_Temp);
  27.   delay_ms(100);
  28. }
  29. }

  30. //SPI口初始化
  31. //这里针是对SPI1的初始化
  32. void SPI1_Init(void)
  33. {
  34. RCC->APB2ENR|=1<<0; //复用
  35. RCC->APB2ENR|=1<<2;       //PORTA时钟使能  
  36. RCC->APB2ENR|=1<<12;      //SPI1时钟使能
  37.    
  38. //这里只针对SPI口初始化
  39. GPIOA->CRL&=0X000FFFFF;
  40. GPIOA->CRL|=0XBBB00000;//PA5.6.7复用     
  41. GPIOA->ODR|=0X7<<5;    //PA5.6.7上拉

  42.   
  43. SPI1->CR1|=0<<10;//全双工模式
  44. SPI1->CR1|=1<<9; //软件nss管理
  45. SPI1->CR1|=1<<8;

  46. SPI1->CR1|=1<<2; //SPI主机
  47. SPI1->CR1|=0<<11;//8bit数据格式
  48. SPI1->CR1|=1<<1; //空闲模式下SCK为1 CPOL=1
  49. SPI1->CR1|=1<<0; //数据采样从第二个时间边沿开始,CPHA=1
  50. SPI1->CR1|=0<<3; //Fsck=Fcpu/256
  51. SPI1->CR1|=0<<7; //MSBfirst

  52. //SPI1->CR2|=1<<6;      //接收缓冲区非空中断使能
  53. //MY_NVIC_Init(8,0,SPI1_IRQChannel,4);  
  54.   
  55. SPI1->CR1|=1<<6; //SPI设备使能
  56.   
  57. }  
  58. //SPI 速度设置函数

  59. void SPI1_SetSpeed(u8 SpeedSet)
  60. {
  61. SPI1->CR1&=0XFFC7;//Fsck=Fcpu/256
  62. if(SpeedSet==SPI_SPEED_2)//二分频
  63. {
  64.   SPI1->CR1|=0<<3;//Fsck=Fpclk/2=36Mhz
  65. }else if(SpeedSet==SPI_SPEED_8)//八分频
  66. {
  67.   SPI1->CR1|=2<<3;//Fsck=Fpclk/8=9Mhz
  68. }else if(SpeedSet==SPI_SPEED_16)//十六分频
  69. {
  70.   SPI1->CR1|=3<<3;//Fsck=Fpclk/16=4.5Mhz
  71. }else      //256分频
  72. {
  73.   SPI1->CR1|=7<<3; //Fsck=Fpclk/256=281.25Khz 低速模式
  74. }
  75. SPI1->CR1|=1<<6; //SPI设备使能  
  76. }
  77. //SPIx 读写一个字节
  78. //TxData:要写入的字节
  79. //返回值:读取到的字节
  80. void SPI1_WriteByte(u8 TxData)
  81. {  
  82. u8 retry=0;   
  83. while((SPI1->SR&1<<1)==0)//等待发送区空
  84. {
  85.   retry++;
  86.   if(retry>200)return;
  87. }   
  88. SPI1->DR=TxData;     //发送一个byte      
  89. }

  90. u8 SPI1_ReadByte(u8 TxData)
  91. {  
  92. u8 retry=0;   

  93. while((SPI1->SR&1<<0)==0) //等待接收完一个byte
  94. {
  95.   retry++;
  96.   if(retry>200)return 0;
  97. }            
  98. return SPI1->DR;          //返回收到的数据      
  99. }

STM32 SPI双机通信.rar

119.95 KB, 下载次数: 79

您需要登录后才可以回帖 登录 | 注册

本版积分规则

29

主题

164

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部