【问题标题】:How to get value from 15th pin of 32bit port in ARM?如何从ARM 32位端口的第15个引脚获取值?
【发布时间】:2009-11-27 19:23:07
【问题描述】:

我正在使用 IC DS1620 读取单行上的 1 位串行数据。我需要使用 ARM 微控制器 (LPC2378) 的端口之一读取这些数据。 ARM 端口是 32 位的。如何将此值转换为 1 位变量?

编辑:换句话说,我需要直接引用端口引脚。

【问题讨论】:

    标签: c embedded arm microcontroller


    【解决方案1】:

    没有 1 位变量,但您可以隔离特定位,例如:

    uint32_t original_value = whatever();
    uint32_t bit15 = (original_value >> 15) & 1; /*bit15 now contains either a 1 or a 0 representing the 15th bit */
    

    注意:我不知道你是从 0 还是 1 开始计算位数,所以 >> 15 可能会差一,但你明白了。

    另一种选择是使用位字段,但这会变得很混乱,而且 IMO 不值得这样做,除非值中的每个位都以某种方式有用。如果您只想要一两个位,则可以使用移位和掩码。

    总的来说,这个article 可能对你有用。

    【讨论】:

    • 另一个问题 - 首先如何将 ARM 微控制器端口值转换为 32 位变量?
    • 那是处理器特定的东西。在 x86 中,您将使用一些程序集或编译器内在来执行 inout 指令来读取和写入 I/O 端口。
    • 在 ARM 上,I/O 端口可能只是映射到特定的内存位置——“内存映射寄存器”。仔细阅读 LPC2378 手册。可能有一个可用的 C 头文件为所有这些寄存器提供名称。
    • 根据您的其余代码,您可能不需要转换。您可以改为执行以下操作: uint32_t bit15 = (original_value) & (1
    • @Ron:很好,如果目标只是做一个布尔测试,那么你的建议可能会编译成稍微更好的代码。
    【解决方案2】:

    对于您的 CPU,应该使用 Evan Teran 的答案。我只是想提一下其他一些 ARM CPU 的位带特性,比如 Cortex-M3。对于 RAM/外设的某些区域,所有位都映射到单独的地址以便于访问。

    更多信息请参见http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0337e/Behcjiic.html

    【讨论】:

      【解决方案3】:

      如果您可以直接访问端口寄存器(我对 ARM 没有任何经验),这很简单,只需将其与您想要的位对应的二进制掩码进行按位与:

      var = (PORT_REGISTER & 0x00008000);
      

      如果第 15 位为“0”,则现在 var 包含 0,如果第 15 位为“1”,则包含 0x00008000。

      另外,如果你想要'0'或'1',你可以改变它:

      var = ((PORT_REGISTER & 0x00008000) >> 15);
      

      【讨论】:

      • 更易读的 0x00008000 形式是 (1 << 15),汇编器或编译器将在翻译时而不是运行时计算。
      【解决方案4】:

      编译器附带的头文件将包含所有微控制器寄存器的声明,以及这些寄存器中的位。

      在这篇具体的文章中,我们假设端口输入寄存器名为PORTA,而您想要的位有一个为其定义的掩码,名为PORTA15

      然后读取该引脚的状态:

      PinIsSet = (PORTA & PORTA15) == PORTA15;
      

      或者等效地,使用ternary operator:

      PinIsSet = (PORTA & PORTA15) ? 1 : 0;
      

      一般来说,请参阅参考手册了解所有寄存器和位的作用。另外,看看一些例子。 (This page on the Keil website 包含两者,网上还有很多其他示例。)

      【讨论】:

        【解决方案5】:

        在 LPC2378(与其他 LPC2xxxx 微控制器系列一样)中,I/O 端口位于系统内存中,因此您需要声明一些变量,如下所示:

        #define  DALLAS_PIN (*(volatile unsigned long int *)(0xE0028000)) /* Port 0 data register */
        #define  DALLAS_DDR (*(volatile unsigned long int *)(0xE0028008)) /* Port 0 data direction reg */
        #define  DALLAS_PIN (1<<15)
        

        请注意0xE0028000是port0的数据寄存器地址,0xE0028008是port0的数据方向寄存器地址。您需要根据应用程序中使用的端口和位来修改它。 之后,在您的代码函数中,写 1、写 0 和读的代码或宏必须是这样的:

        #define  set_dqout()    (DALLAS_DDR&=~DALLAS_PIN)   /* Let the pull-up force one, putting I/O pin in input mode */
        #define  reset_dqout()  (DALLAS_DDR|=DALLAS_PIN,DALLAS_PORT&=~DALLAS_PIN) /* force zero putting the I/O in output mode and writing zero on it */
        #define  read_dqin()    (DALLAS_DDR&=~DALLAS_PIN,((DALLAS_PORT & DALLAS_PIN)!= 0)) /* put i/o in input mode and test the state of the i/o pin */
        

        我希望这会有所帮助。

        问候!

        【讨论】:

          【解决方案6】:

          如果测试位,最好记住 C 的运算符评估顺序,例如

          if( port & 0x80 && whatever() )
          

          可能会导致意想不到的行为,就像你刚才写的那样

          if( port & (0x80 && whatever()) )
          

          但可能会提醒

          if( (port & 0x80) && whatever() )
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2010-12-09
            • 2011-10-21
            • 2013-06-29
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-12-26
            相关资源
            最近更新 更多