Problem med mitt program

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
Kalf
Inlägg: 249
Blev medlem: 5 november 2005, 09:59:45

Problem med mitt program

Inlägg av Kalf »

Hej. Jag har ett litet problem med mitt program här. Jag har skrivit ett servo kontroller program eller vad man skall säga. Detta styrs via RS232 från PC'n. Jag använder mikroC som kompilator för uC'n samt visual C++ för PC'n

Processorn jag använder är en 16F628A. såhär ser koden i uC'n ut:

Kod: Markera allt

//Variabler för datapaket
unsigned short pak_action = 0b00000001;
unsigned short pak_value = 0xb6; //oxb6(59) - 0xb6(182)
unsigned short pak_reday = 0x00;

//Variabler för servo vinklar
unsigned short J0_angle = 0x6b;
unsigned short J1_angle = 0xb6;
unsigned short J2_angle = 0xb6;
unsigned short J3_angle = 0xb6;
unsigned short J4_angle = 0xb6;
//Övriga variabler
unsigned int cnt = 0;

void main(void)
{
     //I/O settings
     TRISA = 0x00;
     PORTA = 0x00;
     Usart_Init(2400);  //Init usart

     while(1)
     {
             //Hämta data
             while(Usart_Data_Ready() == 0);    //Vänta på data
             J0_angle = Usart_Read();              //Tilldela värde
             while(Usart_Data_Ready() == 0);    //Vänta på data
             J1_angle = Usart_Read();              //Tilldela värde
             while(Usart_Data_Ready() == 0);    //Vänta på data
             J2_angle = Usart_Read();              //Tilldela värde
             while(Usart_Data_Ready() == 0);    //Vänta på data
             J3_angle = Usart_Read();              //Tilldela värde
             while(Usart_Data_Ready() == 0);    //Vänta på data
             J4_angle = Usart_Read();              //Tilldela värde/

             while(Usart_Data_Ready() == 0)
             {
                 //Starta motorerna
                 while(J0_angle >= cnt) {
                         PORTA |= 0b00000001;
                         cnt++;
                 }
                 PORTA = 0;
                 cnt = 0;
                 while(J1_angle >= cnt) {
                         PORTA |= 0b00000010;
                         cnt++;
                 }
                 PORTA = 0;
                 cnt = 0;
                 while(J2_angle >= cnt) {
                         PORTA |= 0b00000100;
                         cnt++;
                 }
                 PORTA = 0;
                 cnt = 0;
                 while(J3_angle >= cnt) {
                         PORTA |= 0b00001000;
                         cnt++;
                 }
                 PORTA = 0;
                 cnt = 0;
                 while(J4_angle >= cnt) {
                         PORTA |= 0b10000000;
                         cnt++;
                 }
                 PORTA  = 0;
                 cnt = 0;
                 delay_ms(10);
             }
     }
}
Och koden i datorn ser utsåhär: (ett utdrag ur den.)

Kod: Markera allt

...
void EnterPosition(void)
{
	int J0_angle = 0;
	int J1_angle = 0;
	int J2_angle = 0;
	int J3_angle = 0;
	int J4_angle = 0;

	system("CLS");
	cout<<"All values 0-100"<<endl;
	cout<<"Enter angle for J0: ";
	cin>>J0_angle;
	while((J0_angle > 10000) || (J0_angle < 0))
	{
		cout<<"You have enterd an invaild number."<<endl<<"Enter a new one: ";
		cin>>J0_angle;
	}
	cout<<"Enter angle for J1: ";
	cin>>J1_angle;
	while((J1_angle > 10000) || (J1_angle < 0))
	{
		cout<<"You have enterd an invaild number."<<endl<<"Enter a new one: ";
		cin>>J1_angle;
	}
	cout<<"Enter angle for J2: ";
	cin>>J2_angle;
	while((J2_angle > 10000) || (J2_angle < 0))
	{
		cout<<"You have enterd an invaild number."<<endl<<"Enter a new one: ";
		cin>>J2_angle;
	}
	cout<<"Enter angle for J3: ";
	cin>>J3_angle;
	while((J3_angle > 10000) || (J3_angle < 0))
	{
		cout<<"You have enterd an invaild number."<<endl<<"Enter a new one: ";
		cin>>J3_angle;
	}
	cout<<"Enter angle for J4: ";
	cin>>J4_angle;
	while((J4_angle > 10000) || (J4_angle < 0))
	{
		cout<<"You have enterd an invaild number."<<endl<<"Enter a new one: ";
		cin>>J4_angle;
	}


	COMPort aPort ("COM1");
	aPort.setBitRate (COMPort::br2400);
	aPort.setParity (COMPort::None);
	aPort.setDataBits (COMPort::db8);
	aPort.setStopBits (COMPort::sb1);

	
	aPort.write(J0_angle);
	Sleep(1);
	aPort.write(J1_angle);
	Sleep(1);
	aPort.write(J2_angle);
	Sleep(1);
	aPort.write(J3_angle);
	Sleep(1);
	aPort.write(J4_angle);
	system("CLS");

}
...
Det problemet jag har är att det funkar jättebra att "ladda över" en gång då ställer servorna in sig som de skall. Men när man gör det igen så kommer det ingen signal ut till servorna. om jag tar och startar om uC'n så funkar det eng gång igen. Jag vet ju på ett ungefär vart problemet ligger, nämligen i förljade rad i uC'ns program:

Kod: Markera allt

//Rad 36
while(Usart_Data_Ready() == 0)
             {

Kan man byta ut det villkoret mot något annat, någon som har något förslag?

MVH
Kalf
Användarvisningsbild
Icecap
Inlägg: 26659
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

Jag har ett program på min hemsida som gör "exakt" detta med samma processor, det finns källkod med (MikroC) och du borde ganska enkelt kunna modifiera det så att det passar.

Kommunikationsprotokollen är förvisso annorlunda men det borde inte vara ett problem.

Finns under "Freebies"
Användarvisningsbild
Kalf
Inlägg: 249
Blev medlem: 5 november 2005, 09:59:45

Inlägg av Kalf »

Jag skrev om din kod för att fungera med mitt PC'program. Men det funkar inte som det skall. När jag kör mitt programm så kan jag ställa in vilket servo jag vill ändra position på och vilket värde som skall ändras. Rätt servo byter position. Men det går alltid till samma position och ställer sig och "vibrerar" Har jag missuppfattat hur din klass fungerar kanske?

Här är båda koderna igen:

Kod: Markera allt

// RC-servo controller
// © Icecap 2006-03-11
// Recieves commands through the serial port and sends out the appropriate datsa om the ports
// Protocoll:
// STX Channel Data ETX (spaces left for clarity only)
// Channel: '0' - '9','A'-'D'
// Data:    '0' - '999'
// I.e. to set channel '1' to midposition (499):
// STX 1499 ETX or in hex: 02 31 34 39 39 03

// Processor:
// PIC16F628A using INTOSC with NOCLKOUT

typedef unsigned char byte;
typedef unsigned int  word;
typedef unsigned long dword;

#define true  1
#define false 0

#define STX 0x02
#define ETX 0x03

#define Channels 13
#define INPUT_SIZE 5

// A few constant definitions
#define Offset  -970
#define Start_Value Offset -499
// The 'Offset' is negative due to the fact that Timer1 counts up an gives a interrupt at overflow
// thus all times are calculated by subtracting them from 0 (zero) - some compensation för code time
// and then subtract the pulse length from the timer value. This means that the value 'Offset' represents
// equals the shortest pulse length possible (1ms).

union
  {
  word W;
  byte B[2];
  } Datas[Channels]; // This allow me to access BOTH as a unsigned int AND as 2 bytes/word
char Input[INPUT_SIZE]; // Room for the incoming data
byte Input_Index; // Input counter and pointer

// The follwing patterns is to select the correct pin on the µC
const byte PatternA[] = {0x01,0x02,0x04,0x08,0x40,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
const byte PatternB[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x04,0x08,0x10,0x20,0x40,0x80};

void Initialize(void)
  {
  OPTION_REG  =  0x87; // Well...stuff!
  CMCON       =  0x07; // No comparator-thingy
  // Set port directions
  TRISA       = 0b00100000; // All out but -MCLR
  TRISB       = 0b00000010; // All out but Serial-in
  // Set port values
  PORTA       = 0x00; // Start value
  PORTB       = 0x00; // Start value
  // Set known good values
  for(Input_Index = 0;Input_Index < Channels;Input_Index++) Datas[Input_Index].W = Start_Value; // Set all to center (1,000ms)
  // Allow interrupts
  PIE1        = 0b00000001; // Allow Timer1 interrupts
  INTCON      = 0b11000000; // Allow interrupts as such
  /*/ Set UART to recieve only, no interrupts
  TXSTA       = 0b00000100; // BRGH = '1'
  RCSTA       = 0b10010000; // Enable continous recieve and clear errors
  SPBRG       = 25; // 9K6,n,8,1*/
  //Usart
  Usart_Init(2400);
  // Start Timer1 on the highest freq.
  T1CON       = 0b00000001;
  // Now set some working values
  Input_Index = 0;
  }

void interrupt(void)
  {
  static byte Sequence, Index, TimeH, TimeL, Pattern_PortA, Pattern_PortB; // Used here only and must be "locked"
  // It's Timer1 overflow (only enabled interrupt), it's a ISR with external interface so be snappy!
  PIR1.TMR1IF   = false;             // Acknowledge the interrupt
  T1CON.TMR1ON  = false;             // Stop the timer
  TMR1H         = TimeH;             // Set pulse time, high byte
  TMR1L         = TimeL;             // Set pulse time, low byte
  T1CON.TMR1ON  = true;              // Start timer again
  PORTA         = Pattern_PortA;     // Rise correct port pin
  PORTB         = Pattern_PortB;     // Rise correct port pin
  // Now the timing is less panic as the external job is done for now
  if(++Index >= Channels) Index = 0; // Count up and around
  TimeH         = Datas[Index].B[1]; // Prepare the values for faster access
  TimeL         = Datas[Index].B[0]; // Prepare the values for faster access
  Pattern_PortA = PatternA[Index];   // Prepare the values for faster access
  Pattern_PortB = PatternB[Index];   // Prepare the values for faster access
  }

void main(void)
  {
  byte Read;
  word Value;
  byte Digit;
  Initialize();
  while(true)
    {
    if(RCSTA & 0b00000110) // Any error exist?
      {
      RCSTA     = 0b10010000; // Erase any errors
      PIR1.RCIF = false;      // Remove it just in case
      }
    if(Usart_Data_Ready() == 1)
      {
      int servo_nr;
      int servo_value;
      while(Usart_Data_Ready() == 0);
      servo_nr = Usart_Read();
      while(Usart_Data_Ready() == 0);
      servo_value = Usart_read();

      Datas[servo_nr].W = servo_value;
      servo_nr = 0;
      servo_value = 0;
      }
    }
  }
Och PC'n:

Kod: Markera allt

COMPort aPort ("COM1");
	aPort.setBitRate (COMPort::br2400);
	aPort.setParity (COMPort::None);
	aPort.setDataBits (COMPort::db8);
	aPort.setStopBits (COMPort::sb1);

	cout << "Servo: ";
	int servo_nr;
	cin >> servo_nr;
	cout << "Position: ";
	int servo_pos;
	cin >> servo_pos;

	aPort.write(servo_nr);
	Sleep(1);
	aPort.write(servo_pos);
	Sleep(1);
Är det min data hantering som inte är rätt?

//Kalf
Användarvisningsbild
Kalf
Inlägg: 249
Blev medlem: 5 november 2005, 09:59:45

Inlägg av Kalf »

Jag har gott tillbaka till min ursprungkod. Problemet verkar inte vara koden utan snarare kopplingen. För nu är det såhär:

Jag kan ändra värdet på servo utgångarna, och ställa om dem. Detta funkar. Men när jag byter värde igen. (skickar data från PC'n igen) Då funkar det inte. Ibland funkar det att göra det en gång till. Men inte alltd. Tar man sedan bort motståndet till MCLR och sätter dit det igen så kan man börja om. Sähär är det kopplat:

mclr: 1kohm till +5V
vss: 0V
rx: tx från PC'n (via en MAX232)
vdd: +5V
RA0: servo 0
RA1: servo 1

//Kalf
Användarvisningsbild
Icecap
Inlägg: 26659
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

Det är INTE kopplingen!

Om signalen oftast kommer fram och tolkas rätt är det INTE kopplingen men koden.

Jag ser att du har fallit i den vanliga fälla: du använder "Usart_Init(2400);" och "Usart_Data_Ready()" men VET du exakt vad de gör?

UART'en ÄR redan initierat och ska du ha 2400 baud är det bara att ändra värdet i SPBRG. Vilket exakta värde framgår av databladet.

"Usart_Data_Ready()" sedan... VET du att den är 1 när det har kommit in en byte? Eller är den bara annat än noll?

Hur säkrar du att din kommunikation är i synk? Om en störning får den att missa 1 byte... vad händer då?

Hur många bytes sändar "aPort.write(servo_nr);"?

Mitt program förväntar sig värden mellan 0 och 1000, hur klarar du av det med 1 byte?

Och sedan är det ingen "klass", det är ett program. Jag förstår av det att du är mer van att programmera på PC än på µC och det är en stor nackdel.

Jag tror att ditt största problem är att du inte vet vilka data som skickas, antalet bytes, det finns ingen synkronisering så att "otillåtna" data kastas och "trasiga" datapaket kommer rätt osv.

Det finns en anledning till att jag har gjort ett ASCII kommandosätt med STX och ETX och det är just att VETA att datan är OK, var de startar och var de slutar.

Jag tror att du helt enkelt ska tänka igenom på ett helt annat plan vad du egentligen gör och vad du vill uppnå, hur du ska säkra dina datas tydlighet och hur många bytes du skickar innan du går vidare för kopplingen är det ingen fel på.
Skriv svar