Не ну можно и до идеала довести
Работает вот такой
Спойлер
Код: Выделить всё
#include <tiny13a.h>
#include <delay.h>
// Declare your global variables here
inline void wr_reg(char cData)
{
char temp = cData;
char i=0;
for(i=0; i<8; i++)
{
PORTB.0 = (temp & 0x80);
#asm("nop");
PORTB.2 = 1;
#asm("nop");
PORTB.2 = 0;
temp = temp << 1;
}
}
inline void latch_reg()
{
#asm("nop");
PORTB.1 = 1;
#asm("nop");
PORTB.1 = 0;
}
flash char cSeg[]={
0b00111111, // 0
0b00000110, // 1
0b01011011, // 2
0b01001111, // 3
0b01100110, // 4
0b01101101, // 5
0b01111101, // 6
0b00000111, // 7
0b01111111, // 8
0b01101111 // 9
};
char cDec = 0;
volatile char cDigit[8];
interrupt [TIM0_COMPA] void timer0_compa_isr(void)
{
wr_reg(1<<cDec);
wr_reg(cDigit[cDec]);
//wr_reg(0b00000000);
latch_reg();
cDec += 1;
if( cDec > 7 )
cDec = 0;
TCNT0 = 0;
}
void toDigits(unsigned char i, unsigned long* ulSum) {
unsigned char j;
j=4;
*ulSum=(5000UL*(*ulSum))/(256UL*1024);
while (j>0) {
j--;
cDigit[i+j] = ~cSeg[*ulSum%10];
*ulSum /=10;
}
*ulSum = 0;
}
#define FIRST_ADC_INPUT 2
#define LAST_ADC_INPUT 3
#define ADC_VREF_TYPE 0x00
unsigned long ulVoltsSum = 0;
char sCounterVSum = 0;
unsigned long ulAmpersSum = 0;
char sCounterASum = 0;
// ADC interrupt service routine
// with auto input scanning
interrupt [ADC_INT] void adc_isr(void)
{
static unsigned char input_index=0;
// Read the AD conversion result
//// Select next ADC input
if (++input_index > LAST_ADC_INPUT)
input_index=FIRST_ADC_INPUT;
ADMUX=ADC_VREF_TYPE +input_index;
if( input_index == 2 )
{
ulVoltsSum += ADCW;
sCounterVSum++;
if( !sCounterVSum )
{
toDigits(0,&ulVoltsSum);
cDigit[1] &= ~0b10000000;
sCounterVSum = 0;
}
}
if( input_index == 3 )
{
ulAmpersSum += ADCW;
sCounterASum++;
if( !sCounterASum )
{
toDigits(4,&ulAmpersSum);
cDigit[4] &= ~0b10000000;
sCounterASum = 0;
}
}
// Delay needed for the stabilization of the ADC input voltage
delay_us(10);
// Start the AD conversion
ADCSRA|=0x40;
}
void main(void)
{
// Declare your local variables here
// Crystal Oscillator division factor: 1
/*#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif*/
// Input/Output Ports initialization
// Port B initialization
// Func5=In Func4=In Func3=In Func2=In Func1=In Func0=Out
// State5=T State4=T State3=T State2=T State1=T State0=0
//PORTB=0x00;
DDRB=0x07;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 9400,000 kHz
// Mode: Normal top=0xFF
// OC0A output: Clear on compare match
// OC0B output: Disconnected
//TCCR0A=0x00;
TCCR0B=0x05;
//TCNT0=0x00;
OCR0A=0x10;
//OCR0B=0x00;
// External Interrupt(s) initialization
// INT0: Off
// Interrupt on any change on pins PCINT0-5: Off
//GIMSK=0x00;
//MCUCR=0x00;
// Timer/Counter 0 Interrupt(s) initialization
TIMSK0=0x04;
// Analog Comparator initialization
// Analog Comparator: Off
ACSR=0x80;
//ADCSRB=0x00;
//DIDR0=0x00;
// ADC initialization
// ADC Clock frequency: 73,438 kHz
// ADC Bandgap Voltage Reference: Off
// ADC Auto Trigger Source: ADC Stopped
// Digital input buffers on ADC0: Off, ADC1: Off, ADC2: On, ADC3: On
DIDR0&=0x03;
DIDR0|=0x24;
ADMUX=FIRST_ADC_INPUT | (ADC_VREF_TYPE & 0xff);
ADCSRA=0xCF;
#asm("sei")
while(1)
{
}
}
Отличия:
Изменил ноги вывода в регистры под свою плату.
Добавил десятичные точки
Сделал быстрее таймер. Дисплей мерцал. Старое значение таймера было выбрано для 4х1 дисплея.
Ну и усреднения 256 отстчетов. Значения меняются примерно 3..4 раза в секунду если дергается. Но в основном это только последний разряд, остальные разряды вполне комфортно читабельны.
Регулировка пока не понял. Но похоже немного нелинейна. Настраиваю на максимальном значении (29В и ток по потенциометру который делит 5В до 0.5В имитируя шунт 0.1Ом) Точно сказать немогу, но пока такое ощущение что в пределах 100мВ погрешность. Прецизионным конечно не назовешь, но в блок питания пойдет. Учитывая что разрешение в 10бит, реально 8, больше и недадут. Ток тоже скурпулезно не мерял, но тоже уплывает порядка 100..200мА. Так как стоит ОУ lm358 меряет не от нуля. И еще небыло отдельного питания для ОУ, подключил его к 5В, выход упирался в 3.6В (тоесть ток показывал 3600мА на дисплее).
Выходной резистор так и не сменил пока, он так 100к и стоял, и все похоже работает. Конденсаторы тоже пока 100пик. В ближайщее время поменяю на рекомендованные вами.
Общие впечатления от поделки хорошие. С продающимися встраиваемыми цифровыми вольтметрами и амперметрами не сравнивал.
Подозреваю в оставшееся место памяти даже влезет и ваттметр или небольшая программа регулятора... Мне нужен был АмперВольтМетр я им ограничиваюсь.
Неудобство использования в том что ОУ требует питания больше 5В. В связи с этим нужно или на самой плате размещать 5ти вольтовый стабилизатор или еще как.
Кто как делает? Обязательно нужен собственный стабилизатор?
Как вы советуете к питанию прикрутить дроссель для фильтрации? Все схемы которые нахожу для более жирных МК, у которых есть Aref. Насколько это вообще актуально?
Kavka, ваш код попозже посмотрю. Может что скрестить можно.