PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : MPLAB 8, ICD2, C30 ... Multitasking?



Kiraminh
04.03.2008, 12:01
Hallo Leute,

ich habe die Tage mal angefangen den dsPIC30F zu proggen. Geht auch ganz gut, bis ich versucht habe multitasking zu implementieren.

Ich habe vorher die typischen Lego-Controller(RCX) programmiert. Ich glaube die waren von Hitachi. Dort konnte man schoen einfach ueber execi(...) usw. mehrere Tasks starten, die "parallel" liefen (ich weiss, dass das nicht wirklich geht, aber ich denke, ihr wisst, was ich meine).

Die Frage ist nun: geht das auch beim dsPIC30F? Wenn ja, hat das wer mit MPLAB hinbekommen? Oder koennt ihr mir eine Alternative nennen?

Vielen Dank schonmal,
Kiraminh

Duke of Doom
05.03.2008, 18:15
Theoretisch ist das natürlich möglich.....

Unter diesem link findest du einen ansatz dafür
http://www.microchipc.com/Hi-Tech_C_multitask/

Kiraminh
11.03.2008, 16:41
Vielen Dank, ich werde mir den mal anschauen.

Ich habe noch eine andere Frage, moechte aber dafuer keinen neuen Thread aufmachen. Ich sizte jetzt schon an die 5 Tage an einem Problem, dessen Ursache ich nicht finde. Ich versuche ueber UART mit dem Pololu Micro Serial Servo Controller zu kommunizieren. Ich dachte, dass das ganz einfach sei, doch leider habe ich mich wohl getaeuscht.

In dem angehaengten Code versuche ich UART zu initialisieren, sowie dem Servo Controller quasi eine Geraetenummer zu geben, da ich vier der Teile nutzen werde. Ich habe die Baudrate in den Bereich gesetzt, der im Manual mir angegeben wurde (ich glaube momentan auf ungefaehr 20.000). Lasse ich den Code laufen sagt mir der Servo Controller, er habe keine Baudrate bekommen, empfaengt demnach natuerlich auch keine Signale. Wenn ich die Baudrate hingegen auf ueber 40k setze (ich habe ueber 900k getestet), dann sagt er mir, dass die Baudrate zu langsam sei.

Kennt irgendwer dieses Phaenomen?

Hier ist der Code, ich entschuldige mich schonmal fuer die Laenge, ich habe sehr viel kommentiert:



//************************************************** ***************
//* main.c *
//************************************************** ***************
//* *
//* Written by: L J Berger *
//* Iensys Ltd *
//* Date: 11th March 2007 *
//* Revision: 1.00 *
//************************************************** ***************
// *
// This programm initializes the servo controller. The ID number *
// is assigned to the device: *
// 0 -> The servo controller reacts to the servo no 0-7 *
// 1 -> The servo controller reacts to the servo no 8-15 *
// 2 -> The servo controller reacts to the servo no 16-23 *
// ... up to servo no 127
//************************************************** ***************

//************************************************** ***************
// Include Files
//************************************************** ***************
#include <p30f6014A.h> //device specific header file
#include <stdlib.h> // for structs being able to refer to itself

//IMPORTANT: Tell the linker to create a 512byte heap. Otherwise
// the dynamic memory allocation cannot be used

//************************************************** ***************
// Config directive to set configuration bits
//************************************************** ***************
/* The internal clock controlling the execution of instructions is obtained
when the clock (from the PLL or directly) is divided by 4.
Example: Let a 10MHz crystal resonator and PLL 4x are selected. This means
that the internal clock is 4x10MHz=40MHz. This value is divided by 4 to
obtain 10MHz (100ns period)
*/
_FOSC(CSW_FSCM_OFF & XT_PLL16); //Fail safe Clock Monitor Off, eXTernal crystal with PLL 4x

/*Configuration of the Watchdog Timer*/
_FWDT(WDT_OFF); // Watchdog Timer off

/* FBORPOR is for voltage protection. The proper execution of the programs
requires a good stability of the power supply. With dsPIC30F one has the
ability of defining a minimum power supply voltage ensuring proper
function of the device. If the supply voltage falls below this limit, the
internal circuit will reset the microcontroller, wait until the supply
voltage returns above the limit, and after the specified power-up delay
time activate the microcontroller starting the execution of the program
from the beginning
*/
// enable Brown-out Reset at 2.0 Volts, initialize Power up Timer to 64ms,
// MCLR pin enabled (not used for I/O)
_FBORPOR(PBOR_ON & BORV_20 & PWRT_64 & MCLR_EN);

//************************************************** ***************
// Macros
//************************************************** ***************
#define FCY 7370000 // 7.37MHz crystal in XT PLL 4x
#define MILLISEC FCY/7370 //definition of a millisecond

//connecting the ports
#define LED1 PORTDbits.RD4
#define LED2 PORTDbits.RD5
#define LED3 PORTDbits.RD6
#define LED4 PORTDbits.RD7
/* The LEDs are used to give an error-code:
RD4 RD5 RD6 RD7 Error
0 0 0 0 No Error
0 0 0 1 Data received fron U2ART
0 0 1 0
0 0 1 1
0 1 0 0 Unable to write to queue, because the heap might be full
0 1 0 1 Unable to delete, queue is empty
*/

//************************************************** ***************
// Definition of global variables and structures
//************************************************** ***************
//UART Initialisation Flags
struct{
unsigned EnTXInterrupt:1;
unsigned TXInterruptMode:1;
unsigned Buffer_free:1;
}UART2Flags;

struct FCFS_queue
{
unsigned data:8;
struct FCFS_queue * next;
};
struct FCFS_queue * UART2TXReg;
//************************************************** ***************
// Definition of functions
//************************************************** ***************
int InitUART(void);
int InitServoController(void);
void DelayNms (unsigned int N);
int queue_add (struct FCFS_queue * head, unsigned int new_data);
int queue_delete (struct FCFS_queue * head);
int generalInits(void);
void UART2Transmission(void);
void __attribute__((__interrupt__))_U2TXInterrupt(void) ;

//************************************************** ***********************
// Implementation of functions
//************************************************** ***********************
//UART is initialized
//data bits has to be either 8 or 9, stop bits either 1 or 2, parity bits either 0 (no parity)
//or 1 (odd parity) or 2 (even parity)
//for more information see Family Reference Manual Section 19 on UART, page 19-3
//for enabling transmission interrupts set EnTXInterrupt and select Transmission Interrupt Mode
//as well as use the Interrupt functions which are currently commented out.
int InitUART(void)
{

U2MODEbits.USIDL = 0; //Continue Operation in Idle mode
U2MODEbits.ALTIO = 0; //Communicate using U2TX and U2RX, not alternate pins
U2MODEbits.WAKE = 0; //Wake-up disabled
U2MODEbits.LPBACK = 0; //Loopback mode disabled
U2MODEbits.ABAUD = 0; //No Autobaud
U2MODEbits.PDSEL = 0; //8-bit data, no parity
U2MODEbits.STSEL = 0; //1 Stop bit


if (UART2Flags.EnTXInterrupt == 1)
{
//Clear Interrupt Status Flag for U2TXIF
IFS1bits.U2TXIF = 0;
//Setting the Interrupt control bit (U2TXIE) in the Interrupt Enable Control register.
IEC1bits.U2TXIE = 1;
//Select Transmit Interrupt Mode:
U1STAbits.UTXISEL = UART2Flags.TXInterruptMode;
}

//Baud Rate: UxBRG = FCY/(16*BaudRate)-1. For 20,000: U2BRG = 23
//BaudRate has to be between 2000 and 40000 for Pololu Micro Serial Servo Controller
U2BRG = 91;

U2STAbits.UTXBRK = 0; //Transmit Break Bit-pin operates normally

//Enable UART2
U2MODEbits.UARTEN = 1;
//Enable Transmission
U2STAbits.UTXEN = 1;

return 0;
}

//Setting and Checking Servo Numbers
int InitServoController(void)
{
if (UART2Flags.Buffer_free)
{
U2TXREG = 0x80;
U2TXREG = 0x02;
U2TXREG = 0x00;
//UART2Flags.Buffer_free = 0;
}
else{
if (!queue_add(UART2TXReg, 0x80)) //first start byte
{
LED2 = 1;
return 1;
}
if (!queue_add(UART2TXReg, 0x02)) //command to change servo numbers
{
LED2 = 1;
return 1;
}
if (!queue_add(UART2TXReg, 0x00)) //servo numbers for this board: 0 -> 0-7, 1 -> 8-15, ...
{
LED2 = 1;
return 1;
}
}
return 0;
}

void DelayNms (unsigned int N)
{
unsigned int j;
while(N--)
for (j=0;j<MILLISEC;j++);
}

//if Interrupts are needed for UART2 Transmission
/*void __attribute__((__interrupt__))_U2TXInterrupt(void)
{
int counter = 0;
if (UART2TXReg != NULL)
{
while (UART2TXReg != NULL && counter < 3)
{
U2TXREG = UART2TXReg->data;
if (queue_delete(UART2TXReg)) return;
counter+=1;
}
UART2Flags.Buffer_free = 0;
}
else UART2Flags.Buffer_free = 1;
//clearing the Interrupt Status Flag
IFS1bits.U2TXIF = 0;
}*/

// Add a new element to the end of the queue
int queue_add (struct FCFS_queue * head, unsigned int new_data)
{
//create new element
struct FCFS_queue * temp = (struct FCFS_queue*) malloc(sizeof(struct FCFS_queue));
//if the heap is full, temp will just carry the NULL pointer.
//to prevent a runtime error this is catched
if (temp == NULL) return 1;
//if temp is not NULL, the data can be written into the struct.
//as this element will be placed at the very end of the queue,
//temp->next can be set to NULL.
temp->data = new_data;
temp->next = NULL;

//go to the end of the queue and add the element
if (head != NULL)
{
while (head->next != NULL) head = head->next;
head->next = temp;
}
//if the queue is empty, then just put it there.
else head = temp;
return 0;
}

// Delete the first element of the queue
int queue_delete (struct FCFS_queue * head)
{
//if head is NULL, no element can be deleted -> ERROR
if (head == NULL)
{
LED2=1;
LED4=1;
return 1;
}
else //there is still at least one element in the queue, that can be deleted
{
struct FCFS_queue * temp = head; //new pointer to the first element
head = head->next; //main pointer of the queue ist shifted one element to the rear
free((void*)temp); //free the allocated memory to prevent memory leaks
}
return 0;
}
//General variables and structures are initialised in this function.
//It is called at the very beginning of main
int generalInits(void)
{
//Information for UART Initialisation
UART2Flags.EnTXInterrupt = 0; // transmission interrupts disabled
UART2Flags.TXInterruptMode = 0; // Interrupt when last character out of the buffer was transferred
UART2Flags.Buffer_free = 1; // at the beginning of course the buffer is free

//Initialisation of Transmitter Register for UART2
UART2TXReg = NULL;

return 0;
}

//This function will be started as a separate task and checks whether there
//is any data in UART2TXReg to be transmitted and whether the buffer is able
//to save this transmission data
//ONLY SUITABLE FOR MULTITASKING
/*void UART2Transmission(void)
{
while (1)
{
if(!U2STAbits.UTXBF && UART2TXReg != NULL)
{
U2TXREG = UART2TXReg->data;
if (queue_delete(UART2TXReg)) return;
}
}
}*/

//************************************************** ***************
// MAIN
//************************************************** ***************
int main (void)
{
//int TaskID_UART2TX = 0;
if (generalInits()) return 1;
if (InitUART()) return 1;

//The task for transmitting via UART cannot be started before
//generalInits and InitUART. Otherwise data will get lost!
//ONLY SUITABLE FOR MULTITASKING
//TaskID_UART2TX = execi(&UART2Transmission, 0, 0, 10, DEFAULT_STACK_SIZE);

if (InitServoController()) return 1;

unsigned int received_data;
while (U2STAbits.URXDA)
{
received_data = U2RXREG;
LED4 = 1;
DelayNms(1000);
LED4= 0;
}


//ONLY SUITABLE FOR MULTITASKING
/*shutdown_task(&TaskID_UART2TX);
kill_task(&TaskID_UART2TX);*/

//Disable UART2:
//U2MODEbits.UARTEN = 0;
return 0;
}


Ich bedanke mich schon mal fuer die Hilfe!

Gruesse,
Kira

Duke of Doom
11.03.2008, 20:16
versuchs doch mal mit der von microchip mitgelieferten headerdatei usart.h.... vielleicht hast du bei der initialisierung einen fehler gemacht. Die Funktionen von Micochip gehen nämlich sicher ......

Kiraminh
12.03.2008, 12:59
also, nach einigem Testen habe ich heraus gefunden, dass mein Code richtig ist. Ich habe das Board via COM-Schnittstelle an meinen PC angeschlossen und sobald etwas zu dem Board gesendet wird, schickt das Board "Hello World" ... ganz easy und es funzt auch! Ergo an der Initialisierung kann es nicht liegen.

Ich werde nun schauen, ob ich hier nicht einen Hardwarefehler meinerseits verursacht habe oder sonst irgendwelche I/O Ports vergessen habe zu definieren.

Ich melde mich, sobald ich das Problem behoben habe. Wenn ihr in der Zwischenzeit noch weitere Ideen habt, nur zu.

@Duke: ich schau mal in die usart.h rein. Ich hoffe die ist gut kommentiert, damit ich auch verstehe, was die da gemacht haben.

gunzelg
17.03.2008, 11:53
Hallo

kann es sein, dass der Servo zwar mittels UART angesteuert wird, selber aber nicht 12Volt-Pegel hat, sondern nur 5 Volt ? Dann wäre auch der Pegel falsch. Da RS232 mit +-12Volt arbeitet und das Signal invertiert.

Gerhard

the_Ghost666
13.04.2008, 19:34
Wie genau ist deine Taktquelle? Unter umständen könnte der Rechner Fehlertoleranter sein als das Servoboard. Hast du alle Zeichen mitgesendet, also auch Zeilenende, jenachdem was das Servoboard braucht?