| ??? 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 |



