Синтаксис с использованием указателей void для функций и структур в простом ядре во встроенной системе - PullRequest
0 голосов
/ 15 октября 2011

Я пишу чрезвычайно простое ядро ​​для класса встроенных систем. Плата TI Stellaris EKI-LM3S8962. Он работает на C и имеет OLED-дисплей. У меня проблемы с указателями на void и отменой ссылки на них. Любая помощь очень ценится.

Моя очень маленькая первоначальная цель - доказать концепцию передачи указателей на функции и указателей на структуры вокруг. Это способ доступа к переменной batteryState, на которую указывает указатель batteryStatePtr, являющийся частью передаваемой структуры данных?

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 * в качестве аргумента и имеет void * на структуру данных. В качестве доказательства концепции я начинаю как можно меньше. Есть две функции, статус и отображение.

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

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

Состояние уменьшает глобальную переменную batteryState через taskDataPtr, которое ей дано. Дисплей объединяет его в строку и показывает его на 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;
}

1 Ответ

0 голосов
/ 17 октября 2011

Способ получения значения batteryState через структуру void * правильный. Для наглядности вот оно: Структура данных с именем data имеет элемент batteryStatusPtr. После получения ptr разыменуйте его, чтобы получить то, на что он указывает. Добавьте больше скобок для порядка операций. (Не уверен на 100%, если это необходимо, но это позволяет мне спать по ночам. Наконец, уменьшите его на 1.

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

В одной строке проблема заключалась в том, что после использования sprintf () для преобразования его в строку и отправки его в функцию отображения значение было искажено каким-то странным числом мусора. Я не знаю почему, но причина была в sprintf (). Я написал свою собственную строку в строковую функцию, и проблема была решена. Sprintf отлично работал на моей Linux-коробке, но тестовой доске Texas Instruments LM3S8962 не понравилось.

Вот урезанная, прокомментированная версия кода. Поскольку я немного новичок (в школе, у меня год опыта программирования на 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))--;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...