在嵌入式系统的简单内核中使用 void 指针表示函数和结构的语法
我正在为嵌入式系统类编写一个非常简单的内核。该板是 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
通过 void* 结构获取 BatteryState 值的方法是正确的。为了清楚起见,这里是:
名为 data 的数据结构有一个名为 BatteryStatusPtr 的成员。获取 ptr 后,取消引用它以获取它所指向的内容。添加更多括号以保证运算顺序。 (不是 100% 确定这些是否有必要,但它可以让我晚上睡觉。最后将其减 1。
在一行中,问题是在使用 sprintf() 将其转换为字符串并将其发送到显示函数之后,该值被一些奇怪的垃圾数字损坏了,但 sprintf() 是原因,我编写了自己的 uint 到字符串函数,问题得到了解决。但德州仪器 LM3S8962 Lumninary 评估板不喜欢它,
因为我有点菜鸟(在学校有一年的 Javascript 编程经验,而不是 C)。 ,据我所知,我对任何错误不承担任何责任,因此我提前道歉。
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.
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.