Здравствуйте коты! я, к сожаленью, полнейший нуль в программировании. Помогите скрестить ежа и ужа. Нашёл в Сети видео вольтметра на семисегментном 3-х индикаторе мк атмега_8 или атмега_16. предел 0...100в с точностью 0,1в... и амперметр 0...100а с точностью 0,1а. шунт 100а 75мВ. Вопрос как правильно скрестить две программы, чтобы атмега оцифровывала поочерёдно эти переменные на входах PA0 и PA1 и выводила на два 3-х разрядных 7-индикатора ОА. программа для вольтметра и амперметра одна. А вот как запихнуть эти две функции в одну микру?
Вариант 1 - написать свою программу (прошивку), если умеете. Вариант 2 - ОПЛАТИТЬ написание своей прошивки Вариант 3 - Тщательнее искать нужную схему Вариант 4 - купить готовый AV метр - https://aliexpress.ru/item/1005001356302861.html
Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ очень важен контроль процесса заряда и разряда для избегания воздействия внешнего зарядного напряжения после достижения 100% заряда. Инженеры КОМПЭЛ подготовили список таких решений от разных производителей.
5 вариант не лучший...и да я ранше тоже сам паял на 7107 сначала дип а потом QFP щас тупа заказали мешок разных с алехи и ставлю не парясь.. 123 конечно возможен но толка из любви к трудностям=садо маза... автору пока 4 вариан такого добра наштампованано на любой вкус и цвет ка с жидами так и на LCD
_________________ ZМудрость(Опыт и выдержка) приходит с годами. Все Ваши беды и проблемы, от недостатка знаний. Умный и у дурака научится, а дураку и .. Алберт Ейнштейн не поможет и ВВП не спасет.и МЧС опаздает
Компания EVE выпустила новый аккумулятор серии PLM, сочетающий в себе высокую безопасность, длительный срок службы, широкий температурный диапазон и высокую токоотдачу даже при отрицательной температуре.
Эти аккумуляторы поддерживают заряд при температуре от -40/-20°С (сниженным значением тока), безопасны (не воспламеняются и не взрываются) при механическом повреждении (протыкание и сдавливание), устойчивы к вибрации. Они могут применяться как для автотранспорта (трекеры, маячки, сигнализация), так и для промышленных устройств мониторинга, IoT-устройств.
Если бы я умел писать прошивки, то у меня проблем было бы намного меньше.. А так- приходится пользоваться тем, что кто- то написал
А чем вас китайские ампервольтметры не устраивают? У меня тоже пара таких валяется, когда я их проверял, там амперметр, даже после попытки его настроить, врал раза в 1,5.. Но как- бы, проблемы с их использованием нет..
#include <avr/io.h> #include <avr/interrupt.h> // библиотека прерываний включена коды символов для индикатора #include <string.h> // 0 1 2 3 4 5 6 7 8 9 нет uint8_t code_numbers_indicator[11] = { 40, 235, 49, 161, 226, 164, 36, 233, 32, 160, 255 };
// кол-во каналов #define nChannels 2 // доп.разрядов на измерение каждого канала #define nExtraBit 3 // кол-во измерений каждого канала #define nMeasPerCh (1 << nExtraBit) // массив с результатами работы АЦП по каналам volatile uint16_t auRawADC[nChannels]; // флаг окончания цикла по каналам volatile uint8_t bADCcomplete;
ISR(ADC_vect) { static uint8_t nMeasure = 0; // номер текущего канала АЦП uint8_t nNowConv = ADMUX & 0b111; // получаем значение из регистра данных auRawADC[nNowConv] += ADCW; if(++nMeasure < nMeasPerCh) { // очередной запуск измерения текущего канала ADCSRA |= 1 << ADSC; } else { // обнуляем счетчик кол-ва измерений nMeasure = 0; // усредняем значение auRawADC[nNowConv] += (1 << (nExtraBit - 1)); auRawADC[nNowConv] >>=nExtraBit; // сброс номера канала ADMUX &= 0b11100000; // если не все каналы оцифрованы if(++nNowConv < nChannels) { ADMUX |= nNowConv; // следующий канал АЦП ADCSRA |= 1 << ADSC; } else { // цикл оцифровки каналов окончен bADCcomplete = 1; } } }
// преобразуем числовые значения в набор сегментов for(uint8_t i = 0; i < NumDigits; ++i) aDisp[i].seg = code_numbers_indicator[aDisp[i].seg]; // десятичная точка aDisp[1].seg &= ~(1<<5); aDisp[4].seg &= ~(1<<5); }
volatile uint8_t nShowDigit;
ISR (TIMER0_COMP_vect) // прерывание по совпадению таймера T0 работа с разрядами индикатора { // отключить общий анод предыдущего индикатора *aDisp[nShowDigit].port |= (1 << aDisp[nShowDigit].pin); // следующая цифра if(++nShowDigit >= NumDigits) nShowDigit = 0; // выставляем сегменты PORTB = aDisp[nShowDigit].seg; // включаем общий анод *aDisp[nShowDigit].port &= ~(1 << aDisp[nShowDigit].pin); }
void Setup(void) { // таймер смены отборажения цифр // Каждая цифра отображается T = 64*(1+OCR0)/F_CPU = 64*(1+24)/1000000=1.6мсек OCR0=24; // число в регистре сравнения COMP TCCR0=0b00001011; // преддделитель /64; сброс по совпадению чисел в регистрах TCNT0 & OCR0 TIMSK|=(1<<1); // вектор прерывания сработает по совпадению // сегменты индикаторов PORTB = 255; // выставляем порт PB в единичное состояние DDRB = 255; // выставляем порт PB на вывод // пины общих анодов на вывод for(uint8_t i = 0; i < NumDigits; ++i) *aDisp[i].ddr |= (1 << aDisp[i].pin); // АЦП ADMUX |=(0<<REFS0)|(0<<REFS1)|(0<<MUX3)|(0<<MUX2)|(0<<MUX1)|(0<<MUX0); // опорное Vref=+AREF(refs0/refs1); входной канал PA0(mux0...mux4) ADCSRA|=(1<<ADEN)|(1<<ADIE)|(1<<ADIF)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); // вкл ацп (aden); разрешение прерывания (adie); предделитель adc /128 (adps0...adps2) DDRA &= ~((1<<1)|(1<<0)); // настраиваем 0 и 1 биты порт А на ввод (вход ацп) }
int main (void) { Setup(); // обнуляем массив значений каналов memset((void*)auRawADC, 0, sizeof(auRawADC)); // флаг окончания цикла оцифровки каналов bADCcomplete = 0; // номер цифры для отображения nShowDigit = 0; sei(); // разрешаем прерывания // запуск АЦП ADCSRA |= 1 << ADSC; while(1) { if(nShowDigit == NumDigits - 1 && bADCcomplete) { dataProcessing(); memset((void*)auRawADC, 0, sizeof(auRawADC)); bADCcomplete = 0; // запуск АЦП ADCSRA |= 1 << ADSC; } } }
Про атмел-студию ничего не могу сказать, т.к. не пользуюсь ей. Может быть, местные обитатели подскажут, как в ней собрать. Я в командной строке make-ом собираю, avr-gcc компилятор. Приложил собранный проект.
#include <avr/io.h> #include <avr/interrupt.h> // библиотека прерываний включена коды символов для индикатора #include <string.h> // 0 1 2 3 4 5 6 7 8 9 нет uint8_t code_numbers_indicator[11] = { 40, 235, 49, 161, 226, 164, 36, 233, 32, 160, 255 };
// кол-во каналов #define nChannels 2 // доп.разрядов на измерение каждого канала #define nExtraBit 3 // кол-во измерений каждого канала #define nMeasPerCh (1 << nExtraBit) // массив с результатами работы АЦП по каналам volatile uint16_t auRawADC[nChannels]; // флаг окончания цикла по каналам volatile uint8_t bADCcomplete;
ISR(ADC_vect) { static uint8_t nMeasure = 0; // номер текущего канала АЦП uint8_t nNowConv = ADMUX & 0b111; // получаем значение из регистра данных auRawADC[nNowConv] += ADCW; if(++nMeasure < nMeasPerCh) { // очередной запуск измерения текущего канала ADCSRA |= 1 << ADSC; } else { // обнуляем счетчик кол-ва измерений nMeasure = 0; // усредняем значение auRawADC[nNowConv] += (1 << (nExtraBit - 1)); auRawADC[nNowConv] >>=nExtraBit; // сброс номера канала ADMUX &= 0b11100000; // если не все каналы оцифрованы if(++nNowConv < nChannels) { ADMUX |= nNowConv; // следующий канал АЦП ADCSRA |= 1 << ADSC; } else { // цикл оцифровки каналов окончен bADCcomplete = 1; } } }
// преобразуем числовые значения в набор сегментов for(uint8_t i = 0; i < NumDigits; ++i) aDisp[i].seg = code_numbers_indicator[aDisp[i].seg]; // десятичная точка aDisp[1].seg &= ~(1<<5); aDisp[4].seg &= ~(1<<5); }
volatile uint8_t nShowDigit;
ISR (TIMER0_COMP_vect) // прерывание по совпадению таймера T0 работа с разрядами индикатора { // отключить общий анод предыдущего индикатора *aDisp[nShowDigit].port |= (1 << aDisp[nShowDigit].pin); // следующая цифра if(++nShowDigit >= NumDigits) nShowDigit = 0; // выставляем сегменты PORTB = aDisp[nShowDigit].seg; // включаем общий анод *aDisp[nShowDigit].port &= ~(1 << aDisp[nShowDigit].pin); }
void Setup(void) { // таймер смены отборажения цифр // Каждая цифра отображается T = 64*(1+OCR0)/F_CPU = 64*(1+24)/1000000=1.6мсек OCR0=24; // число в регистре сравнения COMP TCCR0=0b00001011; // преддделитель /64; сброс по совпадению чисел в регистрах TCNT0 & OCR0 TIMSK|=(1<<1); // вектор прерывания сработает по совпадению // сегменты индикаторов PORTB = 255; // выставляем порт PB в единичное состояние DDRB = 255; // выставляем порт PB на вывод // пины общих анодов на вывод for(uint8_t i = 0; i < NumDigits; ++i) *aDisp[i].ddr |= (1 << aDisp[i].pin); // АЦП ADMUX |=(0<<REFS0)|(0<<REFS1)|(0<<MUX3)|(0<<MUX2)|(0<<MUX1)|(0<<MUX0); // опорное Vref=+AREF(refs0/refs1); входной канал PA0(mux0...mux4) ADCSRA|=(1<<ADEN)|(1<<ADIE)|(1<<ADIF)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); // вкл ацп (aden); разрешение прерывания (adie); предделитель adc /128 (adps0...adps2) DDRA &= ~((1<<1)|(1<<0)); // настраиваем 0 и 1 биты порт А на ввод (вход ацп) }
int main (void) { Setup(); // обнуляем массив значений каналов memset((void*)auRawADC, 0, sizeof(auRawADC)); // флаг окончания цикла оцифровки каналов bADCcomplete = 0; // номер цифры для отображения nShowDigit = 0; sei(); // разрешаем прерывания // запуск АЦП ADCSRA |= 1 << ADSC; while(1) { if(nShowDigit == NumDigits - 1 && bADCcomplete) { dataProcessing(); memset((void*)auRawADC, 0, sizeof(auRawADC)); bADCcomplete = 0; // запуск АЦП ADCSRA |= 1 << ADSC; } } }
вставил Atmel Studio 7.0 все, ничего там собирать не надо.
да код рабочий теперь осталось понять куда в шпротеусе подключать вход делителя вольтметра и выход усилка амперметра и как индикаторы к меге подключать ну вот же тупой бл
_________________ душа человеческая темна и с легкостью обращается ко злу
Вход делителя вольтметра и выход усилка амперметра - PA0, PA1. Катоды (сегменты) всех индикаторов - как и в оригинальной схеме, через токоограничительные резисторы к порту PB. Общие аноды 1-го 3-х разрядного индикатора - как в оригинальной схеме, через транзисторные ключи, старший PD7, средний PC0, младший PC1. Общие аноды 2-го 3-х разрядного индикатора - так-же через транзисторные ключи, старший PС2, средний PC3, младший PC4.
Подключение сегментов жестко задано - порт PB с привязкой каждого сегмента к конкретному пину.
// 2 индикатора 6 цифр по-сегментно typDigit aDisp[NumDigits] = { {&DDRD, &PORTD, 7, 10}, // общий анод старшего разряда 1-го индикатора {&DDRC, &PORTC, 0, 0}, // общий анод среднего разряда 1-го индикатора {&DDRC, &PORTC, 1, 0}, // общий анод младшего разряда 1-го индикатора {&DDRC, &PORTC, 2, 10}, // общий анод старшего разряда 2-го индикатора {&DDRC, &PORTC, 3, 0}, // общий анод среднего разряда 2-го индикатора {&DDRC, &PORTC, 4, 0} // общий анод младшего разряда 2-го индикатора };
Всё это можно вынести в отдельный файл и приинклюдить. (Номера твоих пинов я сюда не подставлял)Чтобы изменить порядок ног сегментов теперь достаточно переписать их номера в первых 8ми строках и весь знакогенератор будет пересчитан автоматически. Не спорю, наверно можно ещё правильней написать, например для ОА/ОК дисплеев автоматизировать перерисовку...
_________________ Просто не учи физику в школе, и вся твоя жизнь будет наполнена чудесами и волшебством Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Ivanoff-iv, вы, наверное, не смотрели 1-ый пост темы. Этот массив определен в приложенной к нему исходному коду программы в соответствии с приципиальной схемой. Предложенное вами решение, конечно-же, более универсальное. Что я и постарался сделать с ОА. Но, "лишние" 44 строки текста при текущих 147 всей программы???
А что не готово? В среде ардуино все делается обычно подключением готовых библиотек. Можно за индикатор тот же TM1637 взять готовым модулем. Добавить библиотеку одна строка, вывести на него еще одна строка)
этот код не усложнит чтение кода (т.к. лежит в отдельном файле) и не утяжеляет прошивку (т.к. обсчитывается на этапе компиляции)... Ну... если проект окончательный и обжалованию... изменению не подлежит, то и ладно... (в конце концов - кто код пишет, тот имена переменным и придумывает )
_________________ Просто не учи физику в школе, и вся твоя жизнь будет наполнена чудесами и волшебством Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 43
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения