ATmega + 12bit ADC
- slav0n
- Опытный кот
- Сообщения: 882
- Зарегистрирован: Ср дек 01, 2010 00:38:15
- Откуда: Харьков
- Контактная информация:
Re: ATmega + 12bit ADC
пересматривать надо не диапазон коррекции, а сам алгоритм.
нужно разделять режим установки уставки тока и рабочий режим.
а то получается фактически медленное ("единичка в секунду") накручивание тока.
нафига в таком случае вообще сдались эти всякие супер-пупер 15-бит, погрешности и тд...
крути ручку тока как попало да и все, эффект будет тот же
нужно разделять режим установки уставки тока и рабочий режим.
а то получается фактически медленное ("единичка в секунду") накручивание тока.
нафига в таком случае вообще сдались эти всякие супер-пупер 15-бит, погрешности и тд...
крути ручку тока как попало да и все, эффект будет тот же
Последний раз редактировалось slav0n Пн сен 06, 2021 08:17:41, всего редактировалось 1 раз.
ohmycode!
primuss3.com
primuss3.com
- Реклама
- Starichok51
- Модератор
- Сообщения: 19054
- Зарегистрирован: Сб авг 14, 2010 15:05:51
- Откуда: г. Озерск, Челябинская обл.
Re: ATmega + 12bit ADC
установка задания и рабочий режим у меня разделены.
устанавливать надо только в режиме "стоп". рабочем режиме крутить ручку бесполезно, так как после пуска запоминается установленное значение.
ты будешь делать, как ты посчитаешь нужным. а мне нравится так, как сделал я.
устанавливать надо только в режиме "стоп". рабочем режиме крутить ручку бесполезно, так как после пуска запоминается установленное значение.
ты будешь делать, как ты посчитаешь нужным. а мне нравится так, как сделал я.
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
- slav0n
- Опытный кот
- Сообщения: 882
- Зарегистрирован: Ср дек 01, 2010 00:38:15
- Откуда: Харьков
- Контактная информация:
Re: ATmega + 12bit ADC
ну, если тебе нравится такая фигня, то зачем оно другим?Starichok51 писал(а):а если автокоррекция успела набрать, допустим, код для 4,6А, а нагрузка захотела взять больше 4,6А (или сделали кз), то в первый момент ток будет 4,6А. и тут же коррекция начнет снижать ток к установленному значению 3А.
Добавлено after 7 minutes 8 seconds:
допустим, наивный юзер ставит ограничение 0.1 А в надежде уберечь свое детище от вони-огони.
ну, значит, он в нем ковыряется-настраивает... время идет, все норм...
тут чувак решает зафорсить режим своей приблуды надеясь на ограничение 0.1А... а твой супер-БП ему куяк, и десяточку ампер в "первый момент"
ohmycode!
primuss3.com
primuss3.com
- Starichok51
- Модератор
- Сообщения: 19054
- Зарегистрирован: Сб авг 14, 2010 15:05:51
- Откуда: г. Озерск, Челябинская обл.
Re: ATmega + 12bit ADC
не в начальный момент, а минут через 15 ...
и по поводу десяточки Ампер я уже согласился с Димой, что нужно ограничить коррекцию 10-15 единицами, чтобы далеко не убежало. или ты этого не читал?
Добавлено after 1 minute 28 seconds:
а по поводу других - еще никто не пожаловался из тех, кто собрал мой проект.
и по поводу десяточки Ампер я уже согласился с Димой, что нужно ограничить коррекцию 10-15 единицами, чтобы далеко не убежало. или ты этого не читал?
Добавлено after 1 minute 28 seconds:
а по поводу других - еще никто не пожаловался из тех, кто собрал мой проект.
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
- slav0n
- Опытный кот
- Сообщения: 882
- Зарегистрирован: Ср дек 01, 2010 00:38:15
- Откуда: Харьков
- Контактная информация:
Re: ATmega + 12bit ADC
это костыли для кривого алгоритмаStarichok51 писал(а): нужно ограничить коррекцию 10-15 единицами, чтобы далеко не убежало
правильный алгоритм никуда убегать не должен
Добавлено after 1 hour 11 minutes 10 seconds:
а крутить ручку физически нет необходимости, "крутит ручку" твой чудо-алгоритмStarichok51 писал(а):установка задания и рабочий режим у меня разделены.
устанавливать надо только в режиме "стоп". рабочем режиме крутить ручку бесполезно, так как после пуска запоминается установленное значение.
Добавлено after 56 minutes 48 seconds:
вести с полей оверсемплинга
Код: Выделить всё
#define ROUNDS (1024 * 2)
. . .
res += ((adc1 * 4550.0 / 102.4 / ROUNDS) - res) * 0.125;ohmycode!
primuss3.com
primuss3.com
- Реклама
Re: ATmega + 12bit ADC
для тока самый раз, максимум 4,550А, разрешение 0,1миллиА.slav0n писал(а):а нафига?
Другой вопрос, а ты с чем сравниваешь показания, какой образцовый прибор используешь?
- slav0n
- Опытный кот
- Сообщения: 882
- Зарегистрирован: Ср дек 01, 2010 00:38:15
- Откуда: Харьков
- Контактная информация:
Re: ATmega + 12bit ADC
я пишу не про абсолютное значение, а про разрешение
т.е. с каким шагом изменяются показания
т.е. с каким шагом изменяются показания
ohmycode!
primuss3.com
primuss3.com
- Starichok51
- Модератор
- Сообщения: 19054
- Зарегистрирован: Сб авг 14, 2010 15:05:51
- Откуда: г. Озерск, Челябинская обл.
Re: ATmega + 12bit ADC
тогда расскажи, чему у тебя равен шаг и чему равно разрешение.
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
- slav0n
- Опытный кот
- Сообщения: 882
- Зарегистрирован: Ср дек 01, 2010 00:38:15
- Откуда: Харьков
- Контактная информация:
Re: ATmega + 12bit ADC
ну, так я же кино показывал с шагом 1 мВ
100 мкВ для реального применения неинтересен, слишком инерционный фильтр получается. оно чисто для спорта
1 десятичный порядок по идее требует как минимум 3 двоичных
100 мкВ для реального применения неинтересен, слишком инерционный фильтр получается. оно чисто для спорта
1 десятичный порядок по идее требует как минимум 3 двоичных
Последний раз редактировалось slav0n Пн сен 06, 2021 19:49:17, всего редактировалось 1 раз.
ohmycode!
primuss3.com
primuss3.com
Re: ATmega + 12bit ADC
Меня интересует максимум и шаг:
максимум 5В шаг 1мВ
максимум 50В шаг 10мВ
максимум 500В шаг 100мВ
максимум 5В шаг 1мВ
максимум 50В шаг 10мВ
максимум 500В шаг 100мВ
- slav0n
- Опытный кот
- Сообщения: 882
- Зарегистрирован: Ср дек 01, 2010 00:38:15
- Откуда: Харьков
- Контактная информация:
Re: ATmega + 12bit ADC
так все это уже давно есть
максимум 5В шаг 1мВ - напрямую с опорой 5в
максимум 50В шаг 10мВ - через делитель 1/10
максимум 500В шаг 100мВ - делитель 1/100
максимум 5В шаг 1мВ - напрямую с опорой 5в
максимум 50В шаг 10мВ - через делитель 1/10
максимум 500В шаг 100мВ - делитель 1/100
ohmycode!
primuss3.com
primuss3.com
- slav0n
- Опытный кот
- Сообщения: 882
- Зарегистрирован: Ср дек 01, 2010 00:38:15
- Откуда: Харьков
- Контактная информация:
Re: ATmega + 12bit ADC
избавился от плавающей точки, а это минус 300Б кода.
Код: Выделить всё
#define ROUNDS 1024
. . .
res1 += (((adc1 >> 5) * 4550 / 1024 / (ROUNDS >> 5)) - res1) >> 2;ohmycode!
primuss3.com
primuss3.com
-
charchyard
- Поставщик валерьянки для Кота
- Сообщения: 2466
- Зарегистрирован: Сб май 07, 2011 17:52:59
Re: ATmega + 12bit ADC
желаю здравия
churchyard in the air. спасибо всем неравнодушным, кто высказывал свои гипотезы.
вот такая кодировка использовалась для одной из двухканальных головок.
вот такая кодировка использовалась для одной из двухканальных головок.
Спойлер
Код: Выделить всё
[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); //отправим значение в функцию вывода на индикатор амперметра
}
}
}
Спойлер
Спойлер
- Вложения
-
- va_meter_400vdc_10adc_ver_1.pdf
- (363.08 КБ) 48 скачиваний
-
- chopper 48vdc_5vdc.pdf
- (409.7 КБ) 38 скачиваний
-
- chopper 38v_5v0.pdf
- (202.06 КБ) 40 скачиваний
душа человеческая темна и с легкостью обращается ко злу
-
charchyard
- Поставщик валерьянки для Кота
- Сообщения: 2466
- Зарегистрирован: Сб май 07, 2011 17:52:59
Re: ATmega + 12bit ADC
Спойлер
Код: Выделить всё
//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); //отправим значение в функцию вывода на индикатор амперметра
}
}
}
- Вложения
-
- copper_24_5_12_12.pdf
- (256.34 КБ) 51 скачивание
душа человеческая темна и с легкостью обращается ко злу
-
charchyard
- Поставщик валерьянки для Кота
- Сообщения: 2466
- Зарегистрирован: Сб май 07, 2011 17:52:59
Re: ATmega + 12bit ADC
вау-вау-метер
- Вложения
-
- display_board_max7219.pdf
- (141.35 КБ) 64 скачивания
душа человеческая темна и с легкостью обращается ко злу
-
charchyard
- Поставщик валерьянки для Кота
- Сообщения: 2466
- Зарегистрирован: Сб май 07, 2011 17:52:59
Re: ATmega + 12bit ADC
Спойлер
новейшее кино про лёд-головку цифровую 100vdc 200adc. для колибровки было задействовано несколько источников тока постояного напряженья. но един член для выстаки верха диапазона энерхетики не хватилло. старую убогую кэтайску узкоглазую с шунтом я выколупал. она на сотку ампериев была. разбежка в покозаниях вольтмера связана с конечной проводимосью верёвок в симинсах и неудачной точкой подключенья внутри. новую голову обернул просто в пакетон от свища и хомутками прищипил. в соседнем дурдоме один пациэнт дюже сильно пережывал за ленейность показомера и в итоге сказал что оно это ему задарром не нада. я првда ему ниччего и не навязывал и посоветовал ему если он в следущий рааз будет пороходить мимо проходить мимо. даальним леском.душа человеческая темна и с легкостью обращается ко злу


