Электроника - это просто Теоретические и практические вопросы для начинающих электронщиков. |
06.05.2012, 02:29
|
|
Почётный гражданин KAZUS.RU
Регистрация: 04.12.2009
Сообщений: 5,455
Сказал спасибо: 73
Сказали Спасибо 2,510 раз(а) в 1,414 сообщении(ях)
|
Re: Амперметр на МК
Сообщение от Yurkin2007
|
При измерении тока просто вычитаете из значения АЦП запомненное значение для "0" и получаете то, что надо
|
А лучше - поставить перемычечку на плате и подписать - "калибровка 0", замкнул - прочиталось значение, запомнилось, от него потом и пляшем.
|
|
|
|
06.05.2012, 06:39
|
|
Почётный гражданин KAZUS.RU
Регистрация: 26.11.2011
Адрес: Анапа
Сообщений: 1,620
Сказал спасибо: 284
Сказали Спасибо 129 раз(а) в 111 сообщении(ях)
|
Re: Амперметр на МК
Scadauser,
Yurkin2007,
большое спасибо! все пины расписаны, поэтому сделаю по нажатию и удержанию двух кнопок (которые уже есть) в течении трех секунд. вольтметр будет привязываться на 5в, амперметр на ноль. 5в буду давать стабилизированное.
|
|
|
|
06.05.2012, 14:15
|
|
Частый гость
Регистрация: 22.12.2006
Сообщений: 8
Сказал спасибо: 140
Сказали Спасибо 0 раз(а) в 0 сообщении(ях)
|
Re: Амперметр на МК
почитал тему, предложу еще один способ измерения постоянного тока в цепи - типа компенсационного: силовой провод продет в отверстие в железном незамкнутом сердечнике. В зазоре сердечника стоит датчик Холла в качестве нуль-индикатора.
Сигнал напряжения с этого датчика усиливается в ток такой силы и полярности, чтобы
размагнитить сердечник. То есть ток выхода усилителя проходит через катушку надетую на этот же самый сердечник. Ампер-витки у нее те же что у первичной, витков много - ток усилителя в столько же раз меньше. Петля авторегулирования замыкается и стремится ловить 0 индукции в сердечнике. Посему проблем с линейностью быть не должно. Предвижу же проблему с устойчивостью усилителя. Из плюсов - дешево и в цепь врезаться не надо. Вот!
|
|
|
|
06.05.2012, 14:44
|
|
Частый гость
Регистрация: 22.12.2006
Сообщений: 8
Сказал спасибо: 140
Сказали Спасибо 0 раз(а) в 0 сообщении(ях)
|
Re: Амперметр на МК
Прошу извинить меня, не продумавши написал. Даже магнитомягкий ферромагнетик имеет коэрцитивную силу (остаточный магнетизм) и в предложенной методе вызовет смещение то в + то в -. Тогда пусть усилитель возбуждается (и в режим ШИМ наверно работать будет) и быстро перемагничивает сердечник. Напряжение с размагничивающей катушки тогда надо проинтегрировать RC-фильтром перед подачей на ЦАП. Жрать поди много будет такая система...В общем, предлагаю в качестве пищи для размышлений -
|
|
|
|
06.05.2012, 15:12
|
|
Почётный гражданин KAZUS.RU
Регистрация: 20.03.2007
Адрес: "Братское кольцо враждебности", т.е. ближайшее заМКАДье.
Сообщений: 6,917
Сказал спасибо: 2,980
Сказали Спасибо 3,161 раз(а) в 2,146 сообщении(ях)
|
Re: Амперметр на МК
Сообщение от onwire
|
почитал тему, предложу еще один способ измерения постоянного тока в цепи - типа компенсационного: силовой провод продет в отверстие в железном незамкнутом сердечнике. В зазоре сердечника стоит датчик Холла в качестве нуль-индикатора.
|
КМК, некоторые LEM'ы и Honeywell'ы имеют именно такую конструкцию. Так-что гистерезис при перемагничивании - решаемая проблема.
|
|
|
|
06.05.2012, 22:37
|
|
Почётный гражданин KAZUS.RU
Регистрация: 29.12.2009
Сообщений: 4,561
Сказал спасибо: 619
Сказали Спасибо 1,813 раз(а) в 974 сообщении(ях)
|
Re: Амперметр на МК
Тыщу лет назад видал я такую конструкцию: силовой провод продет через ферритовое кольцо.
На кольце 2 обмотки: сигнальная намотана нормально, а подмагничивающая по внешнему краю кольца (т.е. ось обмотки совпадает с продетым проводом). Такая обмотка, питаемая переменным подмагничиванием, не создает отклика в сигнальной обмртке, так как они перпендикулярны, но от подмагничиания меняется магнитная проницаемость феррита (он же нелинеен).
Поэтому, если появляется ток в продетом проводе - то его поле модулируется изменяющейся проницаемостью феррита, и в сигнальной обмотке наводится сигнал, пропорциональный току в проводе.
Но здесь применить такую вещь сложно, поскольку от полярности будет зависеть фаза снимаемого переменного сигнала, придется городить фазовый детектор.
Но как пища для размышлений - тож неплохо)))))))
__________________
оставил форум, защищая свою честь и достоинство.
|
|
|
|
10.05.2012, 08:54
|
|
Почётный гражданин KAZUS.RU
Регистрация: 26.11.2011
Адрес: Анапа
Сообщений: 1,620
Сказал спасибо: 284
Сказали Спасибо 129 раз(а) в 111 сообщении(ях)
|
Re: Амперметр на МК
Ну, вроде завелось. на тычки "пальцем" во входа операционника реагирует.
http://www.youtube.com/watch?v=wzLri...ature=youtu.be
Помогите оптимизировать программу? 99,7% занято в тиньке 261, а хочется еще калибровку вольтметра..
Код:
|
/*
*/
#define F_CPU 8000000UL
#include ‹avr/io.h›
#include ‹avr/interrupt.h›
#include ‹avr/eeprom.h›
/* пины */
#define SH_CP PB0 //защелка регистра
#define ST_CP PB1 //clock регистра
#define DATA PB2 //данные в регистр
#define LED_BRI PB4 //яркость подсветки (программный шим)
#define BUT_MODE PB3 //кнопка выбора режима
#define BUT_BRI PB5 //кнопка выбора яркости
#define RED_LED PA3 //красный светодиод галактека опасносте
#define EX_LED PA0 //вход сигнала габаритов
/* настройки */
#define TAXO_DIV 4 //количество импульсов за оборот коленвала
#define TAXOLED_DIV 200 //оборотов на один светодиод
#define AMP_DIV 2 //делитель (коэффициент) амперметра. На него делится значение +-512
#define VOLTMETER_DIV 25 //резисторный делитель * опорное напряжение (5в) и еще что то
#define OFF_TIME 30000 //время выключения при бортовом ниже OFF_VOLT
#define OFF_VOLT 130 //порог, ниже которого устройство отрубается через OFF_TIME
/* вспомогательное */
//настройки
/* переменные */
volatile unsigned char mode=0; //0 - вольтметр, 1 - амперметр, 2 - тахометр
volatile unsigned char mode_off=0; //0 - дисплей выкл, 1 - дисплей вкл
volatile unsigned long millis; //счетчик прошедших миллисекунд с начала работы
volatile unsigned long prev_millis_main; //храним время последнего вызова главного цикла
volatile unsigned long prev_millis_off; //храним время отключения если низкое бортовое
volatile unsigned int last_press_time; //переменная для определения длительности нажатия BUT_MODE
volatile unsigned char taxo_tmp; //временная переменная тахометра, используемая в прерывании
volatile unsigned int taxo; //переменная тахометра
volatile signed int amp; //переменная амперметра
volatile unsigned char amp_sign; //знак амперметра
volatile unsigned int amp_null; //соответствие уровня АЦП нулю показаний амперметра
volatile unsigned int volt; //переменная напряжения
volatile unsigned char to_display[4]; //цифры и символы для вывода на дисплей
volatile unsigned char to_led_line[3]; //светодиодная линейка тахометра
volatile unsigned char digit_step; //шаг вывода на дисплей/текущая цифра
volatile unsigned char bri[2]; //яркость дисплея и светодиодов линейки тахометра
volatile unsigned char bri_step; //шаг цикла яркости
//цифры ==›dp gfedcba
static unsigned char symbols[14] = {
0b00111111, //0 [0]
0b00000110, //1 [1]
0b01011011, //2 [2]
0b01001111, //3 [3]
0b01100110, //4 [4]
0b01101101, //5 [5]
0b01111101, //6 [6]
0b00000111, //7 [7]
0b01111111, //8 [8]
0b01101111, //9 [9]
0b00000000, //sp[10]
0b01110111, //A [11]
0b00111110, //U [12]
0b01000000 //- [13]
};
/* вспомогательные функции */
//пауза
void pause(unsigned int _pause){
unsigned int i;
for (i = _pause * 1000; i›0; i--) asm("nop");
}
//ADC function - оцифровка
unsigned int ADC_input(unsigned char _pin) {
//выбор пина
if (_pin == 1) ADMUX = (1 ‹‹ MUX0); //ADC1
if (_pin == 2) ADMUX = (1 ‹‹ MUX1); //ADC2
ADCSRA |= (1 ‹‹ ADEN);
ADCSRA |= (1 ‹‹ ADSC); // Включаем оцифровку
while (ADCSRA & (1 ‹‹ ADSC)); //Ждем окончания
ADCSRA &= ~(1‹‹ADEN); // остановим оцифровку
return (ADCL|ADCH‹‹8); //отдаем результат
}
//заносит цифры и символы в массив to_display
void to_numbers(unsigned int _number) {
to_display[0] = 0;
to_display[1] = 0;
to_display[2] = 0;
to_display[3] = 0;
//разбираем число на символы
while (_number ›= 1000) {
_number -= 1000;
to_display[0]++;
}
while (_number ›= 100) {
_number -= 100;
to_display[1]++;
}
while (_number ›= 10) {
_number -= 10;
to_display[2]++;
}
to_display[3] = _number;
if(mode == 0) to_display[0] = 12; //если режим вольтметра выводим U
if(mode == 1 && amp_sign == 1) to_display[0] = 13; //если режим амперметра и разряд выводим минус
else if(mode == 1) to_display[0] = 11; //если режим амперметра выводим А
if((mode==0 || mode ==1 ) && to_display[1]==0) to_display[1] = 10; //если режим амер/вольтметра и первый ноль, ставим взамен пробел
}
//формирование потока на регистр из одного байта
void shiftout(char _byte){
//цикл по битам
for (char i=0; i‹=7; i++) {
if(_byte&(1‹‹i)) PORTB |= (1‹‹DATA);
else PORTB &= ~(1‹‹DATA);
//обозначим clock
PORTB |= (1‹‹SH_CP);
PORTB &= ~(1‹‹SH_CP);
}
}
//вывод данных в регистры
void out(void) {
PORTA |= ((1‹‹PA4)|(1‹‹PA5)|(1‹‹PA6)|(1‹‹PA7)); //выключим катоды дисплея
PORTB &= ~(1‹‹LED_BRI); //выключим катод светодиодов
if(mode_off==1) {
PORTB &= ~(1‹‹ST_CP); //снимем "защелку" 74HC595
//обнулим посылки в регистры линейки
for (unsigned char i=0; i‹=2; i++)
to_led_line[i] = 0x0;
//готовим посылки в регистры
for (char i=0; i‹=23; i++) {
if((taxo/TAXOLED_DIV) ›= i+1) {
if (i ‹ 8) { to_led_line[2] |= (1 ‹‹ i); }
if ((i ›= 8) && (i ‹ 16)) { to_led_line[1] |= (1 ‹‹ i-8); }
if (i ›= 16) { to_led_line[0] |= (1 ‹‹ i-16); }
}
}
//отсылаем посылки
for (unsigned char i=0; i‹=2; i++)
shiftout(to_led_line[i]);
//отсылаем в регистр дисплея состояние
//if((mode == 0 || mode == 1) && digit_step == 2) shiftout(symbols[to_display[digit_step]] | (1‹‹7)); //если вольтметр или амперметр ставим точку на втором разряде
//else shiftout(symbols[to_display[digit_step]]); //иначе просто отсылаем
shiftout(symbols[to_display[digit_step]]); //долбанный дисплей не имеет точек ((
PORTB |= (1‹‹ST_CP); //установим "защелку" 74HC595
//цикл яркости, управляем катодами
if((PINA&(1‹‹EX_LED)&&bri_step ‹= bri[0]) || (!(PINA&(1‹‹EX_LED))&&bri_step ‹= bri[1])) { //если установленная яркость разрешает вывод (с учетом сигнала габаритов)
//катоды дисплея
PORTA &= ~(1‹‹(digit_step+4)); //включим нужный катод
//яркость светодиодов
PORTB |= (1‹‹LED_BRI); //включим катод светодиодов
}
//изменение шагов
digit_step++;
if(digit_step == 4) {
digit_step = 0;
bri_step++;
if(bri_step == 9) bri_step = 0;
}
}//mode_off
}
//обработчик таймера
ISR (TIMER1_COMPA_vect) {
millis++; //счетчик миллисекунд
out(); //обновим дисплей
}
//обработчик прерывания (импульсы с тахометра)
ISR (INT0_vect) {
taxo_tmp++;
}
/* Главное тело программы */
int main(void) {
//настройки пинов
DDRA = 0b11111000; //катоды дисплея, аварийный светодиод
PORTA = 0b00000001; //подтягивающий резистор входа габаритов
DDRB = 0b00010111; //управление регистрами, управление яркостью
PORTB = 0b01101000; //подтягивающие резисторы кнопок, тахометра (прерывание)
//прерывания
MCUCR = (1‹‹ISC01) | (1‹‹ISC00); //rising of int0
GIMSK = (1‹‹INT0); //тахометр на INT0 (PB6)
//настройка таймера
OCR1C = 125; // основной счетчик
//OCR1A = 200; //значение совпадения (скважность)
//TCCR1A = (2 ‹‹ COM1A0) | (1 ‹‹ PWM1A); //FastPwm PB1
TCCR1A = (1 ‹‹ PWM1A); //FastPwm
//TCNT1 = 0;
PLLCSR = (1 ‹‹ PLLE);
while (!(PLLCSR & (1 ‹‹ PLOCK)));
PLLCSR = (1 ‹‹ PLLE);
TCCR1B = (1 ‹‹ CS10) | (1 ‹‹ CS11) | (1 ‹‹ CS12); //=8000000/64/125(OCR1C) = 1000hz
TIMSK = (1‹‹OCIE1A); //вызов функции по прерыванию
asm("sei"); //разрешить прерывания
//частота АЦП
ADCSRA = (1 ‹‹ ADPS2)|(1 ‹‹ ADPS1)|(1 ‹‹ ADPS0); // Делитель clock / 128
//зададим на дисплее "минусы" при включении
//mode = 9; //костыль против точки на 2-и сегменте
//for(int x=0; x‹=3; x++)
// to_display[x]=13;
//тест линеек - вверх
//for (int x=1; x ‹= 24; x++) {
// taxo = x * TAXOLED_DIV;
//pause(1500+x*2);
// _delay_ms(50 + x*2);
// }
//вниз
// for (int x=23; x ›= 1; x--) {
// taxo = x * TAXOLED_DIV;
//pause(1000+x*2);
// _delay_ms(50 + x*2);
//}
//читаем настройки из eeprom
//режим работы
mode = eeprom_read_byte((unsigned char*)0x00);
//яркость без габаритов и с ними
bri[0] = eeprom_read_byte((unsigned char*)0x01); //яркость без габаритов
bri[1] = eeprom_read_byte((unsigned char*)0x02); //яркость с габаритами
if(bri[0] ‹ 2 || bri[0] › 8) bri[0] = 8; //если яркость за пределами, ставим максимальную
if(bri[1] ‹ 2 || bri[1] › 8) bri[1] = 8;
//"ноль" амперметра
amp_null = eeprom_read_word((unsigned int*)0x03);
if (amp_null == 0) amp_null = 500;
/* главный цикл */
while(1){
//время рассчитать значения, опросить кнопки
if(millis ›= (prev_millis_main + 200)) {
prev_millis_main = millis; //выравниваем счетчики времени
//расчет тахометра
taxo = ((taxo_tmp * 5 * 60) / TAXO_DIV); //рассчитываем с учетом количества импульсов за оборот коленвала, приводим к об/сек, далее к об/мин
taxo_tmp = 0; //сбрасываем временный счетчик
//расчет амперметра
amp = ADC_input(1); //0..1023
if (amp ‹ amp_null) {
amp_sign = 1;
amp = (amp_null - amp) / AMP_DIV;
}
else {
amp_sign = 0;
amp = (amp - amp_null) / AMP_DIV;
}
//расчет вольтметра
volt = VOLTMETER_DIV * ADC_input(2) / 102; //Расчитываем по делителю
//опрашиваем кнопки
if(!(PINB&(1‹‹BUT_MODE))) { //BUT_MODE
last_press_time = millis;
while(!(PINB&(1‹‹BUT_MODE))) pause(1);
//определим долгое нажатие - калибровка
if ((millis - last_press_time) ›= 5000) { //больше пяти секунд и режим амперметра
//калибровка амперметра (запись в еепром нуля показаний)
amp_null = ADC_input(1);
eeprom_write_word((unsigned int*)0x03, amp_null);
}
else { //если короткое нажатие
//перебор режима
prev_millis_off = millis;
if(mode_off==1){ //если дисплей включен
mode++;
if(mode ›= 3) mode = 0;
eeprom_write_byte((unsigned char*)0x00, mode);
} //mode off
}
} //BUT_MODE
if(!(PINB&(1‹‹BUT_BRI))){ //BUT_BRI (2..4..6..8)
//перебор режима
prev_millis_off = millis;
if(mode_off==1){ //если дисплей включен
if(PINA&(1‹‹EX_LED)) { //сигнала габаритов нет
bri[0] += 2;
if(bri[0] › 8) bri[0] = 2;
eeprom_write_byte((unsigned char*)0x01, bri[0]);
}
else {
bri[1] += 2;
if(bri[1] › 8) bri[1] = 2;
eeprom_write_byte((unsigned char*)0x02, bri[1]);
}
} //mode off
}
//выбор отображения по режиму
if(mode == 0) to_numbers(volt); //режим амперметра
if(mode == 1) to_numbers(amp); //режим вольтметра
if(mode == 2) to_numbers(taxo); //режим тахометра
//if(mode == 3) to_numbers(bri[0]); //режим отладки
//if(mode == 4) to_numbers(bri[1]); //режим отладки
if(volt ‹ OFF_VOLT && millis › prev_millis_off + OFF_TIME) mode_off=0; //если таймаут и низкое бортовое (двиг не заведен) - выключить дисплей
else { //иначе
if(mode_off == 0) prev_millis_off = millis; //если первый цикл после включения - уравняем время
mode_off=1; //включим дисплей
}
//RED_LED - аварийный светодиод
if(taxo › 4000 || volt ‹= 130 || amp_sign == 1) PORTA |= (1‹‹RED_LED);
else PORTA &= ~(1‹‹RED_LED);
}//расчеты, опрос кнопок
} //главный цикл
} |
Последний раз редактировалось whoim; 10.05.2012 в 09:02.
|
|
|
|
10.05.2012, 13:17
|
|
Заблокирован
Регистрация: 27.03.2007
Сообщений: 1,328
Сказал спасибо: 12
Сказали Спасибо 576 раз(а) в 460 сообщении(ях)
|
Re: Амперметр на МК
Сообщение от whoim
|
Помогите оптимизировать программу
|
Для утрамбовки программы очень полезно выкинуть все действия деления.
Вот, к примеру, Ваш тахометр. При выбранной периодичности 200мс шаг измерения будет 75 об/мин. Некошерно. Я думаю, лучше сделать период 150мс, тогда шаг будет 100 об/мин, если, конечно, у Вас 4 импульса за 1 оборот коленвала. Тогда делаем просто taxo = taxo_tmp; будет в сотнях об/мин, и исчезнут промежуточные умножения и деления. Для отображения на индикаторе делаем дополнительную проверку режима. Для отображения на линейном LED-индикаторе taxo = taxo ››1; для шага 200.
Конечно, для остальных показаний период 150мс слишком мал, цифры будут слишком быстро меняться. Ну, можно сделать остальные измерения через раз, т.е. с периодом 300мс. Будет даже лучше.
Вот, от одного деления уже избавились.
Для вольтметра и амперметра подобрать резисторы в делителях для круглых коэффициентов и заменить деление на простой сдвиг.
|
|
|
Эти 2 пользователя(ей) сказали Спасибо Yurkin2007 за это сообщение:
|
|
|
10.05.2012, 18:16
|
|
Почётный гражданин KAZUS.RU
Регистрация: 26.11.2011
Адрес: Анапа
Сообщений: 1,620
Сказал спасибо: 284
Сказали Спасибо 129 раз(а) в 111 сообщении(ях)
|
Re: Амперметр на МК
в чем суть "сдвига"?
|
|
|
|
10.05.2012, 18:36
|
|
Почётный гражданин KAZUS.RU
Регистрация: 20.03.2007
Адрес: "Братское кольцо враждебности", т.е. ближайшее заМКАДье.
Сообщений: 6,917
Сказал спасибо: 2,980
Сказали Спасибо 3,161 раз(а) в 2,146 сообщении(ях)
|
Re: Амперметр на МК
Сообщение от whoim
|
в чем суть "сдвига"?
|
Вай-вай... sancta simplicans. N/8 = N››3. Деление (программное, с циклами и пр. "ништяками") заменяется сдвигом, который реализуется одной (ну пусть даже тремя) командами АЛУ.
|
|
|
Сказали "Спасибо" ForcePoint
|
|
|
Ваши права в разделе
|
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 05:10.
|
|