Примерно так: Синус табличный, 8-битные знаковые целые, используется еще и для формирования трех фаз 400Гц, поэтому количество точек кратно трем:
class sinus
{
public:
typedef int8_t result_t;
typedef uint16_t phase_t; // [0.. 2 * M_PI) - phase
typedef uint16_t index_t; // [0.. PERIOD / 128 * 2) - table index
static phase_t const PERIOD = 170 * 3 * 128U; // 170 = 510 / 3
static result_t value(phase_t phase);
static index_t index(phase_t phase);
static result_t value_by_index (phase_t phase);
private:
static result_t PROGMEM const Envelope[PERIOD / 128 * 2];
};
#if defined(__AVR__)
INLINE sinus::result_t sinus::value(phase_t phase)
{
return pgm_read_byte(&Envelope[index(phase)]);
}
INLINE sinus::result_t sinus::value_by_index(index_t index)
{
return pgm_read_byte(&Envelope[index]);
}
#else
INLINE sinus::result_t sinus::value(phase_t phase)
{
return Envelope[index(phase)];
}
INLINE sinus::result_t sinus::value_by_index(index_t index)
{
return Envelope[index];
}
#endif
INLINE sinus::index_t sinus::index(phase_t phase)
{
return phase >> 7;
} Массив огибающей содержит две копии синуса чтобы не думать о выходе индекса за пределы массива при вычислении сдвинутого по фазе синуса.
Вычисление амплитуд:
inline void synchro_driver::set_angle(angle_t angle)
{
sinus::index_t Angle_idx = sinus::index(angle);
Amplitude[PHASE_A] = sinus::value_by_index(Angle_idx + sinus::index(sinus::PERIOD / 3 * 0));
Amplitude[PHASE_B] = sinus::value_by_index(Angle_idx + sinus::index(sinus::PERIOD / 3 * 1));
Amplitude[PHASE_C] = sinus::value_by_index(Angle_idx + sinus::index(sinus::PERIOD / 3 * 2));
}
Вычисление значений ШИМ:
inline void synchro_driver::drive(sinus::result_t excitation_sample)
{
Output[PHASE_A] = 0x80 - uint16_t(excitation_sample * Amplitude[PHASE_A]) / 128;
Output[PHASE_B] = 0x80 - uint16_t(excitation_sample * Amplitude[PHASE_B]) / 128;
Output[PHASE_C] = 0x80 - uint16_t(excitation_sample * Amplitude[PHASE_C]) / 128;
}
inline output_t synchro_driver::output(output_no_t output_no) { return Output[output_no]; }
вычисление фазы и огибающей для обмотки возбуждения:
inline void excitation::drive()
{
phase_t Phase_tmp = Phase;
if(Phase_tmp < STEP)
Phase_tmp += PERIOD;
Phase_tmp -= STEP;
Phase = Phase_tmp;
}
inline sinus::result_t excitation::sample() { return sinus::value(Phase); }
Собственно обработчик прерывания:
ISR(TIMER0_OVF_vect)
{
PHASE_A_OCR = Needle[0].output(synchro_driver::PHASE_A);
PHASE_B_OCR = Needle[0].output(synchro_driver::PHASE_B);
PHASE_C_OCR = Needle[0].output(synchro_driver::PHASE_C);
Excitation.drive();
sinus::result_t Exc_sample = Excitation.sample();
PHASE_E_OCR = 0x80 + Exc_sample;
PHASE_F_OCR = 0x80 - Exc_sample; // Bridge connection
Needle[0].drive(Exc_sample);
}
Выходы ШИМ раскачиваются L293D или полумостами IR2104+IR7103, их питание 24-30в. На авиационных указателях получаю точность установки стрелки порядка градуса.
Будут вопросы - стучитась в почту (указана в профиле).