Files

188 lines
5.3 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* @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);
} } } }