OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 4871|回复: 14

求一个同时读取8个IO输入的操作(PF0-PF7)

[复制链接]

7

主题

23

帖子

0

精华

初级会员

Rank: 2

积分
71
金钱
71
注册时间
2017-12-4
在线时间
28 小时
发表于 2018-5-14 14:59:46 | 显示全部楼层 |阅读模式
5金钱
求一个同时读取8个IO输入的操作(PF0-PF7),然后把他们放到一个 内存中,用16进制表示。自己是这样实现的

unsigned char  data=0;
data =GPIO_ReadInputDataBit(GPIOF,GPIO_Pin_7);//8位
   data << 1;
   data |= GPIO_ReadInputDataBit(GPIOF,GPIO_Pin_6);//7位
   data << 1;
   data |= GPIO_ReadInputDataBit(GPIOF,GPIO_Pin_5);//6位
   data << 1;
   data |= GPIO_ReadInputDataBit(GPIOF,GPIO_Pin_4);//5位
   data << 1;
   data |= GPIO_ReadInputDataBit(GPIOF,GPIO_Pin_3);//4位
   data << 1;
   data |= GPIO_ReadInputDataBit(GPIOF,GPIO_Pin_2);//3位
   data << 1;
   data |= GPIO_ReadInputDataBit(GPIOF,GPIO_Pin_1);//2位
   data << 1;
   data |= GPIO_ReadInputDataBit(GPIOF,GPIO_Pin_0);//1位

这样很浪费时间,没有一起直接操作的吗?就像发送这样
#define Dataout(x)   GPIO_Write(GPIOF,x)   //声明低8位输出
直接操作Dataout(data) 就好了

最佳答案

查看完整内容[请看2#楼]

你应该看下寄存器版本。 GPIO不论设置成什么状态,都有IDR和ODR两个寄存器(皆为16BIT,对应PX0-PX15)。 当GPIO被配置成OUT时,读取IDR数据对应的bit是输出的状态,但是这对OUT没任何影响。 同样的,GPIO配置成IN时,读取ODR是无意义的。 并不是说配置成了输出,就不能读取其寄存器。 别用如果不理解底层就用库函数版本,就有这样的缺陷了。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

33

主题

984

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
8024
金钱
8024
注册时间
2014-8-13
在线时间
1595 小时
发表于 2018-5-14 14:59:47 | 显示全部楼层
貌似大神 发表于 2018-5-14 18:15
这个方法可以用,但是 项目导致的引脚数本来就不多了,想尽量节省资源

你应该看下寄存器版本。
GPIO不论设置成什么状态,都有IDR和ODR两个寄存器(皆为16BIT,对应PX0-PX15)。
当GPIO被配置成OUT时,读取IDR数据对应的bit是输出的状态,但是这对OUT没任何影响。
同样的,GPIO配置成IN时,读取ODR是无意义的。

并不是说配置成了输出,就不能读取其寄存器。
别用如果不理解底层就用库函数版本,就有这样的缺陷了。
回复

使用道具 举报

4

主题

79

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
294
金钱
294
注册时间
2018-1-31
在线时间
46 小时
发表于 2018-5-14 15:26:39 | 显示全部楼层
GPIO_ReadInputData
回复

使用道具 举报

7

主题

23

帖子

0

精华

初级会员

Rank: 2

积分
71
金钱
71
注册时间
2017-12-4
在线时间
28 小时
 楼主| 发表于 2018-5-14 15:31:54 | 显示全部楼层

这不就 一下子读完了,浪费了8个脚
回复

使用道具 举报

4

主题

79

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
294
金钱
294
注册时间
2018-1-31
在线时间
46 小时
发表于 2018-5-14 17:46:55 | 显示全部楼层
貌似大神 发表于 2018-5-14 15:31
这不就 一下子读完了,浪费了8个脚

你意思是:调用这个函数就必须16个脚全部设置为输入?
据我的认识,就算我只用一个管脚,我也可以用这个函数读16个管脚的状态,其他管脚做什么没关系,反正读回来的值你又不用,用你关系的BIT就可以了
回复

使用道具 举报

7

主题

23

帖子

0

精华

初级会员

Rank: 2

积分
71
金钱
71
注册时间
2017-12-4
在线时间
28 小时
 楼主| 发表于 2018-5-14 18:15:32 | 显示全部楼层
屋脊雀 发表于 2018-5-14 17:46
你意思是:调用这个函数就必须16个脚全部设置为输入?
据我的认识,就算我只用一个管脚,我也可以用这个 ...

这个方法可以用,但是 项目导致的引脚数本来就不多了,想尽量节省资源
回复

使用道具 举报

4

主题

79

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
294
金钱
294
注册时间
2018-1-31
在线时间
46 小时
发表于 2018-5-14 20:36:39 | 显示全部楼层
貌似大神 发表于 2018-5-14 18:15
这个方法可以用,但是 项目导致的引脚数本来就不多了,想尽量节省资源

大哥,你还是不明白,这个函数怎么会影响你的资源呢?
PF0-PF7接按键输入
PF8-PF15其他,随便,做什么功能都可以
ColSta = GPIO_ReadInputData(GPIOF);
ColSta低八位就是你要的状态。
哪里浪费资源了?

如果是我没看懂,请指正。
回复

使用道具 举报

9

主题

507

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3347
金钱
3347
注册时间
2013-4-10
在线时间
333 小时
发表于 2018-5-14 21:48:04 | 显示全部楼层
x =(u8)GPIOD->IDR;  // 这样一次读取

回复

使用道具 举报

7

主题

23

帖子

0

精华

初级会员

Rank: 2

积分
71
金钱
71
注册时间
2017-12-4
在线时间
28 小时
 楼主| 发表于 2018-5-15 14:24:43 | 显示全部楼层
mack13013 发表于 2018-5-14 14:59
你应该看下寄存器版本。
GPIO不论设置成什么状态,都有IDR和ODR两个寄存器(皆为16BIT,对应PX0-PX15)。 ...

非常感谢。你说的,道理我懂,目前的确用不到高八位,所以我说可以使用。重点在于担心以后,可能也要用他们读其他的IO ,那样就不行了,当然 我可以选别的IO,问题就在于,IO都被用的差不多。目前也在学习寄存器版本的一些知识。
回复

使用道具 举报

7

主题

23

帖子

0

精华

初级会员

Rank: 2

积分
71
金钱
71
注册时间
2017-12-4
在线时间
28 小时
 楼主| 发表于 2018-5-15 14:28:04 | 显示全部楼层
屋脊雀 发表于 2018-5-14 20:36
大哥,你还是不明白,这个函数怎么会影响你的资源呢?
PF0-PF7接按键输入
PF8-PF15其他,随便,做什么 ...

首先,函数可以用,是肯定的。换个问题吧,如果16个全是输入模式,我只要低八位呢?因为项目后面很可能要继续加东西,比如又需要一组输入IO,那这种方法就要换了。(IO口用的差不多了)
回复

使用道具 举报

4

主题

79

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
294
金钱
294
注册时间
2018-1-31
在线时间
46 小时
发表于 2018-5-15 14:58:26 | 显示全部楼层
貌似大神 发表于 2018-5-15 14:28
首先,函数可以用,是肯定的。换个问题吧,如果16个全是输入模式,我只要低八位呢?因为项目后面很可能要 ...

实在抱歉,我还是不明白你的顾虑
16个全是输入,用这个接口读,你之要低八位就用低八位啊?读回内存了,你想用几位就几位。
有什么问题?
读不用的输入IO会有什么影响?
回复

使用道具 举报

33

主题

984

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
8024
金钱
8024
注册时间
2014-8-13
在线时间
1595 小时
发表于 2018-5-15 19:17:05 | 显示全部楼层
本帖最后由 mack13013 于 2018-5-15 19:27 编辑
貌似大神 发表于 2018-5-15 14:24
非常感谢。你说的,道理我懂,目前的确用不到高八位,所以我说可以使用。重点在于担心以后,可能也要用他 ...

哎,回复你这个帖子真是费了我的劲了,本来想简简单单说一下,又怕你再有疑问,索性多花点功夫做个全科普吧,累。

第一,给你看一下GPIO结构,下图就是GPIO结构,并且我在图上做简单标示:
IO.jpg

(补充一下:图片上下面的红字的意思是:输出寄存器对IO引脚的影响,要受输出控制和输出控制后面的推挽结构控制。简单的说,输出寄存器想要影响IO状态,还要看输出控制、推挽结构答不答应)

每一个IO引脚都有上图那么一个结构,并且同一组引脚的输入寄存器和输出寄存器在地址上是连续的,比如PF0-PF15的IDR地址上连续,ODR地址上也连续,PE0-PE15也是如此,为什么这样设计呢?
这样设计,在操作上是可以“一次”读取的,比如我要获取PF0-PF15的IO输入状态,那么我直接u16 uwPFStatus = GPIOF->IDR;这样我通过一条语句就把PF的16个引脚状态读取完成。

有人说,我只想读取某些引脚状态,不想全读,是不是可以?比如LZ一楼所做的操作:分8次分别读取PF0-PF7的状态,LZ的代码如下:
[mw_shl_code=c,true]data =GPIO_ReadInputDataBit(GPIOF,GPIO_Pin_7);//8位
   data << 1;
    data |= GPIO_ReadInputDataBit(GPIOF,GPIO_Pin_6);//7位
   data << 1;
    data |= GPIO_ReadInputDataBit(GPIOF,GPIO_Pin_5);//6位
   data << 1;
    data |= GPIO_ReadInputDataBit(GPIOF,GPIO_Pin_4);//5位
   data << 1;
    data |= GPIO_ReadInputDataBit(GPIOF,GPIO_Pin_3);//4位
   data << 1;
    data |= GPIO_ReadInputDataBit(GPIOF,GPIO_Pin_2);//3位
   data << 1;
    data |= GPIO_ReadInputDataBit(GPIOF,GPIO_Pin_1);//2位
   data << 1;
    data |= GPIO_ReadInputDataBit(GPIOF,GPIO_Pin_0);//1位[/mw_shl_code]

哎,想法很好,没什么用,而且可能做了不必要的操作。我们来看下GPIO_ReadInputDataBit这个函数是个什么鬼,这个函数在stm32fXxx_gpio.c中如下:
[mw_shl_code=c,true]@endverbatim
  * @{
  */

/**
  * @brief  Reads the specified input port pin.
  * @param  GPIOx: where x can be (A..K) to select the GPIO peripheral for STM32F405xx/407xx and STM32F415xx/417xx devices
  *                      x can be (A..I) to select the GPIO peripheral for STM32F42xxx/43xxx devices.
  *                      x can be (A, B, C, D and H) to select the GPIO peripheral for STM32F401xx devices.
  * @param  GPIO_Pin: specifies the port bit to read.
  *         This parameter can be GPIO_Pin_x where x can be (0..15).
  * @retval The input port pin value.
  */
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;
}[/mw_shl_code]

这里面有这么一句:
  if ((GPIOx->IDR & GPIO_Pin) != (uint32_t)Bit_RESET)
也就是说,这个函数最终还是读取GPIOF->IDR(另外,也看出了,库函数里面还是操作寄存器),并且LZ那样写代码是更加繁琐
(本来读取IDR一次就完成了,LZ读取了8次,也就是说LZ的读取不是”同时“,如果在LZ读取这8次信号的时候,信号发生了变化...)

所以LZ要达成的目的更准确的方法是这样:u16 uwPFStatusIn = GPIOF->IDR;,但是LZ又说了,他只想要低8位,那就这样:
u8 ucPFLowByteIn = GPIOF->IDR & 0xFF;当然,如果遇到类型不匹配错误或者警告自行添加强制转换就可以了。

至于LZ说的要把高8位用做他出,这个也简单,如果是复用,直接操作复用寄存器,如果高8位当作IO输入或者输出,直接操作对应的寄存器:
输入:
u8 ucPFHighByteIn = (GPIOF->IDR >> 8)  & 0xFF;
或者
u16 uwPFHighWordIn =  GPIOF->IDR & 0xFF00;

输出:
u16 uwPFHighByteOut = xx;//(xx是你要设置的状态)
GPIOF->ODR &= 0xFFFF00FF;//擦除高8位状态
GPIOF->ODR |= uwPFHighByteOut;//想一下uwPFHighByteOut应该怎么构造?


留下几个思考坑:
1、IO结构图中施密特那里的开关是指开关控制,还是指开关信号(数字信号)?
2、无论IDR还是ODR,都是32位的噢,呵呵,why?
3、GPIO_TypeDef??????这个东西有什么用?为什么这么用?
4、不考虑Verilog语言特性,FPGA在物理结构上一个最小单元是什么样的(实际上非常复杂)?相应的,STM32之类的MCU的微电子制造结构?
5、现在看的话,是不是应该入门学寄存器,熟稔之后寄存器和库函数随便选?而且学习寄存器版本,只需要学一个流水灯就够了(有充分的数
电基础,一个流水灯就足够了解STM32开发的底层原理了,然后寄存器和库函数自己选)。
6、输出、输入的上、下拉;输出的推挽,以及输入的浮空如何实现的?


另外:代码我随手在网页上打的,数据类型转换,错误检查什么的没做,请大家不要在意这些细节,让我完美装逼。。。





回复

使用道具 举报

7

主题

23

帖子

0

精华

初级会员

Rank: 2

积分
71
金钱
71
注册时间
2017-12-4
在线时间
28 小时
 楼主| 发表于 2018-5-15 20:35:42 | 显示全部楼层
mack13013 发表于 2018-5-15 19:17
哎,回复你这个帖子真是费了我的劲了,本来想简简单单说一下,又怕你再有疑问,索性多花点功夫做个全科普 ...

非常感谢,没想到一个小小的问题,暴露了自己这么多的不足。之前忙着赶进度,就直接上手了,看来要加紧打牢一下基础。留下的问题,回去好好琢磨,最后再次感谢!麻烦了。
回复

使用道具 举报

7

主题

23

帖子

0

精华

初级会员

Rank: 2

积分
71
金钱
71
注册时间
2017-12-4
在线时间
28 小时
 楼主| 发表于 2018-5-15 20:37:18 | 显示全部楼层
屋脊雀 发表于 2018-5-15 14:58
实在抱歉,我还是不明白你的顾虑
16个全是输入,用这个接口读,你之要低八位就用低八位啊?读回内存了 ...

谢谢你的答疑。这里也有自己的原因,自己基础不牢,看问题片面,容易钻进牛角尖。因为不理解,所以阐述问题,也片面。 麻烦你了
回复

使用道具 举报

2

主题

9

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
269
金钱
269
注册时间
2017-12-14
在线时间
30 小时
发表于 2018-5-15 22:33:20 | 显示全部楼层
回复

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-8 04:43

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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