188 lines
5.3 KiB
C
188 lines
5.3 KiB
C
/**
|
||
* @file DAC.c
|
||
* @brief Управление внешним ЦАП и формирование аналогового задания нагрузки.
|
||
*
|
||
* Формирует последовательный поток через GPIO, рассчитывает временные интервалы
|
||
* относительно READY_FREQ и выдаёт нормированное значение Anal_output().
|
||
* Линии CLK/CS/DATA управляются непосредственно, поэтому порядок переключений
|
||
* и программные задержки являются частью аппаратного протокола и не должны
|
||
* переставляться без проверки осциллографом.
|
||
*/
|
||
#include "DSP2833x_Device.h" // DSP281x Headerfile Include File
|
||
#include "DSP2833x_SWPrioritizedIsrLevels.h"
|
||
#include "filter_bat2.h"
|
||
#include "measure.h"
|
||
|
||
#include "RS485.h"
|
||
#include "message.h"
|
||
#include "DAC.h"
|
||
#include "package.h"
|
||
#include "tools.h"
|
||
|
||
#include "peripher.h"
|
||
#include "log_to_mem.h"
|
||
|
||
#define dCLK_1() GpioDataRegs.GPBSET.bit.GPIO63=1
|
||
#define dCLK_0() GpioDataRegs.GPBCLEAR.bit.GPIO63=1
|
||
#define dCS_1() GpioDataRegs.GPBSET.bit.GPIO59=1
|
||
#define dCS_0() GpioDataRegs.GPBCLEAR.bit.GPIO59=1
|
||
|
||
unsigned long WAKEpowse;
|
||
unsigned long IMPowse;
|
||
unsigned int period_dac, time_dac;
|
||
|
||
/**
|
||
* @brief Переводит физические интервалы профиля нагрузки в тики READY_FREQ.
|
||
* @post Обновлены WAKEpowse, period_dac и time_dac.
|
||
*/
|
||
void Setup_DAC_time(void)
|
||
{
|
||
WAKEpowse = 3L * DAC_FREQ +1;
|
||
|
||
period_dac = READY_FREQ / DAC_FREQ;
|
||
time_dac = LOAD_TIME * DAC_FREQ;
|
||
}
|
||
|
||
/** @brief Устанавливает логический уровень последовательной линии DATA ЦАП. */
|
||
void dOUT(int x)
|
||
{
|
||
if(x) GpioDataRegs.GPBSET.bit.GPIO60=1;
|
||
else GpioDataRegs.GPBCLEAR.bit.GPIO60=1;
|
||
}
|
||
|
||
/** @brief Формирует короткую аппаратно-зависимую задержку между фронтами GPIO. */
|
||
void wast()
|
||
{
|
||
int i;
|
||
|
||
for(i=0;i<25;i++);
|
||
}
|
||
|
||
/**
|
||
* @brief Последовательно передаёт одно управляющее слово во внешний ЦАП.
|
||
* @param word Слово протокола, выдаваемое по DATA синхронно с CLK.
|
||
* @note CS и CLK переключаются программно; порядок фронтов менять нельзя.
|
||
*/
|
||
void dSEND(unsigned int word)
|
||
{
|
||
int i;
|
||
|
||
dCS_0(); DSP28x_usDelay(1L);
|
||
|
||
for(i=0;i<16;i++)
|
||
{
|
||
dCLK_1();
|
||
dOUT((word & 0x8000)?1:0); word = word<<1; DSP28x_usDelay(1L);
|
||
dCLK_0(); DSP28x_usDelay(1L);
|
||
}
|
||
dCS_1();
|
||
}
|
||
|
||
/** @brief Устанавливает CS, CLK и DATA в безопасные уровни ожидания. */
|
||
void Init_DAC(void)
|
||
{
|
||
dSEND(0x9002|0x0000);
|
||
toggle_RES_OUT_1();
|
||
}
|
||
|
||
/**
|
||
* @brief Масштабирует прикладное задание и отправляет код во внешний ЦАП.
|
||
* @param vrot Требуемое значение в прикладных единицах.
|
||
* @param maxx Значение полной шкалы; должно быть больше нуля.
|
||
* @details Результат ограничивается аппаратным диапазоном перед формированием
|
||
* управляющего слова, поэтому выход не переполняется при завышенном задании.
|
||
*/
|
||
void Anal_output(long vrot, long maxx)
|
||
{
|
||
long out;
|
||
static int x;
|
||
|
||
out = DAC_min() + vrot * DAC_max() / maxx - vrot * DAC_min() / maxx ;
|
||
|
||
x=0;// !x; тщетно бытие
|
||
|
||
if(cCalibrDac) out=DAC_cal();
|
||
|
||
out = out & 0xFFF;
|
||
|
||
if(x) dSEND(out|0x0000|0x0000);
|
||
else dSEND(out|0x8000|0x0000);
|
||
|
||
modbus[123] = out;
|
||
|
||
modbus[0x1C] = 40L + vrot * 200 / maxx - vrot * 40 / maxx ;
|
||
|
||
/*
|
||
if(!no_write)
|
||
{
|
||
Test_mem_limit(4);
|
||
|
||
Log_to_mem(modbus[0x7B]);
|
||
Log_to_mem(modbus[0x63]);
|
||
Log_to_mem(modbus[0x1C]);
|
||
Log_to_mem(modbus[0x1D]);
|
||
|
||
}
|
||
*/
|
||
|
||
|
||
}
|
||
|
||
/**
|
||
* @brief Выполняет очередной шаг временного профиля аналоговой нагрузки.
|
||
* @details Использует IMPowse как фазу профиля и на границах интервалов
|
||
* выбирает новое задание, передаваемое через Anal_output().
|
||
*/
|
||
void Load_runner()
|
||
{
|
||
static unsigned int count_dac=0, count_load=0, x=1;
|
||
float sinus=0;
|
||
int kod;
|
||
|
||
if(IMPowse) IMPowse--;
|
||
if(++count_dac >= period_dac)
|
||
{
|
||
count_dac=0;
|
||
|
||
if(WAKEpowse)
|
||
{
|
||
--WAKEpowse;
|
||
|
||
if( (WAKEpowse == DAC_FREQ/2*6)||
|
||
(WAKEpowse == DAC_FREQ/2*5)||
|
||
(WAKEpowse == DAC_FREQ/2*4)||
|
||
(WAKEpowse == DAC_FREQ/2*3)||
|
||
(WAKEpowse == DAC_FREQ/2*2)||
|
||
(WAKEpowse == DAC_FREQ/2*1) )
|
||
{
|
||
Init_DAC(); x=1;
|
||
} }
|
||
|
||
else
|
||
{
|
||
if(cUMPstart)
|
||
{
|
||
if(count_load > (time_dac/2))count_load++;
|
||
|
||
if(++count_load > time_dac) count_load = time_dac;
|
||
|
||
// sinus = ((float)(DAC_stop - DAC_go) / 16.0 * count_load) + ((float)(DAC_go - 4.0) / 16.0 * time_dac);
|
||
sinus = (10.0 / 16.0 * count_load) + (2.0 / 16.0 * time_dac);
|
||
}
|
||
else
|
||
{ count_load = 0;
|
||
sinus=0;
|
||
x = (x+1)&0x3FF;
|
||
}
|
||
|
||
if(!x || cInitDac)
|
||
{
|
||
Init_DAC(); x=1; cInitDac=0;
|
||
}
|
||
else
|
||
{
|
||
kod = (int)sinus;
|
||
|
||
Anal_output(kod, time_dac);
|
||
} } } }
|