在嵌入式系统的简单内核中使用 void 指针表示函数和结构的语法

发布于 2024-12-09 17:08:08 字数 3920 浏览 0 评论 0原文

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

我最初的小目标是证明传递函数指针和结构指针的概念。这是我访问指针 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” 找到重要区域。taskPtr

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

指向一个函数,该函数采用 void* 作为参数,并具有 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;
}

I'm writing an extremely simple kernel for an embedded systems class. The board is the TI Stellaris EKI-LM3S8962. It runs C and has an OLED display. I am having issues with void pointers and de-referencing them. Any help is much appreciated.

My very small initial goal is to prove the concept of passing function pointers and struct pointers around. Is this the way that I access the var batteryState pointed to by the pointer batteryStatePtr which is part of the data struct passed in?

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)--;
    ...

Here is a very stripped down version of my code, the important region can be located by ctrl-f "HERE IS"

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

The taskPtr points to a function that takes a void* as an arg and has a void* to a data struct. As a proof of concept I'm starting as small as possible. There are two functions, status and display.

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

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

Status decrements the global variable batteryState through the taskDataPtr it is given. Display concatenates it onto a string and shows it on the 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;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

酒浓于脸红 2024-12-16 17:08:09

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

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

在一行中,问题是在使用 sprintf() 将其转换为字符串并将其发送到显示函数之后,该值被一些奇怪的垃圾数字损坏了,但 sprintf() 是原因,我编写了自己的 uint 到字符串函数,问题得到了解决。但德州仪器 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))--;
    }
}

The way of getting at the value batteryState through the void* structure is correct. For clarity, here it is:
The data structure called data has a member called batteryStatusPtr. After getting the ptr, dereference it to get at what it is pointing at. Add more parenthesis for order of operations. (not 100% sure if those are necessary, but it allows me to sleep at night. Finally decrement it by 1.

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

In one line the problem was after using sprintf() to convert it to a string, and sending it to a display function, the value became corrupted with some strange garbage number. I don't know why, but sprintf() was the cause. I wrote my own uint to string function and the problem was solved. The sprintf worked fine on my linux box, but the Texas Instruments LM3S8962 Lumninary Evaluation Board did not like it.

Here is a stripped down, commented version of the code. As I'm a bit of a noob (in school, have a year of programming experience in Javascript, not C), I will take no responsibility for any errors. This is to the best of my knowledge. Perhaps in the process of stripping it is broken so I apologize in advance.

// 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))--;
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文