Исппытания на нагрев проводились на постоянном токе. В обе обмотки запускался одинаковый ток dc11.5a. Примерно через полчаса сопротивление датчика упало до Rntc ~ 1 100R, что соответствует нагреву обмоток +80...85С...




Код: Выделить всё
/*
* ver. 1.0;
* 99.9v; 9.99a; 1 000w max
*
* прошивка для работы с 2-мя 3-х разрядными 7seg_led дисплеями (без индикации режимов);
* регулировка тока нелинейная, с ускорением, (999 шагов); шаг регулировки тока - 0.01a;
* регулировка напряжения нелинейная, с ускорением (999 шагов); шаг регулировки напряжения - 0.1v;
* Vref_cur/Vref_vlt (max) = 2Vref mcp49422;
* Vref_adc = 4v096;
* Vref_dac = 4v096;
* chipset: ATMega 8a-PU (PDIP-28); mcp4922; mcp3204; max7219; acs712T-30; ntc = 20k(25C)
*/
/*Other Linker Flags - активизация режима вычислений с плавающей точкой */
/*-Wl,-u,vfprintf -lprintf_flt -lm */
#define F_CPU 16000000UL //тактовая частота мк (unsigned long)
#include <avr/io.h> //подключение библиотеки "ввод/вывод" мк
#include <util/delay.h> //подключение библиотеки "пауза" мк
#include <avr/interrupt.h> //подключение библиотеки "прерывание" мк
#include <stdio.h> //подключение библиотеки ввод/вывод мк
#include <stdlib.h> //подключение стандартной библиотеки мк
#include <avr/eeprom.h>
//--- объявляем переменные ---
char ovh; /*флаг перегрев */
char ovl; /*флаг перегрузка */
char rly_enbl; /*флаг разрешения включения выходного реле */
char chnl; /*ch_n - канал внешнего ацп)*/
//------------------------
/*тактовые кнопки энкодеров */
char pwr_cnt; /*антидребезг для кнопки pwr_btn */
char pwr_st; /*статус триггера pwr_st: 0 or 1 */
char pwr_psh; /*флаг "нажатие на кнопку pwr_btn: 0 or 1 */
char out_cnt; /*антидребезг для кнопки out_rly */
char out_st; /*статус триггера out_st: 0 or 1 */
char out_psh; /*флаг "нажатие на кнопку out_rly: 0 or 1 */
//------------------------
/*энкодеры */
/*тактовые кнопки энкодеров*/
#define btn_thrshld_max 0x7F /*верхний предел подавления дребезга контактов кнопки: 127 */
#define btn_thrshld 0x14 /*предел подавления дребезга контактов кнопки: 20 */
/*encoder */
#define enc_vlt_top 999 /*верхний предел счётчика импульсов энкодера vlt*/
#define enc_cur_top 999 /*верхний предел счётчика импульсов энкодера cur */
#define clk_cur PIND & (1<<PIND0) /*если clk_cur = 1 */
#define dt_cur PIND & (1<<PIND1) /*если dt_cur = 1 */
#define dt_vlt PIND & (1<<PIND3) /*если dt_vlt = 1 */
#define clk_vlt PIND & (1<<PIND4) /*если clk_vlt = 1 */
//------------------------
char spn_enc_vlt; /*флаг начала вращения по часовой стрелке (clk wise)*/
char spn_enc_cur; /*флаг начала вращения по часовой стрелке (clk wise)*/
unsigned short cnt_enc_vlt; /*счётчик импульсов энкодера enc_vlt = 0...999pls */
unsigned short cnt_enc_cur; /*счётчик импульсов энкодера enc_cur = 0...999pls */
//------------------------
/*eeprom */
volatile char uiAddress; /*переменная для записи в eeprom байта адреса */
volatile unsigned char strg_h_vlt; /*старший байт данных положения энкодера enc_vlt */
volatile unsigned char strg_l_vlt; /*младший байт данных положения энкодера enc_vlt */
volatile unsigned char strg_h_cur; /*старший байт данных положения энкодера enc_cur */
volatile unsigned char strg_l_cur; /*младший байт данных положения энкодера enc_cur */
volatile unsigned int EEMEM rg_h_vlt; /*адрес старшего байта данных положения энкодера enc_vlt_set в eeprom */
volatile unsigned int EEMEM rg_l_vlt; /*адрес младшего байта данных положения энкодера enc_vlt_set в eeprom */
volatile unsigned int EEMEM rg_h_cur; /*адрес старшего байта для сохранения положения энкодера enc_cur_set в eeprom */
volatile unsigned int EEMEM rg_l_cur; /*адрес младшего байта для сохранения положения энкодера enc_cur_set в eeprom */
//------------------------
/*RAM */
unsigned char Byte; /*регистр TWDR */
volatile char adres; /*переменная для чтения/записи байта адреса RAM */
volatile unsigned char data; /*переменная для чтения/записи байта данных RAM */
volatile unsigned char mem_byte; /*байт данных RAM */
volatile char adrs; /*адрес ячейки RAM */
volatile char vlt; /*адрес ячейки RAM для записи байта vlt_dac */
volatile char cur; /*адрес ячейки RAM для записи байта cur_dac */
//------------------------
/*dual DAC */
unsigned char cmd_vlt; /*8-bit команда конфигурации для DAC vlt_prst */
unsigned char cmd_cur; /*8-bit команда конфигурации для DAC cur_prst */
unsigned short Vref_vlt; /*опорное напряжение канала регулятора Vout */
unsigned short Vref_cur; /*опорное напряжение канала регулятора Iout */
unsigned char msb; /*старший байт 2-х байтного слова 8-bit MSB */
unsigned char lsb; /*младший байт 2-х байтного слова 8-bit LSB */
//------------------------
/*таймер прерываний */
char inrpt_cnt; /*переменная счётчика сканирующего таймера */
/*SPI */
unsigned char byte; /*байт регистра SPDR */
//------------------------
/*индикация параметров на 4-dgt 7-seg LED */
unsigned short number; /*переменная для разложения 4-х разрядного числа по разрядам дисплея */
unsigned short vlt_prst; /*уровень Vprst = 0...99.9v для отображения на индикаторе */
unsigned short cur_prst; /*уровень Iprst = 0...9.99a для отображения на индикаторе */
//------------------------
/*переменные для работы LED_DRV */
unsigned char Dgt[0x0F] = {}; /*пустой массив из 16 переменных Sgn/Dgt: десятичные цифры 0-9 и знаки */
unsigned char dt_in[8] = {}; /*пустой массив из 8 переменных: байты dt[rg] регистров озу led-драйвера)*/
char dg; /*адрес rg байта внутренноего озу led-драйвера для загрузки данных dt[rg]*/
unsigned char ovld; /*цифра или знак для индикации режима overload */
unsigned char ovht; /*цифра или знак для индикации режима overheat */
unsigned char flt; /*цифра или знак для индикации режима fault */
unsigned char V; /*десятичная цифра разряда Dgt_6-Dgt_8 для отображения разложенной величины V */
unsigned char I; /*десятичная цифра разряда Dgt_3-Dgt_5 для отображения разложенной величины I */
unsigned char M; /*знак разряда Dgt_1-Dgt_8 */
//------------------------
/*внешний ацп mcp3204 */
unsigned short thrm_value; /*12-bit результат преобразования chnl_0 */
unsigned short cur_value; /*12-bit результат преобразования chnl_1 */
unsigned short vlt_value; /*12-bit результат преобразования chnl_2 */
unsigned short ovrld_value; /*12-bit результат преобразования chnl_3 */
/*сглаживающие фильтры */
unsigned short At; /*At=thrm_value */
unsigned short Mt1; /*промежуточный результата работы сглаживающего фильтра в канале_0 */
unsigned short Mt; /*окончательный результат работы сглаживающего фильтра в канале_0 */
unsigned short Ao; /*Ao=ovrld_value */
unsigned short Mo1; /*промежуточный результата работы сглаживающего фильтра в канале_3 */
unsigned short Mo; /*окончательный результат работы сглаживающего фильтра в канале_3 */
unsigned short dt_v; //результат преобразования adc_code ацп в измеренное выходное напряжение [V]
float Av; //Av=dt_v
float Mv1; //промежуточный результата работы сглаживающего фильтра в канале_1 [V]
unsigned short Mv; //окончательный результат работы сглаживающего фильтра в канале_1 [V]
unsigned short dt_i; //результат преобразования adc_code в измеренный ток [I]
float Ai; //Ai=dt_i
float Mi1; //промежуточного результата работы сглаживающего фильтра в канале_2 [I]
unsigned short Mi; //окончательный результат работы сглаживающего фильтра в канале_2 [I]
//------------------------
/*переопределения */
/*интервал вектора прерывания ISR_TIMER2_COMP_vect */
#define intrvl 64 /* */
/*ADC */
#define msb_cnfg 0x06 /*msb-байт конфигурации mcp3204: 0b 0000 0110; 0x06; dec6 */
#define lsb_cnfg (chnl<<6) /*lsb-байт конфигурации mcp3204: 0b d1d00 0000; */
/*выходные параметры */
#define voltage Mv /*усреднённое значение выходного напряжения */
#define current Mi /*усреднённое значение выходного тока */
/*внутренние параметры */
#define Vref_adc 4.096 /*Vref_adc = 4v096 */
#define Vref_dac 2.56 /*Vref_dac = 2v56 */
#define therm Mt /*усреднённое значение ацп термодатчика */
#define overload Mo /*усреднённое значение ацп выхода */
#define thrm_pwm_off 0xCE4 /*3 300 - уровень температуры отключение pwm по перегреву трансформатора PT (~90C)*/
#define thrm_pwm_on 0xB36 /*2 870 - уровень температуры включения pwm по охлаждению трансформатора PT (~75C)*/
#define thrm_fan_on 0xBB8 /*2 570 - уровень температуры включения fan по перегреву трансформатора PT (~65C)*/
#define thrm_fan_off 0x7D0 /*2 000 - уровень температуры отключения fan по охлаждению трансформатора PT (<50C)*/
#define cur_fan_on 0xC8 /*2.00a - значение выходного тока для включения fan */
#define cur_fan_off 0x96 /*1.50a - значение выходного тока для выключения fan */
#define ovrld_on 0xE1F /*3 615 - adc-code при перегрузке на выходе */
#define ovrld_off 0xCE4 /*3 330 - adc-code при нормальном состоянии выхода */
#define ovrcrs_on 0 /*0 - adc-code при переполюсовке на выходе */
#define ovrcrs_off 0x73A /*1 850 - adc-code при нормальном состоянии выхода */
/*предустановки выходных параметров */
#define V_prst vlt_prst /*уровень предустановки выходного напряжения */
#define I_prst cur_prst /*уровень предустановки выходного тока */
/*коэффициенты преобразования для вольтметра и амперметра */
#define Kv 0.1 /*коэффициент преобразования для вычисления напряжения Kv ~ 2*1/(4095*4.096/999)*/
#define Ki 0.07 /*коэффициент преобразования для вычисления тока Ki ~ 1.43*1/(4095*4.096/999)*/
/*коэффициенты сглаживания фильтров Кальмана */
#define Ks_t 0.025
#define Ks_o 0.025
#define Ks_v 0.05
#define Ks_i 0.05
/*DAC */
#define dac_cur 0x10 /*конфигурация для канала цап Vref_cur */
#define dac_vlt 0x90 /*конфигурация для канала цап Vref_vlt */
/*умножающие коэффиценты для формирования уровней опорных напряжений Vref_vlt/Vref_cur */
#define Kvlt 4.00 /*ref_vlt = cnt_enc_vlt * Kvlt ~ 4.1...4.2v max (Vref_dac = +2v56)*/
#define Kcur 4.00 /*ref_cur = cnt_enc_cur * Kcur ~ 4.1...4.2v max (Vref_dac = +2v56)*/
/*коэффициенты преобразования для предустановок preset вольтметра, амперметра */
#define Kv_st 1 /*Vset = vlt_enc_pls * Kv_st = 999*1.0 = 99.90v */
#define Ki_st 1 /*Iset = cur_enc_pls * Ki_st = 999*1.0 = 9.99a */
/*управление и индикация */
/*входы тактовых кнопок энкодеров */
#define out_on !(PIND&(1<<PIND2)) /*нажатие кнопки out_on/off: PD2_lo */
#define out_off PIND&(1<<PIND2) /*отпускание кнопки out_on/off: PD2_hi */
#define pwr_on !(PIND&(1<<PIND5)) /*нажатие кнопки pwr_on: PD5_lo */
#define pwr_off PIND&(1<<PIND5) /*отпускание кнопки pwr_off: PD5_hi */
/*знаки массива Sign[5]*/
#define A 0x77 /*Sgn[0] = A */
#define C 0x4E /*Sgn[1] = C */
#define E 0x4F /*Sgn[2] = E */
#define F 0x47 /*Sgn[3] = F */
#define H 0x37 /*Sgn[4] = H */
#define L 0x1C /*Sgn[5] = L */
#define O 0x7E /*Sgn[6] = O */
#define P 0x67 /*Sgn[7] = P */
#define S 0x5B /*Sgn[8] = S */
#define U 0x3E /*Sgn[8] = U */
//------------------------
/*состояния управляющих входов */
#define cc_mod PIND&(1<<PIND6) /*cc_mode: PD6_hi */
#define cv_mod !(PIND&(1<<PIND6)) /*cv_mod_mode: PD6_lo */
#define god_st PIND&(1<<PIND7) /*good_state: PD7_hi */
#define flt_st !(PIND&(1<<PIND7)) /*fault_state: PD7_lo */
//------------------------
/*выходы */
#define fan_on PORTC &= ~(1<<PORTC1) /*команда "fan_on_cmd"(PC1_lo)*/
#define fan_off PORTC |= (1<<PORTC1) /*команда "fan_off_cmd"(PC1_hi)*/
//------------------------
#define pwm_on PORTC &= ~(1<<PORTC2) /*команда включения стартового реле и контроллера "pwm_on_cmd"(PC2_lo)*/
#define pwm_off PORTC |= (1<<PORTC2) /*команда выключения стартового реле и контроллера "pwm_off_cmd"(PC2_hi)*/
//------------------------
#define rly_on PORTC &= ~(1<<PORTC3) /*команда включения выходного реле "rly_on_cmd"(PC3_lo)*/
#define rly_off PORTC |= (1<<PORTC3) /*команда выключения выходного реле "rly_off_cmd"(PC3_hi)*/
//------------------------
/*SPI (mode 0.0)*/
/*опрос внешнего 4-x канального adc */
#define CSA_lo PORTB &= ~(1<<PORTB0) /*CS_adc = 0*/
#define CSA_hi PORTB |= (1<<PORTB0) /*CS_adc = 1 */
/*отправка данных на внешний led_drv */
#define Ld_hi PORTB |= (1<<PORTB1) /*load = 1 */
#define Ld_lo PORTB &= ~(1<<PORTB1) /*load = 0 */
/*отправка данных на внешний 2-x канальный DAC */
#define CSD_lo PORTB &= ~(1<<PORTB2) /*CS_dac = 0*/
#define CSD_hi PORTB |= (1<<PORTB2) /*CS_dac = 1 */
//------------------------
#define MOSI_lo PORTB &= ~(1<<PORTB3) /*MOSI = 0 */
#define MOSI_hi PORTB |= (1<<PORTB3) /*MOSI = 1 */
//------------------------
#define SCK_lo PORTB &= ~(1<<PORTB5) /*CLK = 0 */
#define SCK_hi PORTB |= (1<<PORTB5) /*CLK = 1 */
//------------------------
/*инициализация прерываний по таймер_2 */
void intrpt_ini(void)
{
MCUCR = 0x00; /*сброс регистра MCUCR */
GICR = 0x00; /*сброс регистра GICR */
TIMSK |= (1<<OCIE2); /*устанавливаем бит разрешения прерывания счетчика по совпадению с OCR2*/
asm ("sei"); /*разрешение глобальных прерываний */
}
/*инициализация счётчика-таймера_2 */
void timer_2_ini(void)
{
ASSR = 0; /*сбрасываем полностью регистр ASSR */
TCCR2 = 0; /*сбрасываем полностью регистр TCCR2 */
TCCR2 |= (1<<WGM21); /* устанавливаем режим СТС (сброс по совпадению)*/
OCR2 = intrvl; /*записываем в регистр число interval для сравнения */
TCCR2 |= (1<<CS22)|(1<<CS21)|(1<<CS20); /*установим делитель Fosc/1024 = 15.625kHz */
}
/*функция записи данных в память */
void EEPROM_write(unsigned int uiAddress, unsigned char ucData)
{
cli(); /*запрет глобальных прерываний */
while(EECR & (1<<EEWE)){} /*ждем освобождения флага окончания последней операцией с памятью */
EEAR = uiAddress; /*устанавливаем адрес */
EEDR = ucData; /*пишем данные в регистр */
EECR |= (1<<EEMWE); /*разрешаем запись */
EECR |= (1<<EEWE); /*пишем байт в память */
sei(); /*разрешение глобальных прерываний */
}
/*функция чтения данных из памяти */
unsigned char EEPROM_read(unsigned int uiAddress)
{
cli(); /*запрет глобальных прерываний */
while(EECR & (1<<EEWE)){} /*ждем освобождения флага окончания последней операцией с памятью */
EEAR = uiAddress; /*устанавливаем адрес */
EECR |= (1<<EERE); /*запускаем операцию считывания из памяти в регистр данных */
sei(); /*разрешение глобальных прерываний */
return EEDR; /*возвращаем результат */
}
/*входы схемы управления */
void input_ini(void)
{
DDRD = 0x00; /*PD0-PD7 as input */
PORTD = 0xFF; /*PD0-PD7 pull-up enabled */
}
/*выходы схемы управления */
void output_ini(void)
{
/*команда fan_cmd_out */
DDRC |= (1<<PORTC1); /*PC1 as output */
PORTC |= (1<<PORTC1); /*PC1_hi */
/*команда pwm_cmd_out */
DDRC |= (1<<PORTC2); /*PC2 as output */
PORTC |= (1<<PORTC2); /*PC2_hi */
/*команда rly_cmd_out */
DDRC |= (1<<PORTC3); /*PC3 as output */
PORTC |= (1<<PORTC3); /*PC3_hi */
}
//------------------------
/*инициализация шины SPI */
void SPI_ini(void)
{
DDRB &= ~(1<<PORTB4); PORTB |= (1<<PORTB4); /*вход регистра SPDR MISO, pull-up=ON */
DDRB |= (1<<PORTB2)|(1<<PORTB1)|(1<<PORTB0); /*pin_out */
PORTB |= (1<<PORTB2)|(1<<PORTB1)|(1<<PORTB0); /*out_hi */
DDRB |= (1<<PORTB3); PORTB &= ~(1<<PORTB3); /*выход регистра SPDR MOSI_lo */
DDRB |= (1<<PORTB5); PORTB &= ~(1<<PORTB5); /*тактирующий сигнал SCK_lo */
SPCR |= (1<<SPE)|(1<<MSTR)|(1<<SPR1)|(1<<SPR0); /*включим шину SPI, объ§вим ведущим, SCK=16MHz/128=125kHz */
}
/*отправка байта в шину SPI */
void SPI_SendByte(unsigned char byte)
{
SPDR = byte; /*запуск передачи данных */
while(!(SPSR & (1<<SPIF))); /*ожидание завершения передачи данных */
}
//------------------------
/*приём байта из шины SPI */
unsigned char SPI_ChangeByte(char byte)
{
SPDR = byte;
while(!(SPSR & (1<<SPIF))); /*подождем пока данные передадутся/обменяются */
return SPDR; /*вернём содержимое регистра SPI */
}
/*функция опроса adc_thrm */
unsigned short rd_adc_thrm(char chnl) /*входной параметр: chnl_adc = 0 */
{
unsigned int b1, b2; /*4-х байтное пространство для битовых операций с байтами b1, b2 */
CSA_lo; /*флаг старта опроса ацп */
/*передача msb-байта; 5 нулевых бит (7.6.5.4.3); стартовый бит (2); выбор режима sngl/diff (1)*/
byte = msb_cnfg; /*strt_bit; sngl_end */
SPI_SendByte(byte); /*отправим в ацп msb-байт конфигурации ацп */
/*передача lsb-байта: выбор канала (7,6)*/
byte = lsb_cnfg; /*0b 0000 0000 */
b1 = SPI_ChangeByte(byte); /*отправим на обмен в ацп lsb-байт конфигурации ацп */
/*передача пустого байта */
byte = 0;
b2 = SPI_ChangeByte(byte); /*отправим на обмен в ацп пустой байт */
b1=(b1<<8)|b2; /*соберём из 2-х обменяных с ацп байтов результат преобразования adc_0 */
b1<<=4; b1>>=4; /*сотрём 4 старших незначащих бита */
CSA_hi; /*флаг окончания опроса ацп */
return (unsigned short)b1; /*возвращаем 12-битный результат ацп-преобразования */
}
/*функция опроса adc_cur */
unsigned short rd_adc_cur(char chnl) /*входной параметр: chnl_adc = 1 */
{
unsigned int b1, b2; /*4-х байтное пространство для битовых операций с байтами b1, b2 */
CSA_lo; /*флаг старта опроса ацп */
/*передача msb-байта; 5 нулевых бит (7.6.5.4.3); стартовый бит (2); выбор режима sngl/diff (1)*/
byte = msb_cnfg; /*strt_bit; sngl_end */
SPI_SendByte(byte); /*отправим в ацп msb-байт конфигурации ацп */
/*передача lsb-байта: выбор канала (7,6)*/
byte = lsb_cnfg; /*0b 0000 0000 */
b1 = SPI_ChangeByte(byte); /*отправим на обмен в ацп lsb-байт конфигурации ацп */
/*передача пустого байта */
byte = 0;
b2 = SPI_ChangeByte(byte); /*отправим на обмен в ацп пустой байт */
b1=(b1<<8)|b2; /*соберём из 2-х обменяных с ацп байтов результат преобразования adc_0 */
b1<<=4; b1>>=4; /*сотрём 4 старших незначащих бита */
CSA_hi; /*флаг окончания опроса ацп */
return (unsigned short)b1; /*возвращаем 12-битный результат ацп-преобразования */
}
/*функция опроса adc_vlt */
unsigned short rd_adc_vlt(char chnl) /*входной параметр: chnl_adc = 2 */
{
unsigned int b1, b2; /*4-х байтное пространство для битовых операций с байтами b1, b2 */
CSA_lo; /*флаг старта опроса ацп */
/*передача msb-байта; 5 нулевых бит (7.6.5.4.3); стартовый бит (2); выбор режима sngl/diff (1)*/
byte = msb_cnfg; /*strt_bit; sngl_end */
SPI_SendByte(byte); /*отправим в ацп msb-байт конфигурации ацп */
/*передача lsb-байта: выбор канала (7,6)*/
byte = lsb_cnfg; /*0b 0000 0000 */
b1 = SPI_ChangeByte(byte); /*отправим на обмен в ацп lsb-байт конфигурации ацп */
/*передача пустого байта */
byte = 0;
b2 = SPI_ChangeByte(byte); /*отправим на обмен в ацп пустой байт */
b1=(b1<<8)|b2; /*соберём из 2-х обменяных с ацп байтов результат преобразования adc_0 */
b1<<=4; b1>>=4; /*сотрём 4 старших незначащих бита */
CSA_hi; /*флаг окончания опроса ацп */
return (unsigned short)b1; /*возвращаем 12-битный результат ацп-преобразования */
}
/*функция опроса adc_ovrld */
unsigned short rd_adc_ovrld(char chnl) /*входной параметр: chnl_adc = 3 */
{
unsigned int b1, b2; /*4-х байтное пространство для битовых операций с байтами b1, b2 */
CSA_lo; /*флаг старта опроса ацп */
/*передача msb-байта; 5 нулевых бит (7.6.5.4.3); стартовый бит (2); выбор режима sngl/diff (1)*/
byte = msb_cnfg; /*strt_bit; sngl_end */
SPI_SendByte(byte); /*отправим в ацп msb-байт конфигурации ацп */
/*передача lsb-байта: выбор канала (7,6)*/
byte = lsb_cnfg; /*0b 0000 0000 */
b1 = SPI_ChangeByte(byte); /*отправим на обмен в ацп lsb-байт конфигурации ацп */
/*передача пустого байта */
byte = 0;
b2 = SPI_ChangeByte(byte); /*отправим на обмен в ацп пустой байт */
b1=(b1<<8)|b2; /*соберём из 2-х обменяных с ацп байтов результат преобразования adc_0 */
b1<<=4; b1>>=4; /*сотрём 4 старших незначащих бита */
CSA_hi; /*флаг окончания опроса ацп */
return (unsigned short)b1; /*возвращаем 12-битный результат ацп-преобразования */
}
/*функция опроса внешнего ацп mcp3204 */
void rd_adc(void)
{
rd_adc_thrm(0);
_delay_us(8);
rd_adc_cur(1);
_delay_us(8);
rd_adc_vlt(2);
_delay_us(8);
rd_adc_ovrld(3);
}
/*функция преобразования результата оцифровки в величину измеренного напряжения */
unsigned short ADCV_Conv(void)
{
/*vlt_value - 12-bit adc-code */
unsigned short dt_v; /*величина измеренного напряжения [V]*/
dt_v = vlt_value * Vref_adc * Kv; /*преобразование 12-bit adc-code в величину измеренного напряжения */
return dt_v; /*возвращаем величину измеренного напряжения в вольтах [V]*/
}
/*функция преобразования результата оцифровки в величину измеренного тока */
unsigned short ADCI_Conv(void)
{
/*cur_value - 12-bit adc-code */
unsigned short dt_i; /*величина измеренного тока [I]*/
dt_i = cur_value * Vref_adc * Ki; /*преобразование 12-битного числа в величину измеренного тока */
return dt_i; /*возвращаем величину измеренного тока в амперах [A]*/
}
/*функция конвертации результатов преобразований в выходные параметры Vout/Iout */
void ADC_Conv(void)
{
ADCV_Conv();
ADCI_Conv();
}
/*функция усреднения сигнала therm */
unsigned short thrm_avr(void)
{
thrm_value = rd_adc_thrm(0); /*считаем результат ацп_0 */
At=thrm_value; /*входной параметр сглаживающего фильра */
//фильтр Кальмана Mn=Ks*An + Mn1*(1-Ks)
Mt = Ks_t * At + Mt1 * (1-Ks_t); /*вычисляем среднее therm=Mt */
Mt1=Mt; /*усредним значение therm */
return (unsigned short)therm; /*возвращаем среднее therm */
}
/*функция измерения и усреднения сигнала voltage */
unsigned short vlt_avr(void)
{
vlt_value = rd_adc_vlt(2); /*считаем результат ацп_1 */
dt_v = ADCV_Conv(); /*преобразуем результат в величину измеренного напряжения [V]*/
Av=dt_v; //входной параметр сглаживающего фильра
//фильтр Кальмана Mn=Ks*An + Mn1*(1-Ks)
Mv = Ks_v * Av + Mv1 * (1-Ks_v); //вычисляем среднее Vavr_out=Mv
Mv1=Mv; //усредним значение Vavr = Vavr_out
return (unsigned short)voltage; /*возвращаем Vout [V]*/
}
/*функция измерения и усреднения сигнала current */
unsigned short cur_avr(void)
{
cur_value = rd_adc_cur(1); /*считаем результат ацп_2 */
dt_i = ADCI_Conv(); /*преобразуем результат в величину измеренного тока [I]*/
Ai=dt_i; //входной параметр сглаживающего фильтра
//фильтр Кальмана Mn=Ks*An + Mn1*(1-Ks)
Mi = Ks_i * Ai + Mi1 * (1-Ks_i); //вычисляем среднее Iavr_out=Mi
Mi1=Mi; //усредним значение Iavr = Iavr_out
return (unsigned short)current; /*возвращаем Iout [A]*/
}
/*функция усреднения сигнала overload */
unsigned short ovrld_avr(void)
{
ovrld_value = rd_adc_ovrld(3); /*считаем результат ацп_3 */
Ao=ovrld_value; /*входной параметр сглаживающего фильра */
//фильтр Кальмана Mn=Ks*An + Mn1*(1-Ks)
Mo = Ks_o * Ao + Mo1 * (1-Ks_o); /*вычисляем среднее ovrld=Mo */
Mo1=Mo; /*усредним значение ovrld */
return (unsigned short)overload; /*возвращаем среднее ovrld */
}
/*преобразование и усреднение параметров */
void avrg(void)
{
thrm_avr(); /*измерение и усреднение температуры */
vlt_avr(); /*измерение и усреднение Vout[V]*/
cur_avr(); /*измерение и усреднение Iout[A]*/
ovrld_avr(); /*измерение и усреднение выхода */
}
//------------------------
/*останов шим по перегреву трансформатора */
void pwm_halt(void)
{
/*во включенном состоянии, если сигнал с термодатчика ниже уровня thrm <= */
if(pwr_st == 1 && therm <= thrm_pwm_on)
{
pwm_on; /*включим шим */
}
/*если во включенном состоянии, сигнал с термодатчика возрос до thrm_value >= */
else if(pwr_st == 1 && therm >= thrm_pwm_off)
{
pwm_off; /*выключим шим */
}
}
/*старт FAN по температуре трансформатора */
void thrm_fan(void)
{
if(therm >= thrm_fan_on) /*если сигнал с термодатчика превысит thrm_value >= */
{
fan_on; /*включим FAN */
}
else if(therm <= thrm_fan_off) /*если сигнал с термодатчика снизиться до thrm_value <= */
{
fan_off; /*выключим FAN */
}
}
/*старт/стоп FAN по выходному току */
void cur_fan(void)
{
if(current >= cur_fan_on) /*если выходной ток превысит current >= 2.0a */
{
fan_on; /*включим FAN */
}
else if(current <= cur_fan_off) /*если выходной ток снизиться до current <= 1.5a */
{
fan_off; /*выключим FAN */
}
}
/*проверка FAN */
void fan_ini(void)
{
if(god_st) /*если, god_st = hi, то...*/
{fan_on; _delay_ms(2000); fan_off;} /*...включаем вентилятор на 2с */
}
/*защита от переполюсовки и перенаряжения на выходе */
char ovrld_out(void)
{
if(god_st && pwr_st == 1) /*проверяем условия */
{
/*выключение выходного реле по переполюсовке или перенапряжению на выходе */
/*если, во включенном состоянии реле, сигнал на входе chnl_3 0v < ovrld < 3.9v */
if(out_st == 1 && overload <= ovrld_on && overload >= ovrcrs_on)
{
ovl = 0; /*сбросим флаг перегрузка */
rly_on; /*включим выходное реле */
}
}
else{ovl = 1; rly_off;}
return ovl; /*вернём флаг */
}
/*опрос кнопки pwr_btn */
char pwr_btn(void) /*опрос кнопки pwr_btn: первое нажатие - pwr_on, второе - pwr_off с подавлением дребезга */
{
/*условие, которое выполнится при нажатии кнопки pwr_btn */
if(pwr_on && pwr_psh == 0) /*если кнопка pwr_btn нажата при сброшенном флаге "кнопка pwr_btn нажата", то...*/
{
pwr_cnt++; /*...инкрементируем счётчик антидребезга кнопки pwr_cnt, ... */
if(pwr_cnt >= btn_thrshld_max){pwr_cnt = btn_thrshld_max;} /*...также если, состояние счётчика >= +127, то останавливаем счёт на этом значении */
else
{ /*...также если, состояние счётчика >= +20, но меньше +127, то останавливаем счёт на этом значении и...*/
if (pwr_cnt >= btn_thrshld && pwr_cnt < btn_thrshld_max)
{
pwr_psh = 1; /*...поднимаем флаг "кнопка pwr_btn нажата" и...*/
pwr_st++; /*...меняем статус триггера pwr_st = hi */
}
} /*далее, если статус триггера принял значение pwr_st = hi, то...*/
if(pwr_st == 1) /*проверяем наличие разрешающих условий pwr_st = hi */
{
pwm_on; /*...включаем стартовое реле и шим-контроллер */
}
else /*иначе, если какое-либо условие включения не соблюдено */
{
pwr_st = 0; /*...сбрасываем статус триггера и...*/
pwm_off; /*...отключаем стартовое реле и шим-контроллер */
}
}
else if(pwr_off && pwr_psh == 1)
{
/*если кнопка pwr_btn нажата и отжата при установленном флаге "кнопка pwr_btn нажата", то...*/
pwr_cnt--; /*...декрементируем счётчик антидребезга кнопки pwr_btn, ... */
if (pwr_cnt <= 0){pwr_cnt = 0;} /*если состояние счётчика <= 0, то останавливаем счёт на этом значении и...*/
pwr_psh = 0; /*...сбрасываем флаг "кнопка pwr_btn нажата" */
}
return pwr_st; /*возвращаем флаг состояния триггера pwr_st */
}
//------------------------
/*управление стартовым реле и pwm-контроллером */
/*проверка на овервольтаж по входу (Vin < ac270v)*/
void inpt_rly_enbl(void)
{
/*если flt_st = hi */
if(god_st && pwr_st == 1){pwm_on;} /*проверка внешнего входа flt_st: если flt_st = 1,
включить входное реле */
else{pwm_off;} /*выключение стартового реле */
}
/*управление выходным реле */
/*проверка на включение pwr_on и овервольтаж по входу */
char outpt_rly_enbl(void)
{
if(god_st && pwr_st == 1){rly_enbl = 1;} /*поднять флаг разрешения включения выходного реле */
else{rly_enbl = 0; rly_off;} /*сбросить флаг */
return rly_enbl; /*возврат флага */
}
/*опрос кнопки out управления выходным реле rly_out */
char rly_out(void) /*опрос кнопки out_btn: первое нажатие - вкл, второе - выкл с подавлением дребезга */
{
/*условие, которое выполнится при нажатии кнопки out_rly, если god_st = hi & pwr_st = hi */
if(out_on && out_psh == 0 ) /*если кнопка out нажата при сброшенном флаге "кнопка out нажата", то...*/
{
out_cnt++; /*...инкрементируем счётчик out_cnt, ... */
if(out_cnt >= btn_thrshld_max){out_cnt = btn_thrshld_max;} /*...также если, состояние счётчика >= +127, то останавливаем счёт на этом значении */
else
{ /*иначе, если состояние счётчика >= +20, но меньше +127, то останавливаем счёт на этом значении и...*/
if (out_cnt >= btn_thrshld && out_cnt < btn_thrshld_max)
{
out_psh = 1; /*...поднимаем флаг "кнопка out нажата" и...*/
out_st++; /*...меняем статус триггера out_st = hi */
}
} /*далее, если статус триггера принял значение out_st = hi, то...*/
if(out_st == 1 && rly_enbl == 1 && pwr_st == 1) /*проверяем наличие разрешающих условий: rly_enbl, out_st и pwr_st */
{
rly_on; /*...включаем выходное реле */
}
else /*иначе ...*/
{
out_st = 0; /*...сбрасываем статус триггера и...*/
rly_off; /*...отключаем выходное реле */
}
}
/*условие, которое выполнится при отпускании кнопки out_btn */
else if(out_off && out_psh == 1) /*если кнопка out нажата и отжата при установленном флаге "кнопка out нажата", то...*/
{
out_cnt--; /*...декрементируем счётчик out_cnt, ... */
if (out_cnt <= 0){out_cnt = 0;} /*если состояние счётчика <= 0, то останавливаем счёт на этом значении и...*/
out_psh = 0; /*...сбрасываем флаг "кнопка out нажата" */
}
return out_st; /*возвращаем статус триггера out_st */
}
/*инициализация шины TWI*/
void TWI_ini(void)
{
TWSR |= (1<<TWPS0); /*F_SCL = 125kHz */
TWBR |= (1<<3); /*TWBR = 0b0000 1000 */
}
/*отправка в ведомое устройство условий старт передачи по шине TWI */
void TWI_StartCondition(void)
{
TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
/*пока флаг TWINT в регистре TWCR не поднят, выполняем цикл while */
while(!(TWCR&(1<<TWINT)));
}
/*отправка в ведомое устройство условий стоп передачи по шине TWI */
void TWI_StopCondition(void){TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN);}
/*функция передачи данных по шине TWI */
void TWI_SendByte(unsigned char Byte)
{
TWDR = Byte; /*запишем байт в регистр данных TWDR */
/*поднимаем флаги разрешений прерывания TWINT и включения шины TWEN */
TWCR = (1<<TWINT)|(1<<TWEN);
while(!(TWCR&(1<<TWINT))); /*ждём установки флага TWINT */
}
/*функция чтение/запись предустановок потенциометров RAM */
void RAM(char adres, unsigned char data)
{
TWI_StartCondition(); /*начало передачи данных */
TWI_SendByte(adres); /*передача управляющей команды/адреса ячейки озу */
TWI_SendByte(data); /*чтение/запись ячейки озу */
TWI_StopCondition(); /*завершение передачи данных */
}
/*функция чтения ячейки adrs RAM */
unsigned char RAM_rd(char adrs)
{
adres = 0xC1 | adrs; /*address = 0b1100 0001 */
RAM(adres, data); /*чтение предустановок потенциометров RAM */
return (unsigned char)mem_byte; /*вернём считанный байт данных RAM */
}
/*функция записи в ячейку adrs RAM */
void RAM_wr(char adrs, unsigned char mem_byte)
{
adres = 0xC0 | adrs; /*address = 0b1100 0000 */
data = cnt_enc_vlt;
RAM(adres, data); /*запись предустановок потенциометров RAM */
}
//------------------------
/*энкодер опорного сигнала vlt_prst */
char enc_vlt_prst(void)
{
static unsigned char idle_ticks = 0; /* Счётчик тиков прерывания (по ~4.16мс)*/
unsigned short step = 1; /* Текущий шаг приращения */
/* Увеличиваем счётчик простоя с защитой от переполнения переменной */
if(idle_ticks < 255) idle_ticks++;
if(spn_enc_vlt & (1<<0)) /*определяем , было или нет зафиксировано вращение энкодера enc_vlt_prst */
{
if(clk_vlt){} /*если clk = hi... */
else
{
if(dt_vlt){} /*...также , если dt = hi...*/
else
spn_enc_vlt = 0; /*...то вращения не зафиксировано : spn_enc_vlt = 0 */
}
}
else /*проверка на вращение по часовой стрелке cw */
{
if(clk_vlt){} /*проверка pin_clk на 0 */
else
{
if(dt_vlt) /*проверка pin_dt на 1 */
{
spn_enc_vlt |= (1<<0); /*зафиксировано вращение cw: spn_enc_vlt = 1 */
/* --- ВРЕМЕННОЙ ВЫЧИСЛИТЕЛЬ ШАГА --- */
if(idle_ticks < 8) step = 20; /* Очень быстро : < ~33 мс между тиками */
else if(idle_ticks < 20) step = 5; /* Средне : < ~83 мс между тиками */
else step = 1; /* Медленно : точная доводка */
idle_ticks = 0; /* Сбрасываем счётчик времени */
/* Применяем шаг с проверкой на верхний предел TOP = 999 */
if(cnt_enc_vlt + step <= enc_vlt_top)
{
cnt_enc_vlt += step;
}
else
{
cnt_enc_vlt = enc_vlt_top; /* Упираемся ровно в потолок */
}
}
}
/*проверка на вращение против часовой стрелки ccw */
if(dt_vlt){} /*проверка pin_dt на 0 */
else
{
if(clk_vlt) /*проверка pin_clk на 1 */
{
spn_enc_vlt |= (1<<0); /*зафиксировано вращение сcw: spn_enc_vlt = 1 */
/* --- ВРЕМЕННОЙ ВЫЧИСЛИТЕЛЬ ШАГА --- */
if(idle_ticks < 8) step = 20;
else if(idle_ticks < 20) step = 5;
else step = 1;
idle_ticks = 0;
/* Применяем шаг с проверкой на нижний предел BOTTOM = 0 */
if(cnt_enc_vlt >= step) cnt_enc_vlt -= step;
else cnt_enc_vlt = 0; /* Упираемся ровно в пол */
}
}
}
return spn_enc_vlt; /*возвращаем флаг */
}
/*энкодер опорного сигнала cur_prset */
char enc_cur_prst(void)
{
static unsigned char idle_ticks = 0; /* Счётчик тиков прерывания (по ~4.16мс)*/
unsigned short step = 1; /* Текущий шаг приращения */
/* Увеличиваем счётчик простоя с защитой от переполнения переменной */
if(idle_ticks < 255) idle_ticks++;
if(spn_enc_cur & (1<<0)) /*определяем , было или нет зафиксировано вращение энкодера enc_cur_prst */
{
if(clk_cur){} /*если clk = hi... */
else
{
if(dt_cur){} /*...также , если dt = hi...*/
else
spn_enc_cur = 0; /*...то вращения не зафиксировано : spn_enc_cur = 0 */
}
}
else /*проверка на вращение по часовой стрелке cw */
{
if(clk_cur){} /*проверка pin_clk на 0 */
else
{
if(dt_cur) /*проверка pin_dt на 1 */
{
spn_enc_cur |= (1<<0); /*зафиксировано вращение cw: spn_enc_cur = 1 */
/* --- ВРЕМЕННОЙ ВЫЧИСЛИТЕЛЬ ШАГА --- */
if(idle_ticks < 8) step = 20; /* Очень быстро : < ~33 мс между тиками */
else if(idle_ticks < 20) step = 5; /* Средне : < ~83 мс между тиками */
else step = 1; /* Медленно : точная доводка */
idle_ticks = 0; /* Сбрасываем счётчик времени */
/* Применяем шаг с проверкой на верхний предел TOP = 999 */
if(cnt_enc_cur + step <= enc_cur_top)
{
cnt_enc_cur += step;
}
else
{
cnt_enc_cur = enc_cur_top; /* Упираемся ровно в потолок */
}
}
}
/*проверка на вращение против часовой стрелки ccw */
if(dt_cur){} /*проверка pin_dt на 0 */
else
{
if(clk_cur) /*проверка pin_clk на 1 */
{
spn_enc_cur |= (1<<0); /*зафиксировано вращение сcw: spn_enc_cur = 1 */
/* --- ВРЕМЕННОЙ ВЫЧИСЛИТЕЛЬ ШАГА --- */
if(idle_ticks < 8) step = 20;
else if(idle_ticks < 20) step = 5;
else step = 1;
idle_ticks = 0;
/* Применяем шаг с проверкой на нижний предел BOTTOM = 0 */
if(cnt_enc_cur >= step) cnt_enc_cur -= step;
else cnt_enc_cur = 0; /* Упираемся ровно в пол */
}
}
}
return spn_enc_cur; /*возвращаем флаг */
}
/*опрос энкодеров */
void enc_prst(void)
{
if(pwr_st == 1) /*блокировка энкодеров в выключенном состоянии */
{
enc_vlt_prst(); /*опрос энкодера Vprst */
enc_cur_prst(); /*опрос энкодера Iprst */
}
}
/*формирование опорного напряжения Vref_vlt */
unsigned short ref_vlt(void)
{
Vref_vlt = Kvlt * cnt_enc_vlt; /*для выполнения условия: 0 <= vol_vlt <= +5v1 */
return (unsigned short)Vref_vlt;
}
/*формирование опорного напряжения Vref_cur */
unsigned short ref_cur(void)
{
Vref_cur = Kcur * cnt_enc_cur; /*для выполнения условия: 0 <= vol_cur <= +5v1 */
return (unsigned short)Vref_cur;
}
/*формирование опорных напряжений Vref_vlt/Vref_cur */
void rfrns(void)
{
ref_vlt();
ref_cur();
}
/*отправка конфигураций и пресетов Vref_vlt/Vref_cur в vlt_dac/cur_dac */
void send_dac(void)
{
unsigned short vlt_1, vlt_2; /*2-х байтные переменные */
vlt_1 = Vref_vlt; /*присваимаем vlt_1 */
vlt_1 <<= 8;
vlt_1 >>= 8; /*стираем старшие 8 бит vol_vlt */
vlt_2 = Vref_vlt; /*присваимаем b2 */
vlt_2 <<= 4; /*стираем старшие незначащие 4 бита vol_vlt */
vlt_2 >>= 12; /*стираем младшие 8 бит vol_vlt */
unsigned short cur_1, cur_2; /*2-х байтные переменные */
cur_1 = Vref_cur; /*присваимаем b1 */
cur_1 <<= 8;
cur_1 >>= 8; /*стираем старшие 8 бит vol_cur */
cur_2 = Vref_cur; /*присваимаем b2 */
cur_2 <<= 4; /*стираем старшие незначащие 4 бита vol_cur */
cur_2 >>= 12; /*стираем младшие 8 бит vol_cur */
cmd_cur = dac_cur|cur_2; /*(0b 0001 0000): выбор канала dac_B; буфер Vref отключен; Vout=2Vref; out_B = enbld */
cmd_vlt = dac_vlt|vlt_2; /*(0b 1001 0000): выбор канала dac_A; буфер Vref отключен; Vout=2Vref; out_A = enbld */
CSD_lo; /*старт отправки данных в cur_dac */
msb = cmd_cur; /*биты конфигурации и старшая часть слова vol_cur */
SPI_SendByte(msb); /*отправляем байт msb в шину SPI */
lsb = cur_1; /*младшая часть слова vol_cur */
SPI_SendByte(lsb); /*отправляем байт lsb в шину SPI */
CSD_hi; /*загрузка данных в vlt_dac */
asm ("nop");
CSD_lo; /*старт отправки данных в vlt_dac */
msb = cmd_vlt; /*биты конфигурации и старшая часть слова vol_vlt */
SPI_SendByte(msb); /*отправляем байт msb в шину SPI */
lsb = vlt_1; /*младшая часть слова vol_vlt */
SPI_SendByte(lsb); /*отправляем байт lsb в шину SPI */
CSD_hi; /*загрузка данных в vlt_dac */
}
/*выключение цап */
void dac_off(void)
{
cmd_vlt = 0; cmd_cur = 0;
Vref_vlt = 0; Vref_cur = 0;
send_dac();
}
/*управление цап */
void dac(void)
{
if(!pwr_st) /*если, питание выключено (pwr_st = lo) */
{
dac_off(); /*выключить dac */
}
else
{
send_dac(); /*в противном случае, разрешить работу dac*/
}
}
//------------------------
/*функция преобразования счётчика импульсов энкодера enc_vlt в уровень предустановки Vprst = 0...99.9v */
unsigned short vlt_cnv(void)
{
vlt_prst = cnt_enc_vlt * Kv_st; /*vlt_prst = 999 * 1.0 = 99.9v */
return vlt_prst; /*возвращаем величину предустановленного напряжения в вольтах [V]*/
}
/*функция преобразования счётчика оборотов энкодера enc_cur в уровень предустановки Iprst = 0...9.99a */
unsigned short cur_cnv(void)
{
cur_prst = cnt_enc_cur * Ki_st; /*cur_prst = 999 * 1.0 = 9.99a */
return cur_prst; /*возвращаем величину предустановленного тока в амперах [A]*/
}
/*конвертация оборотов энкодеров в пресеты Vprst/Iprst */
void cnt_cnv(void)
{
vlt_cnv(); /*Vprst = 0...99.9v */
cur_cnv(); /*Iprst = 0...9.99a */
}
//------------------------
/*функция сохранения положений энкодеров в eeprom при выключении питания */
void wr_enc_st(void)
{
strg_h_vlt = cnt_enc_vlt>>8; /*сотрём младший байт переменной и запишем результат в байт mem_h_vlt */
strg_l_vlt = cnt_enc_vlt<<8; /*сотрём старший байт переменной и запишем результат в байт mem_l_vlt */
strg_h_cur = cnt_enc_cur>>8; /*сотрём младший байт переменной и запишем результат в байт mem_h_cur */
strg_l_cur = cnt_enc_cur<<8; /*сотрём старший байт переменной и запишем результат в байт mem_l_cur */
if(pwr_st){}
else /*сохраняем байты в ячейки eeprom при выключении питания */
{
EEPROM_write(rg_h_vlt, strg_h_vlt); /*сохраняем старший байт strg_h_vlt в ячейку rg_h_vlt */
EEPROM_write(rg_l_vlt, strg_l_vlt); /*сохраняем младший байт mem_l_vlt в ячейку rg_l_vlt */
EEPROM_write(rg_h_cur, strg_h_cur); /*сохраняем старший байт mem_h_cur в ячейку rg_h_cur */
EEPROM_write(rg_l_cur, strg_l_cur); /*сохраняем младший байт mem_h_vlt в ячейку rg_h_vlt */
}
}
/*функция чтения байтов пресета rd_enc_vlt из eeprom при включении питания */
void rd_enc_st(void)
{
unsigned short b1, b2; /*2-х байтные переменные */
if(pwr_st) /*считываем байты из ячеек eeprom при включении питания */
{
strg_h_vlt = EEPROM_read(rg_h_vlt); /*считываем переменную с еепром (адрес rg_h_vlt)*/
strg_l_vlt = EEPROM_read(rg_l_vlt); /*считываем переменную с еепром (адрес rg_l_vlt)*/
strg_h_cur = EEPROM_read(rg_h_cur); /*считываем переменную с еепром (адрес rg_h_cur)*/
strg_l_cur = EEPROM_read(rg_l_cur); /*считываем переменную с еепром (адрес rg_l_cur)*/
b1 = strg_h_vlt<<8; /*перемещаем старшие биты в старший байт */
b2 = strg_h_cur<<8; /*перемещаем старшие биты в старший байт */
cnt_enc_vlt = b1|strg_l_vlt; /*складываем старший и младший байты в 2-х байтное слово */
cnt_enc_cur = b2|strg_l_cur; /*складываем старший и младший байты в 2-х байтное слово */
}
else{}
}
/*отправка данных в led_drv max7219 */
void send_drv(unsigned char rg, unsigned char dt)
{
Ld_lo; /*старт передачи */
/*отправка данных в драйвер led_drv_0 */
byte = rg; /*адресный байт */
SPI_SendByte(byte);
byte = dt; /*байт данных */
SPI_SendByte(byte);
Ld_hi; /*загрузка данных в регистры хранения */
}
/*выключаем декодирование led_drv */
void drv_sgn_ini(void)
{
send_drv(0x09, 0x00); /*выключаем режим декодирования для всех разрядов */
send_drv(0x0B, 0x07); /*количество сканируемых разрядов дисплея: 0-7 */
send_drv(0x0A, 0x0A); /*DC=21/32 - яркость свечения */
send_drv(0x0C, 0x01); /*drv_on */
}
/*настройка led_drv на декодирование */
void drv_dgt_ini(void)
{
send_drv(0x09, 0xFF); /*включаем режим декодирования для всех разрядов */
send_drv(0x0B, 0x07); /*количество сканируемых разрядов дисплея: 0-7 */
send_drv(0x0A, 0x0A); /*DC=21/32 - яркость свечения */
send_drv(0x0C, 0x01); /*drv_on */
/*dg - количество сканируемых разрядов led-драйвера */
for(dg=1;dg<9;dg++) /*цикл передачи данных dt[rg] для адресов с 1 по 8 */
{
/*B-code (0x0F) = blank digit */
send_drv(dg, 0x0F); /*гасим все разряды до момента вывода информации */
}
}
/*очистка дисплея */
void clr_drv(void)
{
send_drv(0x0C, 0); /*команда drv_dsbl */
return;
}
/*-.H.E.L.L.O.*/
void ledprint_hello(void)
{
Dgt[1] = 0x08; /*8 */
Dgt[1] = Dgt[1]|0x80; /*dp */
Dgt[2] = 0x08; /*8*/
Dgt[2] = Dgt[2]|0x80; /*dp */
Dgt[3] = 0x00; /*O*/
Dgt[3] = Dgt[3]|0x80; /*dp */
Dgt[4] = 0x0D; /*L*/
Dgt[4] = Dgt[4]|0x80; /*dp */
Dgt[5] = 0x0D; /*L*/
Dgt[5] = Dgt[5]|0x80; /*dp */
Dgt[6] = 0x0B; /*E*/
Dgt[6] = Dgt[6]|0x80; /*dp */
Dgt[7] = 0x0C; /*H*/
Dgt[7] = Dgt[7]|0x80; /*dp */
Dgt[8] = 0x0A; /*-*/
Dgt[8] = Dgt[8]|0x80; /*dp */
for(M=1;M<9;M++) /*начнём цикл отправки символов в разряды 1-8 дисплея */
{
dt_in[M] = Dgt[M]; /*присвоим элементам массива dt_in[M] значения из массива Dgt[M] */
send_drv(M, dt_in[M]); /*отправим байты dt_in[M] в разряды 1-8 дисплея */
}
}
/*разложение знаков символа AC_FAULT по разрядам дисплея */
void ac_flt(void)
{
Dgt[8] = 0x0A; /*-*/
Dgt[7] = 0x0A; /*-*/
Dgt[6] = 0x0A; /*-*/
Dgt[1] = 0x0A; /*-*/
Dgt[5] = 0x0A; /*-*/
Dgt[4] = 0x0A; /*-*/
Dgt[3] = 0x0A; /*-*/
Dgt[2] = 0x0A; /*-*/
for(flt=1;flt<9;flt++) /*начнём цикл отправки символов в разряды 1-8 дисплея */
{
dt_in[flt] = Dgt[flt]; /*присвоим элементам массива dt_in[flt] значения из массива Dgt[flt] */
send_drv(flt, dt_in[flt]); /*отправим байты dt_in[flt] в разряды - дисплея */
}
}
/*разложение знаков символа OVERHEAT по разрядам дисплея */
void overht(void)
{
Dgt[8] = 0x0C; /*H */
Dgt[7] = 0x0C; /*H */
Dgt[6] = 0x0C; /*H */
Dgt[1] = 0x0C; /*H */
Dgt[5] = 0x0C; /*H */
Dgt[4] = 0x0C; /*H */
Dgt[3] = 0x0C; /*H */
Dgt[2] = 0x0C; /*H */
for(ovht=1;ovht<9;ovht++) /*начнём цикл отправки символов в разряды 1-8 дисплея */
{
dt_in[ovht] = Dgt[ovht]; /*присвоим элементам массива dt_in[ovht] значения из массива Dgt[ovht] */
send_drv(ovht, dt_in[ovht]); /*отправим байты dt_in[ovht] в разряды - дисплея */
}
}
/*разложение знаков символа OVERLOAD по разрядам дисплея */
void overld(void)
{
Dgt[8] = 0x0D|0x80; /*.*/
Dgt[7] = 0x0C|0x80; /*.*/
Dgt[6] = 0x0D|0x80; /*.*/
Dgt[1] = 0x0D|0x80; /*.*/
Dgt[5] = 0x0D|0x80; /*.*/
Dgt[4] = 0x0D|0x80; /*.*/
Dgt[3] = 0x0D|0x80; /*.*/
Dgt[2] = 0x0D|0x80; /*.*/
for(ovld=1;ovld<9;ovld++) /*начнём цикл отправки символов в разряды 1-8 дисплея */
{
dt_in[ovld] = Dgt[ovld]; /*присвоим элементам массива dt_in[ovld] значения из массива Dgt[ovld] */
send_drv(ovld, dt_in[ovld]); /*отправим байты dt_in[ovld] в разряды - дисплея */
}
}
/*разложение переменной number по разрядам вольтметра (Dgt[6]-Dgt[8]) */
void number_vlt(unsigned short number) /*целое число из регистра number */
{
if(number <= 0x3E7) /*если Vout <= 99.9v, то выводим на дисплей результат */
{
Dgt[8] = number/100 ? number/100 : 0x0F; /*сотни /гасим старший незначащий нуль */
Dgt[7] = number%100/10; /*десятки */
Dgt[7] = Dgt[7]|0x80; /*вкл децимальную точку в разряде Digit_7 */
Dgt[6] = number%10; /*единицы */
}
else /*иначе, выводим на дисплей <OL-> (overload) */
{
Dgt[8]=0x00; /*O*/
Dgt[7]=0x0D; /*L*/
Dgt[6]=0x0A; /*-*/
}
/*цикл отправки в разряды led-драйвера по адресам rg = 6-8 данных dt[rg] = number/x */
for(V=6;V<9;V++) /*заполняем разряды вольтметра цифрами разложенного Vprst/Vout */
{
dt_in[V] = Dgt[V]; /*присвоим элементам массива dt_in[V] значения из массива Dgt[V] */
send_drv(V, dt_in[V]); /*отправим байты dt_in[V] по разрядам 6-8 драйвера */
}
}
/*разложение переменной number по разрядам амперметра (Dgt[3]-Dgt[5]) */
void number_cur(unsigned short number) /*целое число из регистра number */
{
if(number <= 0x3E7) /*если Iout <= 9.99a, то выводим на дисплей результат */
{
Dgt[5] = number/100; /*единицы */
Dgt[5] = Dgt[5]|0x80; /*вкл децимальную точку в разряде Digit_5 */
Dgt[4] = number%100/10; /*десятые доли */
Dgt[3] = number%10; /*сотые доли */
}
else /*иначе, выводим на дисплей <OL-> (overload) */
{
Dgt[5]=0x00; /*O*/
Dgt[4]=0x0D; /*L*/
Dgt[3]=0x0A; /*-*/
}
/*цикл отправки в разряды led-драйвера по адресам rg = 3-5 данных dt[rg] = number/x */
for(I=3;I<6;I++) //заполняем разряды вольтметра цифрами разложенного Iset
{
dt_in[I] = Dgt[I]; /*присвоим элементам массива dt_in[I] значения элементов из массива Dgt[I] */
send_drv(I, dt_in[I]); /*отправим байты dt_in[I] по разрядам 3-5 драйвера */
}
}
/*индикация FAULT */
void ledprint_flt(void)
{
if(pwr_st) /*если pwr_st = 1 */
{
drv_dgt_ini();
if(flt_st){ac_flt();} /*ac_fault */
}
else{clr_drv();}
}
/*индикация OVRHEAT */
void ledprint_ovrht(void)
{
if(pwr_st) /*если pwr_st = 1 */
{
drv_dgt_ini();
if(therm >= thrm_pwm_off){overht();} /* */
}
else{clr_drv();}
}
/*индикация OVRLOAD */
void ledprint_ovrld(void)
{
if(pwr_st) /*если pwr_st = 1 & god_st = 0 */
{
drv_dgt_ini();
if(ovl){overld();} /*если флаг ovl = 1: overload */
}
else{clr_drv();}
}
void ledprint(void)
{
/*если out_st = 0 */
if(pwr_st && !out_st && god_st && !ovh)/* && !ovl)*/
{
drv_dgt_ini();
number_vlt(V_prst); /*отправим V_prst на индикатор вольтметра */
number_cur(I_prst); /*отправим I_prst на индикатор амперметра */
}
else{clr_drv();} /*если pwr_st = 0 гасим индикатор */
/*если out_st = 1 */
if(pwr_st && out_st && god_st)/**/
{
drv_dgt_ini();
number_vlt(voltage); /*отправим Vout на индикатор вольтметра */
number_cur(current); /*отправим Iout на индикатор амперметра */
}
else{clr_drv();} /*если pwr_st = 0 гасим индикатор */
if(pwr_st && flt_st) /*если flt_st = 1 */
{
drv_dgt_ini();
ac_flt(); /*ac_fault */
}
else{clr_drv();} /*если pwr_st = 0 гасим индикатор */
// if(pwr_st && therm >= thrm_pwm_off) /* */
// {
// drv_dgt_ini();
//
// overht(); /* */
// }
// else{clr_drv();} /*если pwr_st = 0 гасим индикатор */
// if(pwr_st && overload < 0xBB8 && overload > 0x200) /*если pwr_st = 1 */
// {
// drv_dgt_ini();
//
// overld(); /*если флаг ovl = 1: overload */
// }
// else{clr_drv();}
}
/*обработчик прерываний счётчика-таймера_2 */
ISR (TIMER2_COMP_vect)
{
rd_adc(); /*опрос внешнего ацп */
ADC_Conv(); /*оцифровка выходных параметров Vout/Iout */
avrg(); /*преобразование и усреднение параметров */
inpt_rly_enbl(); /*проверка условий запуска стартового реле перед включением и мгновенное отключение */
pwr_btn(); /*опрос кнопки pwr_on */
outpt_rly_enbl(); /*проверка условий запуска выходного реле перед включением и мгновенное отключение */
rly_out(); /*опрос кнопки out_on */
pwm_halt(); /*останов шим по перегреву */
thrm_fan(); /**/
cur_fan(); /**/
ovrld_out(); /*защита от переполюсовки и перенаряжения на выходе */
enc_prst(); /*опрос энкодеров */
rfrns(); /*формирование опорных напряжений Vref_vlt/Vref_cur */
cnt_cnv(); /*конвертация импульсов энкодеров в пресеты Vprst/Iprst */
dac(); /*включение и отправка данных в dual DAC */
ledprint(); /*вывод выходных параметров V/I на дисплей */
}
int main(void)
{
/*адреса RAM для чтения последних предустановок потенциометров Vprst/Iprst */
vlt = 2; /*адрес vlt = 2 */
cur = 4; /*адрес cur = 4 */
/*адреса eeprom для чтения последних положений энкодеров Vprst/Iprst поред выключением */
rg_h_vlt = 1; /*адрес старшего байта данных положения энкодера enc_vlt_set в eeprom */
rg_l_vlt = 2; /*адрес младшего байта данных положения энкодера enc_vlt_set в eeprom */
rg_h_cur = 3; /*адрес старшего байта для сохранения положения энкодера enc_cur_set в eeprom */
rg_l_cur = 4; /*адрес младшего байта для сохранения положения энкодера enc_cur_set в eeprom */
/*счётчики импульсов энкодеров */
cnt_enc_vlt = 0; /*сброс счётчиков */
cnt_enc_cur = 0;
/*флаги кнопки pwr_btn */
pwr_cnt = 0; /*сброс счётчика антидребезга кнопки pwr_btn */
pwr_psh = 0; /*срос флага "нажатие на кнопку pwr_btn */
pwr_st = 0; /*сброс триггера кнопки pwr_btn */
/*флаги кнопки out_rly */
out_cnt = 0; /*сброс счётчика антидребезга кнопки out_rly btn */
out_psh = 0; /*срос флага "нажатие на кнопку out_rly btn */
out_st = 0; /*сброс триггера кнопки out_rly */
/*шина TWI */
// TWI_ini(); /*инициализация шины TWI */
// RAM(adres, data); /*функция чтение/запись RAM */
// RAM_rd(adrs); /*функция чтения ячейки adrs RAM */
// RAM_wr(adrs, mem_byte); /*функция записи в ячейку adrs RAM */
// Vref_vlt = RAM_rd(adrs); /*читаем данные 2 ячейки RAM и присваиваем переменной Vref_vlt */
// Vref_cur = RAM_rd(adrs); /*читаем данные 4 ячейки RAM и присваиваем переменной Vref_cur */
/*шина SPI */
SPI_ini(); /*инициализация шины SPI */
SPI_SendByte(byte); /*отправка данных в шину SPI */
SPI_ChangeByte(byte); /*приём данных из шины SPI */
/*порты вход/выход*/
input_ini(); /*инициализация входов */
output_ini(); /*инициализация выходов */
pwr_btn();
rd_enc_st(); /*функция чтения байтов пресетов из eeprom при включении питания */
drv_dgt_ini(); /*настройка led_drv на декодирование */
ledprint_hello(); /*приветствие */
fan_ini(); /*проверка fan start 2s */
timer_2_ini(); /*инициализация счётчика-таймера_2 */
intrpt_ini(); /*разрешение прерываний */
_delay_ms(2000); /*задержка pwm_cmd_dly = 2s */
while(1) /*основной цикл */
{
// pwr_btn(); /*опрос кнопки pwr_on */
// rd_enc_st(); /*функция чтения байтов пресетов из eeprom при включении питания */
// wr_enc_st();
// clr_drv(); /*очистка дисплея */
}
}



