Я использую исключительно свои библиотеки. Писать их приходится всего один раз.
Все проекты построены под одному и тому же шаблону, прототипу.
Для процов, к которым нет нормального C++ компилятора и среду, построение аналогичное, но не такое красивое

Например, вот так выглядит весь
main.cpp:
Код
#include "TApplication.h"
// Единственный экзэмпляр приложения
static TApplication application;
int main()
{
application.run();
}
// Системный таймер для синхронизации приложения (период составляет ровно 1 мс)
extern "C" void SysTick_Handler()
{
application.synchronize();
}
Заметьте - во всем проекте только один глобальный объект, да и тот виден только в main.cpp
Вот часть
TApplication.h:
Код
#include "..\Target\TTargetSTM32.h"
#include "..\RTOS\RTOS_TNKernel.h"
.....
class TApplication
{
public:
void run(void);
inline void synchronize(void) { _rtos.synchronize(); }
// для примера
void LED_On(void) { _target.setPinToLOW(PORT_LED_RED, PIN_LED_RED); } // Включить красный светодиод
void LED_Off(void) { _target.setPinToHIGH(PORT_LED_RED, PIN_LED_RED); } // Выключить красный светодиод
private:
class TThreadDisplay : public TThread<THREAD_DISPLAY_STACK_SIZE, THREAD_DISPLAY_PRIORITY>
{
typedef UNSIGNED8 TCommand;
typedef UNSIGNED8 TData;
typedef UNSIGNED8 TPositionX;
typedef UNSIGNED8 TPositionY;
typedef const char TChar;
public:
virtual void initialize(void * bodyArgument);
private:
virtual void body(void);
void fill(TData);
void gotoXY(TPositionX, TPositionY);
void sendCommand(TCommand);
void sendData(TData);
void printChar(TChar);
void printString(TChar*, TPositionX, TPositionY);
THardwareSTM32 * _target;
};
class TThreadWatchDog : public TThread<THREAD_WATCH_DOG_STACK_SIZE, THREAD_WATCH_DOG_PRIORITY>
{
virtual void initialize(void * bodyArgument);
virtual void body(void);
THardwareSTM32 * _target;
};
.......
private:
TKernel _rtos;
THardwareSTM32 _target;
TThreadDisplay _threadDisplay;
.....
};
Вот часть
TApplication.cpp:
Код
void TApplication::TThreadWatchDog::initialize(void * bodyArgument)
{
_target = (THardwareSTM32*)bodyArgument;
_target->initializeWatchDogTimer(12); // Период сторожевого таймер 12 мс
}
void TApplication::TThreadWatchDog::body(void)
{
_target->updateWatchDogTimer(); // Сбрасывать сторожевой таймер каждые 10 мс
sleep(10);
}
Вот часть
THardwareSTM32.h:
Код
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
......
typedef unsigned UNSIGNED;
typedef unsigned char UNSIGNED8;
typedef unsigned short UNSIGNED16;
typedef unsigned int UNSIGNED32;
typedef unsigned long long UNSIGNED64;
typedef signed char SIGNED8;
typedef signed short SIGNED16;
typedef signed int SIGNED32;
typedef signed long long SIGNED64;
typedef float FLOAT32;
typedef double FLOAT62;
........
class THardwareSTM32
{
public:
typedef UNSIGNED8 TInterruptChannel;
typedef UNSIGNED8 TInterruptPreemptionPriority;
typedef UNSIGNED8 TInterruptSubPriority;
typedef UNSIGNED32 TSystemTimerPeriodMs;
typedef UNSIGNED16 TWatchDogTimerPeriodMs;
typedef UNSIGNED32 TUserTimerPeriodUs;
typedef UNSIGNED8 TUserTimerChannel;
.....
void reset(void);
void initializeWatchDogTimer(TWatchDogTimerPeriodMs);
void updateWatchDogTimer(void);
void setSystemFrequency(TSystemFrequency);
void initializeMainTimer(TSystemTimerPeriodMs);
THardwareSTM32();
~THardwareSTM32() { reset(); }
....
TSystemFrequency GetSystemFrequency() const { return(_systemFrequency); }
void initializeUserTimer(TUserTimerChannel channel, TUserTimerPeriodUs periodUs);
void userTimerInterruptHandler(TUserTimerChannel channel);
void initializePIN(GPIO_TypeDef*, TGPIO_Pins, TGPIO_Mode, TGPIO_Speed);
inline void setPinToHIGH(GPIO_TypeDef* GPIOx, TGPIO_Pins pin)
{ GPIOx->BSRR = pin; }
inline void setPinToLOW(GPIO_TypeDef* GPIOx, TGPIO_Pins pin)
{ GPIOx->BRR = pin; }
inline bool isPinHIGH(GPIO_TypeDef* GPIOx, TGPIO_Pins pin)
{ return((GPIOx->IDR & pin) != 0); }
inline bool isPinLOW(GPIO_TypeDef* GPIOx, TGPIO_Pins pin)
{ return((GPIOx->IDR & pin) == 0); }
....
private:
inline void disableAllInterrupts(void) { asm ("cpsid I"); }
inline void enableAllInterrupts(void) { asm ("cpsie I"); }
.....
private:
TSystemFrequency _systemFrequency;
....
};
В итоге, аппартная, т.е. платформозависимая часть изолирована от основного кода - Application, RTOS, если используется - тоже изолирована от кода, поскольку RTOS - тоже отчасти платформозависима.
Глобальных переменных вообще нет! (кроме одной - типа TApplication, которую никто и "не видит"). Подобное построение я позаимствовал из старого-доброго Borland Builder C++. В принципе, по мне - у них задумка хорошая, но уж больно "тяжелая".
В итоге, как видите, получается легко сопровождаемый код. Каждая часть его может целиком использоваться в других проектах, т.к. другие проекты построены аналогично.
Шаблоны использую только свои, в них использую очень простые вещи.
А если проект большой, то такое пострение проекта позволяет четко разделить работу между людьми.
Потом, если позволяет время, можно легко оптимизировать куски низкоуровневого кода.
В принципе, весь проект целиком можно написать на ПК, а потом "подцепить" к нему соответствующий железу THardware и TKernel (RTOS).