简体   繁体   English

是否可以通过C变量而不是使用GPIO_Pin_N值读取和/或写入端口?

[英]Is it possible to read and/or write ports via a C variable instead of using GPIO_Pin_N values?

All the sample code I can find accesses ports like so: 我可以找到的所有示例代码都可以访问端口,如下所示:

GPIO_SetBits(GPIOE, GPIO_Pin_9 | GPIO_Pin_13);

Which looked OK at first, until I tried to reference LEDs (my port E) by index (0-7). 最初看起来还不错,直到我尝试通过索引(0-7)引用LED(我的端口E)。 A switch or a LUT is a solution, but I don't like either. switch或LUT是解决方案,但我都不喜欢。 Is it possible to declare eg uint8_t and map it to the specific range of pins of a certain port? 是否可以声明例如uint8_t并将其映射到某个端口的特定引脚范围?

The standard Cortex-M3/M4 memory map allows for the CPU to have so-called "bit-band" aliases of regions, in which writing to each word in the bit-band alias performs an automatic read-modify-write to alter the target bit in the corresponding region. 标准的Cortex-M3 / M4内存映射允许CPU具有区域的所谓“位带”别名,其中对位带别名中的每个字进行写入都会自动执行读取-修改-写入操作,以更改相应区域中的目标位。

Taking the STM32F411 (Cortex-M4F) manual I have to hand as an example, that shows the peripheral region 0x40000000-0x400FFFFF is covered by a bit-band alias in the region 0x42000000-0x43FFFFFF . 以STM32F411(Cortex-M4F)手册为例,该示例显示外围区域0x40000000-0x400FFFFF被区域0x42000000-0x43FFFFFF的位带别名0x42000000-0x43FFFFFF Thus for instance on that device (if I've got my maths right) each word from 0x42420280-0x42420300 corresponds to a bit in the GPIO port E data register GPIOE_ODR at 0x40021014 , so this: 因此,例如在该设备上(如果我的数学正确的话),来自0x42420280-0x42420300每个单词对应于GPIO端口E数据寄存器GPIOE_ODR中位于0x40021014 ,因此:

volatile int *leds = (void *)0x42420280;
leds[x] = 1; /* only bit 0 of the bit-band word actually holds data */

makes the hardware perform the tidily-abstracted equivalent of this: 使硬件执行与​​此类似的抽象方法:

volatile int *leds = (void *)0x40021014;
int val = *leds;
val |= (1 << x);
*leds = val;

If you have a suitable device, don't want to update multiple bits at once, and don't mind the extra overhead vs. a single access to the regular register in some cases (eg writing the set/clear registers instead of the data), it's a pretty neat trick. 如果您有合适的设备,则不想一次更新多个位,也不必介意额外的开销,而在某些情况下(例如,写入设置/清除寄存器而不是数据)与常规寄存器的一次访问无关),这是一个非常巧妙的技巧。

The values of the GPIO_Pin_X constants are defined as bit positions within a 16-bit value, with pin 0 as the least significant bit and pin 15 as the most significant: GPIO_Pin_X常量的值定义为16位值内的位位置,其中引脚0为最低有效位,引脚15为最高有效位:

#define GPIO_Pin_0                 ((uint16_t)0x0001)  /*!< Pin 0 selected */
#define GPIO_Pin_1                 ((uint16_t)0x0002)  /*!< Pin 1 selected */
#define GPIO_Pin_2                 ((uint16_t)0x0004)  /*!< Pin 2 selected */
[...]
#define GPIO_Pin_15                ((uint16_t)0x8000)  /*!< Pin 15 selected */

(This is why you can OR them together to write to multiple pins!) (这就是为什么您可以将它们或在一起写入多个引脚的原因!)

If you need to index pins dynamically, you can do so using a macro like: 如果您需要动态索引引脚,则可以使用如下宏:

#define GPIO_Pin(x) ((uint16_t) 1 << (x))

busses are fixed width you cannot change that hardware with software, and no you cannot break up a fixed sized register in a peripheral into smaller parts with software. 总线是固定宽度的,因此您无法使用软件更改硬件,也不能使用软件将外围设备中的固定大小的寄存器分解为较小的部分。 You can possibly make it appear in software to do such a thing but in the end the real code generated by the high level code will still do read-modify-writes or whatever is needed or supported based on bus or peripheral register sized transactions. 您可以使它出现在软件中来执行此操作,但是最终,由高级代码生成的实际代码仍会进行读取-修改-写入操作,或者根据总线或外围寄存器大小的事务进行所需或支持的操作。

Trying to make things smaller even making variables byte sized vs the native size of registers ultimately creates more or inefficient code. 试图使事情变得更小,甚至使变量的大小与寄存器的本机大小相比,最终都会产生更多或效率低下的代码。 So trying to understand why you would want to do such a thing anyway. 因此,尝试了解您为什么仍要这样做。

An stm32 I recently played with has a bit clear/set register where writing a one clears or sets the output state of a pin. 我最近玩过的stm32有一个位清除/设置寄存器,在其中写入一个清除或设置引脚的输出状态。 In the logic it simply clears or sets the flip flop controlling that port output, which in logic they can/do implement the backend of a control into smaller parts, but from software you cannot directly access those in non-aligned, not properly sized transfers. 在逻辑上,它只是清除或设置控制该端口输出的触发器,从逻辑上讲,它们可以/确实将控件的后端实现为更小的部分,但是您不能从软件中直接访问未对齐,大小不正确的传输中的那些。 Some companies require you, in software, to do a read-modify-write. 一些公司要求您使用软件进行读-修改-写操作。 So using an stm32 with these kinds of features (other brands may also have similar features, sometimes using the address, sometimes like this but in separate registers one for setting one for clearing) actually makes your code about as simple as it can be. 因此,使用具有这些功能的stm32(其他品牌可能也具有类似的功能,有时使用地址,有时像这样,但在单独的寄存器中设置一个清除位)实际上使您的代码尽可能简单。

You are more than welcome to create as many defines as you want for combinations of gpio pins so that in your main code you only need one mnemonic instead of multiples orred together if that is your desire. 我们非常欢迎您为gpio引脚组合创建任意数量的定义,以便在您的主代码中只需要一个助记符,而不是多个助记符即可。

You do not have to have a function for setting the bits if you can get the compiler to reliably generate a str of the right size, and the right combination if bits in a single define you can simply the code into an a = b; 如果可以使编译器可靠地生成正确大小的str,则不必具有设置位的功能;如果在单个定义中的位可以将代码简单地转换为a = b,则不必具有正确的组合。 situation. 情况。

My guess from your vague question, is a LUT is the optimal solution. 从您模糊的问题中我猜得出,LUT是最佳解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 可以使用 ioctl() 将 9 针串行端口用作“GPIO”吗? - Possible to use a 9 Pin Serial port as “GPIO” using ioctl()? 如何使用inb()和outb()读取和写入GPIO值 - How to read and write GPIO values with inb() and outb() 如何使用C代码引用Arduino Uno中的特定GPIO引脚? - How to refer to a specific GPIO pin in an Arduino Uno using C code? 从CC2530的GPIO引脚读取 - Read from GPIO Pin on CC2530 在Linux AUART内核驱动程序中,如何使用I2C GPIO扩展器的引脚而不是RTS来控制RS485方向? - How to use I2C GPIO expander's pin instead of RTS to control the RS485 direction, in Linux AUART kernel driver? 通过C使用Windows读取以&#39;\\ n&#39;(换行符)结尾的字符串 - read a '\n' (newline) terminated string using windows via C 我可以从GPIO的输出引脚读取有效信号吗? - Can I read a valid signal from an output pin of GPIO? ARM linux用户空间gpio操作使用mmap / dev / mem方法(能够写入GPIO寄存器,但无法读取它们) - ARM linux userspace gpio operations using mmap /dev/mem approach (able to write to GPIO registers, but fail to read from them) 在 C 中使用读写通过网络发送整数值的问题 - Problems with sending integer values over network using read & write in C 整洁/紧凑的 C 代码,用于在微控制器上使用多个 GPIO 端口 - Neat/compact C code for working with multiple GPIO ports on a microcontroller
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM