[STM32] 单片机IO口模拟SPI,读取不到发回来的数,确认管脚上有高...

[复制链接]
3006|24
 楼主| any012 发表于 2015-8-10 16:11 | 显示全部楼层 |阅读模式
本帖最后由 any012 于 2015-8-18 16:56 编辑

用IO口模拟SPI,用的PB4做的MISO脚。
读取数据时出错,总是接收不到数据,后来用示波器测量了下IO口,有高低电平。
于是用以下部分测试,如果PB4是0的话,spi_misoValue加一,然后用串口将spi_misoValue发上来。
结果判断PB4是0的话,spi_misoValue没执行这段自加12次;
如果判断PB4是1的话,spi_misoValue始终没有自加。
好象是时序出了问题?没有在正确的时间端判断PB4?






----------------------------2015.08.18-----------------------------
上传下现在的程序,希望有空闲的朋友帮我看下。
工程是以野火历程的模板建的,我水平有限,写的有点混乱,见笑。



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
 楼主| any012 发表于 2015-8-10 16:23 | 显示全部楼层
完整函数,该函数参考AD7320芯片的官方参考例子。
  1. u16 ReadFromADT7310ViaSPI(u8 reg_address)
  2. {
  3.         u8 i;
  4.         u8 spi_Value;
  5.                
  6.         spi_Value = (0x78 & ((reg_address + 8) << 3));
  7.         ADT7310_CS(1);
  8.         SPI_SCL(1);
  9.         ADT7310_CS(0);
  10.         ADT7310Delay(5);
  11.        
  12.         for(i = 0; i < 8; i++)
  13.         {
  14.                 SPI_SCL(0);
  15.                 if((spi_Value & 0x80) == 0x80)
  16.                         SPI_MOSI(1);
  17.                 else
  18.                         SPI_MOSI(0);
  19.                 ADT7310Delay(5);
  20.                 SPI_SCL(1);
  21.                 spi_Value = (spi_Value << 1);
  22.                 ADT7310Delay(5);       
  23.         }
  24.         for(i = 0; i < 16; i++)
  25.         {
  26.                 SPI_SCL(0);
  27. //                spi_misoValue = (spi_misoValue << 1);
  28. //                ADT7310Delay(6);
  29.                 if(GPIO_ReadInputDataBit(GPIOB, 4) == 1)
  30.                         spi_misoValue++;
  31. //                        spi_misoValue |= 0x0001;
  32. //                else
  33. //                        spi_misoValue &= 0xfffe;
  34.                 ADT7310Delay(8);
  35.                 SPI_SCL(1);
  36.                 ADT7310Delay(8);
  37.         }
  38.         SPI_SCL(1);
  39.         ADT7310_CS(1);
  40.         GPIOA->ODR ^= GPIO_Pin_0;
  41.         return spi_misoValue;
  42. }
改成这样,判断PB4是不是1来控制spi_misoValue自加一的话,发上来的数是01,好像只是自加了一次就再也不自加了。
NE5532 发表于 2015-8-10 17:05 | 显示全部楼层
把输入端口用电阻固定拉到VCC和GND,看能不能读到FF和00,否则检查端口方向设置是否正确。
 楼主| any012 发表于 2015-8-10 17:27 | 显示全部楼层
本帖最后由 any012 于 2015-8-10 17:31 编辑

if(GPIO_ReadInputDataBit(GPIOB, 4) == 0)
                        spi_misoValue++;
把这句话放到主函数里,spi_misoValue自加;

但改成
if(GPIO_ReadInputDataBit(GPIOB, 4) == 1)
                        spi_misoValue++;
就不自加了...
----------------------------------------
谢谢版主回复,明天再试吧,下班了。

ningling_21 发表于 2015-8-11 08:16 | 显示全部楼层
any012 发表于 2015-8-10 17:27
if(GPIO_ReadInputDataBit(GPIOB, 4) == 0)
                        spi_misoValue++;
把这句话放到主函数 ...

进入调试状态单步运行看能否检测到高电平
songchenping 发表于 2015-8-11 13:09 | 显示全部楼层
或许是配置的不对,或许是读的时间不对。
 楼主| any012 发表于 2015-8-18 16:43 | 显示全部楼层
NE5532 发表于 2015-8-10 17:05
把输入端口用电阻固定拉到VCC和GND,看能不能读到FF和00,否则检查端口方向设置是否正确。 ...

写了个程序,根据PB4口电平高低控制LED灯亮灭,没问题,排除PB4口损坏的可能。
又修改现在的程序,判断PB4电压高低,如果是高,则让LED1取反,如果是低,则让LED2取反。
结果LED2不停的闪,LED1无反应(常亮).
用示波器测量LED2波形,发现是经过一段低电平后,有8组脉冲,这8组脉冲应该是读SPI_MISO信号时的16次循环引起的。
感觉还是不能读取到高电平,好像程序里读的管脚和PCB管脚不一致。可查了手册及PCB,是一致的,是PB4.
 楼主| any012 发表于 2015-8-18 16:44 | 显示全部楼层
写了个程序,根据PB4口电平高低控制LED灯亮灭,没问题,排除PB4口损坏的可能。
又修改现在的程序,判断PB4电压高低,如果是高,则让LED1取反,如果是低,则让LED2取反。
结果LED2不停的闪,LED1无反应(常亮).
用示波器测量LED2波形,发现是经过一段低电平后,有8组脉冲,这8组脉冲应该是读SPI_MISO信号时的16次循环引起的。
感觉还是不能读取到高电平,好像程序里读的管脚和PCB管脚不一致。可查了手册及PCB,是一致的,是PB4.
  1. u16 ReadFromADT7310ViaSPI(u8 reg_address)
  2. {
  3.         u8 i;
  4.         u8 spi_Value;
  5.                
  6.         spi_Value = (0x78 & ((reg_address + 8) << 3));
  7.         ADT7310_CS(1);
  8.         SPI_SCL(1);
  9.         ADT7310_CS(0);
  10.         ADT7310Delay(5);
  11.        
  12.         for(i = 0; i < 8; i++)
  13.         {
  14.                 SPI_SCL(0);
  15.                 if((spi_Value & 0x80) == 0x80)
  16.                         SPI_MOSI(1);
  17.                 else
  18.                         SPI_MOSI(0);
  19.                 ADT7310Delay(5);
  20.                 SPI_SCL(1);
  21.                 spi_Value = (spi_Value << 1);
  22.                 ADT7310Delay(5);       
  23.         }
  24.         for(i = 0; i < 16; i++)
  25.         {
  26.                 SPI_SCL(0);
  27.                 spi_misoValue = (spi_misoValue << 1);
  28.                 ADT7310Delay(10);
  29.                 if(GPIO_ReadInputDataBit(GPIOB, 4) == 1)
  30.                         GPIOA->ODR ^= GPIO_Pin_1;
  31.                 else
  32.                         GPIOA->ODR ^= GPIO_Pin_2;
  33. //                        spi_misoValue |= 0x0001;
  34. //                else
  35. //                        spi_misoValue &= 0xfffe;
  36.                 ADT7310Delay(2);
  37.                 SPI_SCL(1);
  38.                 ADT7310Delay(8);
  39.         }
  40.         SPI_SCL(1);
  41.         ADT7310_CS(1);
  42.         GPIOA->ODR ^= GPIO_Pin_0;
  43.         return spi_misoValue;
  44. }
 楼主| any012 发表于 2015-8-18 16:45 | 显示全部楼层
ningling_21 发表于 2015-8-11 08:16
进入调试状态单步运行看能否检测到高电平

没有JTAG接口...
 楼主| any012 发表于 2015-8-18 16:49 | 显示全部楼层
songchenping 发表于 2015-8-11 13:09
或许是配置的不对,或许是读的时间不对。

PB4设的悬浮输入,PCB板上有上拉电阻,而且在PB4管脚上用示波器能测到高低电平。
时序的话,找的ADT7320的官网例子修改的。
ningling_21 发表于 2015-8-18 17:24 | 显示全部楼层
any012 发表于 2015-8-18 16:49
PB4设的悬浮输入,PCB板上有上拉电阻,而且在PB4管脚上用示波器能测到高低电平。
时序的话,找的ADT7320 ...

注意: 当做GPIO用的端口要和JTAG 端口分开,否则就有问题,看你都刚好用到JTAG的几个脚
 楼主| any012 发表于 2015-8-18 17:27 | 显示全部楼层
ningling_21 发表于 2015-8-18 17:24
注意: 当做GPIO用的端口要和JTAG 端口分开,否则就有问题,看你都刚好用到JTAG的几个脚 ...

当时想用硬件SPI的,所以用了SPI2的这几个脚,实际上并没有用IO口的复用功能。
而且,PB4控制LED灯亮灭也没问题的。
ningling_21 发表于 2015-8-18 17:31 | 显示全部楼层
any012 发表于 2015-8-18 17:27
当时想用硬件SPI的,所以用了SPI2的这几个脚,实际上并没有用IO口的复用功能。
而且,PB4控制LED灯亮灭也 ...

能否换成SPI1试试?
songchenping 发表于 2015-8-18 19:02 | 显示全部楼层
any012 发表于 2015-8-18 16:49
PB4设的悬浮输入,PCB板上有上拉电阻,而且在PB4管脚上用示波器能测到高低电平。
时序的话,找的ADT7320 ...

按我的方法就是单独调试SPI和ADC芯片。先用IO口模拟读取ADC值,通了后再看SPI波形是否正确。最后再一起调试。
 楼主| any012 发表于 2015-8-18 21:11 | 显示全部楼层
现在就是IO口模拟SPI。
 楼主| any012 发表于 2015-8-19 09:20 | 显示全部楼层
觉得也有可能是经过高速光耦,有一定的延时,读取的时刻不对。
ayb_ice 发表于 2015-8-19 09:48 | 显示全部楼层
any012 发表于 2015-8-10 16:23
完整函数,该函数参考AD7320芯片的官方参考例子。
改成这样,判断PB4是不是1来控制spi_misoValue自加一的话 ...

if(GPIO_ReadInputDataBit(GPIOB, 4) == 1)

这样使用是错误的,因为返回值的字节型的,并没有转换成布尔型,只有GPIO的位0才可以这样调用,
如果返回高电平返回值其实是(1<<4)

通用的调用应该这样
if(GPIO_ReadInputDataBit(GPIOB, 4)  ==  0)  // 0

if(GPIO_ReadInputDataBit(GPIOB, 4)  !=0 )  // 1

评分

参与人数 1威望 +2 收起 理由
any012 + 2 很给力!

查看全部评分

 楼主| any012 发表于 2015-8-20 11:05 | 显示全部楼层
本帖最后由 any012 于 2015-8-20 11:06 编辑
ayb_ice 发表于 2015-8-19 09:48
if(GPIO_ReadInputDataBit(GPIOB, 4) == 1)

这样使用是错误的,因为返回值的字节型的,并没有转换成布尔 ...

谢谢!如果我改成if(GPIO_ReadInputDataBit(GPIOB, 4) == 0x01) 呢?
ayb_ice 发表于 2015-8-20 11:53 | 显示全部楼层
any012 发表于 2015-8-20 11:05
谢谢!如果我改成if(GPIO_ReadInputDataBit(GPIOB, 4) == 0x01) 呢?

说的很清楚了
始终都不可能等于1的,始终条件不满足

评分

参与人数 1威望 +2 收起 理由
any012 + 2 赞一个!

查看全部评分

zhaoyu2005 发表于 2015-8-21 08:36 | 显示全部楼层
ayb_ice 发表于 2015-8-19 09:48
if(GPIO_ReadInputDataBit(GPIOB, 4) == 1)

这样使用是错误的,因为返回值的字节型的,并没有转换成布尔 ...

STM32库函数
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
  uint8_t bitstatus = 0x00;
  
  /* Check the parameters */
  assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
  assert_param(IS_GET_GPIO_PIN(GPIO_Pin));
  
  if ((GPIOx->IDR & GPIO_Pin) != (uint32_t)Bit_RESET)
  {
    bitstatus = (uint8_t)Bit_SET;
  }
  else
  {
    bitstatus = (uint8_t)Bit_RESET;
  }
  return bitstatus;
}

返回的是0x00或者0x01,这样判断应该没问题的
类似的还有uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
至于不能读取正确的值,建议单步调试,看数值和电平是否对应

评分

参与人数 1威望 +2 收起 理由
any012 + 2 很给力!

查看全部评分

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

本版积分规则

35

主题

232

帖子

6

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