打印
[STM32]

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

[复制链接]
2186|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-----------------------------
上传下现在的程序,希望有空闲的朋友帮我看下。
工程是以野火历程的模板建的,我水平有限,写的有点混乱,见笑。


V1_0.zip (2.52 MB)

相关帖子

沙发
any012|  楼主 | 2015-8-10 16:23 | 只看该作者
完整函数,该函数参考AD7320芯片的官方参考例子。
u16 ReadFromADT7310ViaSPI(u8 reg_address)
{
        u8 i;
        u8 spi_Value;
               
        spi_Value = (0x78 & ((reg_address + 8) << 3));
        ADT7310_CS(1);
        SPI_SCL(1);
        ADT7310_CS(0);
        ADT7310Delay(5);
       
        for(i = 0; i < 8; i++)
        {
                SPI_SCL(0);
                if((spi_Value & 0x80) == 0x80)
                        SPI_MOSI(1);
                else
                        SPI_MOSI(0);
                ADT7310Delay(5);
                SPI_SCL(1);
                spi_Value = (spi_Value << 1);
                ADT7310Delay(5);       
        }
        for(i = 0; i < 16; i++)
        {
                SPI_SCL(0);
//                spi_misoValue = (spi_misoValue << 1);
//                ADT7310Delay(6);
                if(GPIO_ReadInputDataBit(GPIOB, 4) == 1)
                        spi_misoValue++;
//                        spi_misoValue |= 0x0001;
//                else
//                        spi_misoValue &= 0xfffe;
                ADT7310Delay(8);
                SPI_SCL(1);
                ADT7310Delay(8);
        }
        SPI_SCL(1);
        ADT7310_CS(1);
        GPIOA->ODR ^= GPIO_Pin_0;
        return spi_misoValue;
}
改成这样,判断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++;
就不自加了...
----------------------------------------
谢谢版主回复,明天再试吧,下班了。

使用特权

评论回复
5
ningling_21| | 2015-8-11 08:16 | 只看该作者
any012 发表于 2015-8-10 17:27
if(GPIO_ReadInputDataBit(GPIOB, 4) == 0)
                        spi_misoValue++;
把这句话放到主函数 ...

进入调试状态单步运行看能否检测到高电平

使用特权

评论回复
6
songchenping| | 2015-8-11 13:09 | 只看该作者
或许是配置的不对,或许是读的时间不对。

使用特权

评论回复
7
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.

使用特权

评论回复
8
any012|  楼主 | 2015-8-18 16:44 | 只看该作者
写了个程序,根据PB4口电平高低控制LED灯亮灭,没问题,排除PB4口损坏的可能。
又修改现在的程序,判断PB4电压高低,如果是高,则让LED1取反,如果是低,则让LED2取反。
结果LED2不停的闪,LED1无反应(常亮).
用示波器测量LED2波形,发现是经过一段低电平后,有8组脉冲,这8组脉冲应该是读SPI_MISO信号时的16次循环引起的。
感觉还是不能读取到高电平,好像程序里读的管脚和PCB管脚不一致。可查了手册及PCB,是一致的,是PB4.
u16 ReadFromADT7310ViaSPI(u8 reg_address)
{
        u8 i;
        u8 spi_Value;
               
        spi_Value = (0x78 & ((reg_address + 8) << 3));
        ADT7310_CS(1);
        SPI_SCL(1);
        ADT7310_CS(0);
        ADT7310Delay(5);
       
        for(i = 0; i < 8; i++)
        {
                SPI_SCL(0);
                if((spi_Value & 0x80) == 0x80)
                        SPI_MOSI(1);
                else
                        SPI_MOSI(0);
                ADT7310Delay(5);
                SPI_SCL(1);
                spi_Value = (spi_Value << 1);
                ADT7310Delay(5);       
        }
        for(i = 0; i < 16; i++)
        {
                SPI_SCL(0);
                spi_misoValue = (spi_misoValue << 1);
                ADT7310Delay(10);
                if(GPIO_ReadInputDataBit(GPIOB, 4) == 1)
                        GPIOA->ODR ^= GPIO_Pin_1;
                else
                        GPIOA->ODR ^= GPIO_Pin_2;
//                        spi_misoValue |= 0x0001;
//                else
//                        spi_misoValue &= 0xfffe;
                ADT7310Delay(2);
                SPI_SCL(1);
                ADT7310Delay(8);
        }
        SPI_SCL(1);
        ADT7310_CS(1);
        GPIOA->ODR ^= GPIO_Pin_0;
        return spi_misoValue;
}

使用特权

评论回复
9
any012|  楼主 | 2015-8-18 16:45 | 只看该作者
ningling_21 发表于 2015-8-11 08:16
进入调试状态单步运行看能否检测到高电平

没有JTAG接口...

使用特权

评论回复
10
any012|  楼主 | 2015-8-18 16:49 | 只看该作者
songchenping 发表于 2015-8-11 13:09
或许是配置的不对,或许是读的时间不对。

PB4设的悬浮输入,PCB板上有上拉电阻,而且在PB4管脚上用示波器能测到高低电平。
时序的话,找的ADT7320的官网例子修改的。

使用特权

评论回复
11
ningling_21| | 2015-8-18 17:24 | 只看该作者
any012 发表于 2015-8-18 16:49
PB4设的悬浮输入,PCB板上有上拉电阻,而且在PB4管脚上用示波器能测到高低电平。
时序的话,找的ADT7320 ...

注意: 当做GPIO用的端口要和JTAG 端口分开,否则就有问题,看你都刚好用到JTAG的几个脚

使用特权

评论回复
12
any012|  楼主 | 2015-8-18 17:27 | 只看该作者
ningling_21 发表于 2015-8-18 17:24
注意: 当做GPIO用的端口要和JTAG 端口分开,否则就有问题,看你都刚好用到JTAG的几个脚 ...

当时想用硬件SPI的,所以用了SPI2的这几个脚,实际上并没有用IO口的复用功能。
而且,PB4控制LED灯亮灭也没问题的。

使用特权

评论回复
13
ningling_21| | 2015-8-18 17:31 | 只看该作者
any012 发表于 2015-8-18 17:27
当时想用硬件SPI的,所以用了SPI2的这几个脚,实际上并没有用IO口的复用功能。
而且,PB4控制LED灯亮灭也 ...

能否换成SPI1试试?

使用特权

评论回复
14
songchenping| | 2015-8-18 19:02 | 只看该作者
any012 发表于 2015-8-18 16:49
PB4设的悬浮输入,PCB板上有上拉电阻,而且在PB4管脚上用示波器能测到高低电平。
时序的话,找的ADT7320 ...

按我的方法就是单独调试SPI和ADC芯片。先用IO口模拟读取ADC值,通了后再看SPI波形是否正确。最后再一起调试。

使用特权

评论回复
15
any012|  楼主 | 2015-8-18 21:11 | 只看该作者
现在就是IO口模拟SPI。

使用特权

评论回复
16
any012|  楼主 | 2015-8-19 09:20 | 只看该作者
觉得也有可能是经过高速光耦,有一定的延时,读取的时刻不对。

使用特权

评论回复
17
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 很给力!
18
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) 呢?

使用特权

评论回复
19
ayb_ice| | 2015-8-20 11:53 | 只看该作者
any012 发表于 2015-8-20 11:05
谢谢!如果我改成if(GPIO_ReadInputDataBit(GPIOB, 4) == 0x01) 呢?

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

使用特权

评论回复
评分
参与人数 1威望 +2 收起 理由
any012 + 2 赞一个!
20
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

粉丝