Обсуждаем контроллеры компании Atmel.
Ответить

Re: 3-х разрядный ампервольтметр на атмега

Сб май 08, 2021 10:48:27

400 + (120 - 400) / 2 = (400 + 120) / 2 = 260

что не так?

Добавлено after 1 hour 41 minute 12 seconds:
slav0n, ваше выражение справедливо пока ADC > Out_To_Display.
Как только ADC станет < Out_To_Display, представляете какой результат получится?

фикс специально для вас:
Код:
Out_To_Display += ((int)ADC - Out_To_Display) / 2;


Добавлено after 23 minutes 12 seconds:
кстати, кому сильно хочется может применять дробные коэффициенты сглаживания:
Код:
Out_To_Display += ((int)ADC - Out_To_Display) * 2 / 3;

Re: 3-х разрядный ампервольтметр на атмега

Сб май 08, 2021 11:28:56

Спасибо, Карбофос :beer:
Спойлер#define F_CPU 16000000UL //тактовая частота мк (unsigned long)
#include <avr/io.h> //подключение библиотеки "ввод/вывод" мк
#include <util/delay.h> //подключение библиотеки "пауза" мк
#include <avr/interrupt.h> //подключение библиотеки "прерывание" мк

#define CLK_0 PORTC &= ~(1<<PORTC0) //отправить 0 на вывод Clk микросхемы MAX7219
#define CLK_1 PORTC |=1<<PORTC0 //отправить 1 на вывод Clk микросхемы MAX7219
#define CS_0 PORTC &= ~(1<<PORTC1) //отправить 0 на вывод Cs микросхемы MAX7219
#define CS_1 PORTC |=1<<PORTC1 //отправить 1 на вывод Cs микросхемы MAX7219
#define DIN_0 PORTC &= ~(1<<PORTC2) //отправить 0 на вывод Din микросхемы MAX7219
#define DIN_1 PORTC |= 1<<PORTC2 //отправить 1 на вывод Din микросхемы MAX7219
#define measure 128 // по результатам 128 измерений вычислить среднее значение measure/128

unsigned int Digit[8]; //массив беззнаковых 4-x байтных переменных Cifra из 8 переменных
unsigned char Data_In[8]; //массив беззнаковых обнобайтных символьных переменных Data_In из 8 переменных
unsigned int Display1_ADC; //беззнаковая 4-х байтная переменная Display1_ADC
unsigned int Display2_ADC; //беззнаковая 4-х байтная переменная Display2_ADC
unsigned char X; //беззнаковая однобайтная символьная переменная X (значение регистра ацп с результатом оцифровки напряжения)
unsigned char I; //беззнаковая однобайтная символьная переменная I (значение регистра ацп с результатом оцифровки тока)

//----------
void port_ini(void) //объявим функцию инициализации порта PB1 (выход сигнала генератора -V=-5v0)
{
PORTB=0x00; //portb сброс
DDRB=0x02; //portb1 на вывод (OC1A)
}
//----------
void init_PWM_timer(void) //функция таймера
{
ASSR=0x00; //сбрасываем полностью регистр assr
TCCR1A |=0b10000001; //Fast PWM oc1a, Clear OC1A on Compare Match, clkT2S/1 (no prescalling)
TCCR1B |=0b00001001;
TCNT1H=0x00; // Timer Value = 0 сброс счётного регистра таймера 1
TCNT1L=0x00;
OCR1AH=0x00; //Output Compare Register = dec85 - в нашем случае это заполнение шим DC~68%
OCR1AL=0x55;
TIMSK|=0x00; //сброс регистра timsk
}
//----------

//********************* Передача данных в Max7219 *****************
void Write_MAX7219(unsigned char Adres_Reg,unsigned char Data_In_Write)
{
unsigned char Adres_Reg_Copy;

Data_In[Adres_Reg] = Data_In_Write;
Adres_Reg_Copy = Adres_Reg; //создадим копию значения переменной Adres_Reg

CS_0; //отправим «0» на вывод CS микросхемы MAX7219, чтобы начать процесс передачи адреса и данных
asm("nop"); //пауза в 1 такт

for(I=0;I<8;I++) //цикл от 0 до 7 с шагом 1, для побитной отправки байта адреса в микросхему MAX7219
{
if((Adres_Reg & 0x80)==0x80) //если 7 бит переменной Adres_reg=1
{
DIN_1; //отправим 1 на вывод Din микросхемы MAX7219
}
else //если 7 бит переменной Adres_reg=0
{
DIN_0; //отправим 0 на вывод Din микросхемы MAX7219
}

//создадим тактовый импульс на выводе CLK микросхемы MAX7219
asm("nop"); //пауза в 1 такт
CLK_1; //отправим 1 на вывод Clk микросхемы MAX7219
asm("nop"); //пауза в 1 такт
CLK_0; //отправим 0 на вывод Clk микросхемы MAX7219
Adres_Reg <<= 1; //сдвинем значение переменной Adres_reg на 1 бит влево
} //выйдем из цикла когда i станет равной 7, т.е. когда отправка байта адреса в микросхему MAX7219 будет окончена

for(I=0;I<8;I++) //цикл от 0 до 7 с шагом 1, для побитной отправки байта данных в микросхему MAX7219
{
if((Data_In[Adres_Reg_Copy] & 0x80)==0x80) //если 7 бит переменной Data_in=1
{
DIN_1; //отправим 1 на вывод Din микросхемы MAX7219
}
else //если 7 бит переменной Data_in=0
{
DIN_0; //отправим 0 на вывод Din микросхемы MAX7219
}

//создадим тактовый импульс на выводе CLK микросхемы MAX7219
asm("nop"); //пауза в 1 такт
CLK_1; //отправим 1 на вывод Clk микросхемы MAX7219
asm("nop"); //пауза в 1 такт
CLK_0; //отправим 0 на вывод Clk микросхемы MAX7219
Data_In[Adres_Reg_Copy] <<= 1; //сдвинем значение переменной Data_in на 1 бит влево
}
//выйдем из цикла когда i станет равной 7, т.е. когда отправка байта данных в микросхему MAX7219 будет окончена
CS_1; //отправим «1» на вывод CS микросхемы MAX7219, чтобы завершить процесс передачи адреса и данных
}


//********************* Инициализация MAX7219 *****************
void Init_MAX7219()
{
Write_MAX7219(0x09,127); //включаем режим BCD code B, для 7 разрядов
Write_MAX7219(0x0A,10); //яркость свечения сегментов 10 (от 0 до 15)
Write_MAX7219(0x0B,7); //число используемых разрядов (7 разрядов)
Write_MAX7219(0x0C,1); //отключаем режим энергосбережения (Shutdown)
}


//******** Функция вывода значений на 7 сегм.индикатор №1 ******
void Out_Display_1(unsigned int Display_Ust)
{
Digit[7]=Display_Ust/100; //сотни
Digit[6]=Display_Ust%100/10; //десятки
Digit[6]=Digit[6]|128; //вкл децимальную точку в разряде Cifra_6
Digit[5]=Display_Ust%10; //единицы


for(X=5;X<8;X++)
{
Data_In[X] = Digit[X];
Write_MAX7219(X,Data_In[X]);
}
}


//******** Функция вывода значений на 7 сегм.индикатор №2 ******
void Out_Display_2(unsigned int Display_Ust)
{
Digit[4]=15; //Отключим не используемую цифру старшего разряда индикатора №2
Digit[3]=Display_Ust/100; //сотни
Digit[2]=Display_Ust%100/10; //десятки
Digit[2]=Digit[2]|128; //вкл децимальную точку в разряде Cifra_2
Digit[1]=Display_Ust%10; //единицы

for(X=1;X<5;X++)
{
Data_In[X] = Digit[X];
Write_MAX7219(X,Data_In[X]);
}
}


//*************************** Функция измерения напряжения на входах АЦП ***************************


unsigned long ADC_Convert (unsigned char Chan_ADC)
{
uint32_t sum = 0;
//ADMUX = ADMUX&224|Chan_ADC;//выберем канал АЦП (обнулим биты MUX4-MUX0 в регистре ADMUX, не изменяя при этом биты 5,6,7, после этого заменим значение битов MUX4-MUX0 на номер(код) канала)
ADMUX = ADMUX & 224; //выберем канал АЦП (сначала обнулим биты MUX4-MUX0 в регистре ADMUX, не изменяя при этом биты 5,6,7)
ADMUX = ADMUX | Chan_ADC; //выберем канал АЦП (затем заменим значение битов MUX4-MUX0 на номер(код) канала)
for(uint8_t i = 0; i < measure; ++i)
{
ADCSRA |= (1<<ADSC); //Начинаем аналого-цифровое преобразование (для этого запишем 1 в бит ADSC регистра ADCSRA)
while((ADCSRA & (1<<ADSC))); //Ждём когда закончиться аналого-цифровое преобразование (преобразование закончится, когда бит ADSC регистра ADCSRA станет равным 0)
sum += ADCW;
}
sum += measure >> 1;
sum /= measure;
return (unsigned long) sum; //Выйдем из функции и вернём (запишем) полученное значение (из регистров результата ADCL и ADCH) в переменную типа unsigned int
}

//************************** Основная функция с бесконечным циклом *******************************
int main(void)
{
DDRC = 7; //биты PC0-PC2 порта PC на вывод

Init_MAX7219(); //Инициализация MAX7219

//---------- АЦП-----------------
ADCSRA |= (1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); //Разрешение использования АЦП, Делитель 16M/128k = 125 кГц
ADMUX &= ~((1<<REFS0)|(1<<REFS1)); //внешний источник опорного напряжения Aref

//----------
port_ini(); //инициализация порта PB1
init_PWM_timer(); //вызов функции таймер 1
OCR1AH = 0x00; //запись в регистр число dec85
OCR1AL = 0x55;
//----------
while(1)
{
Display1_ADC = ADC_Convert(4); //Считаем значение с 4 канала АЦП
Out_Display_1(Display1_ADC); //Отправим считанное значение в функцию вывода на индикатор №1
_delay_ms(200);

Display2_ADC = ADC_Convert(3); //Считаем значение с 3 канала АЦП
Out_Display_2(Display2_ADC); //Отправим считанное значение в функцию вывода на индикатор №2
_delay_ms(200);
}
}

вот с таким кондом заработала платка без мигалова этого раздражающего. второй канал тоже работает, но проверить его полноценно смогу только в мастерской. надо запустить в шунт 75мВ сотку амперов с источника лбп. пока только от омметра подавал на второй вход ацп - канал работает. и второй вариант собрать на линейном дадчеге Холла ss-495a.
СпойлерИзображение Изображение

Re: 3-х разрядный ампервольтметр на атмега

Сб май 08, 2021 11:31:01

charchyard писал(а):вот с таким кондом заработала платка
кондом древний, спору нет.
прощай будущее с таким кондомом

Re: 3-х разрядный ампервольтметр на атмега

Сб май 08, 2021 14:03:01

slav0n писал(а):фикс специально для вас:
что? (int)ADC ? Это жестко.
slav0n писал(а):что не так?
может как нибудь так
Код:
(int16_t)(ADC - Out_To_Display)
да и деление на 2 заменить сдвигом
Код:
((int16_t)(ADC - Out_To_Display))>>1

slav0n писал(а):прощай будущее с таким кондомом
особенно деление на 17

Re: 3-х разрядный ампервольтметр на атмега

Сб май 08, 2021 15:11:14

Dimon456 писал(а):да и деление на 2 заменить сдвигом

сдвигать знаковое целое - лютая ересь

Re: 3-х разрядный ампервольтметр на атмега

Сб май 08, 2021 16:01:00

slav0n, недостаток Вашего метода в том, что остаток при делении теряется, т.е. если ADC стабилен и прирос на число меньшее делителя, то показания дисплея не изменятся...

Re: 3-х разрядный ампервольтметр на атмега

Сб май 08, 2021 16:04:43

Ivanoff-iv писал(а):если ADC стабилен и прирос на число меньшее делителя, то показания дисплея не изменятся...

хде я?!!
если ADC стабилен ... то показания дисплея не изменятся

Re: 3-х разрядный ампервольтметр на атмега

Сб май 08, 2021 16:13:10

ладно, "достаточно стабилен" в смысле не дёргается...
поставишь такой сглаживатель на дисплей вольтметра и будешь всё время напряжение завышать.

Re: 3-х разрядный ампервольтметр на атмега

Сб май 08, 2021 16:16:39

все зависит от коэффа
1 - повторитель
0 - сам розум маєш шо таке

Re: 3-х разрядный ампервольтметр на атмега

Сб май 08, 2021 16:17:06

или вдруг надо сильно сглаживать (делитель = 100) так вообще показаний не дождёшься..

Re: 3-х разрядный ампервольтметр на атмега

Сб май 08, 2021 16:38:14

тыж вумный, должен понять шо тут на самом деле не дялитель, а множитель 0→1

Добавлено after 11 minutes 17 seconds:
дети, зарубайте себе на носи
в системе без ОС, зглаживание происхотит в моске

Добавлено after 3 minutes 33 seconds:
вчера било 400, сегодня 120, тебе показали 260
шо ти хочиш ще?

Re: 3-х разрядный ампервольтметр на атмега

Сб май 08, 2021 16:47:43

вчера было 400, сегодня 401, и завтра 401, и послезавтра... а ты об этом и не узнаешь...

Re: 3-х разрядный ампервольтметр на атмега

Сб май 08, 2021 17:47:27

эсли информер = 0, то да, объебалово
якщо информер = 1, то все шаги записаны
информер = 1/2, хуйло...

Добавлено after 13 minutes 54 seconds:
цифры не мелькают, но живешь вчерашним днем

Добавлено after 16 minutes 6 seconds:
дети, внимайте, я ушел

Re: 3-х разрядный ампервольтметр на атмега

Сб май 08, 2021 18:12:47

Dimon456 писал(а):да и деление на 2 заменить сдвигом

сдвигать знаковое целое - лютая ересь


В машинных кодах для сдвига вправо есть специальная команда с сохранением знака - ASR Reg. Может С компилер это учитывает? (это предположение, а не утверждение)

Re: 3-х разрядный ампервольтметр на атмега

Сб май 08, 2021 19:26:16

lizard66 писал(а):В машинных кодах для сдвига вправо есть специальная команда с сохранением знака - ASR Reg. Может С компилер это учитывает?
Вот asm код
Спойлер
Код:
volatile uint16_t Out_To_Display;
volatile uint16_t ADC_t;
Код:
         Out_To_Display += ((int16_t)(ADC_t-Out_To_Display))>>1;
  18:   80 91 00 00    lds   r24, 0x0000   ; 0x800000 <__SREG__+0x7fffc1>
  1c:   90 91 00 00    lds   r25, 0x0000   ; 0x800000 <__SREG__+0x7fffc1>
  20:   40 91 00 00    lds   r20, 0x0000   ; 0x800000 <__SREG__+0x7fffc1>
  24:   50 91 00 00    lds   r21, 0x0000   ; 0x800000 <__SREG__+0x7fffc1>
  28:   20 91 00 00    lds   r18, 0x0000   ; 0x800000 <__SREG__+0x7fffc1>
  2c:   30 91 00 00    lds   r19, 0x0000   ; 0x800000 <__SREG__+0x7fffc1>
  30:   84 1b          sub   r24, r20
  32:   95 0b          sbc   r25, r21
  34:   95 95          asr   r25
  36:   87 95          ror   r24
  38:   82 0f          add   r24, r18
  3a:   93 1f          adc   r25, r19
  3c:   90 93 00 00    sts   0x0000, r25   ; 0x800000 <__SREG__+0x7fffc1>
  40:   80 93 00 00    sts   0x0000, r24   ; 0x800000 <__SREG__+0x7fffc1>
и для сравнения деление
Код:
  Out_To_Display += ((int16_t)(ADC_t-Out_To_Display))/2;
  18:   80 91 00 00    lds   r24, 0x0000   ; 0x800000 <__SREG__+0x7fffc1>
  1c:   90 91 00 00    lds   r25, 0x0000   ; 0x800000 <__SREG__+0x7fffc1>
  20:   40 91 00 00    lds   r20, 0x0000   ; 0x800000 <__SREG__+0x7fffc1>
  24:   50 91 00 00    lds   r21, 0x0000   ; 0x800000 <__SREG__+0x7fffc1>
  28:   20 91 00 00    lds   r18, 0x0000   ; 0x800000 <__SREG__+0x7fffc1>
  2c:   30 91 00 00    lds   r19, 0x0000   ; 0x800000 <__SREG__+0x7fffc1>
  30:   84 1b          sub   r24, r20
  32:   95 0b          sbc   r25, r21
  34:   97 fd          sbrc   r25, 7
  36:   01 96          adiw   r24, 0x01   ; 1
  38:   95 95          asr   r25
  3a:   87 95          ror   r24
  3c:   82 0f          add   r24, r18
  3e:   93 1f          adc   r25, r19
  40:   90 93 00 00    sts   0x0000, r25   ; 0x800000 <__SREG__+0x7fffc1>
  44:   80 93 00 00    sts   0x0000, r24   ; 0x800000 <__SREG__+0x7fffc1>
Проблема в том что при входных данных
Код:
         Out_To_Display = 400;
         ADC = 120;
на выходе Out_To_Display при делении на 2 получает завышенное показание на 1, то есть 121, а при сдвиге, ровно 120.

Re: 3-х разрядный ампервольтметр на атмега

Сб май 08, 2021 20:38:37

Наверное, эта пара строк вас смутила:
Код:
  34:   97 fd          sbrc   r25, 7
  36:   01 96          adiw   r24, 0x01   ; 1

Это стандартная коррекция при инвертировании знака числа.
Как видно, при использовании операции сдвига, эта коррекция не выполняется.
Т.о. в данном случае правильно делить, а не сдвигать.
на выходе Out_To_Display при делении на 2 получает завышенное показание на 1, то есть 121, а при сдвиге, ровно 120.

Это неверно.

Re: 3-х разрядный ампервольтметр на атмега

Сб май 08, 2021 21:03:01

Карбофос писал(а):Это стандартная коррекция при инвертировании знака числа.
Да, только эту коррекцию надо будет потом отнимать.
Карбофос писал(а):Т.о. в данном случае правильно делить, а не сдвигать.
Правильно будет без приведения типов.
Карбофос писал(а):Это неверно.
По чему неверно, прокрутите в цикле раз так нцать.

Re: 3-х разрядный ампервольтметр на атмега

Сб май 08, 2021 21:09:32

Карбофос писал(а):Это стандартная коррекция при инвертировании знака числа.
какая еще коррекция?
возьмем простой пример:
03 - 05 = FE. а FE - это и есть -2, то есть правильный результат.
а после прибавления 1 получим -1, то есть неправильный результат.

Re: 3-х разрядный ампервольтметр на атмега

Сб май 08, 2021 21:10:14

алгоритм slav0n'а, ещё плох тем, что дисплей 0 показывать будет только при включении, а потом как не опускай напряжение - нуля на дисплее уже не добиться...
я помню гдето тоже пытался применить такой код - не понравилось... с накопителем лучше.

Re: 3-х разрядный ампервольтметр на атмега

Вс май 09, 2021 00:20:43

ага, нуля нима, но есть минуса

Добавлено after 17 minutes 38 seconds:
вчира било 0, седня 0, показали 0
вчира било 10, седня -10, показали раздватри
вчира било 10, седня -5, показали раздватри
вчира било -10, седня 5, показали раздватри
Ответить