Не обновляются данные на вольтметре из семисегментника и atmega328

b707
Offline
Зарегистрирован: 26.05.2017

bibo пишет:

Вообще, я просто хотел использовать измеренное в фуннкции getAVccVoltage напряжение питания при расчете замеряемого напряжения на четвертом пине ацп.

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

Эту проблему лучше решать аппаратно - берете стабилитрон и заводите его выход на AREF в качестве надежного опорного.

sadman41
Offline
Зарегистрирован: 19.10.2016

Вроде как не стабилитрон полагается, а специальный источник опорного напряжения.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

bibo пишет:

вообще, я не понимаю, почему вся программа ломается, если поэкспериментировать в каком-либо месте, а затем вернуть все на свои места?

Потому, что Вы её не понимаете.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

bibo пишет:

вот почему у меня навернулся замер внешнего напряжения?? что изменилось??

#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

unsigned int z=0;//переменная для икpементирования
unsigned char x=1;//переменная для функции ISR
unsigned int R1=0,R2=0, R3=0;
unsigned int y=0;//переменная для икpементирования
//unsigned int zzz;
float Uvh;//переменная для записи напряжения
const int Koef=1;//коэффициент
int K1;
unsigned int sec;
//unsigned int sec1;
float Vcc;
float U;

static const float internalRefference = 1.1;//измеренное вольтметром внутреннее опорное напряжение

// Делитель частоты для ADC
static const uint8_t adcPrescaler =(1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);//устанавливаем частоту дискретизации делитель 128(частота дискретизации 16000000/128=125кГц)
static const uint8_t refAVcc = (1<<REFS0);	//	AVcc как опорное
static const uint8_t inpVbg = (1<<MUX3) | (1<<MUX2) | (1<<MUX1); // измеряем Vbg (1.1В)


//	Включение ADC
static inline void adcEnable(void) {
	PRR &= ~(1<<PRADC);//пишем нуль в нулевой бит регистра, отвечающего за обесточивание компонентов МК, чтобы исключить выключение ацп
	ADCSRA |= (1<<ADEN);//включаем ацп
	//ADCSRB|=(0<<ADTS2)|(0<<ADTS1)|(0<<ADTS0);//включаем режим постоянного измерения
}

//
//	Замер напряжения питания
//
float getAVccVoltage(void) {
	adcEnable();
	ADMUX = refAVcc | inpVbg;	// Измеряем Vbg, используя AVcc как опорное
	ADCSRA |= adcPrescaler | (1<<ADSC); //	Запускаем преобразование
	while(ADCSRA & (1<<ADSC)); // Ждём завершения преобразования
	return internalRefference * 1023 / ADC; // Считаем AVcc
}


/*замер внешнего напряжения*/
float voltage_ext(void){
	adcEnable();
	ADCSRA|=adcPrescaler;//делитель 128(частота дискретизации 16000000/128=125кГц)
	ADMUX|=refAVcc;//источник опорного напряжения 5 вольт
	ADMUX|=(0<<MUX3)|(1<<MUX2)|(0<<MUX1)|(0<<MUX0);//включаем ADC4 0100
	ADMUX|=(0<<ADLAR);//выравнивание
	ADCSRA|=(1<<ADSC);//запускаем работу ацп
while(ADCSRA & (1<<ADSC)); // Ждём завершения преобразования
return ADC*5.00/1024;// напряжение в  вольтах
}



unsigned int digits[10]=
{
	~0b00111111,//0
	~0b00000110,//1
	~0b01011011,//2
	~0b01001111,//3
	~0b01100110,//4
	~0b01101101,//5
	~0b01111101,//6
	~0b00000111,//7
	~0b01111111,//8
~0b01101111,};//9

/*настраиваем таймер-счетчик 0*/
void init_TC0(void){
	TCCR0A|=(0<<WGM00)|(0<<WGM01);//режим normal(сброс по переполнению)
	TCCR0B |=(1<<CS02)|(0<<CS01)|(0<<CS00);//делитель 256
	TIMSK0|=(1<<TOIE0);//сброс по переполнению
	TIFR0|=(1<<TOV0);
	TCNT0=0;

}


/*настраиваем порты*/

void init_ports(void){

	DDRC|=(1<<PC0)|(1<<PC1)|(1<<PC2);//аноды семисегментника
	DDRC&=~(1<<PC4);//adc4
	//DDRB|=(1<<PB0)|(1<<PB2)|(1<<PB4);//leds
	//DDRB&=~(1<<PB5);//button
	DDRD=0xFF;//весь порт Д на выход(катоды семисегментника)
	//PORTB|=(0<<PB0)|(0<<PB2)|(0<<PB4)|(1<<PB5);//leds&&button
	PORTC|=(1<<PC0)|(1<<PC1)|(1<<PC2)|(1<<PC4);
	PORTD =0xFF;//логическая единица на порту Д,чтобы семисегментник не светился

}



/*обрабатываем прерывания при переполнении счетчика*/
ISR(TIMER0_OVF_vect){
	if(x==1){PORTC=0b00000100;PORTD=digits[R1];} //при первом прерывании на порту С включаем третий бит, в порт д выводим число, высчитанное в функции vse_chislo
	if(x==2){PORTC=0b00000010;PORTD=digits[R2];if(Uvh>=10){PORTD&=~(1<<PD7);}
	else {PORTD&=~(0<<PD7);}}
	if(x==3){PORTC=0b00000001;PORTD=digits[R3];if(Uvh<10){PORTD&=~(1<<PD7);}
	else{PORTD&=~(0<<PD7);}}
	x++;
	if(x>3){x=1;};
	
	
}


void number(unsigned int part_of_number){
	R1=part_of_number%10; //единицы
	R2=part_of_number%100/10;//десятки
R3=part_of_number/100;}//сотни





int main(void){

	init_ports();
	init_TC0();
	sei();
	

	while(1){
	//выводим на семисегментник напряжение, измеряемое на 4ом пине ацп
		if (TCNT0==255)sec++;
		if(sec==100){Uvh=voltage_ext();sec=0;}//записываем в переменную значения ацп по таймеру
	
		if(Uvh<10)
		{
			K1=100;
		}
		else
		{K1=10;
		}

		number(Uvh*K1); //вывод в вольтах
		
		
		
		

	}
}

Наверное, потому, что в посте #50 Вы просто не измеряете его. Вы же просто выбросили все вызовы функции getAVccVoltage и не вызываете её нигде ни разу. И как же она Вам змерять-то будет?

bibo
Offline
Зарегистрирован: 26.03.2018

b707 пишет:

 

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

Эту проблему лучше решать аппаратно - берете стабилитрон и заводите его выход на AREF в качестве надежного опорного.

 

Спасибо за подсказку.

Просто у меня задача не сварганить некий вольтметр, а ликбез.

Я тут сушу вам мозг не затем, чтобы заиметь вольтметр, а затем, чтобы познать новое)

bibo
Offline
Зарегистрирован: 26.03.2018

ЕвгенийП пишет:

Потому, что Вы её не понимаете.

Это очень бы хотелось исправить)

bibo
Offline
Зарегистрирован: 26.03.2018

ЕвгенийП пишет:

bibo пишет:

вот почему у меня навернулся замер внешнего напряжения?? что изменилось??

#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

unsigned int z=0;//переменная для икpементирования
unsigned char x=1;//переменная для функции ISR
unsigned int R1=0,R2=0, R3=0;
unsigned int y=0;//переменная для икpементирования
//unsigned int zzz;
float Uvh;//переменная для записи напряжения
const int Koef=1;//коэффициент
int K1;
unsigned int sec;
//unsigned int sec1;
float Vcc;
float U;

static const float internalRefference = 1.1;//измеренное вольтметром внутреннее опорное напряжение

// Делитель частоты для ADC
static const uint8_t adcPrescaler =(1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);//устанавливаем частоту дискретизации делитель 128(частота дискретизации 16000000/128=125кГц)
static const uint8_t refAVcc = (1<<REFS0);	//	AVcc как опорное
static const uint8_t inpVbg = (1<<MUX3) | (1<<MUX2) | (1<<MUX1); // измеряем Vbg (1.1В)


//	Включение ADC
static inline void adcEnable(void) {
	PRR &= ~(1<<PRADC);//пишем нуль в нулевой бит регистра, отвечающего за обесточивание компонентов МК, чтобы исключить выключение ацп
	ADCSRA |= (1<<ADEN);//включаем ацп
	//ADCSRB|=(0<<ADTS2)|(0<<ADTS1)|(0<<ADTS0);//включаем режим постоянного измерения
}

//
//	Замер напряжения питания
//
float getAVccVoltage(void) {
	adcEnable();
	ADMUX = refAVcc | inpVbg;	// Измеряем Vbg, используя AVcc как опорное
	ADCSRA |= adcPrescaler | (1<<ADSC); //	Запускаем преобразование
	while(ADCSRA & (1<<ADSC)); // Ждём завершения преобразования
	return internalRefference * 1023 / ADC; // Считаем AVcc
}


/*замер внешнего напряжения*/
float voltage_ext(void){
	adcEnable();
	ADCSRA|=adcPrescaler;//делитель 128(частота дискретизации 16000000/128=125кГц)
	ADMUX|=refAVcc;//источник опорного напряжения 5 вольт
	ADMUX|=(0<<MUX3)|(1<<MUX2)|(0<<MUX1)|(0<<MUX0);//включаем ADC4 0100
	ADMUX|=(0<<ADLAR);//выравнивание
	ADCSRA|=(1<<ADSC);//запускаем работу ацп
while(ADCSRA & (1<<ADSC)); // Ждём завершения преобразования
return ADC*5.00/1024;// напряжение в  вольтах
}



unsigned int digits[10]=
{
	~0b00111111,//0
	~0b00000110,//1
	~0b01011011,//2
	~0b01001111,//3
	~0b01100110,//4
	~0b01101101,//5
	~0b01111101,//6
	~0b00000111,//7
	~0b01111111,//8
~0b01101111,};//9

/*настраиваем таймер-счетчик 0*/
void init_TC0(void){
	TCCR0A|=(0<<WGM00)|(0<<WGM01);//режим normal(сброс по переполнению)
	TCCR0B |=(1<<CS02)|(0<<CS01)|(0<<CS00);//делитель 256
	TIMSK0|=(1<<TOIE0);//сброс по переполнению
	TIFR0|=(1<<TOV0);
	TCNT0=0;

}


/*настраиваем порты*/

void init_ports(void){

	DDRC|=(1<<PC0)|(1<<PC1)|(1<<PC2);//аноды семисегментника
	DDRC&=~(1<<PC4);//adc4
	//DDRB|=(1<<PB0)|(1<<PB2)|(1<<PB4);//leds
	//DDRB&=~(1<<PB5);//button
	DDRD=0xFF;//весь порт Д на выход(катоды семисегментника)
	//PORTB|=(0<<PB0)|(0<<PB2)|(0<<PB4)|(1<<PB5);//leds&&button
	PORTC|=(1<<PC0)|(1<<PC1)|(1<<PC2)|(1<<PC4);
	PORTD =0xFF;//логическая единица на порту Д,чтобы семисегментник не светился

}



/*обрабатываем прерывания при переполнении счетчика*/
ISR(TIMER0_OVF_vect){
	if(x==1){PORTC=0b00000100;PORTD=digits[R1];} //при первом прерывании на порту С включаем третий бит, в порт д выводим число, высчитанное в функции vse_chislo
	if(x==2){PORTC=0b00000010;PORTD=digits[R2];if(Uvh>=10){PORTD&=~(1<<PD7);}
	else {PORTD&=~(0<<PD7);}}
	if(x==3){PORTC=0b00000001;PORTD=digits[R3];if(Uvh<10){PORTD&=~(1<<PD7);}
	else{PORTD&=~(0<<PD7);}}
	x++;
	if(x>3){x=1;};
	
	
}


void number(unsigned int part_of_number){
	R1=part_of_number%10; //единицы
	R2=part_of_number%100/10;//десятки
R3=part_of_number/100;}//сотни





int main(void){

	init_ports();
	init_TC0();
	sei();
	

	while(1){
	//выводим на семисегментник напряжение, измеряемое на 4ом пине ацп
		if (TCNT0==255)sec++;
		if(sec==100){Uvh=voltage_ext();sec=0;}//записываем в переменную значения ацп по таймеру
	
		if(Uvh<10)
		{
			K1=100;
		}
		else
		{K1=10;
		}

		number(Uvh*K1); //вывод в вольтах
		
		
		
		

	}
}

Наверное, потому, что в посте #50 Вы просто не измеряете его. Вы же просто выбросили все вызовы функции getAVccVoltage и не вызываете её нигде ни разу. И как же она Вам змерять-то будет?

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

b707
Offline
Зарегистрирован: 26.05.2017

bibo пишет:

Просто у меня задача не сварганить некий вольтметр, а ликбез.

Я тут сушу вам мозг не затем, чтобы заиметь вольтметр, а затем, чтобы познать новое)

я вам уже несколько раз писал - вам книжки надо читать. А вы вместо этого пытаетесь программировать бездумным подбором операторов. Никакой пользы от этого вам не будет - через неделю все забудете, как и не знали.

bibo
Offline
Зарегистрирован: 26.03.2018

Все верно. Так и сделаю. Пойду читать программистскую библию.