Pomoc s kodem v C pro ATtiny13A
Moderátor: Moderátoři
Pomoc s kodem v C pro ATtiny13A
Zdravím,
byl by někdo z přítomných schopen a zejména ochoten mi pomoct s kódem v C pro ATtiny13A?
O co jde: potřebuji udělat úplně jednoduchý modul zajišťující pomalý analogový track and hold (podrobněji na schématu v příloze).
Jako skvělou inspiraci jsem našel https://adnbr.co.uk/articles/adc-and-pwm-basics . Je tam asi skoro všechno*, nicméně jako programátorský laik nejsem schopen ty ukázky "učesat a slepit" do jednoho zdrojového souboru, který bych předhodil překladači (nejspíš avr-gcc).
Jako alternativu (pro mě asi lepší) zvažuji Arduino IDE, kde jsem si už doinstaloval podporu pro ATtiny13, ale zůstávám "zaseknutý" na oné neschopnosti kód z příkladů "učesat a slepit".
(*) V ukázkových příkladech chybí mnou požadovaná klíčová funkce /HOLD a není tam ani použitý watchdog
Výstupem pro mě by tedy měl být jeden textový soubor (co nejvíce podobný těm příkladům a s ponechanými komentáři), který bych si už dále sám upravoval a současně se na tom učil.
Pokud by to nebylo triviální, můžeme se dohodnout na vhodné odměně.
Díky
--
Jirka
byl by někdo z přítomných schopen a zejména ochoten mi pomoct s kódem v C pro ATtiny13A?
O co jde: potřebuji udělat úplně jednoduchý modul zajišťující pomalý analogový track and hold (podrobněji na schématu v příloze).
Jako skvělou inspiraci jsem našel https://adnbr.co.uk/articles/adc-and-pwm-basics . Je tam asi skoro všechno*, nicméně jako programátorský laik nejsem schopen ty ukázky "učesat a slepit" do jednoho zdrojového souboru, který bych předhodil překladači (nejspíš avr-gcc).
Jako alternativu (pro mě asi lepší) zvažuji Arduino IDE, kde jsem si už doinstaloval podporu pro ATtiny13, ale zůstávám "zaseknutý" na oné neschopnosti kód z příkladů "učesat a slepit".
(*) V ukázkových příkladech chybí mnou požadovaná klíčová funkce /HOLD a není tam ani použitý watchdog
Výstupem pro mě by tedy měl být jeden textový soubor (co nejvíce podobný těm příkladům a s ponechanými komentáři), který bych si už dále sám upravoval a současně se na tom učil.
Pokud by to nebylo triviální, můžeme se dohodnout na vhodné odměně.
Díky
--
Jirka
- ZdenekHQ
- Administrátor
- Příspěvky: 25593
- Registrován: 21 črc 2006, 02:00
- Bydliště: skoro Brno
- Kontaktovat uživatele:
Mám dojem, že jdeš s kanónem na vrabce.
Ten obvod se správně jmenuje "sample and hold". Pokud je sepnuto, napětí na výstupu odpovídá napětí na vstupu. Pokud je rozepnuto, drží hodnotu. Procesor netřeba. Technicky to lze zapojit tak, že se na "hold" přepíná až při změně řídícího signálu, jinak ten kondík vůbec není v cestě signálu.
Nakonec případná analogová filtrace bývá taky daleko efektivnější.
Převod na PWM na výstupu je taky daleko jednodušší, nejsi limitovaný taktem procesoru.
Ten obvod se správně jmenuje "sample and hold". Pokud je sepnuto, napětí na výstupu odpovídá napětí na vstupu. Pokud je rozepnuto, drží hodnotu. Procesor netřeba. Technicky to lze zapojit tak, že se na "hold" přepíná až při změně řídícího signálu, jinak ten kondík vůbec není v cestě signálu.
Nakonec případná analogová filtrace bývá taky daleko efektivnější.
Převod na PWM na výstupu je taky daleko jednodušší, nejsi limitovaný taktem procesoru.
Naposledy upravil(a) ZdenekHQ dne 28 kvě 2021, 14:54, celkem upraveno 1 x.
Pro moje oslovení klidně použijte jméno Zdeněk
Správně navržené zapojení je jako recept na dobré jídlo.
Můžete vynechat půlku ingrediencí, nebo přidat jiné,
ale jste si jistí, že vám to bude chutnat[?]
Správně navržené zapojení je jako recept na dobré jídlo.
Můžete vynechat půlku ingrediencí, nebo přidat jiné,
ale jste si jistí, že vám to bude chutnat[?]
Bohužel nikoliv.ZdenekHQ píše:Mám dojem, že jdeš s kanónem na vrabce.
Ten obvod se správně jmenuje "sample and hold". Pokud je sepnuto, napětí na výstupu odpovídá napětí na vstupu. Pokud je rozepnuto, drží hodnotu. Procesor netřeba.
Nakonec případná analogová filtrace bývá taky daleko efektivnější.
Převod na PWM na výstupu je taky daleko jednodušší.
Analogový sample and hold je sice teoreticky možný, ale reálně není s rozumnou součástkovou základnou schopen udržet hold hodnotu déle než řekněme jednotky, max. desítky minut. Já to potřebuju teoreticky "na furt", lépe řečeno do doby vypnutí obvodu.
Jsem založením analogový hw elektronik s praxí mnoho desítek let a nepochybuj o tom, že kdyby to bylo možné, už dávno jsem tu dvojici OZ, spínač, kondenzátor a pár odporů použil...
- ZdenekHQ
- Administrátor
- Příspěvky: 25593
- Registrován: 21 črc 2006, 02:00
- Bydliště: skoro Brno
- Kontaktovat uživatele:
Děláš klasickou chybu, že navrhneš pouze vlastní řešení a nenapíšeš PROČ. Pak se nediv podobným reakcím. Tak hodně štěstí.
Pro moje oslovení klidně použijte jméno Zdeněk
Správně navržené zapojení je jako recept na dobré jídlo.
Můžete vynechat půlku ingrediencí, nebo přidat jiné,
ale jste si jistí, že vám to bude chutnat[?]
Správně navržené zapojení je jako recept na dobré jídlo.
Můžete vynechat půlku ingrediencí, nebo přidat jiné,
ale jste si jistí, že vám to bude chutnat[?]
Tak jsem ti to slepila dohromady, ale nemám to teď na čem vyzkoušet. ![Very Happy :D](./images/smilies/icon_biggrin.gif)
![Very Happy :D](./images/smilies/icon_biggrin.gif)
Kód: Vybrat vše
// 9.6 MHz, built in resonator
#define F_CPU 9600000
#define PWM_OUT 1 //PWM output on PB1
#define HOLD 4 // HOLD signal on PB4
#include <avr/io.h>
void adc_setup (void)
{
// Set the ADC input to PB2/ADC1
ADMUX |= (1 << MUX0);
ADMUX |= (1 << ADLAR);
// Set the prescaler to clock/128 & enable ADC
ADCSRA |= (1 << ADPS1) | (1 << ADPS0) | (1 << ADEN);
}
int adc_read (void)
{
// Start the conversion
ADCSRA |= (1 << ADSC);
// Wait for it to finish
while (ADCSRA & (1 << ADSC));
return ADCH;
}
void pwm_setup(void)
{
// Set Timer 0 prescaler to clock/8.
// At 9.6 MHz this is 1.2 MHz.
TCCR0B |= (1 << CS01) | (1 << CS00);
// Set to 'Fast PWM' mode
TCCR0A |= (1 << WGM01) | (1 << WGM00);
// Clear OC0B output on compare match, upwards counting.
TCCR0A |= (1 << COM0B1);
}
void pwm_write (int val)
{
OCR0B = val;
}
// ... adc_setup, adc_read, pwm_setup, pwm_write ...
int main (void)
{
int adc_in;
// LED is an output.
DDRB |= (1 << PWM_OUT);
DDRB &= ~(1<<HOLD); // Makes HOLD pin of PORTB as Input
adc_setup();
pwm_setup();
while (1) {
// Get the ADC value
adc_in = adc_read();
if (PINB & (1<<HOLD)) {
// Now write it to the PWM counter
pwm_write(adc_in);
}
}
}
Díky moc, ATtiny13 budu mít k dispozici až příští týden, dám vědět.lesana87 píše:Tak jsem ti to slepila dohromady, ale nemám to teď na čem vyzkoušet.![]()
Mimochodem jsem si nevšiml, že na původním odkazu https://adnbr.co.uk/articles/adc-and-pwm-basics je až dole další odkaz na https://gist.github.com/adnbr/9289235 a tam je ten mnou požadovaný "učesaný a slepený" kód z příkladů vcelku... Samozřejmě tam není funkce /HOLD.
Watchdog v Tebou slepeném kódu zatím zřejmě není, šel by dopsat?
Přidání watchdogu pro kód výše.
první číslo znamená, číslo řádku, kam nakopírovat...
Mimochodem kód výše je 8bit. ADC hodnota a 8bit. PWM. Modernější např. attiny1614 má 16bit. timer, takže PWM zde může být 16bit. rozlišení...
první číslo znamená, číslo řádku, kam nakopírovat...
Kód: Vybrat vše
/* 7 */ #include <avr/wdt.h>
/* 57 */ wdt_enable(WDTO_500MS);
/* 59 */ wdt_reset();
Díky moc, zkusím v týdnu, až budu fyzicky mít tu ATtiny13A. Napíšu sem výsledek.bdn píše:Přidání watchdogu pro kód výše.
první číslo znamená, číslo řádku, kam nakopírovat...Kód: Vybrat vše
/* 7 */ #include <avr/wdt.h> /* 57 */ wdt_enable(WDTO_500MS); /* 59 */ wdt_reset();
Ano, já vím, že ATtiny13 má osmibitový PWM a že v tom kódu se využívá jen horních 8 bitů z 10bit ADC (autor to popisuje na zdrojové stránce).bdn píše: Mimochodem kód výše je 8bit. ADC hodnota a 8bit. PWM. Modernější např. attiny1614 má 16bit. timer, takže PWM zde může být 16bit. rozlišení...
Jenže: existuje ATtiny (popř. prostě nějaký Atmel) v osmivývodovém pouzdře a s 10bit ADC i PWM? Při zběžném hledání jsem neuspěl, našel jsem pouze PICy a tam bych potřeboval, aby mi někdo vhodný program napsal úplně komplet... Osmivývodové pouzdro potřebuju kvůli místu na DPS.
Tak po dalších neumělých úpravách z mé strany vzniklo něco jako funkční kód, osobně úspěšně ověřený s ATtiny13A.
Maximalizoval jsem frekvenci PWM (původní kód poskytoval cca 550 Hz, nyní cca 35,71 kHz), dvojnásobně zrychlil A/D převodník, použil pro něj vnitřní referenci 1,1 V . Jo a 8 bitů PWM stačí (lépe řečeno musí stačit)...
Pro mě je zajímavé, že tento kód lze vložit do Arduino IDE (samozřejmě při nastavení správné "desky", zde MCU na ATtiny13), kompilace normálně proběhne bez chyb a stejně tak se exportuje i výsledný *.hex. Čili není třeba se zabývat s avr-gcc v konzoli a s hledáním správných parametrů překladu.
Pak už jen vhodný programátor a je hotovo![Wink ;-)](./images/smilies/icon_wink.gif)
Tímto děkuji všem zúčastněným...
Maximalizoval jsem frekvenci PWM (původní kód poskytoval cca 550 Hz, nyní cca 35,71 kHz), dvojnásobně zrychlil A/D převodník, použil pro něj vnitřní referenci 1,1 V . Jo a 8 bitů PWM stačí (lépe řečeno musí stačit)...
Pro mě je zajímavé, že tento kód lze vložit do Arduino IDE (samozřejmě při nastavení správné "desky", zde MCU na ATtiny13), kompilace normálně proběhne bez chyb a stejně tak se exportuje i výsledný *.hex. Čili není třeba se zabývat s avr-gcc v konzoli a s hledáním správných parametrů překladu.
Pak už jen vhodný programátor a je hotovo
![Wink ;-)](./images/smilies/icon_wink.gif)
Tímto děkuji všem zúčastněným...
Kód: Vybrat vše
// Track and hold (sample and hold) circuit with ATtiny13A
// voltage input on pin 7 (PB2/ADC1), PWM output on pin 6 (PB1),
// control input (H=track, L=hold) on pin 3 (PB4)
// fclk 9.6 MHz, built in resonator
// original source: https://adnbr.co.uk/articles/adc-and-pwm-basics
// original source: https://gist.github.com/adnbr/9289235
// modification: http://www.ebastlirna.cz/modules.php?name=Forums&file=viewtopic&p=1175950
#define F_CPU 9600000
#define PWM_OUT 1 //PWM output on PB1
#define HOLD 4 // HOLD signal on PB4
#include <avr/io.h>
#include <avr/wdt.h>
void adc_setup (void)
{
// Set the ADC input to PB2/ADC1
ADMUX |= (1 << MUX0);
ADMUX |= (1 << ADLAR);
ADMUX |= (1 << REFS0); // set ADC ref. to internal ref. 1.1V
// Set the prescaler to clock/128 & enable ADC (fclk for ADC cca 75 kHz)
//ADCSRA |= (1 << ADPS1) | (1 << ADPS0) | (1 << ADEN);
// Set the prescaler to clock/64 & enable ADC (fclk for ADC cca 150 kHz)
ADCSRA |= (1 << ADPS1) | (0 << ADPS0) | (1 << ADEN);
}
int adc_read (void)
{
// Start the conversion
ADCSRA |= (1 << ADSC);
// Wait for it to finish
while (ADCSRA & (1 << ADSC));
return ADCH;
}
void pwm_setup(void)
{
// Set Timer 0 prescaler to fclk/n
//TCCR0B |= (1 << CS01) | (1 << CS00);//n=64, fpwm cca 550 Hz
//TCCR0B |= (1 << CS01) | (0 << CS00);//n=8, fpwm cca 4.464 kHz
TCCR0B |= (0 << CS01) | (1 << CS00);//n=1=no prescaling, fpwm cca 35.71 kHz
// Set to 'Fast PWM' mode
TCCR0A |= (1 << WGM01) | (1 << WGM00);
// Clear OC0B output on compare match, upwards counting.
TCCR0A |= (1 << COM0B1);
}
void pwm_write (int val)
{
OCR0B = val;
}
// ... adc_setup, adc_read, pwm_setup, pwm_write, watchdog ...
int main (void)
{
int adc_in;
// LED is an output.
DDRB |= (1 << PWM_OUT);
DDRB &= ~(1<<HOLD); // Makes HOLD pin of PORTB as Input
adc_setup();
pwm_setup();
wdt_enable(WDTO_500MS);
while (1) {
// Get the ADC value
wdt_reset();
adc_in = adc_read();
if (PINB & (1<<HOLD)) {
// Now write it to the PWM counter
pwm_write(adc_in);
}
}
}