找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 85|回复: 1
打印 上一主题 下一主题
收起左侧

C51单片机使用硬件SPI通讯W25Q16 flash芯片,MISO无信号

[复制链接]
跳转到指定楼层
楼主
如图,SPI通讯主机正常发送信号,但从机一直保持低电平。初始化的时候我把SPI的口都设置为推挽输出高电平状态,空闲时MISO也应该是高,但不知道什么原因拉低了。求助,帮忙分析一下代码。多谢!!
  1. #include "H/Function_Init.H"

  2. #define SPI_CS   P07  // 自定义片选引脚

  3. // W25Q16指令集
  4. #define W25Q16_Write_Status   0x01         //W25Q16写状态寄存器指令
  5. #define W25Q16_Read_Status    0x05         //W25Q16读状态寄存器指令
  6. #define W25Q16_Write_Enable   0x06         //写使能指令
  7. #define W25Q16_Page_Program   0x02         //页编程指令

  8. #define W25Q16_Read_Data      0x03         //读使能指令
  9. #define W25Q16_SectorErase    0x20         //快B删除指令
  10. #define W25Q16_Chip_Erase     0xc7         //擦除W25Q16芯片

  11. #define W25Q16_Device_ID                        0x90       //读芯片ID

  12. uint8_t SPI0_Master_SendData[3][8] = {
  13.         {0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8},
  14.         {0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18},
  15.         {0xAA,0xBB,0xCC,0xDD,0xEE,0xFF,0x00,0x00}
  16.     };
  17. volatile uint8_t SPI0_Slaver_ReceiveData[8];
  18. uint8_t TxXferCount = 0;  //SPI/TWI发送数据数目
  19. uint8_t RxXferCount = 0;  //SPI/TWI接受数据数目
  20. bit SPI0Flag = 0;

  21. void Delay(unsigned long int delaycnt)
  22. {
  23.    while(delaycnt--);
  24. }
  25. /*****************************************************
  26. *函数名称:void SPI0_Init(void)
  27. *函数功能:SPI0初始化
  28. *入口参数:void
  29. *出口参数:void
  30. *****************************************************/
  31. void SPI0_Init(void)
  32. {
  33.   OTCON |= 0X10;        //设置SPI0工作模式
  34.   US0CON0 = 0x23;       //-设置SPI0为主设备,SCK空闲时间为低电平,SCK周期第一沿采集数据,时钟速率为Fsy/8,模式0
  35.   US0CON1 = 0x00;       //MSB优先发送,8位传输,bit0:TXE=0不允许发送中断,TXE=1允许中断
  36.   US0CON0 |= 0x80;      //开启SPI0
  37.   IE1 |= 0x01;
  38.   EA = 1;
  39. }
  40. /*****************************************************
  41. *函数名称:void TWI0/PI/UART1_Int() interrupt 7
  42. *函数功能:USCI0中断函数
  43. *入口参数:void
  44. *出口参数:void
  45. *****************************************************/
  46. void SPI0_Int(void) interrupt 7    //SPI0中断函数
  47. {
  48.   if(US0CON1 & 0X08)  //发送缓存器空标志判断
  49.   {
  50.     US0CON1 &= ~0X08;
  51.   }
  52.   if(US0CON1 & 0X80)  //数据传输完成标志位判断
  53.   {
  54.     US0CON1 &= ~0X80;
  55.     SPI0Flag = 1;
  56.   }
  57. }
  58. //SPI口读写数据
  59. unsigned char SPI0_WriteReadByte(unsigned char TxData)
  60. {
  61.          unsigned char RxData = 0;
  62.    US0CON2 = TxData;
  63. //         while(SPI0Flag == 0);               //等待发送完成        
  64.          while(!(SPI0Flag == 1));
  65.          SPI0Flag = 0;
  66.          RxData = US0CON2;               
  67.          return RxData ;
  68. //         return US0CON2;
  69. }
  70. //读取W25QXX的状态寄存器
  71. unsigned char W25Q16_ReadStatus(void)   
  72. {  
  73.         unsigned char W25Q16_statusbyte=0;   
  74.         SPI_CS=0;                                   //使能器件   
  75.         SPI0_WriteReadByte(W25Q16_Read_Status);    //发送读取状态寄存器命令   
  76.         W25Q16_statusbyte=SPI0_WriteReadByte(0xff);               //读取一个字节  
  77.         SPI_CS=1;                                 //取消片选     
  78.         return W25Q16_statusbyte;   
  79. }
  80. //等待空闲
  81. void W25Q16_Wait_Busy(void)   
  82. {   SPI_CS = 0;
  83.         while(W25Q16_ReadStatus()&0x01);   // 等待BUSY位清空
  84.         SPI_CS = 1;
  85. }
  86. // W25Q16写使能,将WEL置位  
  87. //W25QXX_WriteEnable  0x06
  88. void W25Q16_WriteEnable(void)        
  89. {
  90.     SPI_CS = 0;
  91.     SPI0_WriteReadByte(W25Q16_Write_Enable);
  92.     SPI_CS = 1;
  93. }
  94. //芯片擦除
  95. void W25Q16_Erase_Chip(void)   
  96. {     
  97. //    W25Q16_Wait_Busy();           
  98.     W25Q16_WriteEnable();                        //SET WEL
  99.           SPI_CS=0;                                    //使能器件   
  100.     SPI0_WriteReadByte(W25Q16_Chip_Erase);       //发送片擦除命令  
  101.                 SPI_CS=1;                                    //取消片选                  
  102.                 W25Q16_Wait_Busy();                                                  //等待芯片擦除结束
  103. }   
  104. // 页写入数据
  105. void W25Q16_WriteData(unsigned long addr, unsigned char *buf, unsigned int len)
  106. {
  107.           unsigned int i = 0;
  108. //          while(W25Q16_ReadStatus()&0x01);       // 判断是否忙
  109.           W25Q16_Wait_Busy();                        
  110.     W25Q16_WriteEnable();                  // 发送写使能
  111.     SPI_CS = 0;
  112.     SPI0_WriteReadByte(W25Q16_Page_Program);     // 发送页编程指令
  113.     SPI0_WriteReadByte((addr >> 16) );          // 地址高位
  114.     SPI0_WriteReadByte((addr >> 8) );
  115.     SPI0_WriteReadByte(addr);
  116.     // 写入数据
  117.     for (i = 0; i < len; i++)
  118.    {
  119.         SPI0_WriteReadByte(buf[i]);
  120.     }
  121.           SPI_CS = 1;  
  122. //    while (W25Q16_ReadStatus() & 0x01);              // 等待写入完成
  123.           W25Q16_Wait_Busy();                                           //等待写入结束               
  124. }
  125. // 从W25Q16读取数据
  126. void W25Q16_ReadData(unsigned long addr, unsigned char *buf, unsigned int len)
  127. {
  128.         unsigned int i = 0;
  129.     SPI_CS = 0;
  130.     SPI0_WriteReadByte(W25Q16_Read_Data);
  131.     SPI0_WriteReadByte((addr >> 16) ); // 地址高位
  132.     SPI0_WriteReadByte((addr >> 8) );
  133.     SPI0_WriteReadByte(addr );   
  134.     // 读取数据
  135.     for (i = 0; i < len; i++)
  136.          {
  137.         buf[i] = SPI0_WriteReadByte(0xFF);
  138.     }
  139.     SPI_CS = 1;
  140. }
  141. //读取芯片ID                  
  142. //0XEF14,表示芯片型号为W25Q16         
  143. unsigned long  W25Q16_ReadID(void)
  144. {
  145.     unsigned long  Temp = 0;      
  146.     SPI_CS=0;                    
  147.     SPI0_WriteReadByte(0x90);//发送读取ID命令        
  148.     SPI0_WriteReadByte(0x00);         
  149.     SPI0_WriteReadByte(0x00);         
  150.     SPI0_WriteReadByte(0x00);                     
  151.     Temp|=SPI0_WriteReadByte(0xFF)<<8;  
  152.     Temp|=SPI0_WriteReadByte(0xFF);     
  153.     SPI_CS=1;                    
  154.     return Temp;
  155. }

  156. /*****************************************************
  157. *函数名称:void main(void)
  158. *函数功能:USCI0测试
  159. *入口参数:void
  160. *出口参数:void
  161. *****************************************************/
  162. void main(void)
  163. {
  164.           unsigned char j=0,i=0;
  165.           unsigned char readBuf[8];
  166.           unsigned long W25Q16_addr = 0x000000; // 起始地址
  167.                 P0CON = 0xf2;           //P07口推挽输出,
  168.           P0 = 0xf0;              //P07初始高电平
  169.     SPI0_Init();        
  170.         
  171.           W25Q16_Erase_Chip();
  172.         while(1)
  173.   {
  174. //                W25Q16_ReadStatus();//读状态位
  175.                   // 读取Flash ID
  176.     W25Q16_ReadID();        
  177.                                                 
  178.                 for(j=0;j<3;j++)
  179.                 {
  180.                      SPI_CS = 0;        
  181.                    W25Q16_WriteData(W25Q16_addr, SPI0_Master_SendData[j], 8);  // 直接写入一行
  182.                          W25Q16_ReadData(W25Q16_addr, &readBuf[j], 8);       // 读取到独立缓冲区
  183.                     SPI_CS = 1;
  184.                          W25Q16_addr += 0x000100;  // 递增地址
  185.                 }                                
  186.                 Delay(5000);
  187.                 P01 = ~P01;
  188.   }
  189. }
复制代码
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:226055 发表于 2025-6-23 10:41 | 只看该作者
    建议你先不要使用硬件SPI调试,可以先使用模拟SPI调试。
    模拟SPI速度慢,牵扯的寄存器比较少,避免是对单片机SPI外设使用不慎导致调不通。




    附件是艾克姆科技的例程源码和PDF说明,这个说明是我目前看到的讲解最详细的一个了。








回复

使用道具 举报

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

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表