Dobrý den,
Řeším problém v tomto programu
#include <avr/io.h>
#include <avr/interrupt.h>
#define potenciometer PA0
char adc;
void init()
{
//Nastavení vstupních a výstupních pinů
DDRA = 0x00;
ADMUX = (1 << REFS0);
ADMUX |= (1 << ADLAR); //reference 5V + pridano ADLAR (pro rozliseni 8 bitu)
ADCSRA |= (1 << ADEN) | (1 << ADIF) | (1 <<ADPS2) | (1 <<ADPS1) | (1 <<ADPS0); //povoleni AD prevodnika, Interrupt flag, preddelicka 128 pri frekvencii hodin 1MHz
sei(); //povolení globálního přerušení
}
unsigned int Read_ADC(unsigned char channel){
ADMUX &= 0xF0; //vloz cislo kanalu, vymaskuj nepouzite bity
ADMUX |= channel & 0x0F;
ADCSRA |= (1 << ADSC); //start prevodu A/D
while(!(ADCSRA & (1<<ADIF))); //cekej na priznak skonceni prevodu
return ADCH; //navratova hodnota - vysledek A/D prevodu 8 bitu
}
int main(void)
{
init(); //inicializuje procesor
while(1)
{
adc = Read_ADC(0) / 2; // omezuje rozsah na 256 / 2
if (adc > 99) //zajištění aby číslo nemělo více než 2 cifry
adc = 99;
vypis(adc); //výpis na displej
}
return 0;
}
Vždy, když dám potenciometr do mezi polohy, tak v promněnné adc se periodicky sřídají 2 hodnoty. Tato chyba se projevuje mezi 1 a 2, 11 a 12, 21 a 22 atd. až do 91 a 92.
Děkuji za rady.
cici
(čiči)
May 17, 2015, 7:20pm
2
to je normální jak nemáš blokovací kondiky a tlimivky na napajeni ADC
Blokovací kondíky a kondenzátory na vstupu ADC mám. Ale divné je, že se hodnota střídá periodicky. 1 2 1 2 a ne např. 1 2 2 1 atd.
Atlan
May 18, 2015, 5:19pm
4
Blizko puzdra uP zapoj medzi AD vstup a zem kondik 10n, inak pri mnene vstupu a startom prevodu by si mal chvilku pockat.
je vyhodne pouzivat preruseni, teda necekat na vysledek a potom ho v preruseni precist do nejake promenne. Dalsi dobra vec je zahazovat dva nejnizsi bity a pouzivat jen 256 hodnot.
Informaci nezahazovat, ale vhodně zpracovat - pokud to charakter aplikace dovolí tak vhodným číslicovým filtrováním. To musí vědět zadavatel co měří a proč. Připravit se o rozlišení je hovadina.
Kondík nepomohl, vstupy v programu neměním.
Co je číslicové filtrování?
Já potřebuji rozsah jen mezi 0 - 99.
Radius
May 21, 2015, 11:52pm
9
Třeba obyčejné průměrování, klouzavý průměr, exponenciální klouzavý průměr… Najdeš na WiKi
Radius
May 21, 2015, 11:59pm
10
Takže ty rozsah celého potenciometru potřebuješ rozprostřít na 0-99 ?
Jestli jo a máš to zapojený mezi 0V-5V a vyvedený střed, tak je lepší informaci zafiltrovat a pak udělat numericky scale [0-1023] na [0-99]
Mohl bych poprosit o ukázku nějakého elegantního řešení. Celkem by mě zajímalo jak na to. Díky
administrator: příspěvek byl upraven
Předchozí příspěvky se necitují.
Souhlasím. Také by mě to zajímalo.
administrator: příspěvek byl upraven
Předchozí příspěvky se necitují.
Radius
May 26, 2015, 9:32pm
13
Tak třeba…
Soft generuje data zatížená šumem, ty filtruje a společně s originálem ukládá do csv souboru. Výstupy jsou v přiložených obrázcích.
DATA_FILTER.ZIP (103 KB)
Dobrý den,
Nedávno se mi do rukou dostal JTAG debuger a zjistil jsem, že hodnoty z ADC jsou správné. Asi tedy bude problém ve 595. Předem děkuji za rady.
/*
* Minutka.c
*
* Created: 17. 4. 2015 15:08:06
* Author: Petr Liška
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 1000000UL
#include <util/delay.h>
//definice portů displeje na portu C
#define MR PC3
#define SHCP PC4
#define STCP PC5
#define OE PC6
#define DS_1 PC2
#define DS_2 PC7
#define tlacitko PD2
#define potenciometer PA0
#define piezo PD3
char vypisovane_cislo_desitky, vypisovane_cislo_jednotky;
volatile char citac = 0;
volatile char adc = 0;
volatile char sviti = 0;
volatile char odpocitavani = 0;
volatile char citac_2 = 0;
char cisla] = {
//hgfedcba
0b00111111, //0
0b00000110, //1
0b01011011, //2
0b01001111, //3
0b01100110, //4
0b01101101, //5
0b01111101, //6
0b00000111, //7
0b01111111, //8
0b01101111 //9
};
ISR (TIMER0_OVF_vect){ //přerušní při přetečení časovače 0
// 2*262,144 = 524,288ms
if(citac_2 == 2){
citac_2=0;
sviti ^= 1;
}
citac_2++;
}
ISR (TIMER1_OVF_vect){ //přerušní při přetečení časovače 1
TCNT1 = 61630; //nastavenie počáteční hodnoty počítadla
citac++;
}
ISR (INT0_vect) { //přerušení při stisku tlačítka (doběžná hrana)
odpocitavani ^= 1;
}
ISR (ADC_vect)
{
adc = (char)ADCH / 2;
}
void init(void)
{
OSCCAL = 0b10101100; // nastavení kalibrační konstanty
//Nastavení vstupních a výstupních pinů
DDRA = 0x00;
DDRB = 0x00;
DDRC = 0xFF;
DDRD = 0xFF;
DDRD &= ~(1 << tlacitko);
//nastavení pull-up rezistoru
PORTD |= (1 << tlacitko);
//vypnutí pieza
PORTD &= ~(1 << piezo);
//595
PORTC |= (1 << MR); //vypnutí master reset
PORTC &= ~(1 << OE); //povolení výstupu na 595
//počítání minut
TIMSK |= (1 << TOIE1); //prerušení při přetečení TCNT1
//ADC
ADMUX |= (1 << REFS0) | (1 << ADLAR);
ADCSRA |= (1 << ADEN) | (1 << ADIF) | (1<<ADATE) | (1<<ADIE) | (1 <<ADPS1) | (1 <<ADPS2) | (1 << ADSC);
//blikání led
TIMSK |= (1 << TOIE0); //prerušenie pri pretečení TCNT0
//ext. přerušení
GICR |= (1 << INT0); //povolení prerušení od INT0
MCUCR |= (1 << ISC01);
sei(); //povolení globálního přerušení
}
void pipani(void) //spouští piezo
{
PORTD |= (1 << piezo);
_delay_ms(200);
PORTD &= ~(1 << piezo);
_delay_ms(200);
}
void vysli_595(void)
{
ADCSRA &= ~(1 << ADEN); // vypnutí AD převodníku
PORTC &= ~(1 << STCP);
for(int i = 0; i != 8; i++)
{
PORTC &= ~(1 << SHCP);
if(vypisovane_cislo_desitky & 0b10000000) //zapis 1 bitu na místo desítek
PORTC &= ~(1 << DS_1);
else
PORTC |= (1 << DS_1);
if(vypisovane_cislo_jednotky & 0b10000000) //zápis 1 bitu na místo jednotek
PORTC &= ~(1 << DS_2);
else
PORTC |= (1 << DS_2);
PORTC |= (1 << SHCP); //nástupná hrana na SHCP
vypisovane_cislo_jednotky <<= 1;
vypisovane_cislo_desitky <<= 1;
}
PORTC |= (1 << STCP); //nástupná hrana na STCP
ADCSRA |= (1 << ADEN) | (1 << ADSC); //zapnutí AD převodníku
}
void prevod_cisla(char cislo) //převádí na desítky a jednotky, zjištuje zda-li se má rozsvítit tečka
{
unsigned char jednotky;
unsigned char desitky;
jednotky = cislo % 10; //zbytek po dělení 10
desitky = cislo / 10; //celoočíselné dělení
vypisovane_cislo_desitky = cisla[desitky];
if(sviti) //pokud se má tečka rozsvítit
vypisovane_cislo_desitky |= (1 << 7); //zmněň bit tečky
else
vypisovane_cislo_desitky &= ~(1 << 7); //zmněň bit tečky
vypisovane_cislo_jednotky = cisla[jednotky];
vysli_595(); //výpis na displej
return;
}
void citani(void) //odpocitava dokud nedojde ke konecné hodnotě
{
while (odpocitavani)
{
if(citac == 60) //pokud uběhla minuta
{
adc--;
citac = 0;
}
prevod_cisla(adc); //převod čísla na desítky a jednotky
if(adc == 0) //pokud čas vypršel
{
while (odpocitavani) //tlačítko není zmáčknuto
{
pipani(); //pípání pieza
}
break; //konec cyklu
}
}
}
void init_citani(void)
{
citac = 0;
ADCSRA &= ~(1 << ADEN); // vypnutí AD převodníku
TCCR1B |= (1 << CS12); //předdelička 256 (32us) zapnutí odpočítávání
TCCR0 |= (1 << CS02) | (1 << CS00); //preddelicka /1024 (1,024ms) zapnutí blikání
citani(); //spouští odpočítávání
TCCR0 &= ~(1 << CS02) | (1 << CS00); // vypnutí blikání
TCCR1B &= ~(1 << CS12); // vypnutí odpočítávání
sviti = 0; //zajistí aby tečka nesvítila
ADCSRA |= (1 << ADEN) | (1 << ADSC); //zapnutí AD převodníku
}
int main(void)
{
init(); //inicializuje procesor(porty,přerušení atd.)
while(1)
{
if (adc > 99) //zajištění aby číslo nemělo více než 2 cifry
adc = 99;
if(odpocitavani) //zjištění zda-li je tlačítko zmáčnuto
{
init_citani(); //inicializuje odpočítavací funkci, která poté volá funkci pro odpočítávání
}
prevod_cisla(adc); //převod čísla na desítky a jednotky a následný výpis na displej
_delay_ms(10);
}
return 0;
}