löst ATmega168 hanteringa av interrupt för servo styrning

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
eAk
Inlägg: 74
Blev medlem: 10 september 2008, 22:50:23
Ort: Kungälv

löst ATmega168 hanteringa av interrupt för servo styrning

Inlägg av eAk »

Jag håller på att försöka förstå mig hur detta med interrupts funkar i ATmega168 processorn.
jag har gjort ett litet experiment att sätta på diod i interrupt delen så jag vet att koden hammnar där iallafall.
men servo styrningen funkar inte.
så jag tänkte se ifall någon här kan hjälpa med att förklara för mig vad jag gör fel.

Tanken med koden är att den ska gå in i interupt var 10ms och lägga till på ett par räknare. har den lagt till så att ena räknaren är 1 = 20ms ska den utföra servo kontroll grejjerna. där jag försöker använda timer2 för att räkna till 2ms och slå 1 på alla benen och i en loop sätta 0 på de ben som är kopplade till motsvarande servon.

walker.c

Kod: Markera allt

#define F_CPU 20000000UL  // 20 MHz


#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

#include "walker.h"

uint8_t timer_extend = 0; //för att räkna till 20ms istället för bara 10
uint8_t klocka_10ms_tic = 0; //Lär ju behöva hålla koll på tiden som löper för servo styrningen.
uint16_t klocka_1sek_tic = 0; //behövs säkert hålla reda på sekunder
/*
Här har vi flera servon som ska ha värdet mellan 78 och 156
195=2.5ms, +90grader=(156=2ms), 0grader=(117=1.5ms), -90grader=(78=1ms) 39=0.5ms
*/
uint8_t servo1 = 117;
uint8_t servo2 = 117;
uint8_t servo3 = 117;
uint8_t servo4 = 117;
uint8_t servo5 = 117;
uint8_t servo6 = 117;
uint8_t servo7 = 117;
uint8_t servo8 = 117;
uint8_t servo9 = 117;

/*interrupt hanterare för timer 0*/
ISR(TIMER0_OVF_vect)
{
	//servo_update();
	if (timer_extend == 1)
	{
		timer_extend = 0;
		TCNT2 =0;
		//ställ alla servo till 1
		while(TCNT2 <= 78)
		{
			_delay_us(1);
		}
		s1_1
		s2_1
		s3_1
		s4_1
		s5_1
		s6_1
		s7_1
		s8_1
		s9_1
		while(TCNT2 <= 160)
		{
			if(TCNT2 >= servo1) //(195=2.5ms, 156=2ms, 117=1.5ms, 78=1ms)
			{
				s1_0
			}
			if(TCNT2 >= servo2)
			{
				s2_0
			}
			if(TCNT2 >= servo3)
			{
				s3_0
			}
			if(TCNT2 >= servo4)
			{
				s4_0
			}
			if(TCNT2 >= servo5)
			{
				s5_0
			}
			if(TCNT2 >= servo6)
			{
				s6_0
			}
			if(TCNT2 >= servo7)
			{
				s7_0
			}
			if(TCNT2 >= servo8)
			{
				s8_0
			}
			if(TCNT2 >= servo9)
			{
				s9_0
			}
		}
	}
	if (timer_extend == 0)
	{
		timer_extend++;
	}
	if(klocka_10ms_tic == 100)
	{
		klocka_1sek_tic++;
		klocka_10ms_tic = 0;
	}
	klocka_10ms_tic++;
}

int main(void)
{
	int i;
	//timer0
	TCCR0A=0b00000000;
	TCCR0B=0b00000101; //1024 prescaler
	TIMSK0=0b00000001;
	//timer2
	TCCR2A=0b00000000;
	TCCR2B=0b00000110; //256prescaler (195=2.5ms, 156=2ms, 78=1ms)

	klocka_10ms_tic = 0;
	klocka_1sek_tic = 0;
	DDRD = 0b10100110;
	DDRC = 0b00000111;
	DDRB = 0b00011001;

	sei();

	while(1)
	{
		//gör något som prata med sonar på I2C och läs av sharp range på ADC
		//få roboten att röra på sig. igenom att hantera servoX variablerna
		//komunicera med omvärlden igenom seriell porten.

		_delay_us(1);
		if(klocka_1sek_tic == 2)
		{
			klocka_1sek_tic = 0;
		}
		
		if(klocka_1sek_tic == 1)
		{
			PORTD |=(1<<1);
		}
		if(klocka_1sek_tic == 0)
		{
			PORTD &=~((1<<1));
		}
	}

}
walker.h

Kod: Markera allt

//196 för 10ms med 8bitars timer med prescale 1024
/*
	I2C
	pc5 = SCL
	pc4 = SDA

	Serial
	pd1 = TX
	pd0 = RX

	Servon
	pb0 = s1
	pb3 = s2
	pb4 = s3
	pb5 = s4
	pd2 = s5
	pd3 = s4
	pd4 = s5
	pd7 = s6
	pc0 = s7
	pc1 = s8
	pc2 = s9

	Sensor
	ADC6 = sharp

	Knapp
	pc3 = knapp1
*/

#define s1_1 PORTB |=(1<<0);
#define s1_0 PORTB &=~((1<<0));

#define s2_1 PORTB |=(1<<3);
#define s2_0 PORTB &=~((1<<3));

#define s3_1 PORTB |=(1<<4);
#define s3_0 PORTB &=~((1<<4));

#define s4_1 PORTD |=(1<<5);
#define s4_0 PORTD &=~((1<<5));

#define s5_1 PORTD |=(1<<2);
#define s5_0 PORTD &=~((1<<2));

#define s6_1 PORTD |=(1<<7);
#define s6_0 PORTD &=~((1<<7));

#define s7_1 PORTC |=(1<<0);
#define s7_0 PORTC &=~((1<<0));

#define s8_1 PORTC |=(1<<1);
#define s8_0 PORTC &=~((1<<1));

#define s9_1 PORTC |=(1<<2);
#define s9_0 PORTC &=~((1<<2));



extern uint8_t timer_extend;
extern uint8_t klocka_10ms_tic;
extern uint16_t klocka_1sek_tic;

extern uint8_t servo1;
extern uint8_t servo2;
extern uint8_t servo3;
extern uint8_t servo4;
extern uint8_t servo5;
extern uint8_t servo6;
extern uint8_t servo7;
extern uint8_t servo8;
extern uint8_t servo9;



extern int main(void);
extern void servo_update(void);
Tackar för all hjälp.
Senast redigerad av eAk 17 september 2008, 01:29:29, redigerad totalt 1 gång.
fjodorr
Inlägg: 163
Blev medlem: 26 april 2005, 10:41:57
Ort: Stockholm

Inlägg av fjodorr »

Hmm var lite svår kod att gå igenom. Många hopp fram och tillbaka. Men ändrar du värdena på servona nån gång eller ligger de på 0grader=(117=1.5ms) hela tiden?

Jag skulle banta koden och få det fungera för ett servo först. Ta det sen vidare.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Bryt ner applikationer i separate delar och testa varje del för sig.
eAk
Inlägg: 74
Blev medlem: 10 september 2008, 22:50:23
Ort: Kungälv

Inlägg av eAk »

Som test ha jag alla på 0grader så ser jag om dom ställer sig där när programet kör igång.

men jag har mekat nu och tror jag kommit fram till att problemet ligger i de globala variablerna.
dom ändras heltenkelt inte.

för sätter jag till att tända en diod i timer0 overflow interrupt vectorn och dioden till 0 i program loopen så blinkar den bara välldigt snabbt så den lyser svagare.

och försöker jag använda mina tidtagnings variabler som ska ökas med 1 var 10ms så gör dom ju heltenkelt inte det eftersom sekunder ligger på 0 helatiden eftersom att lampan blinkar om jag ställer den till på i varje interrupt.

Så kan man inte använda globala variabler i interrupt eller har jag gjort något stort fel. för i princip samma kod med globala variabler funkar på min pic18f2520 (dock så pollar den efter interrupt flaggan och går inte in i interrupt.)
eAk
Inlägg: 74
Blev medlem: 10 september 2008, 22:50:23
Ort: Kungälv

Inlägg av eAk »

LÖST! :)

One last note on interrupt routines: Item #1 in the WinAVR FAQ is this: Global variables that are used in interrupt routines must be declared as volatile. This ensures that the compiler doesn't optimize that variable and jeopardize its ability to be used inside interrupt routines.

Nu tänds och släcks dioden varannan sekund. då måste jag få servona till att börja funka som dom ska.
Skriv svar