Projekt: Inkrementálny snímač otáčok

Z SensorWiki
Prejsť na: navigácia, hľadanie

Zadanie

F. Inkrementálny snímač otáčok

Pripojte IRC k mikropočítaču a na displeji zobrazte aktuálnu rýchlosť. Doplňte zariadenie o možnosť riadenia otáčok motorčeka pomocou PWM.

MotorEMG30.jpg

Literatúra:


  1. Vytvorte program, ktorý bude schopný regulovať otáčky motora pomocou PWM modulácie signálu
  2. Pomocou inkrementálneho snímača merajte otáčky motora, zobrazujte ich na LCD displej

Riešenie


Reguláciu otáčok motora sme zabezpečili pomocou PWM modulácie, pričom sme menili hodnotu striedy. Zabezpečili sme tak zmenu strednej hodnoty napätia privádzaného na motor.

Súbor-PWM duty cycle with label.gif

PWM moduláciu sme realizovali pomocou časovača. Vybrali sme si časovač Timer2, ktorý dokázal pracovať v 8-bitovom režime. Pri frekvencii 16 MHz sme tým pádom vytvorili periódu opakovania PWM 61 Hz. Keď by sme zvolili vyššiu periódu opakovania, motor mal vplyvom induktancie pri riadení silne nelineárnu prevodovú charakteristiku.

Hodnotu striedy sme menili pomocou tlačítok integrovaných na LCD displeji. Veľkosť zmeny kroku sme zvolili: malý ±1% a veľký ±10%.

Pomocou inkrementálneho snímača otáčok sme merali hodnotu otáčok motora za sekundu. Prepočet sme realizovali pomocou časovača Timer1. Na základe zmeny hodnoty v Input Caprute registri sme generovali prerušenie, ktoré následne vypočítalo aktuálnu hodnotu otáčok motora. Pomocou príslušných funkcií v knižnici lcd.c sme túho hodnotu vzpísali na LCD displej. Pri pretečení počítadla časovača sme generovali prerušenie, ktoré detekovalo kedy motor stojí. Na LCD displej sme vtedy vypísali reťazec: stop.

Motor sme zapojili podľa schémy priloženej k zadaniu. Schému zapojenia motora a halovho inkrementálneho snímača nájdete tu: zapojenie

Po úspešnej realizácii projektu sme namerali prevodovú charakteristiku motora v závislosti od zmeny striedy. Meranie sme realizovali pri akcelerácii aj decelerácii motora. Krok striedy sme menili po 5%. Charakteristika je zobrazená na nasledujúcom obrázku.

Prevovoda charakteristika.png

Ukážka zdrojového kódu


Pripojenie jednotlivých pinov ATmega328:

┌──────┬──────────────┬────────────────┬───────────────────────────────┐
│ PIN  │  PRIPOJENIE  │  FARBA VODIČA  │            INFO               │
├──────┼──────────────┼────────────────┼───────────────────────────────┤
│ D8   │  irc B out   │    oranžová    │              -                │
│ D11  │  pwm motor   │        -       │ cez odpor na bázu tranzistora │
│ D3   │  led         │        -       │ na doske, inicializovaný out  │
└──────┴──────────────┴────────────────┴───────────────────────────────┘
ostatné podľa schémy zapojenia

Externé súbory: zaver.h, lcd.c, lcd.h


Kód v jayzku C:

/*
 *   Created: 12/12/2012 12:12:12
 *   Authors: Lukas Mrva (55716), Vladimir Reksak (55720)
 */

#include <avr/io.h>
#include <avr/interrupt.h>
#include "zaver.h"
#include "lcd.h"
#include <inttypes.h>
#include <stdio.h>

// deklaracia premennych
unsigned int buttons;
unsigned int strieda = 10;
unsigned int state = 0xFF;

volatile unsigned char stop=1, stop2=1;

// definovanie obsluhy preruseni
ISR(TIMER1_OVF_vect)
{
	stop = stop2 = 1; // ked motor stoji, je overflow, stop aj stop2 = 1
}

ISR(TIMER1_CAPT_vect)
{
	TCNT1 = 0; // po zaznamenani hodnoty v capture registri vznulujeme pocitadlo, mame cas jednej otacky
	if (stop2==0) stop = 0; // ak dvakrat po sebe nastane prerusenie od pretecenia bez zaznamenania capture, motor stoji
	stop2 = 0;
}

FILE mystdout = FDEV_SETUP_STREAM(lcdDataWrite, NULL, _FDEV_SETUP_WRITE);  // je  nova funkcia pre jeden znak

// hlavny program
int main(void)
{
	stdout = &mystdout;
	// inicializacia timerov, portov a displeja, povolenie preruseni
	port_init();
	timer2_init();
	lcdInit4();
	timer1_init();	
	asm("sei");
	
	unsigned char lcdpresc=0;
    
	// hlavna slucka programu
    while(1)
    {    
		delay_ms(55);
		buttons=ReadButtons(); // zaznamenanie stlacenia tlacitka na LCD displeji, trva 20ms
		
		PORTB &= 0xDF; // otestovanie tlacitka
		
		if (buttons & (1<<3))
			  {
				PORTB |= (0x01<<5);	 //blik led pri stlaceni tlacidla
				strieda = strieda +10; // inkrementacia striedz - velky skok	  					   
			  }
			 
		if (buttons & (1<<0))
				{
					PORTB |= (0x01<<5);	 //blik led pri stlaceni tlacidla
					strieda = strieda - 10; // dekrementacia striedz - velky skok	
				}
		
		if (buttons & (1<<2))
				{
					PORTB |= (0x01<<5);	 //blik led pri stlaceni tlacidla
					strieda++; // inkrementacia striedz - maly skok	
				}
		
		if (buttons & (1<<1))
				{
					PORTB |= (0x01<<5);	 //blik led pri stlaceni tlacidla
					strieda--; // inkrementacia striedz - maly skok	
				}
		
		
		if(strieda>200) // ak podtiekla premenna
				strieda = 0;
		if(strieda>100) // ohranicenie maxima
				strieda = 100;
		
			
		if (buttons) lcdpresc=200; // po stlaceni tlacitka okamzity vypis
		
		// zabazpecenie pomalejsieho vypisu, kazdy 10. krok 
		if (lcdpresc++ > 10)
		{
				lcdpresc=0;
				lcdControlWrite(1<<LCD_CLR);
				lcdControlWrite(0x40);
		
				printf("TAU=%3d%%",strieda);
				lcdControlWrite(0x40+0x80);
				if (stop) printf("  stop  ");
				else printf("%4d rpm",(5000000/ICR1));	
		}	
		
		timer2_generator(strieda);
	
    }
}



// --- FUNKCIE ---
void port_init(void)
{	
	// inicializacia portov
	DDRB |= (1 << PORTB3)|(1 << PORTB1)|(1 << PORTB2); // PB1, PB2 - pwm vystup na servo
	PORTB |= (1<<PORTB0); // pull up na ICP1
}


void timer1_init(void) // pwm na servopohon
{
	TCNT1 = 0;

	TCCR1B = (1 << CS11) | (1 << CS10); // nastavenie predelicky
	// obsah registra: ICNC1 ICES1 – WGM13 WGM12 CS12 CS11 CS10
	
	TIMSK1 =  (1 << ICIE1) | (1 << TOIE1); // zapneme prerusenie od ICP a timer overflow
	// obsah registra: – – ICIE1 – – OCIE1B OCIE1A TOIE1
}


void timer2_init(void) // inicializacia timera obsluhujuceho PWM
{
	TCNT2 = 0;
	OCR2A = 0x05; // zakladne nastavenie striedz - 10%
	
	TCCR2A |= (1 << COM2A1) | (1 << WGM21) | (1 << WGM20);
	// obsah registra: COM2A1 COM2A0 COM2B1 COM2B0 – – WGM21 WGM20
	
	TCCR2B |=  (1 << CS20) | (1 << CS21) | (1 << CS22);
	// obsah registra: FOC2A FOC2B – – WGM22 CS22 CS21 CS20
}


void timer2_generator(unsigned int tau) // uprava PWM, vstup do funkcie hodnota striedy [%]
{
	OCR2A = (tau*2)+(tau/2);
	if (tau) TCCR2A |= (1 << COM2A1);
	else TCCR2A &= ~(1 << COM2A1); // ak mame striedu 0%, vypiname vystupny pin PWM modu
}


void delay_ms(unsigned int ms)
{
	unsigned int index;

	while (ms)
	{
		index = F_CPU / 5003;    // presna hodnota, aby sme dostali 1ms
		
		while (index)
		{
			asm volatile ("nop");
			index--;
		}
		ms--;
	}
}

Obrázková dokumentácia


NahladProjektIRC 1.jpg

NahladProjektIRC 2.jpg

NahladProjektIRC 3.jpg