【问题标题】:Syntax using void pointers for functions and structs in simple kernel on an embedded system在嵌入式系统的简单内核中使用 void 指针表示函数和结构的语法
【发布时间】:2011-10-15 00:47:34
【问题描述】:

我正在为嵌入式系统类编写一个极其简单的内核。该板是 TI Stellaris EKI-LM3S8962。它运行 C 并具有 OLED 显示屏。我遇到了 void 指针和取消引用它们的问题。非常感谢任何帮助。

我最初的小目标是证明传递函数指针和结构指针的概念。这是我访问指针 batteryStatePtr 指向的 var batteryState 的方式,它是传入的数据结构的一部分?

void status (void* taskDataPtr) {
    // make a temporary pointer to a Status Data Struct type
    SDS* data;
    // set data equal to the void* taskDataPtr now cast as a SDS pointer
    data = (SDS*)(taskDataPtr);
    (*data->batteryStatePtr)--;
    ...

这是我的代码的一个非常精简的版本,重要区域可以通过 ctrl-f "HERE IS" 定位

struct MyStruct {
     void (*taskPtr)(void*);
     void* taskDataPtr;
};
typedef struct MyStruct TCB;

taskPtr 指向一个函数,该函数接受一个 void* 作为 arg,并且有一个 void* 指向一个数据结构。作为概念证明,我从尽可能小的开始。有两个功能,状态和显示。

typedef struct DisplayDataStruct {
    uint*  batteryStatePtr;
} DDS;
DDS DisplayData;

typedef struct StatusDataStruct {
    uint* batteryStatePtr;
} SDS;
SDS StatusData;

Status 通过给定的 taskDataPtr 递减全局变量 batteryState。 Display 将它连接到一个字符串上并在 OLED 上显示。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef unsigned int uint;
typedef unsigned char uchar;
typedef unsigned short ushort;

void status (void* taskDataPtr);
void display (void* taskDataPtr);

void delay(uint msDelay);

//  Declare a TCB structure
struct MyStruct {
      void (*taskPtr)(void*);
      void* taskDataPtr;
};
typedef struct MyStruct TCB;

// status var
uint batteryState = 200;

typedef struct DisplayDataStruct {
    uint*  batteryStatePtr;
} DDS;
DDS DisplayData;

typedef struct StatusDataStruct {
    uint* batteryStatePtr;
} SDS;
SDS StatusData;

void main(void)
{
    DisplayData.batteryStatePtr = &batteryState;

    StatusData.batteryStatePtr = &batteryState;

      int i = 0;  //  queue index
      TCB* aTCBPtr;

      TCB* queue[2];

      TCB StatusTCB;
      TCB DisplayTCB;

      StatusTCB.taskPtr = status;
      StatusTCB.taskDataPtr = (void*)&StatusData;
      DisplayTCB.taskPtr = display;
      DisplayTCB.taskDataPtr = (void*)&DisplayData;

      // Initialize the task queue
      queue[0] = &StatusTCB;
      queue[1] = &DisplayTCB;

      // schedule and dispatch the tasks
      while(1)
      {
          for (i = 0; i < 2; i++) {
             aTCBPtr = queue[i];
             aTCBPtr->taskPtr( (void*)(aTCBPtr->taskDataPtr) );
          }
          systemState = (systemState + 1) % 100;
          delay(50);
      }
}

void status (void* taskDataPtr) {
    // return if systemState != 0 aka run once every 5 sec
    if (systemState) {
      return;
    }
    // make a temporary pointer to a Status Data Struct type
    SDS* data;
    // set data equal to the void* taskDataPtr now cast as a SDS pointer
    data = (SDS*)(taskDataPtr);


    // HERE IS where I am stumped. Is (*data->batteryStatePtr)-- the way you do this????
    // access the batteryStatePtr through the struct data
    // then dereference the whole thing to get at batteryState
    if ((*(data->batteryStatePtr)) > 0) {
      // decrement batteryState
      (*(data->batteryStatePtr))--;
    }
    return;
}

void display (void* taskDataPtr) {
    // run once every 5 sec
    if (systemState) {
      return;
    }
    DDS* data;
    data = (DDS*) taskDataPtr;
    char hold[12] = "Batt: ";
    char numHold[4];
    sprintf(numHold, "%u", (*(data->batteryStatePtr)));
    strcat(hold, numHold);

    // display the string hold
    RIT128x96x4StringDraw(hold, 15, 44, 15);
    return;
}

// use for loops to waste cycles, delay taken in ms
void delay(uint msDelay)
{
      // when i == 60000 and j == 100 function delays for ~ 7.6 sec
      msDelay = msDelay * 150 / 19;
      volatile unsigned long i = 0;
      volatile unsigned int j = 0;

      for (i = msDelay; i > 0; i--) {
             for (j = 0; j < 100; j++);
      }
      return;
}

【问题讨论】:

  • (*(data-&gt;batteryStatePtr))-- 应该没问题...您认为有什么特别的原因吗?
  • 感谢您的回复。我认为这是一个问题,因为它不起作用而且我的指针专业知识很少。我只是想把那个语法添加到一堆我知道的东西中,这不是完全错误的。
  • 编译器是否给出警告? systemState 声明在哪里?
  • “它不起作用”是什么意思 - 您希望看到什么以及您实际看到了什么?是不是显示中的值没有减少?您是否已验证它在状态任务中递减?您可能必须使 batteryStatePtr 指针易失,以便编译器始终生成从内存读取的代码,而不是缓存值。
  • 确保您没有丢失任何头文件或源文件...我在任何地方都没有看到 RIT128x96x4StringDraw()systemState 的声明,也没有看到任何 #include 的声明t 标准 C RTL 头文件

标签: c void-pointers embedded


【解决方案1】:

通过void*结构获取值batteryState的方式是正确的。为了清楚起见,这里是: 名为 data 的数据结构有一个名为 batteryStatusPtr 的成员。获得 ptr 后,取消对它的引用以获取它所指向的内容。为操作顺序添加更多括号。 (不是 100% 确定这些是否有必要,但它可以让我在晚上睡觉。最后将其减 1。

(*(data->batteryStatusPtr))--;

在一行中,问题是在使用 sprintf() 将其转换为字符串并将其发送到显示函数后,该值被一些奇怪的垃圾数字破坏了。我不知道为什么,但 sprintf() 是原因。我将自己的 uint 写入字符串函数,问题就解决了。 sprintf 在我的 linux 机器上运行良好,但德州仪器 LM3S8962 Lumninary 评估板不喜欢它。

这是代码的精简、注释版本。由于我有点菜鸟(在学校,有一年的 Javascript 编程经验,而不是 C 语言),因此我对任何错误概不负责。这是据我所知。也许在剥离的过程中它坏了,所以我提前道歉。

// typedef uint as an unsigned integer for reference
typedef unsigned int uint;

// typedef TCB as a structure with two elements,
// first a address of a function (actually not 100% sure about this one,
//  i'm kinda a noob but I think that's right)
// second a void pointer to a struct that stores data
struct MyStruct {
    void (*taskPtr)(void*);
    void* taskDataPtr;
};
typedef struct MyStruct TCB;

// declare a data struct SDS which holds data for the status function
// there is only one variable in there, a uint* to the batteryState
// called batteryStatePtr
typedef struct StatusDataStruct {
    uint* batteryStatePtr;
} SDS;

// declare the global variable batteryState
uint batteryState;

// declare the function status that returns void and accepts a void* taskDataPtr
void status (void* taskDataPtr);

void main() {

    // declare a status TCB
    TCB StatusTCB;
    // declare a StatusDataStructure called StatusData
    SDS StatusData;

    // set the SDS task pointer to the address of the function status
    StatusTCB.taskPtr = &status;
    // set the SDS task data pointer to the address of the StatusDataStructure
    // which is cast as a void pointer
    StatusTCB.taskDataPtr = (void*)&StatusData;

    // declare a TCB pointer task and point it at the StatusTCB
    TCB* taskPtr = &StatusTCB;

    // call the status function through the TCBPtr and send it the dataStruct
    // associated with that TCB (StatusData)
    TCBPtr->taskPtr( (void*)(TCBPtr->taskDataPtr) );
}

void status (void* taskDataPtr) {
    // make a temporary pointer to a Status Data Struct type
    SDS* data;
    // set data equal to the void* taskDataPtr now cast as a SDS pointer
    data = (SDS*)(taskDataPtr);
    // access the global variable batteryState through the data struct associated
    // with the status TCB, of type SDS
    // decrement it if greater than 0
    if ((*(data->batteryStatePtr)) > 0) {
        (*(data->batteryStatePtr))--;
    }
}

【讨论】:

    猜你喜欢
    • 2021-04-20
    • 1970-01-01
    • 1970-01-01
    • 2012-04-08
    • 1970-01-01
    • 2014-01-13
    • 2013-01-05
    • 2016-03-21
    • 1970-01-01
    相关资源
    最近更新 更多