??? 06/06/11 16:00 Read: times |
#182505 - Servo control blues |
Guys I need a bit of advice on some code I've written in Keil in C for an 89C51 core microcontroller. It's a simple application really and I was staggered when I've found that in practice it didn't work (It does work well while emulating the program in Keil step by step). It isn't the most elegant of codes, it's supposed to be quick and dirty to get things done (I know...I know).
The code I've written is supposed to set a servo to turn to 90 degrees, then force the microcontroller to wait for an incoming input through serial and turn the microcontroller accordingly (U to turn right and D to turn left). A normally closed Emergency button is connected with INT0 (set to operate at negative edge triggering in code). When it's pressed the ISR should execute, which should stop the servo motor from turning and if it's pressed for a minimum of 10 seconds the system should reset i.e. control passes back to the main program. That's the basic operation. As I said it does work well when debugging it in Keil. Problem is, in practice the application works well when the system receives the first external interrupt (i.e. emergency button is pressed), but than after about a couple of seconds, the micro re-executes the ISR without any external INT0 trigger! (Used LEDs to check if this is what's happening and seems the case). I'm sure I'm missing something out. Any help would be appreciated. Thanks in advance! Kai #include <reg52.h> sbit L_G = P0^0; // Green Led sbit L_R = P0^2; // Red Led sbit buz = P0^4; // Buzzer sbit srv = P0^6; // Servo sbit eme2 = P0^7; // not used sbit intbut = P3^2; // interrupt pin unsigned char mychar; unsigned int on, off, rotL, rotR, ctr = 0; unsigned int i, x, y, delay, dly = 0; int RST = 0; void main (void) { // datasheet pg62 setting timer mode // Timer 1 = 1 ( Gate1 = 0, C/T1# = 0, M11 = 2, M01 = 0) // Timer 0 = 2 ( Gate0 = 0, C/T0# = 0, M11 = 0, M01 = 1) TMOD = 0x21; //use Timer1 auto-reload & Timer 0 16 bit timer // setting baudrate value using the following eauqation //TH1 = 256 - ((Crystal / 384) / Baud) //TH1 = 256 - ((18,432,000 / 384) / 9600 ) //TH1 = 256 - ((48,000) / 9600) //TH1 = 256 - 5 = 251 TH1 = 0xFB; SCON = 0x50; //8-bit UARTVariable, pg 54 TR1 = 1; //start timer IT0=1; //set external interrupt 0 negative edge-triggered EX0=1; //enable external interrupt 0 interrupt EA=1; //enable global interrupt L_R = 0; // set the servo position to 90 degrees for (ctr = 0; ctr <= 10; ctr++) { // _________ // |_____________________ // 1.49ms 19.59ms //1.49 on for (on = 0; on <= 100; on++); { srv = 0; } //18.1ms off for (off = 0; off <= 5900; off++); { srv = 1; } } while(1) { //while(RI == 0); //wait to receive mychar = SBUF; //save serial input value in mychar if (mychar == 'U') { // servo up, active state // set the servo position to 0 degrees L_G = 0; //Green LED on L_R = 1; //Red LED off for (rotL = 0; rotL <= 10; rotL++) { // _________ // |_____________________ // 0.955ms 18.087ms //0.955ms on //was 185 change to 150 for (on = 0; on <= 650; on++); { srv = 0; } //18.087ms off for (off = 0; off <= 5250; off++); { srv = 1; } } } else if (mychar == 'D') { // Servo down, active state // set the servo position to 180 degrees L_G = 0; //Green LED on L_R = 1; //Red LED off for (rotR = 0; rotR <= 10; rotR++) { // _________ // |_____________________ // 1.809ms 17.575ms //1.809ms on for (on = 0; on <= 550; on++); { srv = 0; } //17.575ms off for (off = 0; off <= 5315; off++); { srv = 1; } } } } } void turn_on(void) interrupt 0 { EA = 0; i, x, y, delay, dly = 0; RST = 0; L_G = 1; //Switch off green LED // 1 timer value shall be 20ms // 500 timer values = 500 * 20ms = 10s // now timer step // Timer 0 step = Crystal/12 // = 18,432,000/12 // = 1536000Hz // Time = 1/Frequency // = 1/1536000 // = 651.041666nS // 1 timer step = 651.041666nS, // ? = 20ms // answer = 20msec / 651.0416667nSec // = 30720 steps // Now TFO overflows at FFFFh // therefore 65536 - 30720 = 34816 // 34816 dec = 8800h // Therefore setting THO = 88h and TLO = 00h // Now including the LED and Buzzer emergency PWM // From the Keil debugger using performance graph it was found // that the delay for flicketing the LED and buzzer takes // Delay start A time = 0.000292 // Delay stop A time = 0.034318 // Therfore total delay time A = 0.034318 - 0.000292 // = 0.034026 seconds // Now if we add the delays together we get // Total delay = (delay Start A till Delay Stop A + 20ms by Timer) // = (0.034026 + 20ms) // = 0.054026 // Now recalculating the for loop for the time // 1 timer step + delay time = 0.55ms // 10s = ? // timer steps = 10/55ms // = 182 while (((i != 182) && (intbut == 0)) || (RST == 0)) { for (i = 0; i < 182; i++) { //Delay A - start for (x = 0; x <= 5200; x++); { L_R = 0; //Red led on for 0.1sec buz = 0; //Buzzer on for 0.1 sec } for (y = 0; y <= 5200; y++); { L_R = 1; //Red Led off for 0.1sec buz = 1; //Buzzer of for 0.1sec } //Delay A - stop //start timer TH0 = 0x88; //set 20ms TL0 = 0x00; TR0 = 1; //start timer while(TF0 == 0); if ((i >= 181) && (intbut == 0)) { RST = 1; //exit interrupt loop TR0 = 0; // stop the timer TF0 = 0; // clear timer 0 overflow flag eme2 = 0; for ( delay = 0; delay <= 10000; delay++) { for (dly = 0; dly <= 100; dly++) {} } eme2 = 1; } else if ((i <= 181) && (intbut == 1) && (RST == 0)) { i = 0; //restart timer for loop if emergency is not pressed } } } RST = 0; //for Good Practice EA = 1; } |
Topic | Author | Date |
Servo control blues | 01/01/70 00:00 | |
it would be nice ... | 01/01/70 00:00 | |
... it would be better ... | 01/01/70 00:00 | |
RE: emulating the program in Keil step by step | 01/01/70 00:00 | |
something *looks* simple doesn't mean it *is* simple | 01/01/70 00:00 | |
Very few simple applications. | 01/01/70 00:00 | |
The 90:10 Rule again | 01/01/70 00:00 |