Spänningen ändras när jag kopplar kretsen till PCn (RS-23

Elektronikrelaterade (på komponentnivå) frågor och funderingar.
Användarvisningsbild
Tengil
Inlägg: 84
Blev medlem: 24 mars 2007, 00:15:46
Ort: Hudiksvall

Inlägg av Tengil »

Jag har nu kopplat in en servo på kretsen samt skrivit en C# program för att kontrollera dess position. Det fungerar... halvbra. Nog för att det funkar som det ska för det mesta, men väldigt ofta blir det störningar på datalinjen. Det första jag gjorde var att implementera mjukvarustyrt dataflöde (XON/XOFF). Det hjälpte lite men det är fortfarande många bytes som läses in helt fel på PIC'en. Jag trodde att det berodde på den ostabila strömförsörjningen (mina LED's dimmar så fort servo rör sig) och försökte sätta dit kondingar lite här o där (det fungerade ju tidigare ;) ). Det hjälpte inte. Jag testade sen att koppla ur servon, men data blev fortfarande korrupt. Jag vet inte riktigt vad jag skall prova med nu.

Koden som ligger o kör på PIC'en (CC5X):

(Hemskt ful, jag vet :P )

Kod: Markera allt

//***************************************************************************************
//	Config
//***************************************************************************************

#pragma chip PIC16F877A

// Used in Stdio.c
#define Clock_4MHz

//***************************************************************************************
//	Constants
//***************************************************************************************

#define DEBUG_LED	PORTB.1
#define SERVO_PIN	PORTB.2

#define LONG_DELAY		0
#define LONG_DELAY_CNT	9
#define OFFSET_DELAY	-0x40
//-157

#define LONG_DELAY_STATE		0
#define OFFSET_DELAY_STATE		1
#define POSITION_DELAY_STATE	2

#define CMD_RESET			0x00
#define CMD_SET_SERVO		0xdf

#define XON			0x11
#define XOFF		0x13

//***************************************************************************************
//	Variables
//***************************************************************************************

uns8 servoState;
uns8 servoDelay;
uns8 longDelayCnt;

//***************************************************************************************
//	Interrupt Service Routine
//***************************************************************************************

#include <int16CXX.h>

#pragma origin 4

interrupt int_server( void)
{
	int_save_registers    // W, STATUS (and PCLATH)

	if (T0IF)  
	{
		// Long delay just ended
		if (servoState == LONG_DELAY_STATE)
		{
			if (--longDelayCnt == 0)
			{
				servoState = OFFSET_DELAY_STATE;
				TMR0 = OFFSET_DELAY;
				SERVO_PIN = 1;
			}
		}
		else if (servoState == OFFSET_DELAY_STATE)
		{
			servoState = POSITION_DELAY_STATE;
			TMR0 = servoDelay;
		}
		else
		{
			servoState = LONG_DELAY_STATE;
			longDelayCnt = LONG_DELAY_CNT;
			TMR0 = LONG_DELAY;
			SERVO_PIN = 0;
		}		

		T0IF = 0;  /* reset flag */
	}

	int_restore_registers // W, STATUS (and PCLATH)
}

//***************************************************************************************
//	Headers
//***************************************************************************************

#include <Stdio.c> 

//***************************************************************************************
//	Function Declarations
//***************************************************************************************

void delay();

//***************************************************************************************
//	Application Entry Point
//***************************************************************************************

void OnSetServo(uns8 param)
{
	servoDelay = 255 - param;
	printf("Servo position: %h\n", param);
}

void init()
{
    PORTC = 0b.0000.0000;
    TRISC = 0b.1000.0000;  //0 = Output, 1 = Input RC7 - Incoming Data RX
	TRISB = 0b.0000.0000;

    SPBRG = 25; //4MHz for 9600 baud rate
    TXSTA = 0b.0010.0100; //8-bit asych mode, high speed uart enabled
    RCSTA = 0b.1001.0000; //Serial port enable, 8-bit asych continous receive mode

    OPTION = 0b.0000.0010; /* prescaler divide by 128 */
    T0IE = 1;   /* enable TMR0 interrupt */
    GIE = 1;

	servoState = LONG_DELAY_STATE;
	longDelayCnt = LONG_DELAY_CNT;
    TMR0 = LONG_DELAY;  

 	// PWM period of ~20ms
	//ADCON2 = 0x06;
	/*
	T2CON = 0b.0000.0111;
	TMR2 = 0;
	PR2 = 75;
	CCP2CON = 0b.0000.1100;
	*/

	// Duty cycle defaults to 5/256%
	//CCPR2L = 8;

	DEBUG_LED = 1;
}

void main()
{
	init();

	putc(XOFF);

    uns8 command;
	uns8 param;
	bit waitingForCommand = 1;

    while(1)
    {
		// Make sure there is no errors halting reception
		CREN = 0;
		CREN = 1;

		if (waitingForCommand)
		{
			putc(XON);
	  		command = getc();
			putc(XOFF);

			waitingForCommand = 0;

			if (command == CMD_RESET)
			{
				// Reset is sent 3 times. Just keep looking for commands.
				waitingForCommand = 1;
			}
			else if (command == CMD_SET_SERVO)
				continue;

			// If the program runs to this position the command was invalid. Continue to wait for a valid one.
			waitingForCommand = 1;
			printf("Unknown command: %h\n", command); //Print what you typed
		}
		else
		{
			putc(XON);
			param = getc();
			putc(XOFF);

			waitingForCommand = 1;

			if (command == CMD_SET_SERVO)
				OnSetServo(param);
		}
    }
}

void delay()
{
	uns8 a, b, c;
	for (a = 0; a < 1; a++)
		for (b = 0; b < 255; b++)
			for (c = 0; c < 255; c++);
}

Edit: Jag kan ju tillägga att hittills har jag aldrig sett några fel i datan som skickas från PIC'en till PC'n. Bara den andra vägen.
sodjan
EF Sponsor
Inlägg: 43247
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> putc(XON);
> command = getc();
> putc(XOFF);

Detta garanterar *inte* att PC'n enbart sändet *ett* tecken mellen varje xon/xoff.
Det finns inget i xon/off som säger att sändningen stoppar direkt.

När man använder xon/xoff så måste man normalt impementera en
buffert så att man inte missar något. Sedan låter man två olika
"nivåer" i bufferten styra xon/xoff. En låg nivå för xon och en hög
nivå för xoff (med marginal mellen xoff-nivån och toppen på bufferten).

Du måste också ha rutiner som *alltid* kan läsa från USART'en så snart det
kommer ett tecken. Och det är ju väldigt enkelt, eftersom du redan
har en interrupt rutin, bara att komplettera med interrupt för USART.
Användarvisningsbild
Tengil
Inlägg: 84
Blev medlem: 24 mars 2007, 00:15:46
Ort: Hudiksvall

Inlägg av Tengil »

Jag kom på att det var det som var problemet och gjorde en mjukvarufix (hack!) på datorn som inte var speciellt bra men löste det just då.

En buffert och interrupts låter dock som en mycket bättre lösning. Jag förstod däremot inte riktigt hur du menar med olika nivåer. Skulle du kunna förklarar det lite mer ingående eller kanske bidra med en länk? :)'

Problemet med att servon nästa släcker nere hela kretsen när den rör sig är kvar... Jag hittade en sida på Internet som rekommenderade att motorer skulle ha en sepparat v-reg för att inte störra uC'ers och liknande. Är det den enda lösningen eller har jag helt enkelt lyckats få tag på en mesig v-reg som inte räcker till?
sodjan
EF Sponsor
Inlägg: 43247
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> Jag förstod däremot inte riktigt hur du menar med olika nivåer...

Buffer = (t.ex) 32 tecken.
25 tecken i bufferten (och ökande) => skicka xoff.
10 tecken i bufferten (och minskande) => skicka xon

Nivåerna får "trimmas" för den aktuella applikationen...

> Jag hittade en sida på Internet som rekommenderade att motorer
> skulle ha en sepparat v-reg för att inte störra uC'ers och liknande.
>Är det den enda lösningen...

kanske det.

> eller har jag helt enkelt lyckats få tag på en mesig v-reg som inte räcker till?

kanske det.
Användarvisningsbild
Tengil
Inlägg: 84
Blev medlem: 24 mars 2007, 00:15:46
Ort: Hudiksvall

Inlägg av Tengil »

Nu stressar jag kanske med den här frågan, men jag har problem med att få min mjukvaru-flödeskontroll att fungera. När jag kommenterara bort XON och XOFF kommandona i koden flyter det bra så länge inte mottagarbuffern blir fylld. Med XON/XOFF kommandona fryser mitt C# program ett tag för att sedan visa input som t ex:
Servo position: 0x84
Servo po position: 0xD0
Servo position: 0xCC
Servo position: 0xC2
Servo position: 0xBC
Servo position: 0xB8
Servo position: 0xB1
Servo position: 0xAB
Servo position: 0sition: 0x7C
Servo position: 0x20
Servo position: 0x26
Servo position: 0x3A
Servo position: 0x5B
Servo po position: 0x79
Servo position: 0xCD
Frysningen uppkommer när XOFF skickas. Det verkar som om datorprogrammet även slutar att lyssna när ett XOFF-tecken anländer.

Här kommer en rejäl bit med PIC-kod. Jag vet dock inte om det verkligen är på PIC'en problemet ligger. Serieportsrutinen i mitt PC program är standardklassen i .NET så den borde ju fungera klanderfritt.

Kod: Markera allt

//***************************************************************************************
//	Config
//***************************************************************************************

#pragma chip PIC16F877A

// Used in Stdio.c
#define Clock_4MHz

#pragma origin 4

//***************************************************************************************
//	Constants
//***************************************************************************************

// USART buffer sizes
#define RC_BUFFER_SIZE			80

// USART buffer low/hight levels (flow control)
#define RC_BUFFER_LOW			5
#define RC_BUFFER_HIGH			60

// Software flow control characters
#define XON						0x11
#define XOFF					0x13

// Servo control
#define LONG_DELAY				100
#define LONG_DELAY_CNT			4
#define OFFSET_DELAY			-70

// Finite state machine states
#define LONG_DELAY_STATE		0
#define OFFSET_DELAY_STATE		1
#define POSITION_DELAY_STATE	2

// PC <-> uC control commands
#define CMD_RESET				0x00
#define CMD_SET_SERVO			0x20
#define CMD_LED1				0x21


//***************************************************************************************
//	Variables
//***************************************************************************************

// Interrupt state saving
uns8 FSRTemp;

// Hardware pins
bit debugLed @ PORTB.1;
bit servoPin @ PORTB.2;

// USART buffers
#pragma rambank 1
char rcBuffer[RC_BUFFER_SIZE];
#pragma rambank -

// USART buffer info
bit sendXOff;
uns8 rcStart;
uns8 rcLength;

// Used to time TMR0 correctly into a good control pulse
uns8 servoState;
uns8 servoDelay;
uns8 longDelayCnt;

//***************************************************************************************
//	Function Prototypes
//***************************************************************************************
	
void SendXOn();
void SendXOff();
uns8 UsartRead();
void UsartWrite(uns8 data);
void UsartPrintf(const char *nate, int16 my_byte);

//***************************************************************************************
//	Interrupt Service Routine
//***************************************************************************************

#include <int16CXX.h>

interrupt int_server( void)
{
	int_save_registers    // W, STATUS (and PCLATH)
	FSRTemp = FSR;

	if (T0IF) // TMR0 interrupt
	{	
		// Long delay just ended
		if (servoState == LONG_DELAY_STATE)
		{
			longDelayCnt--;
			if (longDelayCnt == 0)
			{
				servoState = OFFSET_DELAY_STATE;
				TMR0 = OFFSET_DELAY;
				servoPin = 1;
			}
			else
			{
				// Since long delay is 0, this is totally unneccesary.
				TMR0 = LONG_DELAY;
			}
		}
		else if (servoState == OFFSET_DELAY_STATE)
		{
			servoState = POSITION_DELAY_STATE;
			TMR0 = servoDelay;
		}
		else
		{
			servoState = LONG_DELAY_STATE;
			longDelayCnt = LONG_DELAY_CNT;
			TMR0 = LONG_DELAY;
			servoPin = 0;
		}		

		T0IF = 0;  /* reset flag */
	}

	if (RCIF && RCIE) // USART receive interrupt
	{
		if (OERR) // Buffer overrun
		{
			CREN = 0; // Clear error flag
			CREN = 1;
		}
		else if (FERR) // Framing error
		{
			rcStart = 0;
			rcLength = 1;
			rcBuffer[0] = RCREG;
		}
		else
		{
			if (rcLength < RC_BUFFER_SIZE)
			{
				uns8 offset = rcStart + rcLength;
				if (offset >= RC_BUFFER_SIZE)
					offset -= RC_BUFFER_SIZE;
				rcBuffer[offset] = RCREG;
				rcLength++;
			}
			
			if (rcLength == RC_BUFFER_HIGH)
			{
				sendXOff = 1;
			}
		}
	}

	FSR = FSRTemp;
	int_restore_registers // W, STATUS (and PCLATH)
}

//***************************************************************************************
//	Send XON software flow control character
//***************************************************************************************

void SendXOn()
{
	UsartWrite(XON);
}

//***************************************************************************************
//	Send XOFF software flow control character
//***************************************************************************************

void SendXOff()
{
	UsartWrite(XOFF);
}

//***************************************************************************************
//	Buffered USART read
//***************************************************************************************

uns8 UsartRead()
{
	if (rcLength == 0)
		return 0xff;

	uns8 data = rcBuffer[rcStart];

	rcStart++;
	rcLength--;

	if (rcStart >= RC_BUFFER_SIZE)
		rcStart = 0;

	if (rcLength == RC_BUFFER_LOW)
		SendXOn();

	return data;
}

//***************************************************************************************
//	Unbuffered USART write (blocking)
//***************************************************************************************

void UsartWrite(uns8 data)
{
	while (TXIF == 0);
	TXREG = data;
}

//***************************************************************************************
//	Binary to hex (Copyright SparkFunElectronics)
//***************************************************************************************

//Returns ASCII Decimal and Hex values
uns8 bin2Hex(char x)
{
   skip(x);
   #pragma return[16] = "0123456789ABCDEF"
}

//***************************************************************************************
//	Formatted USART write (Copyright SparkFunElectronics)
//***************************************************************************************

//Prints a string including variables
void UsartPrintf(const char *nate, int16 my_byte)
{
    uns8 i, k, m, temp;
    uns8 high_byte = 0, low_byte = 0;
    uns8 y, z;
    
    uns8 decimal_output[5];
    
    for(i = 0 ; ; i++)
    {
        k = nate[i];

        if (k == '\0') 
            break;

        else if (k == '%') //Print var
        {
            i++;
            k = nate[i];

            if (k == '\0') 
                break;
            else if (k == '\\') //Print special characters
            {
                i++;
                k = nate[i];
                
                UsartWrite(k);
                

            } //End Special Characters
            else if (k == 'b') //Print Binary
            {
                for( m = 0 ; m < 8 ; m++ )
                {
                    if (my_byte.7 == 1) UsartWrite('1');
                    if (my_byte.7 == 0) UsartWrite('0');
                    if (m == 3) UsartWrite(' ');
                    
                    my_byte = my_byte << 1;
                }
            } //End Binary               
            else if (k == 'd') //Print Decimal
            {
                //Divide number by a series of 10s
                for(m = 4 ; my_byte > 0 ; m--)
                {
                    temp = my_byte % (uns16)10;
                    decimal_output[m] = temp;
                    my_byte = my_byte / (uns16)10;               
                }
                
                for(m++ ; m < 5 ; m++)
                    UsartWrite(bin2Hex(decimal_output[m]));
    
            } //End Decimal
            else if (k == 'h') //Print Hex
            {
                //New trick 3-15-04
                UsartWrite('0');
                UsartWrite('x');
                
                if(my_byte > 0x00FF)
                {
                    UsartWrite(bin2Hex(my_byte.high8 >> 4));
                    UsartWrite(bin2Hex(my_byte.high8 & 0b.0000.1111));
                }

                UsartWrite(bin2Hex(my_byte.low8 >> 4));
                UsartWrite(bin2Hex(my_byte.low8 & 0b.0000.1111));

            } //End Hex
            else if (k == 'f') //Print Float
            {
                UsartWrite('!');
            } //End Float
            else if (k == 'u') //Print Direct Character
            {
                //All ascii characters below 20 are special and screwy characters
                //if(my_byte > 20) 
                    UsartWrite(my_byte);
            } //End Direct
                        
        } //End Special Chars           

        else
            UsartWrite(k);
    }    
}

//***************************************************************************************
//	OnSetServo command handler
//		param:	0x00 -> 0xff 
//				Position of servo axis
//***************************************************************************************

void OnSetServo(uns8 param)
{
	servoDelay = 255 - param;
	UsartPrintf("Servo position: %h\n", param);
}

//***************************************************************************************
//	OnLed1 command handler
//		param:	0x00 or 0x01
//				Led on/off
//***************************************************************************************

void OnLed1(uns8 param)
{
	if (param == 0)
		debugLed = 0;
	else
		debugLed = 1;

	UsartPrintf("LED1 state: %h\n", param);
}

//***************************************************************************************
//	Application initialization
//***************************************************************************************

void init()
{
    PORTC = 0b.0000.0000;
    TRISC = 0b.1000.0000;  //0 = Output, 1 = Input RC7 - Incoming Data RX
	TRISB = 0b.0000.0000;

    SPBRG = 25; //4MHz for 9600 baud rate
    TXSTA = 0b.0010.0100; //8-bit asych mode, high speed uart enabled
    RCSTA = 0b.1001.0000; //Serial port enable, 8-bit asych continous receive mode

    OPTION = 0b.0000.0010; // TMR0 prescaler divide by 8
    T0IE = 1; // Enable TMR0 interrupt
	RCIE = 1; // Enable USART RC interrupt
	TXIE = 0; // Disable USART TX interrupt
    GIE = 1;

	// RS-232 software flow control status
	sendXOff = 0;
	rcStart = 0;
	rcLength = 0;

	// Servo control
	servoState = LONG_DELAY_STATE;
	longDelayCnt = LONG_DELAY_CNT;
    TMR0 = LONG_DELAY; 

	debugLed = 1;
}

//***************************************************************************************
//	Application Entry Point
//***************************************************************************************

void main()
{
	init();

    uns8 command;
	uns8 param;
	bit waitingForCommand = 1;

    while (1)
    {
		if (sendXOff)
		{
			SendXOff();
			sendXOff = 0;
		}

		if (rcLength > 0)
		{
			if (waitingForCommand)
			{
				command = UsartRead();
	
				waitingForCommand = 0;
	
				switch (command)
				{
				case CMD_RESET:
					// Reset is sent 3 times. Just keep looking for commands.
					waitingForCommand = 1;
					break;
				case CMD_SET_SERVO:
				case CMD_LED1:
					break;
				default:
					// If the program 	runs to this position the command was invalid. Continue to wait for a valid one.
					waitingForCommand = 1;
					UsartPrintf("Unknown command: %h\n", command);
					break;

				}
	

			}
			else
			{
				param = UsartRead();
	
				waitingForCommand = 1;
	
				switch (command)
				{
				case CMD_SET_SERVO:
					OnSetServo(param);
					break;
				case CMD_LED1:
					OnLed1(param);
					break;
				}	
			}
		}
    }
}
Skriv svar