【问题标题】:How to access struct fields pointers inside another struct and write correctly?如何访问另一个结构内的结构字段指针并正确写入?
【发布时间】:2017-09-22 07:03:25
【问题描述】:

我有以下结构(来自我正在使用的库)和一些字段,我想用 OR 操作分配一个新值。但我正在调试,我看不到 stm32l4xx_hal_tim.c 文件中的内容:

 typedef struct
 {
   TIM_TypeDef              *Instance;     /*!< Register base address  */
   TIM_Base_InitTypeDef     Init;          /*!< TIM Time Base required parameters */
   HAL_TIM_ActiveChannel    Channel;       /*!< Active channel                    */
   DMA_HandleTypeDef        *hdma[7];      /*!< DMA Handlers array This array is accessed by a @ref DMA_Handle_index */
   HAL_LockTypeDef          Lock;          /*!< Locking object                    */
   __IO HAL_TIM_StateTypeDef   State;         /*!< TIM operation state               */
 }TIM_HandleTypeDef;


typedef struct
{
  __IO uint32_t CR1;         /*!< TIM control register 1,                   Address offset: 0x00 */
  __IO uint32_t CR2;         /*!< TIM control register 2,                   Address offset: 0x04 */
  __IO uint32_t SMCR;        /*!< TIM slave mode control register,          Address offset: 0x08 */
  __IO uint32_t DIER;        /*!< TIM DMA/interrupt enable register,        Address offset: 0x0C */
  __IO uint32_t SR;          /*!< TIM status register,                      Address offset: 0x10 */
  __IO uint32_t EGR;         /*!< TIM event generation register,            Address offset: 0x14 */
  __IO uint32_t CCMR1;       /*!< TIM capture/compare mode register 1,      Address offset: 0x18 */
  __IO uint32_t CCMR2;       /*!< TIM capture/compare mode register 2,      Address offset: 0x1C */
  __IO uint32_t CCER;        /*!< TIM capture/compare enable register,      Address offset: 0x20 */
  __IO uint32_t CNT;         /*!< TIM counter register,                     
 } TIM_TypeDef;

我定义了一部分代码:TIM_HandleTypeDef TIMER_Struct;

我想访问 TIM_TypeDef 结构的字段“CR1”,即 TIM_HandleTypeDef 的“*Instance”字段。所以我在函数 DRV_TIMER_init() 中通过这种方式完成了它:

  #include "main.h"
  #include "stm32l4xx_hal_tim.h"

  uint32_t uwPrescalerValue = 0;
  TIM_HandleTypeDef TIMER_Struct;
  void DRV_TIMER_init(void);

 int main(void)
 {  

   DRV_TIMER_init();
   while(1)
   {

   }

 }

 //where uint32_t SystemCoreClock = 4000000; in other system source file.
 void DRV_TIMER_init(void)
 {
  uwPrescalerValue = (uint32_t)(SystemCoreClock / 1000000) - 1;
  TIMER_Struct.Init.Period            = 100 - 1;
  TIMER_Struct.Init.Prescaler         = uwPrescalerValue;
  TIMER_Struct.Init.ClockDivision     = 0; // these accesses work

  TIMER_Struct.Instance -> CR1 |= 0x01 << 3; // this no works

 }

即使我直接写:

 TIMER_Struct.Instance -> CR1 = 0xFFFFFFFF; 

静止不动。

我认为这可能是我没有适当控制指针访问或类似的事实。但是我看不到如何访问和修改注释字段的内容。因为我可以看到(调试模式)其余的结构字段更新是如何正确写入的。

这里有什么更正建议吗?

TIMER_Struct.Instance -> CR1 = 0xFFFFFFFF; 

我尝试了不同的方法来获得它,但没有成功。我需要新的想法。

【问题讨论】:

  • 建议:摆脱那个 STlib HAL 膨胀软件并直接写入寄存器。编写驱动程序来抽象硬件。写你的问题:阅读How to Ask,提供minimal reproducible example。四个月后,你应该知道它是如何工作的。
  • @Olaf 不幸的是我不能选择这个选项。使用 HAL_lib 是一个项目规范,我正在使用的所有 fw 都是几个月前基于 HAL_libs 开发的。但是,我想知道我的访问方式是否做错了,以便了解如何在未来的情况下面对它。
  • 您是否为TIMER_Struct.Instance 创建了一个指向的对象?请出示您的minimal reproducible example
  • 不,我不知道。如果我必须创建一个对象 TIMER_Struct.Instance,如果可能的话,我想了解原因。现在我正在对示例进行一些更改。它将很快更新。谢谢。请让我几分钟。
  • 可能你没有正确初始化结构。您正在正确访问该成员,因此原因是发布的代码之外的内容。

标签: c pointers struct embedded


【解决方案1】:
TIM_TypeDef              *Instance;

只是一个不指向任何地方的指针,所以你不能取消引用它

你在 lib 的某个地方定义了一个这样的宏:

#define TIM    (TIM_TypeDef*)0xDEADBEEF;

这就是将寄存器映射到内存的方式

尝试像这样修改您的代码:

TIMER_Struct.Instance = (TIM_Typedef*)0xDEADBEEF;

或者只是

TIMER_Struct.Instance = TIM;

 TIMER_Struct.Instance -> CR1 |= 0x01 << 3;

应该有效

【讨论】:

  • 在TIMER_Struct.Instance = TIM之后;我应该怎么做才能在 CR1 中写入?
  • 在 TIMER_Struct.Instance = TIM 之后; TIMER_Struct.Instance 行 -> CR1 |= 0x01
  • 如果你不允许使用 HAL 结构你可以这样做:看看 CR 寄存器是多少位,假设它是 32 位,看看这个寄存器的起始地址是什么,试试像这样 - #define TIM_CR1 ( * ((volatile unsigned int*)0xstarting address) ) 而不是只写 TIM_CR1 |=0xFFFFFFFF;
  • 事实上,Hal 文件在此处将 TIM7 地址定义为: ((TIM_TypeDef *)0x1400U)+((uint32_t)0x40000000U) ,因此我这样做了: TIMER_Struct.Instance = ((TIM_TypeDef *)0x1400U )+((uint32_t)0x40000000U);正如你之前所说。但是在调试这一行之后,所有实例寄存器都得到了:0xFFFFFFF,这很疯狂。我会尝试你的最后一个选择。
  • 你确定这是正确的宏吗?我认为它应该是这样的:((TIM_TypeDef *)(0x1400U + 0x40000000U))
【解决方案2】:

我想你忘了定义TIMER_Struct.Instance

TIM_HandleTypeDef TIMER_Struct;
TIMER_Struct.Instance = TIM1;
//Now you can access TIMER_Struct.Instance
TIMER_Struct.Instance->CR1 = (uint32_t)0xFFFFFFFF;

但我更喜欢使用 CMSIS 来写入寄存器。不需要 HAL。使用 CMSIS 写入寄存器可能如下所示:

TIM1->CR1=(uint32_t)0xFFFFFFFF

【讨论】:

  • 对不起,我用了这两种方法,但仍然没有效果。
  • 查看来自 STM32CubeL4 的示例项目,并在编写自己的代码之前尝试让它们运行。正如我所看到的,您在这里遗漏了很多东西。您永远不会配置您的 SystemClock。我看不到对HAL_Init() 的呼叫。定时器的时钟是否启用? (__HAL_RCC_TIMxx_CLK_ENABLE()宏)
  • 定时器运行正常。我只想更改一些更新位配置。 CubeL4 中没有定时器的例子。而我所看到的其他人并没有处理我有任何指针的问题。是的,我有时钟配置。但是我必须尽量减少示例,以便直接显示我需要解决的问题。指针处理和结构字段访问。我无法通过 HAL 结构写入定时器配置寄存器。
  • 这很奇怪,我无法在我的 stm32f7 上重现该问题。我可以在 stm32l4 的参考手册中找到的唯一限制是:“32 位外设寄存器必须由字(32 位)写入。所有其他外设寄存器必须由半字(16 位)写入或字(32 位)。” - 所以我的最后一个想法是尝试将值显式转换为uint32_t,因为这应该适用于每个寄存器。
【解决方案3】:

我找到了解决方案。首先,您必须启用外设时钟。如果不是,则不会对定时器寄存器产生任何影响,因为指针结构字段直接指向硬件寄存器分配。这就是为什么我在调试时查看我的 struct var 时看不到任何更新的原因。

我在写入分配后启用了 clk(使用 hal_xxx_init())。那是我的错误。

这部分代码是更正的地方:

//where uint32_t SystemCoreClock = 4000000; in other system source file.
void DRV_TIMER_init(void)
{
  uwPrescalerValue = (uint32_t)(SystemCoreClock / 1000000) - 1;
  TIMER_Struct.Init.Period            = 100 - 1;
  TIMER_Struct.Init.Prescaler         = uwPrescalerValue;
  TIMER_Struct.Init.ClockDivision     = 0; // these accesses work

  if (HAL_TIM_Base_Init(&TIMER_Struct) != HAL_OK)
  {
     /* Initialization Error */
     TIM_Error_Handler();
  }

  TIMER_Struct.Instance -> CR1 |= 0x01 << 3; // this works now

}

如果你试图把最后一句话放在:

HAL_TIM_Base_Init(&TIMER_Struct); 

没有

TIMER_Struct.Instance -> CR1 = xxx; //write mode register acces

会有效果。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-07-10
    • 2014-06-09
    • 2014-07-06
    • 1970-01-01
    • 2014-11-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多