Пн сен 06, 2021 07:43:09
Пн сен 06, 2021 08:17:00
Пн сен 06, 2021 08:28:03
ну, если тебе нравится такая фигня, то зачем оно другим?Starichok51 писал(а):а если автокоррекция успела набрать, допустим, код для 4,6А, а нагрузка захотела взять больше 4,6А (или сделали кз), то в первый момент ток будет 4,6А. и тут же коррекция начнет снижать ток к установленному значению 3А.
Пн сен 06, 2021 08:41:57
Пн сен 06, 2021 10:52:55
это костыли для кривого алгоритмаStarichok51 писал(а): нужно ограничить коррекцию 10-15 единицами, чтобы далеко не убежало
а крутить ручку физически нет необходимости, "крутит ручку" твой чудо-алгоритмStarichok51 писал(а):установка задания и рабочий режим у меня разделены.
устанавливать надо только в режиме "стоп". рабочем режиме крутить ручку бесполезно, так как после пуска запоминается установленное значение.
#define ROUNDS (1024 * 2)
. . .
res += ((adc1 * 4550.0 / 102.4 / ROUNDS) - res) * 0.125;
Пн сен 06, 2021 17:55:48
для тока самый раз, максимум 4,550А, разрешение 0,1миллиА.slav0n писал(а):а нафига?
Пн сен 06, 2021 18:24:31
Пн сен 06, 2021 18:43:01
Пн сен 06, 2021 19:43:37
Пн сен 06, 2021 19:46:22
Пн сен 06, 2021 19:50:50
Сб сен 11, 2021 08:39:41
#define ROUNDS 1024
. . .
res1 += (((adc1 >> 5) * 4550 / 1024 / (ROUNDS >> 5)) - res1) >> 2;
Вт сен 26, 2023 15:38:49
[code]//ATmega_8A + max7219 + mcp3201_0 + mcp3201_1
//va-meter +0...399.99vdc / +0...9.999adc
//16MHz
#define F_CPU 16000000UL //тактовая частота мк (unsigned long)
#include <avr/io.h> //подключение библиотеки "ввод/вывод" мк
#include <util/delay.h> //подключение библиотеки "пауза" мк
#include <avr/interrupt.h> //подключение библиотеки "прерывание" мк
#define Vref 4.096 //+Vref=4.096vdc
#define Kv 4.195 //коэффициент преобразования для вычислнения величины [V] Kv=4096*4.096/3999
#define Ki 1.678 //коэффициент преобразования для вычислнения величины [I] Ki=4096*4.096/9999
#define ADC_CS0_0 PORTB &= ~(1<<PORTB0) //ADC_CS0=0
#define ADC_CS0_1 PORTB |= (1<<PORTB0) //ADC_CS0=1
#define ADC_CS1_0 PORTB &= ~(1<<PORTB2) //ADC_CS1=0
#define ADC_CS1_1 PORTB |= (1<<PORTB2) //ADC_CS1=1
#define ADC_CLK_0 PORTB &= ~(1<<PORTB5) //ADC_CLK=0
#define ADC_CLK_1 PORTB |= (1<<PORTB5) //ADC_CLK=1
#define DRV_CLK_0 PORTC &= ~(1<<PORTC0) //DRV_CLK=0
#define DRV_CLK_1 PORTC |= (1<<PORTC0) //DRV_CLK=1
#define DRV_CS_0 PORTC &= ~(1<<PORTC1) //DRV_CS=0
#define DRV_CS_1 PORTC |= (1<<PORTC1) //DRV_CS=1
#define DRV_MOSI_0 PORTC &= ~(1<<PORTC2) //DRV_MOSI=0
#define DRV_MOSI_1 PORTC |= (1<<PORTC2) //DRV_MOSI=1
#define measure 0x01 // по результатам 1 измерений вычислить средне-арифметическое значение (VOLn=1+...+VOLn=1)/1
//----------
unsigned int Digit[8]; //массив беззнаковых целочисленных переменных Digit из 8 переменных (8 разрядов драйвера 7seg LED-дисплея)
unsigned char DRV_MOSI[8]; //массив беззнаковых однобайтных символьных переменных DRV_MOSI из 8 переменных (адреса и команды для конфигурирования драйвера)
unsigned int Display2_ADC; //беззнаковая целочисленная переменная Display2_ADC
unsigned char V; //беззнаковая однобайтная символьная переменная V (значение регистра ацп с результатом оцифровки напряжения)
unsigned char I; //беззнаковая однобайтная символьная переменная I (значение регистра ацп с результатом оцифровки тока)
unsigned int adc_conv count; // переменная для задержки обновления данных на индикаторах
unsigned int dt_v; //12-битный результат оцифровки величины [V]
float Av; //Av=dt_v
float Mv; //окончательный результат работы сглаживающего фильтра в канале [V]
float Mv1 = 0; //сброс промежуточного результата работы сглаживающего фильтра в канале [V]
float Ks_v = 0.05; //коэффициент сглаживания в канале [V]
unsigned int dt_i; //12-битный результат оцифровки величины [I]
float Ai; //Ai=dt_i
float Mi; //окончательный результат работы сглаживающего фильтра в канале [I]
float Mi1 = 0; //сброс промежуточного результата работы сглаживающего фильтра в канале [I]
float Ks_i = 0.05; //коэффициент сглаживания в канале [I]
//--- инициализация CS0 ---
void CS0_ini(void) //функция инициализации порта PB0
{
DDRB |= (1<<PORTB0); //PB0 на вывод
PORTB |= (1<<PORTB0); //PB0_hi
}
//--- инициализация CS1 ---
void CS1_ini(void) //функция инициализации порта PB2
{
DDRB |= (1<<PORTB2); //PB2 на вывод
PORTB |= (1<<PORTB2); //PB2_hi
}
//--- инициализация генератора ---
void PB1_ini(void) //функция инициализации порта PB1
{
DDRB |= (1<<PORTB1); //PB1 на вывод (oc1a)
PORTB &= ~(1<<PORTB1); //PB1 сброс
}
//--- инициализация PB2 ---
/*void PB2_ini(void) //функция инициализации порта PB2 (выход запуска генератора +Vpwr = +9...12v)
{
DDRB |= (1<<PORTB2); //PB2 на вывод (oc1b)
PORTB &= ~(1<<PORTB2); //PB2 сброс
}*/
//--- инициализация таймера oc1a ---
void oc1a(void) //функция таймера
{
ASSR=0x00; //сбрасываем полностью регистр assr
TCCR1A |= ((1<<COM1A1)|(1<<WGM10)); //Fast PWM oc1a, Clear oc1a on Compare Match, clkT2S/1 (no prescalling)
TCCR1B |= ((1<<WGM12)|(1<<CS10));
TCNT1H=0x00; // Timer Value = 0 сброс счётного регистра таймера 1
TCNT1L=0x00;
OCR1AH=0x00;
OCR1AL=0x55; //Output Compare Register = dec85 - заполнение шим +DC~33%
TIMSK=0x00; //сброс регистра timsk
}
//--- инициализация таймера oc1b ---
/*void oc1b(void) //функция таймера
{
ASSR=0x00; //сбрасываем полностью регистр assr
TCCR1A |= ((1<<COM1B1)|(1<<WGM10)); //Fast PWM oc1b, Clear oc1b on Compare Match, clkT2S/1 (no prescalling)
TCCR1B |= ((1<<WGM12)|(1<<CS10));
TCNT1H=0x00; // Timer Value = 0 сброс счётного регистра таймера 2
TCNT1L=0x00;
OCR1BH=0x00;
OCR1BL=0x64; //Output Compare Register = dec100 - заполнение шим +DC~40%
TIMSK=0x00; //сброс регистра timsk
}*/
//--- инициализация шины SPI_ADC ---
void ADC_SPI_ini(void)
{
DDRB &= ~(1<<PORTB4); PORTB |= (1<<PORTB4); //MISO, pull-up=ON
DDRB |= ((1<<PORTB5)|(1<<PORTB2)|(1<<PORTB0)); //выход ADC_CLK, выход ADC_CS1, выход ADC_CS0
PORTB |= ((1<<PORTB2)|(1<<PORTB0));
PORTB &= ~(1<<PORTB5); //сброс шины SPI_ADC
SPCR = ((1<<SPE)|(1<<MSTR)|(1<<SPR1)|(1<<SPR0)); //включим шину SPI, объ§вим ведущим, SCK=16e+06/128=125kHz
}
//--- функция передачи/приёма данных по шине SPI ---
void SPI_SendByte(char byte)
{
SPDR = byte; //
while(!(SPSR & (1<<SPIF))); //подождем пока данные передадутс¤
}
unsigned char SPI_ChangeByte(char byte)
{
SPDR = byte;
while(!(SPSR & (1<<SPIF))); //подождем пока данные передадутс¤ (обмен¤ютс¤)
return SPDR;
}
//--- функция опроса внешнего АЦП mcp3201_0 ---
unsigned int Read_3201_0(unsigned char channel)
{
unsigned int b1,b2;
ADC_CS0_0; //CS0=0
b1=SPI_ChangeByte(0); //первый байт
b2=SPI_ChangeByte(0); //второй байт
b1=(b1<<8)|b2; //собираем два байта в двухбайтовую величину
b1<<=3;
b1>>=4; //убираем ненужные биты (3 слева и 1 справа)
ADC_CS0_1; //CS0=1
return b1; //возвращаем 12-битный результат ацп-преобразования
}
//--- функция опроса внешнего АЦП mcp3201_1 ---
unsigned int Read_3201_1(unsigned char channel)
{
unsigned int b1,b2;
ADC_CS1_0; //CS1=0
b1=SPI_ChangeByte(0); //первый байт
b2=SPI_ChangeByte(0); //второй байт
b1=(b1<<8)|b2; //собираем два байта в двухбайтовую величину
b1<<=3;
b1>>=4; //убираем ненужные биты (3 слева и 1 справа)
ADC_CS1_1; //CS1=1
return b1; //возвращаем 12-битный результат ацп-преобразования
}
//--- инициализация шины данных SPI_DRV драйвера max7219 ---
void DRV_SPI_ini(void)
{
DDRC = 0x07; //биты PС0-PС2 порта PС на вывод
PORTC &= ~((1<<PORTC2)|(1<<PORTC1)|(1<<PORTC0)); //PС0-PС2 сброс
}
//--- функция побитовой отправки данных в драйвер max7219 ---
void Send_max7219(unsigned char rg, unsigned char dt) //
{
unsigned char rg_copy; //копия значения переменной rg
unsigned char i; //переменная для побитной отправки данных в драйвер индикаторов
DRV_MOSI[rg] = dt; //
rg_copy = rg; //создадим копию значения переменной rg
DRV_CS_0; //отправим «0» на вывод CS микросхемы MAX7219, чтобы начать процесс передачи адреса и данных
asm("nop"); //пауза в 1 такт
for(i=0;i<8;i++) //цикл от 0 до 7 с шагом 1, для побитовой отправки байта адреса в микросхему MAX7219
{
if((rg & 0x80)==0x80) //пока rg * 0b1000 0000 > 0, ...
{
DRV_MOSI_1; //...отправим 1 на вывод Din микросхемы MAX7219
}
else //если же rg * 0b1000 0000 = 0, ...
{
DRV_MOSI_0; //...отправим 0 на вывод Din микросхемы MAX7219
}
//создадим тактовый импульс на выводе CLK микросхемы MAX7219
asm("nop"); //пауза в 1 такт
DRV_CLK_1; //отправим 1 на вывод Clk микросхемы MAX7219
asm("nop"); //пауза в 1 такт
DRV_CLK_0; //отправим 0 на вывод Clk микросхемы MAX7219
rg <<= 1; //сдвинем значение переменной rg на 1 бит влево
} //выйдем из цикла когда i станет равной 7, т.е. когда отправка байта адреса в микросхему MAX7219 будет окончена
for(i=0;i<8;i++) //цикл от 0 до 7 с шагом 1, для побитовой отправки байта данных в микросхему MAX7219
{
if((DRV_MOSI[rg_copy] & 0x80)==0x80) //пока rg * 0b1000 0000 > 0, ...
{
DRV_MOSI_1; //...отправим 1 на вывод Din микросхемы MAX7219
}
else //если же rg * 0b1000 0000 = 0, ...
{
DRV_MOSI_0; //отправим 0 на вывод Din микросхемы MAX7219
}
//создадим тактовый импульс на выводе CLK микросхемы MAX7219
asm("nop"); //пауза в 1 такт
DRV_CLK_1; //отправим 1 на вывод Clk микросхемы MAX7219
asm("nop"); //пауза в 1 такт
DRV_CLK_0; //отправим 0 на вывод Clk микросхемы MAX7219
DRV_MOSI[rg_copy] <<= 1; //сдвинем значение переменной DRV_MOSI на 1 бит влево
}
//выйдем из цикла когда i станет равной 7, т.е. когда отправка байта данных в микросхему MAX7219 будет окончена
DRV_CS_1; //отправим «1» на вывод CS микросхемы MAX7219, чтобы завершить процесс передачи адреса и данных
}
//--- инициализация драйвера max7219 ---
void MAX7219_ini(void)
{
Send_max7219(0x09,0xFF); //(номер регистра, данные) включаем режим BCD code B, для 0-7 разрядов
Send_max7219(0x0A,0x0A); //DC = 21/32 яркость свечения
Send_max7219(0x0B,0x07); //число используемых разрядов (0-7 разрядов)
Send_max7219(0x0C,0x01); //отключаем режим энергосбережения (Shutdown)
for(V=1;V<9;V++)
{
Send_max7219(V,0x0F);
}
}
//--- Функция вывода значений на индикатор вольтметра ---
void ledprint_1(unsigned int number)
{
Digit[8]=number/1000 ? number/1000: 0x0F; //гашение незначащего нуля в разряде "тысячи"
Digit[7]=number/1000 || number%1000/100 ? number%1000/100: 0x0F; //гашение незначащего нуля в разряде "сотни"
Digit[6]=number%100/10; //десятки
Digit[6]=Digit[6]|128; //вкл децимальную точку в разряде Digit_6
Digit[5]=number%10; //единицы
for(V=5;V<9;V++)
{
DRV_MOSI[V] = Digit[V];
Send_max7219(V,DRV_MOSI[V]);
}
}
//--- функция вывода значений на индикатор амперметра ---
void ledprint_2(unsigned int number)
{
Digit[4]=number/1000; //тысячи
Digit[4]=Digit[4]|128; //вкл децимальную точку в разряде Digit_4
Digit[3]=number%1000/100; //сотни
Digit[2]=number%100/10; //десятки
Digit[1]=number%10; //единицы
for(I=1;I<5;I++)
{
DRV_MOSI[I] = Digit[I];
Send_max7219(I,DRV_MOSI[I]);
}
}
//--- функция оцифровки напряжения ---
float ADCV_Conv(unsigned int dt_v)
{
float dt_v1; //тип данных с плавающей точкой
dt_v1=((float)dt_v*(Vref))/Kv; //преобразование 12-битного числа типа float в величину измеренного напряжения
unsigned int adcv_tmp = 0; //сброс переменной для хранения промежуточных результатов оцифровки
unsigned char adcv_counter = 0; //сброс переменной усреднения оцифровки measure
if(adcv_counter < measure)
{
adcv_tmp += dt_v1; //adcv_tmp = adcv_tmp + dt_v1
adcv_counter ++;
}
else
{
dt_v1 = adcv_tmp >> 0; //adcv_tmp / measure
adcv_counter = 0; //сброс счётчика усреднения
adcv_tmp = 0; //сброс регистра промежуточных результатов оцифровки
}
return dt_v1; //возвращаем величину измеренного напряжения в вольтах [V]
}
//--- функция оцифровки тока ---
float ADCI_Conv(unsigned int dt_i)
{
float dt_i1; //тип данных с плавающей точкой
dt_i1=((float)dt_i*(Vref))/Ki; //преобразование 12-битного числа типа float в величину измеренного тока
unsigned int adci_tmp = 0; //сброс переменной для хранения промежуточных результатов оцифровки
unsigned char adci_counter = 0; //сброс переменной усреднения оцифровки measure
if(adci_counter < measure) //пока число в счётчике измерений меньше предельного количества измерений measure...
{ //...суммируем результаты оцифровки в регистре промежуточных результатов
adci_tmp += dt_i1; //adci_tmp = adci_tmp + dt_i1
adci_counter ++; //...продолжаем инкрементировать счётчик измерений
}
else //если же счётчик накопил предельное кол-во измерений...
{ //...то выходим из цикла накопления в регистре и находим среднее арифметическое...
dt_i1 = adci_tmp >> 0; //...adci_tmp / measure (сдвигаем данные в регистре накопления на 5 разрядов вправо, что равнозначно /2^5=32 )
adci_counter = 0; //сброс счётчика усреднения
adci_tmp = 0; //сброс регистра промежуточных результатов оцифровки
}
return dt_i1; //возвращаем величину измеренного тока в амперах [A]
}
//--- основная функция с бесконечным циклом ---
int main(void)
{
float dt_v=0; //сброс на ноль SPDR
float dt_i=0; //сброс на ноль SPDR
CS0_ini(); //инициализация порта PB0
CS1_ini(); //инициализация порта PB2
PB1_ini(); //инициализация порта PB1
//PB2_ini(); //инициализация порта PB2
oc1a(); //инициализация генератора
OCR1AH = 0x00; //запись в регистр сравнения ocr1a...
OCR1AL = 0x55; //...числа dec85
//oc1b(); //инициализация инвертора +5v >> +9...12v
//OCR1BH = 0x00; //запись в регистр сравнения ocr1a...
//OCR1BL = 0x64; //...числа dec100
ADC_SPI_ini(); //инициализация шины SPI
DRV_SPI_ini(); //инициализация шины данных драйвера
MAX7219_ini(); //инициализация MAX7219
//ADCV_ini(); //инициализация внутреннего АЦП
//----------
while(1)
{
dt_v = ADCV_Conv(Read_3201_0(0)); //считаем значение SPDR АЦП напряжения
Av=dt_v; //
Mv = Ks_v * Av + Mv1 * (1-Ks_v); //фильтр Кальмана Mn=Ks*An + Mn1*(1-Ks)
Mv1=Mv; //
dt_i = ADCI_Conv(Read_3201_1(1)); //считаем значение SPDR АЦП тока
Ai=dt_i; //
Mi = Ks_i * Ai + Mi1 * (1-Ks_i); //фильтр Кальмана Mn=Ks*An + Mn1*(1-Ks)
Mi1=Mi; //
adc_conv count++; //инкрементируем счётчик ацп-преобразователя
if(adc_conv count==1000) // выводим на дисплеи результат только каждого n=1000 преобразования
{
adc_conv count=0; //сброс счётчика ацп-преобразований
ledprint_1(Mv); //отправим значение в функцию вывода на индикатор вольтметра
ledprint_2(Mi); //отправим значение в функцию вывода на индикатор амперметра
}
}
}
Ср окт 04, 2023 17:32:34
//ATmega_8A + max7219 + mcp3201_0 + mcp3201_1
//va-meter +0...409.6vdc / +0...9.999adc
//16MHz
#define F_CPU 16000000UL //тактовая частота мк (unsigned long)
#include <avr/io.h> //подключение библиотеки "ввод/вывод" мк
#include <util/delay.h> //подключение библиотеки "пауза" мк
#include <avr/interrupt.h> //подключение библиотеки "прерывание" мк
#define Vref 4.096 //+Vref=4.096vdc
#define Kv 4.096 //коэффициент преобразования для вычислнения величины [V] Kv=4096*4.096/4096
#define Ki 1.678 //коэффициент преобразования для вычислнения величины [I] Ki=4096*4.096/10 000
#define ADC_CS0_0 PORTB &= ~(1<<PORTB0) //ADC_CS0=0
#define ADC_CS0_1 PORTB |= (1<<PORTB0) //ADC_CS0=1
#define ADC_CS1_0 PORTB &= ~(1<<PORTB2) //ADC_CS1=0
#define ADC_CS1_1 PORTB |= (1<<PORTB2) //ADC_CS1=1
#define ADC_CLK_0 PORTB &= ~(1<<PORTB5) //ADC_CLK=0
#define ADC_CLK_1 PORTB |= (1<<PORTB5) //ADC_CLK=1
#define DRV_CLK_0 PORTC &= ~(1<<PORTC0) //DRV_CLK=0
#define DRV_CLK_1 PORTC |= (1<<PORTC0) //DRV_CLK=1
#define DRV_CS_0 PORTC &= ~(1<<PORTC1) //DRV_CS=0
#define DRV_CS_1 PORTC |= (1<<PORTC1) //DRV_CS=1
#define DRV_MOSI_0 PORTC &= ~(1<<PORTC2) //DRV_MOSI=0
#define DRV_MOSI_1 PORTC |= (1<<PORTC2) //DRV_MOSI=1
//----------
unsigned int Digit[8]; //массив беззнаковых целочисленных переменных Digit из 8 переменных (8 разрядов драйвера 7seg LED-дисплея)
unsigned char DRV_MOSI[8]; //массив беззнаковых однобайтных символьных переменных DRV_MOSI из 8 переменных (адреса и команды для конфигурирования драйвера)
unsigned char n; //символьная переменная (максимальное количество разрядов led-драйвера n=8)
unsigned char V; //символьная переменная V (значение регистра ацп с результатом оцифровки напряжения)
unsigned char I; //символьная переменная I (значение регистра ацп с результатом оцифровки тока)
unsigned int count; //переменная для задержки обновления данных на индикаторах
unsigned short dt_v; //12-битный результат оцифровки величины [V]
float Av; //Av=dt_v
float Mv; //окончательный результат работы сглаживающего фильтра в канале [V]
float Mv1 = 0; //сброс промежуточного результата работы сглаживающего фильтра в канале [V]
float Ks_v = 0.05; //коэффициент сглаживания в канале [V]
unsigned short dt_i; //12-битный результат оцифровки величины [I]
float Ai; //Ai=dt_i
float Mi; //окончательный результат работы сглаживающего фильтра в канале [I]
float Mi1 = 0; //сброс промежуточного результата работы сглаживающего фильтра в канале [I]
float Ks_i = 0.05; //коэффициент сглаживания в канале [I]
//--- инициализация CS0 ---
void CS0_ini(void) //функция инициализации порта PB0
{
DDRB |= (1<<PORTB0); //PB0 на вывод
PORTB |= (1<<PORTB0); //PB0_hi
}
//--- инициализация CS1 ---
void CS1_ini(void) //функция инициализации порта PB2
{
DDRB |= (1<<PORTB2); //PB2 на вывод
PORTB |= (1<<PORTB2); //PB2_hi
}
//--- инициализация генератора ---
void PB1_ini(void) //функция инициализации порта PB1
{
DDRB |= (1<<PORTB1); //PB1 на вывод (oc1a)
PORTB &= ~(1<<PORTB1); //PB1 сброс
}
//--- инициализация PB2 ---
/*void PB2_ini(void) //функция инициализации порта PB2 (выход запуска генератора +Vpwr = +9...12v)
{
DDRB |= (1<<PORTB2); //PB2 на вывод (oc1b)
PORTB &= ~(1<<PORTB2); //PB2 сброс
}*/
//--- инициализация таймера oc1a ---
void oc1a(void) //функция таймера
{
ASSR=0x00; //сбрасываем полностью регистр assr
TCCR1A |= ((1<<COM1A1)|(1<<WGM10)); //Fast PWM oc1a, Clear oc1a on Compare Match, clkT2S/1 (no prescalling)
TCCR1B |= ((1<<WGM12)|(1<<CS10));
TCNT1H=0x00; // Timer Value = 0 сброс счётного регистра таймера 1
TCNT1L=0x00;
OCR1AH=0x00;
OCR1AL=0x55; //Output Compare Register = dec85 - заполнение шим +DC~33%
TIMSK=0x00; //сброс регистра timsk
}
//--- инициализация таймера oc1b ---
/*void oc1b(void) //функция таймера
{
ASSR=0x00; //сбрасываем полностью регистр assr
TCCR1A |= ((1<<COM1B1)|(1<<WGM10)); //Fast PWM oc1b, Clear oc1b on Compare Match, clkT2S/1 (no prescalling)
TCCR1B |= ((1<<WGM12)|(1<<CS10));
TCNT1H=0x00; // Timer Value = 0 сброс счётного регистра таймера 2
TCNT1L=0x00;
OCR1BH=0x00;
OCR1BL=0x64; //Output Compare Register = dec100 - заполнение шим +DC~40%
TIMSK=0x00; //сброс регистра timsk
}*/
//--- инициализация шины SPI_ADC ---
void ADC_SPI_ini(void)
{
DDRB &= ~(1<<PORTB4); PORTB |= (1<<PORTB4); //MISO, pull-up=ON
DDRB |= ((1<<PORTB5)|(1<<PORTB2)|(1<<PORTB0)); //выход ADC_CLK, выход ADC_CS1, выход ADC_CS0
PORTB |= ((1<<PORTB2)|(1<<PORTB0));
PORTB &= ~(1<<PORTB5); //сброс шины SPI_ADC
SPCR = ((1<<SPE)|(1<<MSTR)|(1<<SPR1)|(1<<SPR0)); //включим шину SPI, объ§вим ведущим, SCK=16e+06/128=125kHz
}
//--- функция передачи/приёма данных по шине SPI ---
void SPI_SendByte(char byte)
{
SPDR = byte; //
while(!(SPSR & (1<<SPIF))); //подождем пока данные передадутс¤
}
unsigned char SPI_ChangeByte(char byte)
{
SPDR = byte;
while(!(SPSR & (1<<SPIF))); //подождем пока данные передадутс¤ (обмен¤ютс¤)
return SPDR;
}
//--- функция опроса внешнего АЦП mcp3201_0 ---
unsigned int Read_3201_0(unsigned char channel)
{
unsigned int b1,b2;
ADC_CS0_0; //CS0=0
b1=SPI_ChangeByte(0); //первый байт
b2=SPI_ChangeByte(0); //второй байт
b1=(b1<<8)|b2; //собираем два байта в двухбайтовую величину
b1<<=3;
b1>>=4; //убираем ненужные биты (3 слева и 1 справа)
ADC_CS0_1; //CS0=1
return b1; //возвращаем 12-битный результат ацп-преобразования
}
//--- функция опроса внешнего АЦП mcp3201_1 ---
unsigned int Read_3201_1(unsigned char channel)
{
unsigned int b1,b2;
ADC_CS1_0; //CS1=0
b1=SPI_ChangeByte(0); //первый байт
b2=SPI_ChangeByte(0); //второй байт
b1=(b1<<8)|b2; //собираем два байта в двухбайтовую величину
b1<<=3;
b1>>=4; //убираем ненужные биты (3 слева и 1 справа)
ADC_CS1_1; //CS1=1
return b1; //возвращаем 12-битный результат ацп-преобразования
}
//--- инициализация шины данных SPI_DRV драйвера max7219 ---
void DRV_SPI_ini(void)
{
DDRC = 0x07; //биты PС0-PС2 порта PС на вывод
PORTC &= ~((1<<PORTC2)|(1<<PORTC1)|(1<<PORTC0)); //PС0-PС2 сброс
}
//--- функция побитовой отправки данных в драйвер max7219 ---
void Send_max7219(unsigned char rg, unsigned char dt) //
{
unsigned char rg_copy; //копия значения переменной rg
unsigned char i; //переменная для побитной отправки данных в драйвер индикаторов
DRV_MOSI[rg] = dt; //
rg_copy = rg; //создадим копию значения переменной rg
DRV_CS_0; //отправим «0» на вывод CS микросхемы MAX7219, чтобы начать процесс передачи адреса и данных
asm("nop"); //пауза в 1 такт
for(i=0;i<8;i++) //цикл от 0 до 7 с шагом 1, для побитовой отправки байта адреса в микросхему MAX7219
{
if((rg & 0x80)==0x80) //пока rg * 0b1000 0000 > 0, ...
{
DRV_MOSI_1; //...отправим 1 на вывод Din микросхемы MAX7219
}
else //если же rg * 0b1000 0000 = 0, ...
{
DRV_MOSI_0; //...отправим 0 на вывод Din микросхемы MAX7219
}
//создадим тактовый импульс на выводе CLK микросхемы MAX7219
asm("nop"); //пауза в 1 такт
DRV_CLK_1; //отправим 1 на вывод Clk микросхемы MAX7219
asm("nop"); //пауза в 1 такт
DRV_CLK_0; //отправим 0 на вывод Clk микросхемы MAX7219
rg <<= 1; //сдвинем значение переменной rg на 1 бит влево
} //выйдем из цикла когда i станет равной 7, т.е. когда отправка байта адреса в микросхему MAX7219 будет окончена
for(i=0;i<8;i++) //цикл от 0 до 7 с шагом 1, для побитовой отправки байта данных в микросхему MAX7219
{
if((DRV_MOSI[rg_copy] & 0x80)==0x80) //пока rg * 0b1000 0000 > 0, ...
{
DRV_MOSI_1; //...отправим 1 на вывод Din микросхемы MAX7219
}
else //если же rg * 0b1000 0000 = 0, ...
{
DRV_MOSI_0; //отправим 0 на вывод Din микросхемы MAX7219
}
//создадим тактовый импульс на выводе CLK микросхемы MAX7219
asm("nop"); //пауза в 1 такт
DRV_CLK_1; //отправим 1 на вывод Clk микросхемы MAX7219
asm("nop"); //пауза в 1 такт
DRV_CLK_0; //отправим 0 на вывод Clk микросхемы MAX7219
DRV_MOSI[rg_copy] <<= 1; //сдвинем значение переменной DRV_MOSI на 1 бит влево
}
//выйдем из цикла когда i станет равной 7, т.е. когда отправка байта данных в микросхему MAX7219 будет окончена
DRV_CS_1; //отправим «1» на вывод CS микросхемы MAX7219, чтобы завершить процесс передачи адреса и данных
}
//--- инициализация драйвера max7219 ---
void MAX7219_ini(void)
{
Send_max7219(0x09,0xFF); //(номер регистра, данные) включаем режим BCD code B, для 0-7 разрядов
Send_max7219(0x0A,0x0A); //DC = 21/32 яркость свечения
Send_max7219(0x0B,0x07); //число используемых разрядов (0-7 разрядов)
Send_max7219(0x0C,0x01); //отключаем режим энергосбережения (Shutdown)
for(n=1;n<9;n++)
{
Send_max7219(n,0x0F); //гасим все разряды драйвера дисплея V/A до момента вывода информации
}
}
//--- функция оцифровки напряжения ---
float ADCV_Conv(unsigned short dt_v)
{
float dt_v1; //величина измеренного напряжения [V]
dt_v1=((float)dt_v*(Vref))/Kv; //преобразование 12-битного числа типа u_int в величину измеренного напряжения (float)
return dt_v1; //возвращаем величину измеренного напряжения в вольтах [V]
}
//--- функция оцифровки тока ---
float ADCI_Conv(unsigned short dt_i)
{
float dt_i1; //величина измеренного тока [I]
dt_i1=((float)dt_i*(Vref))/Ki; //преобразование 12-битного числа типа u_int в величину измеренного тока (float)
return dt_i1; //возвращаем величину измеренного тока в амперах [A]
}
//--- функция вывода значений на индикатор вольтметра 000.0v ---
void ledprint_1(unsigned int number) //number - величина измеренного напряжения Mv
{
if((float)Mv < 4090) //если Mv <= 409.0, то выводим на дисплей результат...
{
Digit[8]=number/1000 ? number/1000 : 0x0F; //тысячи /гасим старший незначащий нуль
Digit[7]=number/1000 || number%1000/100 ? number%1000/100 : 0x0F; //сотни /гасим младший незначащий нуль
Digit[6]=number%100/10; //десятки
Digit[6]=Digit[6]|0x80; //вкл децимальную точку в разряде Digit_6
Digit[5]=number%10; //единицы
}
else //...в противном случае, выводим на дисплей -0L- (overload)
{
Digit[8]=0x0A; //<<->>
Digit[7]=0x00; //<<0>>
Digit[6]=0x0D; //<<L>>
Digit[5]=0x0A; //<<->>
}
for(V=5;V<9;V++) //заполняем разряды вольтметра цифрами разложенного Mv
{
DRV_MOSI[V] = Digit[V]; //
Send_max7219(V,DRV_MOSI[V]); //
}
}
//--- функция вывода значений на индикатор амперметра ---
void ledprint_2(unsigned int number)
{
if((float)Mi < 9980) //если Mi < 9.980, то выводим на дисплей результат...
{
Digit[4]=number/1000; //тысячи
Digit[4]=Digit[4]|128; //вкл децимальную точку в разряде Digit_4
Digit[3]=number%1000/100; //сотни
Digit[2]=number%100/10; //десятки
Digit[1]=number%10; //единицы
}
else //...в противном случае, выводим на дисплей -0L- (overload)
{
Digit[4]=0x0A; //<<->>
Digit[3]=0x00; //<<0>>
Digit[2]=0x0D; //<<L>>
Digit[1]=0x0A; //<<->>
}
for(I=1;I<5;I++)
{
DRV_MOSI[I] = Digit[I];
Send_max7219(I,DRV_MOSI[I]);
}
}
//--- основная функция с бесконечным циклом ---
int main(void)
{
float dt_v=0; //сброс на ноль SPDR
float dt_i=0; //сброс на ноль SPDR
CS0_ini(); //инициализация порта PB0
CS1_ini(); //инициализация порта PB2
PB1_ini(); //инициализация порта PB1
//PB2_ini(); //инициализация порта PB2
oc1a(); //инициализация генератора
OCR1AH = 0x00; //запись в регистр сравнения ocr1a...
OCR1AL = 0x55; //...числа dec85
//oc1b(); //инициализация инвертора +5v >> +9...12v
//OCR1BH = 0x00; //запись в регистр сравнения ocr1a...
//OCR1BL = 0x64; //...числа dec100
ADC_SPI_ini(); //инициализация шины SPI
DRV_SPI_ini(); //инициализация шины данных драйвера
MAX7219_ini(); //инициализация MAX7219
//ADCV_ini(); //инициализация внутреннего АЦП
//----------
while(1)
{
dt_v = ADCV_Conv(Read_3201_0(0)); //считаем значение SPDR АЦП напряжения
Av=dt_v; //
Mv = Ks_v * Av + Mv1 * (1-Ks_v); //фильтр Кальмана Mn=Ks*An + Mn1*(1-Ks)
Mv1=Mv; //
dt_i = ADCI_Conv(Read_3201_1(1)); //считаем значение SPDR АЦП тока
Ai=dt_i; //
Mi = Ks_i * Ai + Mi1 * (1-Ks_i); //фильтр Кальмана Mn=Ks*An + Mn1*(1-Ks)
Mi1=Mi; //
count++; //инкрементируем счётчик ацп-преобразователя
if(count==750) // выводим на дисплеи результат только каждого n=750 преобразования
{
count=0; //сброс счётчика ацп-преобразований
ledprint_1(Mv); //отправим значение в функцию вывода на индикатор вольтметра
ledprint_2(Mi); //отправим значение в функцию вывода на индикатор амперметра
}
}
}
Пт окт 06, 2023 16:20:43
Ср ноя 01, 2023 13:56:42