- Akku Tests und Balkonkraftwerk Speicher         
Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 10 von 17

Thema: Timing bzw. Semi-multitasking

  1. #1
    Neuer Benutzer Öfters hier
    Registriert seit
    04.01.2008
    Beiträge
    9

    Timing bzw. Semi-multitasking

    Anzeige

    Powerstation Test
    Hallo zusammen,

    bin seit einer Woche stolzer Besitzer eines RP6 mit Erweiterungsplatine.
    Mit Elektronik hab ich schon etwas Erfahrung aus dem Modellbaubereich und vom PC-Basteln.

    Probleme bereitet mir momentan eher die Programmierung, da ich (außer Quellcodes auf nem CPD 6128 mit Basic 1.1 von 1985 eintippen) noch keine Erfahrungen habe.

    Jetzt mal endlich zu meinem Problem:

    Basis ist das Move2-Programm für die Erweiterungsplatine.
    Ich habe an dessen I/O´s 4 LED´s angeschlossen, die ich während des gesamten Programmablaufs innerhalb eines bestimmten Taktes blinken lassen will. Weiterhin habe ich einen Servo an Interupt 2 angelötet, den ich später einmal ansteuern will. Auf dem Servo sitzt ein Suchscheinwerfer, der über einen BC517 auf I/O 3 läuft. Dieser Scheinwerfer schaltet sich ab eine bestimmten Wert ein, der vorab über die LDR´s der Basis ermittelt werden.

    Rein technisch funktioniert die Sache wunderbar. Auch der Programmablauf selbst funktioniert einwandfrei, aber zu langsam.

    Der Ablauf der LED´s und die Abfrage der LDR´s nehmen soviel Zeit in Anspruch, dass für die Hauptprogrammfunktionen keine Zeit mehr bleibt. Dementsprechend erkennt der RP6 ein Hinterniss, fährt dann ein ganzes Stück weiter (gegen das Hinternis) und fängt dann mit dem Ausweichmanöver an).

    Da der Atmel ja nicht wirklich Multitaskingfähig ist, muss ich das irgendwie anders lösen. Ich nehme an, dass es zuviel Zeit benötigt, die Ports für die LED´s einzeln zu schalten, mir fällt aber keine bessere Möglichkeit ein, ohne in die Library des Controll-Boards einzugreifen. Das wollte ich erst dann, wenn ich mich mit dem Spaß ein bischen besser auskenne. Hat jemand einen Rat, wie man das eleganter lösen kann?

    Hier mal der Code (nur die Änderungen an der Move2, sonst wirds zu viel)

    Bitte nicht lachen, wenn das völlig Banane ist, ich hab wirklich null Ahnung von C und kämpf mich grad durch ein Buch, was für die Atmel´s wohl nicht wirklich taugt...

    Gruß

    Markus

    Code:
    void eigenefunktion(void) /*schaltet die LEDs/*
    {
    
    
    PORTC |= IO_PC7;  
    mSleep(80);
    PORTC &= ~IO_PC7;
    mSleep(80);
    PORTC |= IO_PC7;  
    mSleep(80);
    PORTC &= ~IO_PC7;
    mSleep(100);
    
    PORTC |= IO_PC5;  
    mSleep(80);
    PORTC &= ~IO_PC5;
    mSleep(80);
    PORTC |= IO_PC5;  
    mSleep(80);
    PORTC &= ~IO_PC5;
    mSleep(100);
    
    PORTC |= IO_PC6;  
    mSleep(80);
    PORTC &= ~IO_PC6;
    mSleep(80);
    PORTC |= IO_PC6;  
    mSleep(80);
    PORTC &= ~IO_PC6;
    mSleep(100);
    
    PORTC |= IO_PC4;  
    mSleep(80);
    PORTC &= ~IO_PC4;
    mSleep(80);
    PORTC |= IO_PC4;  
    mSleep(80);
    PORTC &= ~IO_PC4;
    mSleep(100);
    
    
    
    }
    
    void task_LDRinfo(void) /*liest die LDRs aus und schaltet Port3 mit Scheinwerfer/*
    
    {
    
    		writeString_P("LDR_L: ");
    		writeIntegerLength(adcLSL, DEC, 4);
    		writeString_P(" ; LDR_R: ");
    		writeIntegerLength(adcLSR, DEC, 4);
    		writeString_P(" ||");
    		if(adcLSL <400) 
    		PORTC |= IO_PC3;
    		if(adcLSL >450)
    		PORTC &= ~IO_PC3;
    
    }
    
    /*****************************************************************************/
    // Main function - The program starts here:
    
    int main(void)
    {
    	initRP6Control();  
    	initLCD();
    	
    DDRC |= IO_PC7;
    DDRC |= IO_PC6;
    DDRC |= IO_PC5;
    DDRC |= IO_PC4;
    DDRC |= IO_PC3;
    PORTC &= ~IO_PC3;

  2. #2
    Erfahrener Benutzer Robotik Einstein Avatar von Dirk
    Registriert seit
    30.04.2004
    Ort
    NRW
    Beiträge
    3.803
    Hallo antanis,

    willkommen im "RP6-Club"!

    Wie du schon gesagt hast:
    Deine "eigenefunktion" blockiert die Hauptprogrammschleife (wenn sie da eingebaut wird) und verhindert die zeitnahe Abarbeitung anderer Tasks.

    Die Lösung dafür sind die Stopwatches.
    Wenn du in der Funktion die mSleep Aufrufe durch Stopwatch-Abfragen ("if (getStopwatch1() > 80 ..." usw) ersetzt, dann wartet die Funktion nicht mehrfach 80ms (gesamt fast 1,4 sec).

    Gruß Dirk

  3. #3
    Neuer Benutzer Öfters hier
    Registriert seit
    04.01.2008
    Beiträge
    9
    Hallo Dirk,

    vielen Dank für den Tip, so in der Art müsste es eigentlich funktionieren. Aber irgendwie krieg ich es nicht hin. Hab mich erstmal auf 2 LED´s konzentriert (Port 7 und 5).
    Code:
    void task_LDRinfo(void)     //LDR für Suchscheinwerfer auswerten
    {
    
    		writeString_P("LDR_L: ");
    		writeIntegerLength(adcLSL, DEC, 4);
    		writeString_P(" ; LDR_R: ");
    		writeIntegerLength(adcLSR, DEC, 4);
    		writeString_P(" ||");
    		if(adcLSL <400) 
    		PORTC |= IO_PC3;
    		if(adcLSL >450)
    		PORTC &= ~IO_PC3;
    
    }
    
    void eigenefunktion(void)
    {
    
    PORTC &= ~IO_PC7; //IO´s erstmal auf LOW schalten
    PORTC &= ~IO_PC6;
    PORTC &= ~IO_PC5;
    PORTC &= ~IO_PC4;
    
    startStopwatch3();                 //Stopwatch Nr. 1 starten
    
    if (getStopwatch3() > 100)   //Stopwatch 1 auswerten
    PORTC |= IO_PC7;             /Wenn Stopwatch über 100-> Ports High
    PORTC |= IO_PC5;
    setStopwatch1(0);             //Stopuhr zurückstellen auf 0
    
    if (getStopwatch3() > 100)  //Stopwatch 1 auswerten
    PORTC &= ~IO_PC7;        // Wenn Stopwatch über 100--> Ports LOW
    PORTC &= ~IO_PC5;   
    setStopwatch3(0);           //Stopuhr wieder zurück
    
    
    int main(void)                          //Hauptprogramm
    {
    	initRP6Control();  
    	initLCD();
    	
    DDRC |= IO_PC7;                    //erstmal Ports festlegen
    DDRC |= IO_PC6;
    DDRC |= IO_PC5;
    DDRC |= IO_PC4;
    DDRC |= IO_PC3;
    
    PORTC &= ~IO_PC3;      /*Den Port für den Suchscheinwerfer auf LOW /*
    
    while(true)         //Endlos-Schleife starten
    	{ 
    		task_LCDHeartbeat();
    		task_checkINT0();
    	    task_I2CTWI();
    		behaviourController();
    		eigenefunktion();    /*Hier sollten nun eigentlich die Ports nach je 100ms high/Low-Schalten /*
    
    		task_LDRinfo(); /*Abfrage für Suchscheinwerfer
    
    	
    		
    
    	}
    	return 0;
    }
    Was ich nicht ganz verstehe: Der Port 3 für den Suchscheinwerfer ist am Anfang immer aktiv ebenso die für die LED´s. Port 3 schalte ich im Hauptprogramm ja aktiv ab (PORTC &= ~IO_PC3; ) die 4 anderen nicht. Diese sind aber nach einmaligen aufleuchten ebenfalls auf Low???

  4. #4
    Neuer Benutzer Öfters hier
    Registriert seit
    04.01.2008
    Beiträge
    9
    Hier mal der ganze Code, falls sich jemand durchbeissen will:



    Code:
    // Includes:
    
    #include "RP6ControlLib.h" 		// The RP6 Control Library. 
    								// Always needs to be included!
    
    #include "RP6I2CmasterTWI.h"	// I2C Master Library
    
    
    /*****************************************************************************/
    /*****************************************************************************/
    // Include our new "RP6 Control I2C Master library":
    
    #include "RP6Control_I2CMasterLib.h"
    
    /*****************************************************************************/
    
    
    /*****************************************************************************/
    // Behaviour command type:
    
    #define IDLE  0
    
    // The behaviour command data type:
    typedef struct {
    	uint8_t  speed_left;  // left speed (is used for rotation and 
    						  // move distance commands - if these commands are 
    						  // active, speed_right is ignored!)
    	uint8_t  speed_right; // right speed
    	unsigned dir:2;       // direction (FWD, BWD, LEFT, RIGHT)
    	unsigned move:1;      // move flag
    	unsigned rotate:1;    // rotate flag
    	uint16_t move_value;  // move value is used for distance and angle values
    	uint8_t  state;       // state of the behaviour
    } behaviour_command_t;
    
    behaviour_command_t STOP = {0, 0, FWD, false, false, 0, IDLE};
    
    /*****************************************************************************/
    // Cruise Behaviour:
    
    #define CRUISE_SPEED_FWD 80 // Default speed 
    
    #define MOVE_FORWARDS 1
    behaviour_command_t cruise = {CRUISE_SPEED_FWD, CRUISE_SPEED_FWD, FWD, 
    								false, false, 0, MOVE_FORWARDS};
    
    /**
     * Cruise Behaviour
     */
    void behaviour_cruise(void)
    {
    
    }
    
    /*****************************************************************************/
    // Escape Behaviour:
    
    #define ESCAPE_SPEED_BWD    80
    #define ESCAPE_SPEED_ROTATE 60
    
    #define ESCAPE_FRONT		1
    #define ESCAPE_FRONT_WAIT 	2
    #define ESCAPE_LEFT  		3
    #define ESCAPE_LEFT_WAIT	4
    #define ESCAPE_RIGHT	    5
    #define ESCAPE_RIGHT_WAIT 	6
    #define ESCAPE_WAIT_END		7
    behaviour_command_t escape = {0, 0, FWD, false, false, 0, IDLE}; 
    
    /**
     * This is the Escape behaviour for the Bumpers.
     */
    void behaviour_escape(void)
    {
    	static uint8_t bump_count = 0;
    	
    	switch(escape.state)
    	{
    		case IDLE: 
    		break;
    		case ESCAPE_FRONT:
    			escape.speed_left = ESCAPE_SPEED_BWD;
    			escape.dir = BWD;
    			escape.move = true;
    			if(bump_count > 3)
    				escape.move_value = 200;
    			else
    				escape.move_value = 140;
    			escape.state = ESCAPE_FRONT_WAIT;
    			bump_count+=2;
    		break;
    		case ESCAPE_FRONT_WAIT:			
    			if(!escape.move)
    			{	
    				escape.speed_left = ESCAPE_SPEED_ROTATE;
    				if(bump_count > 3)
    				{
    					escape.move_value = 110;
    					escape.dir = RIGHT;
    					bump_count = 0;
    				}
    				else 
    				{
    					escape.dir = LEFT;
    					escape.move_value = 75;
    				}
    				escape.rotate = true;
    				escape.state = ESCAPE_WAIT_END;
    			}
    		break;
    		case ESCAPE_LEFT:
    			escape.speed_left = ESCAPE_SPEED_BWD;
    			escape.dir 	= BWD;
    			escape.move = true;
    			if(bump_count > 3)
    				escape.move_value = 160;
    			else
    				escape.move_value = 100;
    			escape.state = ESCAPE_LEFT_WAIT;
    			bump_count++;
    		break;
    		case ESCAPE_LEFT_WAIT:
    			if(!escape.move)
    			{
    				escape.speed_left = ESCAPE_SPEED_ROTATE;
    				escape.dir = RIGHT;
    				escape.rotate = true;
    				if(bump_count > 3)
    				{
    					escape.move_value = 100;
    					bump_count = 0;
    				}
    				else
    					escape.move_value = 65;
    				escape.state = ESCAPE_WAIT_END;
    			}
    		break;
    		case ESCAPE_RIGHT:	
    			escape.speed_left = ESCAPE_SPEED_BWD ;
    			escape.dir 	= BWD;
    			escape.move = true;
    			if(bump_count > 3)
    				escape.move_value = 160;
    			else
    				escape.move_value = 100;
    			escape.state = ESCAPE_RIGHT_WAIT;
    			bump_count++;
    		break;
    		case ESCAPE_RIGHT_WAIT:
    			if(!escape.move)
    			{ 
    				escape.speed_left = ESCAPE_SPEED_ROTATE;		
    				escape.dir = LEFT;
    				escape.rotate = true;
    				if(bump_count > 3)
    				{
    					escape.move_value = 100;
    					bump_count = 0;
    				}
    				else
    					escape.move_value = 65;
    				escape.state = ESCAPE_WAIT_END;
    			}
    		break;
    		case ESCAPE_WAIT_END:
    			if(!(escape.move || escape.rotate))
    				escape.state = IDLE;
    		break;
    	}
    }
    
    /**
     * Bumpers Event handler
     */
    void bumpersStateChanged(void)
    {
    	if(bumper_left && bumper_right)
    	{	
    		sound(200,100,0);
    		escape.state = ESCAPE_FRONT;
    				
    	}
    	else if(bumper_left) 
    	{	
    		sound(200,25,10);
    		sound(150,25,0);
    		if(escape.state != ESCAPE_FRONT_WAIT) 
    			escape.state = ESCAPE_LEFT;
    			
    	}
    	else if(bumper_right)
    	{	
    		sound(200,25,10);
    		sound(150,25,0);
    		if(escape.state != ESCAPE_FRONT_WAIT)
    			escape.state = ESCAPE_RIGHT;
    			
    	}
    }
    
    /*****************************************************************************/
    // Avoid Behaviour:
    
    #define AVOID_SPEED_L_ARC_LEFT  20
    #define AVOID_SPEED_L_ARC_RIGHT 80
    #define AVOID_SPEED_R_ARC_LEFT  80
    #define AVOID_SPEED_R_ARC_RIGHT 20
    
    #define AVOID_SPEED_ROTATE 	60
    
    #define AVOID_OBSTACLE_RIGHT 		1
    #define AVOID_OBSTACLE_LEFT 		2
    #define AVOID_OBSTACLE_MIDDLE	    3
    #define AVOID_OBSTACLE_MIDDLE_WAIT 	4
    #define AVOID_END 					5
    behaviour_command_t avoid = {0, 0, FWD, false, false, 0, IDLE};
    
    /**
     * Avoid behaviour with ACS IR Sensors.
     */
    void behaviour_avoid(void)
    {
    	static uint8_t last_obstacle = LEFT;
    	static uint8_t obstacle_counter = 0;
    	switch(avoid.state)
    	{
    		case IDLE: 
    			if(obstacle_right && obstacle_left)
    				avoid.state = AVOID_OBSTACLE_MIDDLE;
    			else if(obstacle_left) 
    				avoid.state = AVOID_OBSTACLE_LEFT;
    			else if(obstacle_right)
    				avoid.state = AVOID_OBSTACLE_RIGHT;
    		break;
    		case AVOID_OBSTACLE_MIDDLE:
    			avoid.dir = last_obstacle;
    			avoid.speed_left = AVOID_SPEED_ROTATE;
    			avoid.speed_right = AVOID_SPEED_ROTATE;
    			if(!(obstacle_left || obstacle_right))
    			{
    				if(obstacle_counter > 3)
    				{
    					obstacle_counter = 0;
    					setStopwatch4(0);
    				}
    				else
    					setStopwatch4(400);
    				startStopwatch4();
    				avoid.state = AVOID_END;
    			}
    		break;
    		case AVOID_OBSTACLE_RIGHT:
    			avoid.dir = FWD;
    			avoid.speed_left = AVOID_SPEED_L_ARC_LEFT;
    			avoid.speed_right = AVOID_SPEED_L_ARC_RIGHT;
    			if(obstacle_right && obstacle_left)
    				avoid.state = AVOID_OBSTACLE_MIDDLE;
    			if(!obstacle_right)
    			{
    				setStopwatch4(500);
    				startStopwatch4();
    				avoid.state = AVOID_END;
    			}
    			last_obstacle = RIGHT;
    			obstacle_counter++;
    		break;
    		case AVOID_OBSTACLE_LEFT:
    			avoid.dir = FWD;
    			avoid.speed_left = AVOID_SPEED_R_ARC_LEFT;
    			avoid.speed_right = AVOID_SPEED_R_ARC_RIGHT;
    			if(obstacle_right && obstacle_left)
    				avoid.state = AVOID_OBSTACLE_MIDDLE;
    			if(!obstacle_left)
    			{
    				setStopwatch4(500);
    				startStopwatch4();
    				avoid.state = AVOID_END;
    			}
    			last_obstacle = LEFT;
    			obstacle_counter++;
    		break;
    		case AVOID_END:
    			if(getStopwatch4() > 1000)
    			{
    				stopStopwatch4();
    				setStopwatch4(0);
    				avoid.state = IDLE;
    			}
    		break;
    	}
    }
    
    /**
     * ACS Event Handler
     */
    void acsStateChanged(void)
    {
    	if(obstacle_left && obstacle_right)
    		statusLEDs.byte = 0b100100;
    	else
    		statusLEDs.byte = 0b000000;
    	statusLEDs.LED5 = obstacle_left;
    	statusLEDs.LED4 = (!obstacle_left);
    	statusLEDs.LED2 = obstacle_right;
    	statusLEDs.LED1 = (!obstacle_right);
    	updateStatusLEDs();
    	if(obstacle_left && obstacle_right)
    	{
    		sound(160,20,0);
    	}
    	else
    	{
    		if(obstacle_left)
    			sound(120,10,0);
    		if(obstacle_right)
    			sound(140,10,0);
    	}
    }
    
    
    /*****************************************************************************/
    // Behaviour waitForStart:
    
    #define PREPARE 1
    #define WAIT 2
    behaviour_command_t waitForStart = {0, 0, FWD, 
    									false, false, 0, PREPARE};
    
    /**
     * Wait for start Behaviour. 
     * You need to clap your hands (or make other noise) three times in order
     * to start the Robot!
     */
    void behaviour_waitForStart(void)
    {
    	static uint8_t peak_count = 3;
    	if(waitForStart.state == PREPARE)
    	{
    		if(getStopwatch2() > 250)
    		{
    			setCursorPosLCD(1, 6); 
    			writeIntegerLengthLCD( peak_count, DEC, 1);
    			dischargePeakDetector();
    			waitForStart.state = WAIT;
    			setStopwatch2(0);
    		}
    	}
    	else if(waitForStart.state == WAIT)
    	{
    		uint8_t key = checkReleasedKeyEvent(); 
    		if(key)
    			waitForStart.state = IDLE;
    		if(getStopwatch2() > 50)
    		{
    			uint16_t tmp = getMicrophonePeak();
    			if(tmp > 4)
    			{
    				externalPort.LEDS = 0;
    				uint16_t i;
    				uint8_t j;
    				for(i = 0, j = 2; i < tmp; i+= 40)
    				{
    					if(i < 40)
    					{
    						externalPort.LEDS++;
    					}
    					else
    					{
    						externalPort.LEDS <<=1;
    						externalPort.LEDS++;
    					}
    				}
    				outputExt();
    				if(tmp > 120)
    				{
    					waitForStart.state = PREPARE;
    					peak_count--;
    				}
    				if(peak_count == 0)
    					waitForStart.state = IDLE;
    			}
    			else
    				setLEDs(0b0000);
    			setStopwatch2(0);
    		}
    	}
    }
    
    /*****************************************************************************/
    // Behaviour check low Battery:
    
    #define BATTERY_LOW 1
    behaviour_command_t checkLowBattery = {0, 0, FWD, 
    									false, false, 0, IDLE};
    
    /**
     * In this behaviour routine, we have nothing to do
     */
    void behaviour_checkLowBattery(void)
    {
    }
    
    /**
     * This is a new Event Handler and it gets called when the Battery Voltage
     * is getting low! The Parameter isVoltageLow is true, when the voltage
     * is low and false, when the voltage is OK.
     */
    void batteryVoltageLow(uint8_t isVoltageLow)
    {
    	if(isVoltageLow)
    		checkLowBattery.state = BATTERY_LOW;
    }
    
    /*****************************************************************************/
    // Behaviour control:
    
    /**
     * This function processes the movement commands that the behaviours generate. 
     * Depending on the values in the behaviour_command_t struct, it sets motor
     * speed, moves a given distance or rotates.
     */
    void moveCommand(behaviour_command_t * cmd)
    {
    	if(cmd->move_value > 0)  // move or rotate?
    	{
    		if(cmd->rotate)
    			rotate(cmd->speed_left, cmd->dir, cmd->move_value, false); 
    		else if(cmd->move)
    			move(cmd->speed_left, cmd->dir, DIST_MM(cmd->move_value), false); 
    		cmd->move_value = 0; // clear move value - the move commands are only
    		                     // given once and then runs in background.
    	}
    	else if(!(cmd->move || cmd->rotate)) // just move at speed? 
    	{
    		changeDirection(cmd->dir);
    		moveAtSpeed(cmd->speed_left,cmd->speed_right);
    	}
    	else if(isMovementComplete()) // movement complete? --> clear flags!
    	{
    		cmd->rotate = false;
    		cmd->move = false;
    	}
    }
    
    /**
     * A small helper function to display the current behaviour on the
     * LCD. It only prints out the active behaviour ONCE, otherwise the
     * text would flicker on the LCD!
     */
    void displayBehaviour(uint8_t behave)
    {
    	static uint8_t compare = 0;
    	if(compare != behave)
    	{
    		compare = behave;
    		clearPosLCD(1, 0, 13);
    		setCursorPosLCD(1, 0); 
    		switch(behave)
    		{
    			case 6: writeStringLCD_P("LOW BATTERY!"); setLEDs(0b0000); break;
    			case 5: writeStringLCD_P("WAIT"); setLEDs(0b0000); break;
    			case 4: writeStringLCD_P("ESCAPE"); setLEDs(0b0110); break;
    			case 3: writeStringLCD_P("AVOID"); setLEDs(0b1001); break;
    			case 2: writeStringLCD_P("CRUISE"); setLEDs(0b0000); break;
    			case 1: writeStringLCD_P("STOP"); setLEDs(0b0000); break;
    		}
    	}
    	if(behave == 2) // If Cruise behaviour is active, show a running light...
    	{
    		static uint8_t runLEDs = 1;
    		static uint8_t dir = 0;
    		if(getStopwatch2() > 100) 
    		{
    			setLEDs(runLEDs); 
    			if(dir == 0)
    				runLEDs <<= 1; 
    			else
    				runLEDs >>= 1;
    			if(runLEDs > 7 ) 
    				dir = 1;			
    			else if (runLEDs < 2 ) 
    				dir = 0;
    			setStopwatch2(0);
    		}
    	}
    	if(behave == 6) // If Battery is low - beep all 3 seconds!
    	{
    		if(getStopwatch2() > 3000)  // We can use Stopwatch2 here and 
    		{							// for several other things because only
    			sound(200,20,20);		// one of these things can be active at 
    			sound(225,20,60);		// the same time! You could not do this if
    			sound(200,20,20);		// there were things that could be active
    			sound(225,20,0);		// at the same time!
    			setStopwatch2(0);
    		}
    	}
    }
    
    /**
     * The behaviourController task controls the subsumption architechture. 
     * It implements the priority levels of the different behaviours. 
     *
     * Here we also show which behaviour is active on the LC-Display!
     *
     */
    void behaviourController(void)
    {
        // Call all the behaviour tasks:
    	behaviour_checkLowBattery();
    	behaviour_waitForStart();
    	behaviour_cruise();
    	behaviour_avoid();
    	behaviour_escape();
    
    
        // Execute the commands depending on priority levels:
    	if(checkLowBattery.state != IDLE) // Highest priority - 6
    	{
    		displayBehaviour(6);
    		moveCommand(&checkLowBattery);
    	}
    	else if(waitForStart.state != IDLE) // Priority - 5
    	{
    		displayBehaviour(5);
    		moveCommand(&waitForStart);
    	}
    	else if(escape.state != IDLE) // Priority - 4
    	{
    		displayBehaviour(4);
    		moveCommand(&escape);
    	}
    	else if(avoid.state != IDLE) // Priority - 3
    	{
    		displayBehaviour(3);
    		moveCommand(&avoid);
    	}
    	else if(cruise.state != IDLE) // Priority - 1
    	{
    		displayBehaviour(2);
    		moveCommand(&cruise); 
    	}
    	else                     // Lowest priority - 0
    	{
    		displayBehaviour(1);
    		moveCommand(&STOP);  // Default command - do nothing! 
    							 // In the current implementation this never 
    							 // happens.
    	}
    }
    
    
    /*****************************************************************************/
    
    /**
     * Prints all Sensor Values on the Serial Interface.
     */
    void printAllSensorValues(void)
    {
    	getAllSensors();		
    	writeString_P("\nRead Sensor Values:\n");
    	writeString_P("PL:");writeIntegerLength(mleft_power,DEC,3);
    	writeString_P(" | PR:");writeIntegerLength(mright_power,DEC,3);
    	writeString_P(" | VL:");writeIntegerLength(mleft_speed,DEC,3);
    	writeString_P(" | VR:");writeIntegerLength(mright_speed,DEC,3);
    	writeString_P(" | DL:");writeIntegerLength(mleft_des_speed,DEC,3);
    	writeString_P(" | DR:");writeIntegerLength(mright_des_speed,DEC,3);
    	writeChar('\n');
    	writeString_P("DSTL:");writeIntegerLength(mleft_dist,DEC,5);
    	writeString_P(" | DSTR:");writeIntegerLength(mright_dist,DEC,5);
    	writeChar('\n');
    	writeString_P("LSL:");writeIntegerLength(adcLSL,DEC,4);
    	writeString_P(" | LSR:");writeIntegerLength(adcLSR,DEC,4);
    	writeString_P(" | MCL:");writeIntegerLength(adcMotorCurrentLeft,DEC,4);
    	writeString_P(" | MCR:");writeIntegerLength(adcMotorCurrentRight,DEC,4);
    	writeString_P(" | BAT:");writeIntegerLength(adcBat,DEC,4);
    	writeString_P(" | AD0:");writeIntegerLength(adc0,DEC,4);
    	writeString_P(" | AD1:");writeIntegerLength(adc1,DEC,4);
    	writeChar('\n');
    }
    
    
    /**
     * Heartbeat function
     */
    void task_LCDHeartbeat(void)
    {
    	if(getStopwatch1() > 500)
    	{
    		static uint8_t heartbeat = false;
    		if(heartbeat)
    		{
    			clearPosLCD(1, 15, 1);
    			heartbeat = false;
    		}
    		else
    		{
    			setCursorPosLCD(1, 15);
    			writeStringLCD_P("*"); 
    			heartbeat = true;
    			printAllSensorValues();
    		}
    		setStopwatch1(0);
    	}
    }
    
    
    /**
     * Timed Watchdog display - the other heartbeat function
     * does not work in this example as we use blocked moving functions here.
     */
    void watchDogRequest(void)
    {
    	static uint8_t heartbeat2 = false;
    	if(heartbeat2)
    	{
    		clearPosLCD(1, 14, 1);
    		heartbeat2 = false;
    	}
    	else
    	{
    		setCursorPosLCD(1, 14);
    		writeStringLCD_P("#"); 
    		heartbeat2 = true;
    	}
    }
    
    /*****************************************************************************/
    // I2C Requests: 
    
    /**
     * The I2C_requestedDataReady Event Handler
     */
    void I2C_requestedDataReady(uint8_t dataRequestID)
    {
    	checkRP6Status(dataRequestID);
    }
    
    /*****************************************************************************/
    // I2C Error handler
    
    /**
     * This function gets called automatically if there was an I2C Error like
     * the slave sent a "not acknowledge" (NACK, error codes e.g. 0x20 or 0x30).
     */
    void I2C_transmissionError(uint8_t errorState)
    {
    	writeString_P("\nI2C ERROR - TWI STATE: 0x");
    	writeInteger(errorState, HEX);
    	writeChar('\n');
    }
    
    void eigenefunktion(void)
    {
    
    PORTC &= ~IO_PC7;
    PORTC &= ~IO_PC6;
    PORTC &= ~IO_PC5;
    PORTC &= ~IO_PC4;
    
    
    startStopwatch3();
    
    if (getStopwatch3() > 100)
    PORTC |= IO_PC7;
    PORTC |= IO_PC5;
    setStopwatch1(0);
    
    if (getStopwatch3() > 100)
    PORTC &= ~IO_PC7;
    PORTC &= ~IO_PC5;   
    setStopwatch3(0);
    
    
    
    
    
    }
    
    void task_LDRinfo(void)
    {
    
    		writeString_P("LDR_L: ");
    		writeIntegerLength(adcLSL, DEC, 4);
    		writeString_P(" ; LDR_R: ");
    		writeIntegerLength(adcLSR, DEC, 4);
    		writeString_P(" ||");
    		if(adcLSL <400) 
    		PORTC |= IO_PC3;
    		if(adcLSL >450)
    		PORTC &= ~IO_PC3;
    
    }
    
    /*****************************************************************************/
    // Main function - The program starts here:
    
    int main(void)
    {
    	initRP6Control();  
    	initLCD();
    	
    DDRC |= IO_PC7;
    DDRC |= IO_PC6;
    DDRC |= IO_PC5;
    DDRC |= IO_PC4;
    DDRC |= IO_PC3;
    PORTC &= ~IO_PC3;
    
    
    
    	
    
    
        
    	writeString_P("\n\nRP6 CONTROL M32 I2C Master Example Program!\n"); 
        writeString_P("\nMoving...\n"); 
    
    	// ---------------------------------------
    	WDT_setRequestHandler(watchDogRequest); 
    	BUMPERS_setStateChangedHandler(bumpersStateChanged);
    	ACS_setStateChangedHandler(acsStateChanged);
    	BATTERY_setLowVoltageHandler(batteryVoltageLow);
    
    	// ---------------------------------------
    	I2CTWI_initMaster(100);  
    	I2CTWI_setRequestedDataReadyHandler(I2C_requestedDataReady);
    	I2CTWI_setTransmissionErrorHandler(I2C_transmissionError);
    
    	sound(180,80,25);
    	sound(220,80,25);
    
    	setLEDs(0b1111);
    
    	showScreenLCD("################", "################");
    	mSleep(500);
    	showScreenLCD("I2C-Master", "Behaviours");
    	mSleep(1000);
    	setLEDs(0b0000);
    	
    	// ---------------------------------------
    	// Setup ACS power:
    	I2CTWI_transmit3Bytes(I2C_RP6_BASE_ADR, 0, CMD_SET_ACS_POWER, ACS_PWR_MED);
    	// Enable Watchdog for Interrupt requests:
    	I2CTWI_transmit3Bytes(I2C_RP6_BASE_ADR, 0, CMD_SET_WDT, true);
    	// Enable timed watchdog requests:
    	I2CTWI_transmit3Bytes(I2C_RP6_BASE_ADR, 0, CMD_SET_WDT_RQ, true);
    
    	startStopwatch1();
    	startStopwatch2();
    
    	showScreenLCD("Active Behaviour", "");
    	
    
    
    	while(true) 
    	{ 
    		task_LCDHeartbeat();
    		task_checkINT0();
    	    task_I2CTWI();
    		behaviourController();
    		eigenefunktion();
    		task_LDRinfo();
    	
    		
    
    	}
    	return 0;
    }
    Vielen Dank schonmal für die Hilfe! Library´s sind wie gesagt unverändert!

    Gruß

    Markus

  5. #5
    Moderator Robotik Visionär Avatar von radbruch
    Registriert seit
    27.12.2006
    Ort
    Stuttgart
    Alter
    61
    Beiträge
    5.799
    Blog-Einträge
    8
    Hallo

    Bei den Lauflichtern in "if(behave == 2)" ab Zeile 470:

    if(runLEDs > 7 ) müßte wohl >5 heisen, weil es 6 LEDs sind.

    Die "eigenefunktion()" vielleicht so:
    Code:
    void eigenefunktion(void)
    {
    	//PORTC &= ~IO_PC7;
    	PORTC &= ~IO_PC6;
    	//PORTC &= ~IO_PC5;
    	PORTC &= ~IO_PC4;
    
    
    	startStopwatch3(); // sollte besser einmalig in main() gestartet werden
    
    	if (getStopwatch3() < 100)
    	{
    		PORTC |= IO_PC7;
    		PORTC |= IO_PC5;
    	}
    	else
    	{
    		PORTC &= ~IO_PC7;
    		PORTC &= ~IO_PC5;
    		if (getStopwatch3() > 200)
    			setStopwatch3(0);
    	}
    }
    Ich kann's nicht kompilieren, das liegt aber nicht nur daran, dass ich das Erweiterungsmodul nicht besitze.

    Meine LEDs bringe ich so zum Blinken:
    Code:
    #include "RP6RobotBaseLib.h"
    
    #define blinkLED6 statusLEDs.LED6=(getStopwatch1() & (1<<6)) && 1
    
    uint8_t blink3;
    
    int main(void)
    {
    	initRobotBase();
    	setLEDs(0);
    
    	//Zeitgeber für das Blinken starten
    	startStopwatch1();
    
    	while(true)
    	{
    		//LED1 blinkt langsam
    		statusLEDs.LED1 ^=(getStopwatch1() & (1<<9));
    
    		//LED2 blinkt schnell
    		statusLEDs.LED2=(getStopwatch1() & (1<<7)) && 1;
    
    		//LED3 blinkt variabel (0 bedeutet aus)
    		blink3=8;
    		statusLEDs.LED3=(getStopwatch1() & (1<<blink3)) && 1;
    
    		//LED4 flasht
    		statusLEDs.LED4=!(getStopwatch1() & (0b101<<6)) && 1;
    
    		//LED5 flackert
    		statusLEDs.LED5=(getStopwatch1() & (0b1001<<5)) && 1;
    
    		//LED6 blinkt mit #define
    		blinkLED6;
    
    		//LED-Status aktuallisieren
    		updateStatusLEDs();
    
    		//das funktioniert natürlich auch mit der pwrLED
    		if (!(getStopwatch1() & (9<<8)) && 1) powerON(); else powerOFF();
    	}
    	return 0;
    }
    Gruß

    mic
    Bild hier  
    Atmel’s products are not intended, authorized, or warranted for use
    as components in applications intended to support or sustain life!

  6. #6
    Neuer Benutzer Öfters hier
    Registriert seit
    04.01.2008
    Beiträge
    9
    Hi mic,

    die Lauflichter tun´s eigentlich. Das ist noch der Originalcode.

    Ich hab an 4 Ports des Controlling-Boards 4 weitere LED´s angeschlossen, die angesteuert werden sollen.

    Danke für den Code für eigenefunktion()
    Was ich nicht verstehe: Du setzt am Anfang immer // wie hier z.b.

    //PORTC &= ~IO_PC7;

    das würde die Funktion aber doch als Kommentar ausblenden? So würde nur PC6 und PC4 high geschaltet werden.

    Stopwatch in Main-Schleife geht klar! (Warum eigentlich? Wird ja immer mit der eigenefunktion() aufgerufen und gestartet?)

    If stopwatch >100 dann LED´s ein //verstanden
    else > LED´s aus // auch verstanden, aber laufe ich da nicht in Gefahr, den Zeitpunkt zwischen Stopwatch >100 aber <200 zu verpassen?

    if stopwatch >200 dann stopwatch zurücksetzen // ist auch klar, damit beginnt es wieder von vorne.


    Ich versuchs mal heute abend, mal sehen was rauskommt. Danke nochmal!

    Gruß

    Markus

  7. #7
    Moderator Robotik Visionär Avatar von radbruch
    Registriert seit
    27.12.2006
    Ort
    Stuttgart
    Alter
    61
    Beiträge
    5.799
    Blog-Einträge
    8
    Hallo Markus

    das würde die Funktion aber doch als Kommentar ausblenden?
    Genau das ist die Absicht. Man könnte den Code natürlich auch löschen, aber manchmal sind es Testvarianten oder Hinweise auf die Änderung. Hier soll es zeigen, dass man die zwei Ports nicht ausschalten muss, weil sie ja später in Abhängigkeit von der StopWatch gesetzt werden. (btw: die Pins werden mit PORTC &= ~IO_PC7; auf low=0V gesetzt wenn sie Ausgang sind.)

    Stopwatch in Main-Schleife geht klar! (Warum eigentlich?...)
    StartStopWatch() sorgt über ein Flag (stopwatches.watches) dafür, dass die betreffende StopWatch() in der Interruptroutine des Timers mitgezählt wird. Einmaliges Setzen dieses Flags genügt, deshalb zentral in main().

    aber laufe ich da nicht in Gefahr, den Zeitpunkt zwischen Stopwatch >100 aber <200 zu verpassen?
    Du hast nicht richtig geschaut, es wird auf <100 und >200 geprüft. Wenn kleiner 100, dann Ausgang setzen, sonst Ausgang löschen und, wenn größer 200 auch StopWatch neu laden. "Größer 200" kann man sicher erkennen, dann wird die StopWatch() neu geladen und auf "kleiner 100" geprüft. Verpassen kannst du dabei eigentlich nichts, nur wenn der Abstand des regelmäsigen Aufrufs von meinefunktion() länger als 100ms dauert, werden die LEDs nie brennen. (Ganz korrekt wäre noch ein Stetzen der Ausgänge beim Löschen der StopWatch(), sonst fehlt in der Hell-Phase die Zeit bis zum nächsten Aufruf von meinefunktion())

    Gruß

    mic
    Bild hier  
    Atmel’s products are not intended, authorized, or warranted for use
    as components in applications intended to support or sustain life!

  8. #8
    Neuer Benutzer Öfters hier
    Registriert seit
    04.01.2008
    Beiträge
    9
    Hallo mic,

    langsam blick ichs.

    Ziel des ganzen ist es, die LED´s in einem bestimmten Takt DURCHGEHEND laufen zu lassen (80ms an, 80ms aus, 80ms an, 100ms aus->Return)

    Wie schaff ich es, diese Routine immer wieder aufzurufen?
    meinefunktion() wird in der Main-schleife ja aufgerufen, dann aber durch die anderen Tasks unterbrochen und erst wieder später aufgenommen, oder??

    kann man while(true) auch in einer funktion einsetzen? wohl kaum, da diese dann ja wieder die Hauptschleife blockiert...

  9. #9
    Moderator Robotik Visionär Avatar von radbruch
    Registriert seit
    27.12.2006
    Ort
    Stuttgart
    Alter
    61
    Beiträge
    5.799
    Blog-Einträge
    8
    Hallo

    Das Task-System des RP6 ist auch eines seiner Highlights. Damit kann er mehrere Abläufe parallel steuern ohne sich zu blockieren. Der Preis dafür ist eben die recht komplizierte Programmierung. Grundsätzlich muss man aber selbst dafür sorgen, dass die einzelnen Tasks abgearbeitet werden und keine Funktion (störend) blockierend auf den Rest des Programms wirkt. Hier ein Beispiel für ein 80an-80aus-80an-100aus-Blinken:
    Code:
    #include "RP6RobotBaseLib.h"
    
    void eigenefunktion(void)
    {
       if (getStopwatch3() < 80)
       {
    		setLEDs(63);
          //PORTC |= IO_PC7;
          //PORTC |= IO_PC5;
       }
       else if (getStopwatch3() < 80+80)
       {
    		setLEDs(0);
          //PORTC &= ~IO_PC7;
          //PORTC &= ~IO_PC5;
       }
       else if (getStopwatch3() < 80+80+80)
       {
    		setLEDs(63);
          //PORTC |= IO_PC7;
          //PORTC |= IO_PC5;
       }
       else if (getStopwatch3() < 80+80+80+100)
       {
    		setLEDs(0);
          //PORTC &= ~IO_PC7;
          //PORTC &= ~IO_PC5;
       }
       else setStopwatch3(0);
    }
    
    
    int main(void)
    {
    	initRobotBase();
    	setLEDs(0);
    	//DDRC |= IO_PC7 | IO_PC6 | IO_PC6 | IO_PC4
       //PORTC &= ~IO_PC7;
       //PORTC &= ~IO_PC6;
       //PORTC &= ~IO_PC5;
       //PORTC &= ~IO_PC4;
    
    	setStopwatch3(0);
    	startStopwatch3();
    
    	while(true)
    	{
    	   eigenefunktion();
    	}
    	return 0;
    }
    Nicht sehr elegant, aber es funktioniert und ist anschaulich...

    Gruß

    mic
    Bild hier  
    Atmel’s products are not intended, authorized, or warranted for use
    as components in applications intended to support or sustain life!

  10. #10
    Neuer Benutzer Öfters hier
    Registriert seit
    04.01.2008
    Beiträge
    9
    Danke mic,

    aber irgendwie haut das mit den Timern noch nicht ganz so hin.
    Die LED´s blinken zwar, aber nicht den Stopwatches entsprechend. Ich denke es liegt daran:

    Annahme: Stopwatch steht bei 40

    If Stopwatch3 < 80 ---> ist True
    If Stopwatch3 < 80+80 ---> ist aber ebenfalls True

    Irgendwie müsste ich es hinbringen dass:

    If Stopwatch3 <80 ABER > 80+80

    Warum eigentlich 80+80 und nicht gleich 160??

    Hier mal ein Beispielcode. Die Ausgabe der Töne erfolgt ohne jede Pause und wiederholt sich ständig, die Werte auf der Stopwatch werden dabei völlig ignoriert. Eigentlich müssten da ein paar Sekunden Pause dazwischen sein. Die Stopwatches gehen ja bis 65 Sekunden...

    Code:
     void thebeeb(void)
    {
    		if (getStopwatch8() < 1000)
    { sound(140,30,25); }
    
    else if (getStopwatch8() < 6000)
    { sound(200,30,25); }
    
    else if (getStopwatch8() < 12000)
    { sound(200,25,25); 
      sound(180,30,40); }
      
    else if (getStopwatch8() < 18000)
    { sound(160,40,25);
      sound(170,30,25); }
      
    else if (getStopwatch8() < 26000)
    { sound(240,20,50);
      sound(140,60,20);
      sound(180,40,25); }
      
      else if (getStopwatch8() < 50000)
      {
      setStopwatch8(0);
    }


    Weder Handbuch, noch I-net haben mir da weitergeholfen.

    Funktionieren auf dem RP5 eigentlich alle C-funktionen, also auch printf oder ähnliches??

    Gruß

    Markus

Seite 1 von 2 12 LetzteLetzte

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

12V Akku bauen