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

Обсуждаем контроллеры компании Atmel.
Ответить
Опытный кот
Аватара пользователя
Сообщения: 882
Зарегистрирован: Ср дек 01, 2010 00:38:15
Откуда: Харьков

Сообщение slav0n »

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

что не так?

Добавлено after 1 hour 41 minute 12 seconds:
[uquote="Dimon456",url="/forum/viewtopic.php?p=4028608#p4028608"]slav0n, ваше выражение справедливо пока ADC > Out_To_Display.
Как только ADC станет < Out_To_Display, представляете какой результат получится?[/uquote]
фикс специально для вас:

Код: Выделить всё

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

Код: Выделить всё

Out_To_Display += ((int)ADC - Out_To_Display) * 2 / 3;
ohmycode!
primuss3.com
Контактная информация:
Реклама
Поставщик валерьянки для Кота
Сообщения: 2466
Зарегистрирован: Сб май 07, 2011 17:52:59

Сообщение charchyard »

Спасибо, Карбофос :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.
СпойлерИзображение Изображение
душа человеческая темна и с легкостью обращается ко злу
Реклама
Опытный кот
Аватара пользователя
Сообщения: 882
Зарегистрирован: Ср дек 01, 2010 00:38:15
Откуда: Харьков

Сообщение slav0n »

charchyard писал(а):вот с таким кондом заработала платка
кондом древний, спору нет.
прощай будущее с таким кондомом
ohmycode!
primuss3.com
Контактная информация:
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

slav0n писал(а):фикс специально для вас:
что? (int)ADC ? Это жестко.
slav0n писал(а):что не так?
может как нибудь так

Код: Выделить всё

(int16_t)(ADC - Out_To_Display)
да и деление на 2 заменить сдвигом

Код: Выделить всё

((int16_t)(ADC - Out_To_Display))>>1
slav0n писал(а):прощай будущее с таким кондомом
особенно деление на 17
Реклама
Эиком - электронные компоненты и радиодетали
Опытный кот
Аватара пользователя
Сообщения: 882
Зарегистрирован: Ср дек 01, 2010 00:38:15
Откуда: Харьков

Сообщение slav0n »

Dimon456 писал(а):да и деление на 2 заменить сдвигом
сдвигать знаковое целое - лютая ересь
ohmycode!
primuss3.com
Контактная информация:
Реклама
Друг Кота
Аватара пользователя
Сообщения: 7077
Зарегистрирован: Пт ноя 11, 2016 05:48:09
Откуда: Сердце Пармы

Сообщение Ivanoff-iv »

slav0n, недостаток Вашего метода в том, что остаток при делении теряется, т.е. если ADC стабилен и прирос на число меньшее делителя, то показания дисплея не изменятся...
Для тех, кто не учил магию мир полон физики :)
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Реклама
Опытный кот
Аватара пользователя
Сообщения: 882
Зарегистрирован: Ср дек 01, 2010 00:38:15
Откуда: Харьков

Сообщение slav0n »

Ivanoff-iv писал(а):если ADC стабилен и прирос на число меньшее делителя, то показания дисплея не изменятся...
хде я?!!
если ADC стабилен ... то показания дисплея не изменятся
ohmycode!
primuss3.com
Контактная информация:
Друг Кота
Аватара пользователя
Сообщения: 7077
Зарегистрирован: Пт ноя 11, 2016 05:48:09
Откуда: Сердце Пармы

Сообщение Ivanoff-iv »

ладно, "достаточно стабилен" в смысле не дёргается...
поставишь такой сглаживатель на дисплей вольтметра и будешь всё время напряжение завышать.
Для тех, кто не учил магию мир полон физики :)
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Опытный кот
Аватара пользователя
Сообщения: 882
Зарегистрирован: Ср дек 01, 2010 00:38:15
Откуда: Харьков

Сообщение slav0n »

все зависит от коэффа
1 - повторитель
0 - сам розум маєш шо таке
ohmycode!
primuss3.com
Контактная информация:
Друг Кота
Аватара пользователя
Сообщения: 7077
Зарегистрирован: Пт ноя 11, 2016 05:48:09
Откуда: Сердце Пармы

Сообщение Ivanoff-iv »

или вдруг надо сильно сглаживать (делитель = 100) так вообще показаний не дождёшься..
Для тех, кто не учил магию мир полон физики :)
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Опытный кот
Аватара пользователя
Сообщения: 882
Зарегистрирован: Ср дек 01, 2010 00:38:15
Откуда: Харьков

Сообщение slav0n »

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

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

Добавлено after 3 minutes 33 seconds:
вчера било 400, сегодня 120, тебе показали 260
шо ти хочиш ще?
ohmycode!
primuss3.com
Контактная информация:
Друг Кота
Аватара пользователя
Сообщения: 7077
Зарегистрирован: Пт ноя 11, 2016 05:48:09
Откуда: Сердце Пармы

Сообщение Ivanoff-iv »

вчера было 400, сегодня 401, и завтра 401, и послезавтра... а ты об этом и не узнаешь...
Для тех, кто не учил магию мир полон физики :)
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Опытный кот
Аватара пользователя
Сообщения: 882
Зарегистрирован: Ср дек 01, 2010 00:38:15
Откуда: Харьков

Сообщение slav0n »

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

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

Добавлено after 16 minutes 6 seconds:
дети, внимайте, я ушел
ohmycode!
primuss3.com
Контактная информация:
Первый раз сказал Мяу!
Аватара пользователя
Сообщения: 35
Зарегистрирован: Чт май 14, 2015 16:58:00
Откуда: Kharkiv

Сообщение lizard66 »

[uquote="slav0n",url="/forum/viewtopic.php?p=4028777#p4028777"]
Dimon456 писал(а):да и деление на 2 заменить сдвигом
сдвигать знаковое целое - лютая ересь[/uquote]

В машинных кодах для сдвига вправо есть специальная команда с сохранением знака - ASR Reg. Может С компилер это учитывает? (это предположение, а не утверждение)
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

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.
Опытный кот
Аватара пользователя
Сообщения: 760
Зарегистрирован: Сб окт 22, 2016 17:33:32
Откуда: кг

Сообщение Карбофос »

Наверное, эта пара строк вас смутила:

Код: Выделить всё

  34:   97 fd          sbrc   r25, 7
  36:   01 96          adiw   r24, 0x01   ; 1
Это стандартная коррекция при инвертировании знака числа.
Как видно, при использовании операции сдвига, эта коррекция не выполняется.
Т.о. в данном случае правильно делить, а не сдвигать.
[uquote="Dimon456",url="/forum/viewtopic.php?p=4028883#p4028883"]на выходе Out_To_Display при делении на 2 получает завышенное показание на 1, то есть 121, а при сдвиге, ровно 120.[/uquote]
Это неверно.
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

Карбофос писал(а):Это стандартная коррекция при инвертировании знака числа.
Да, только эту коррекцию надо будет потом отнимать.
Карбофос писал(а):Т.о. в данном случае правильно делить, а не сдвигать.
Правильно будет без приведения типов.
Карбофос писал(а):Это неверно.
По чему неверно, прокрутите в цикле раз так нцать.
Модератор
Аватара пользователя
Сообщения: 19077
Зарегистрирован: Сб авг 14, 2010 15:05:51
Откуда: г. Озерск, Челябинская обл.

Сообщение Starichok51 »

Карбофос писал(а):Это стандартная коррекция при инвертировании знака числа.
какая еще коррекция?
возьмем простой пример:
03 - 05 = FE. а FE - это и есть -2, то есть правильный результат.
а после прибавления 1 получим -1, то есть неправильный результат.
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Друг Кота
Аватара пользователя
Сообщения: 7077
Зарегистрирован: Пт ноя 11, 2016 05:48:09
Откуда: Сердце Пармы

Сообщение Ivanoff-iv »

алгоритм slav0n'а, ещё плох тем, что дисплей 0 показывать будет только при включении, а потом как не опускай напряжение - нуля на дисплее уже не добиться...
я помню гдето тоже пытался применить такой код - не понравилось... с накопителем лучше.
Для тех, кто не учил магию мир полон физики :)
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Опытный кот
Аватара пользователя
Сообщения: 882
Зарегистрирован: Ср дек 01, 2010 00:38:15
Откуда: Харьков

Сообщение slav0n »

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

Добавлено after 17 minutes 38 seconds:
вчира било 0, седня 0, показали 0
вчира било 10, седня -10, показали раздватри
вчира било 10, седня -5, показали раздватри
вчира било -10, седня 5, показали раздватри
ohmycode!
primuss3.com
Контактная информация:
Ответить

Вернуться в «AVR»