Přechod z ATmega8 na ATmega168

Cus,
snažím se přejít z ATmega8 na ATmega168, ale nemůžu to pořád nastavit.
Původně to bylo takhle.


void uart_putc(unsigned char data )
{
	while ( !( UCSRA & (1<<UDRE)) )
	;
	UDR = data;
	
}
// get char
unsigned char uart_getc( void )
{
	/* Wait for data to be received */
	while ( !(UCSRA & (1<<RXC)) )
	;
	/* Get and return received data from buffer */
	return UDR;
}

---
/***** inicializace uart  *****/
	UCSRA = 0x00;
	UBRRH = 0x00;
	UBRRL = 51;   // 9600 baud
	UCSRB |= (1<<TXEN) | (1<<RXEN);
	UCSRC = 0x86;  // ramec dat:  8 datovych, 1 stop bit, bez parity
	
	TIMSK = 0b00010001; //bit 0 - povolení přerušení při přetečení od timeru 0, bit 4 - povolení přerušení timer 1
	TCCR0 = 5; //předdělička na 1024, timer 0
	TCCR1B = 0b00001010; //předdělička na 8(bit 1); (bit 3) nastavení CTC modu
	OCR1A = 100; // 460 při 18,xx MHz, 199 při 8 MHz
	TCCR2 = 0b00000100; // předdělicka timeru 2 na 64
----
TIMSK ^= 0b01000000; //povolení přerušení od timeru 2
TIMSK &= (~(1 << 6)); //zakázání přerušení od přetečení timeru 2

Co kdyby sis prošel datasheet s zjistil si rozdíly ?

Například datový registr UARTu :
ATmega8 má UDR, ATmega168 má UDR0.

atd.

Proč je v těch názvech to malé n? Za to mám dosadit 0?

Taky jsem se na tom před časem zasekl. Vytiskni si seznam registrů obou mcu z DS a uprav názvy registrů podle konkrétního mcu.

Protože některé mcu mají více USARTů. ATmega168 má jen USART0, ale třeba ATmega164/324/644/1284 má USART0 a USART1. Proto asi je USART u těchto procesorů pojmenován jako USART0 - hlavně kvůli jednodušší přenositelnosti programu mezi různými mcu. ATmega1280/2560 má dokonce 4 USARTy.

Takže ano - místo “n” dosaď “0”.

tak jsem se to pokusil předělat

void uart_putc(unsigned char data )
{
	while ( !( UCSR0A & (1<<UDRE0)) )
	;
	UDR0 = data;
	
}
// get char
unsigned char uart_getc( void )
{
	/* Wait for data to be received */
	while ( !(UCSR0A & (1<<RXC0)) )
	;
	/* Get and return received data from buffer */
	return UDR0;
}

---

UCSR0A = 0x00;
	UBRR0H = 0x00;
	UBRR0L = (unsigned char) 51;   // 9600 baud
	UCSR0B |= (1<<TXEN0) | (1<<RXEN0);
	UCSR0C |= (1<<UMSEL00) | (1<<UCSZ00) | (1<<UCSZ01);  // ramec dat:  8 datovych, 1 stop bit, bez parity
	
	TIMSK0 = (1<<TOIE0); //povolení přerušení od přetečení timeru 0
	TCCR0B |= (1<<CS00) | (1<<CS02); //předělička timeru 0 na 1024
	
	TIMSK1 = (1<<OCIE1A); //povolení přerušení od timeru 1 (CTC)
	TCCR1B |= (1<<CS11) | (1<<WGM12); //předělicka na 8 a nastavebí CTC módu
	OCR1AL = 99; // 460 při 18,xx MHz, 199 při 8 MHz (1. 8 bitů)
	OCR1AH = 0; //(zbytek bitů)
	
	TCCR2B = (1<<CS22); //předdělicka timeru 2 na 64

na timeru 0 má blikat ledka a jen svítí a na timeru 1 je servo a to zajede do krajní polohy (cukaně, čož je podle mích zkušeností neustále 5V)

Nevíte co stím?
pokus1.c (7.19 KB)

Když takový projekt nefunguje, je zvykem zkoušet jeho činnosti odděleně (blikání, UART, servo)
Ostatně ten kód je zřejmě pro krokový motor, ne pro servo.
Asi by ses jako začátečník neměl pouštět do takových komplikovaných věcí.

Zkus začít jako většina z nás, třeba takto:.

  1. úloha
    Rozblikej Ledku na některém portu.

  2. úloha
    Když není stisknuté tlačítko Ledka bliká pomalu, pokud držíš tlačítko bliká rychle.

Potom zkus spustit seriovou komunikaci přes UART:

  1. úloha
    Avr přijme znak z terminálu v PC a vyšle ho zpátky.

  2. úloha
    Když z terminálu pošleme ‘1’ Led bliká pomalu, když pošleme ‘2’ bliká rychle.

atd.

Dobrý zdroj informací je
avrfreaks.net/index.php?name … file=index

Pokud ti dělá problémy angličtina, zkus aspoň toto
svetelektro.com/clanky/kniha-pro … c-557.html

Skoro všechno už jsem dělal. Jsou tam dva krokový motory a jedno servo.
A předtím to fungovalo, jen po tom předělání to ani nebliká.

Bude tam nějaká drobnost, kterou jsi přehlédnul. V čem to překládáš ? Pokud stejný kód chodil ve stejném překladači, pak by změna proceroru neměla mít na překlad (po úpravě kódu na správné registry) žádný vliv. Myslím tím samozřejmě použití proměnných apod.

Ještě přidám pár drobností spíš pro efektivitu překladu než pro funkčnost. Některé změny můžou jenom zpřehlednit zápis,
ale některé ovlivní i rychlost programu (třeba i dost výrazně). Záleží na inteligenci překladače a nastavení
optimalizací. Každopádně změny proveď teprve až Ti to bude šlapat.

	citacTimeru1 += 1;
	citacTimeru1 = citacTimeru1 % 200;

můžeš nahradit

	citacTimeru1++;
	citacTimeru1 %= 200;

nebo

	citacTimeru1 = (++citacTimeru1)%200;

=========================================

			poziceMotoru1 -= 1;
			poziceMotoru1 = (poziceMotoru1 + 8) % 8;

můžeš nahradit

			poziceMotoru1 = (--poziceMotoru1 + 8) % 8;

=========================================

	if (x<0)
	{
		return -x;
	}
	else
	{
		return x;
	}

můžeš nahradit

	return (x<0)?-x:x;

=========================================

Tohle už povede ke zrychlení kódu :

	citacTimeru2 +=1; //1/(f*1000000/(2^8*1024[preddelicka]))*1000*citac [ms]
	if (citacTimeru2 >= 6)
	{
		
		citacTimeru2 = 0;
	}

můžeš nahradit

	citacTimeru2 --; //1/(f*1000000/(2^8*1024[preddelicka]))*1000*citac [ms]
	if (!citacTimeru2)
	{
		
		citacTimeru2 = 6;
	}

případně

	if (!(--citacTimeru2))
	{
			citacTimeru2 = 6;
	}

Důvod je jednoduchý. Při dekrementaci se při dosažení nuly nastaví příznak Z.
Kontroler tak nemusí inkrementovat proměnnou a následně ji kontrolovat na hodnotu.
Po dosažení nuly se nastaví příznak a podle něj se vyhodnotí podmínka. Tohle Ti žádná
optimalizace neudělá. Nesmíš ale zapomenout v “inicializační” části programu (před
hlavní nekonečnou smyčkou) všechny takto používané proměnné nastavit buď na startovací
hodnotu (citacTimeru2 = 6) nebo alespoň na 1, protože jinak by první cyklus trval
celý rozsah proměnné.

=========================================

A ještě jeden tip :

	dioda +=1;
	if (dioda > 20)
	{
		PORTD ^= 0x80;
		dioda = 0;
	}

můžeš nahradit

	if (!(--dioda))
	{
		PIND = 0x80;
		dioda = 20;
	}

PIND je tam správně. Pokud se ptáš proč, tak zkus kouknout do datasheetu, odpověď tam najdeš. :wink:

Zkusil jsem to nechat na začátku blikat s frekvencí 1 Hz a blikalo to výrazně pomaleji
Pojistky jsem zkontroloval a jsou defaultní

Už jsem to našel v datasheetu bylo to nastavený na 1 MHz místo 8 :slight_smile:

Objevil se jiný problém, sice s touto věcí moc nesouvisí, ale nevím kam to zařadit tak to napíšu zde.

Pomocí dvou krokových motorů se potřebuji po přímce dostat z jednoho bodu do druhého. Jeden motor hýbe s jednou osou a druhý s druhou. ATmega dostane informaci kam se má dostat. Spočítá jaký jsou to směry na osách a spočítá jednotlivé vzdálenosti, pak vyhodnotí jaká je delší a spustí timer. Ten otáčí motorem, který musí ujet delší vzdálenost. A v programu běží smyčka která se snaží druhým motorem hýbat druhou osou tak, aby to byla co nejrovnější úsečka.

Ta část s delší osou funguje dobře, jen a smyčka by nic nedělala.

Kód timeru:


if (!(--citacTimeru2)) 
   { 
	   if (XJeVetsiNezY)
	   {
		   poziceMotoru1 -= zx;
		   poziceMotoru1 = (poziceMotoru1 + 8) % 8;
		   PORTC &= 0b11110000;
		   PORTC |= pole[poziceMotoru1];
		   ++ax;
		   x += zx;
		   if (ax == dx)
		   {
			   TIMSK2 = 0; //zakázání přerušení od přetečení timeru 2
		   }
	   } 
	   else
	   {
		   poziceMotoru2 += zy;
		   poziceMotoru2 = (poziceMotoru2 + 8) % 8;
		   PORTB = pole[poziceMotoru2];
		   ++ay;
		   y += zy;
		   if (ay == dy)
		   {
			   TIMSK2 = 0; //zakázání přerušení od přetečení timeru 2
		   }
	   }
	   
	   citacTimeru2 = 10; 
   } 
}

Smyčka:

void tisk(void) {
	ay = 0;
	ax = 0;
	
	if (p != DOLE)
	{
		p = DOLE;
		_delay_ms(100);
	}
	
	xp = x2 | (x1 << 8);
	yp = y2 | (y11 << 8);
	// zjištení směru posunu//
	if (y < yp)
	{
		zy = 1;
	}
	else
	{
		zy = -1;
	}
	if (x < xp)
	{
		zx = 1;
	}
	else
	{
		zx = -1; 
	}
	// výpočet vzádlenosti//
	dx = xp - x;
	dy = yp - y;
	dx = ABS(dx);
	dy = ABS(dy);
	if (dx > dy)
	{
		XJeVetsiNezY = 1;
		TIMSK2 = (1<<TOIE2); //povolení přerušení od timeru 2
		while ((ax == dx) && (ax == dx))
		{
			
			if (dy * ax > ay * dx) // dopočítávání jestli se blíží úsečce
			{
				poziceMotoru2 -= zy;
				poziceMotoru2 = (poziceMotoru2 + 8) % 8;
				PORTB = pole[poziceMotoru2];
				++ay;
				y += zy;
			}
		}
	}
	else
	{
		XJeVetsiNezY = 0;
		TIMSK2 = (1<<TOIE2); //povolení přerušení od timeru 2
		while ((ax == dx) && (ay == dy))
		{
			
			if (dy * ax > ay * dx)
			{
				poziceMotoru1 += zx;
				poziceMotoru1 = (poziceMotoru1 + 8) % 8;
				PORTC &= 0b11110000;
				PORTC |= pole[poziceMotoru1];
				++ax;
				x += zx;
			}
		}
		uart_putc(90);
	}
	
}

Hodnoty proměnných jsou 0-3300