paulfjujo
Advanced Member level 4
- Joined
- Jun 9, 2008
- Messages
- 1,468
- Helped
- 298
- Reputation
- 596
- Reaction score
- 285
- Trophy points
- 1,363
- Location
- France 01800
- Activity points
- 10,630
Follow along with the video below to see how to install our site as a web app on your home screen.
Note: This feature may not be available in some browsers.
void Interrupt() iv 0x0004 ics ICS_AUTO {
//void Interrupt(){
unsigned int TMR1_value;
... etc ..
void interrupt() <-- Works OK
{
... etc ...
For paulfjujo...
I am very bored right now, so I made same project, but using your project settings (internal 4MHz osc) - attached
Tested with scope traces and with hobby servo - works well.
Gives accurate 0.5ms to 2.5ms high from 0-5V ADC input - for full range servo operation - 20ms repetition rate. Two channels.
High pulse is a fraction less than 7-bits (128 count) resolution on RD0, a fraction less than 8-bits resolution on RD1.
Do not understand why it does not work for you.
Telling differentlyHello,
I found the problem !
My compiler config :
Tools
....Output
......compiler
........Case sensitive coché <- to respect 100% original syntax
in fact, the original problem is on your side
because the correct syntaxe for interrupt is
First letter i in lowercase
Code:void interrupt() <-- Works OK { ... etc ...
compiler doesn't gives any error msg about that !
just ignore the code
OK ! I see.Ignore the side-discussion between paulfjujo and I about the 'timer-calculator' bug Interupt vs interrupt. We learnt from it, but it is unlikely to matter to you. Ideally we would have discussed on a separate thread.
Ask away - helping is fun, and I already learnt more by helping you, than you learnt from being helped.
You understand perfectly.Case sensitive empty.
That means, void interrupt() or void Interrupt() are considerate as similar in the code
The compiler will not report a problem with Interrupt or interrupt case sensitivity turned on.And faults detected In case of ?
#define Version "2020_0918"
#define Directory "C:\\_MikroC\\_MesProjets_MikroC\\_16F877_2servomoteurs"
#define Source "Test_2_servo_16F887_using_State_Machine_TMR2_TMR1_2xEA_"
#define Project "Test_2servo_16F887_State_Machine_TMR2_TMR1_2xEA_2020_09.mcppi"
#define MCU "P16F887 Dip40"
#define FOSC_INTERNE // not needed if FOSC= 4MHZ , because is the default value
#define FOSC "4Mhz"
// voir SQA_test_cde_2servo_16F887_2020_0916.scana
//CONFIG1 : $2007 : 0x2CF4
//CONFIG2 : $2008 : 0x0700
#define Bavard
//ac:pinout
//ac:SQA_analyze
// https://www.edaboard.com/threads/16f887-2-axis-joystick-drive-2-servomotors.394685/
// 2 axes joysticks drives 2 servos :
// Servo motor control signals on RB0 and RB1
// Analogue inputs on RA0 and RA1
// MCU : PIC 16F887, internal fosc 4 MHz
// Driving of 2 servomotors :
// Timer2 drive State machine
// one step to built the start pulse beginning at a minima of 1mS
// the Timer1 elapsed time value comes from EA0 or EA1 to complete the total time SERVO ON
// maxima is 2mS !
// - servomotor LOWER (360 ° turn) on PORTD.B0 (pin 19),
// > Servomotor TOWER PRO MG995 (360 °),
// - servomotor UPPER (180 °/270 ° turn) on PORTD.B1 (pin 20),
// > Servomotor TOWER PRO MG996R (180 °/270 °),
// global variables
volatile unsigned int Consigne1=0;
volatile unsigned int Consigne2=0;
volatile unsigned int Value_Timer1 ;
int Step=0;
sbit Servo_Lower at PORTD.B0 ;
sbit Servo_Upper at PORTD.B1 ;
sbit Servo_Lower_dir at TRISD.B0 ;
sbit Servo_Upper_dir at PORTD.B1 ;
sbit SQA at PORTC.B3 ;
sbit SQA_dir at TRISC.B3 ;
int i,j,k;
char CRam1[80];
char c1,cx;
// void Toto_le_Rigolo() iv 0x0004 ics ICS_AUTO {
//}
void Interrupts() iv 0x0004 ics ICS_AUTO {
//or
//void interrupt () // OK
//void Interrupt() // <- BAD if "Case sensitive" option is checkek for compiler !
//{
unsigned int TMR1_value; // temporary calculation value
//TXREG='@'; // to test if interrupt fire
if ((TMR2IE_bit) && (TMR2IF_bit))
{
switch (Step)
{
case 0: // 1rst ms ON on Servo Lower
SQA=1;
Servo_Lower=1;
Servo_Upper=0;
TMR1ON_bit=0;
TMR1IF_bit=0;
TMR1IE_bit=0;
Step++;
break;
case 1:
Servo_Lower=1;
Servo_Upper=0; // TON= 1ms + TMR1 time
Value_Timer1= 65535-Consigne1;
TMR1H= Value_Timer1>>8;
TMR1L= Value_Timer1 & 0x00FF;
TMR1IF_bit=0;
TMR1IE_bit=1;
TMR1ON_bit=1;
Step++;
break;
case 2 :
Servo_Lower=0; // 1rst ms ON on Servo UPPER
Servo_Upper=1;
TMR1IE_bit=0;
TMR1ON_bit=0;
TMR1IF_bit=0;
Step++;
break;
case 3:
Servo_Upper=1; // TON= 1ms + TMR1 time
Servo_Lower=0;
Value_Timer1= 65535-Consigne2;
TMR1H= Value_Timer1>>8;
TMR1L= Value_Timer1 & 0x00FF;
TMR1IF_bit=0;
TMR1IE_bit=1;
TMR1ON_bit=1;
Step++;
break;
case 4 :
Servo_Lower=0; // 1rst ms ON on Servo UPPER
Servo_Upper=0;
TMR1IE_bit=0;
TMR1ON_bit=0;
TMR1IF_bit=0;
SQA=0;
Step++;
break;
case 19 :
Step=0;
break;
default:
Step++;
break;
}
PR2 = 249;
TMR2IF_bit = 0;
}
// ---------- TMR1 --------------------
if ( (TMR1IE_bit) && (TMR1IF_bit) )
{ // handle timer 1 interrupt
if (Step==2) Servo_Lower=0;
if (Step==4) Servo_Upper=0;
TMR1ON_bit=0;
TMR1IE_bit=0;
TMR1IF_bit = 0;
}
}
void Init_Timer2()
{
// at Fosc=4MHz Actual Interrupt Time : 1 ms
//Prescaler 1:1; Postscaler 1:4; TMR2 Preload = 249;
T2CON = 0x1C;
PR2 = 250;
TMR2IE_bit = 1;
INTCON = 0xC0;
}
//Timer1 at Fosc=4MHz
//Prescaler 1:1; TMR1 Preload = 65036; Actual Interrupt Time : 500 us
//Place/Copy this part in declaration section
void Init_Timer1(){
T1CON = 0x01;
TMR1IF_bit = 0;
TMR1H = 0xFE;
TMR1L = 0x0C;
TMR1IE_bit = 0;
INTCON= 0x00;
}
void CRLF1(void)
{
UART1_Write(13);
UART1_Write(10);
}
void Print( char *T)
{
while(*(T)>0)
{
UART1_Write(*(T++));
}
}
void CPrint(const char *T1)
{
while(*(T1)>0)
{
UART1_Write(*(T1++));
}
}
void main()
{
#ifdef FOSC_INTERNE
OSCCON=0;
OSCCON.IRCF2=1; // 4MHz
OSCCON.IRCF1=1;
OSCCON.IRCF0=0;
OSCCON.SCS=1;
//OSCCON=0b01110001 ; // 8MHz (111) & SCS=1 (sinon 4 MHz par defaut)
//OSCCON=0b01100001 ; // 4 MHz par defaut
#endif
ANSEL=0x03;
TRISC = 0x00;
TRISD = 0x00;t
PORTC = 0x00;
PORTD = 0x00;
SQA_dir=0;
SQA=0;
ADC_Init();
UART1_Init(19200);
// vider le registre de transmission
if (UART1_Tx_Idle() == 1) UART1_Write(' ');
CRLF1();
CPrint(" Compiler: MikroC 7.60 \r\n");
CPrint(" Directory : "Directory"\r\n");
CPrint(" Source : "Source"Version"Version"\r\n");
CPrint(" Test 2 servo , MCU" MCU" FOSC="FOSC"\r\n");
CPrint(" Servomotor LOWER 270° : TOWER PRO M996R (270°) \r\n");
CPrint(" Servomotor UPPER x360° : TOWER PRO MG995 (360°)\r\n");
CPrint(" Usage de Timer2 pour gerer une machine d'etat \r\n");
CRLF1();
Init_Timer1(); // sans interrupt
PEIE_bit=1;
GIE_bit=1;
Init_Timer2(); // avec interrupt armée
Step=0;
// -------------- main loop ---------------------------
while(1)
{
// consigne 0 à 1000µS + offset constant de 1ms généré par Timer2
// soit gamme de 1 à 2mS
Consigne1 = ADC_Read(0);
Consigne2 = ADC_Read(1);
#ifdef Bavard
CPrint(" Consigne1 Lower Servo :");
WordToStr(Consigne1 ,CRam1);
Print(CRam1);
CPrint(" Consigne2 Upper Servo :");
WordToStr(Consigne2 ,CRam1);
Print(CRam1);
CRLF1();
Delay_1sec(); // à modifier si besoin
#else
Delay_ms(20);
#endif
}
}
/*
on terminal display
Compiler: MikroC 7.60
Directory<NUL><SOH>
Compiler: MikroC 7.60
Directory : C:\_MikroC\_MesProjets_MikroC\_16F877_2servomoteurs
Source : Test_2_servo_16F887_using_State_Machine_TMR2_TMR1_2xEA_Version2020_0918
Test 2 servo , MCUP16F887 Dip40 FOSC=4Mhz
Servomotor LOWER 270° : TOWER PRO M996R (270°)
Servomotor UPPER x360° : TOWER PRO MG995 (360°)
Usage de Timer2 pour gerer une machine d'etat
Consigne1 Lower Servo : 164 Consigne2 Upper Servo : 167
Consigne1 Lower Servo : 167 Consigne2 Upper Servo : 167
Consigne1 Lower Servo : 183 Consigne2 Upper Servo : 182
Consigne1 Lower Servo : 170 Consigne2 Upper Servo : 172
Consigne1 Lower Servo : 163 Consigne2 Upper Servo : 165
Consigne1 Lower Servo : 172 Consigne2 Upper Servo : 168
Consigne1 Lower Servo : 183 Consigne2 Upper Servo : 183
*/
Merci Paul !another way using Timer2 to drive a state machine
whis a step time of 1mS
so one step is used to build the first mS,
second step to add the Timer1 value
(corresponding time = analog value 0 to 1023 (µS))
to obtain a range of 1 to 2mS
repeat time after step 19
Step 0 ...to Step 19 => every 20mS
Step 3 and 4 used for the other servo
Code:#define Version "2020_0918" #define Directory "C:\\_MikroC\\_MesProjets_MikroC\\_16F877_2servomoteurs" #define Source "Test_2_servo_16F887_using_State_Machine_TMR2_TMR1_2xEA_" #define Project "Test_2servo_16F887_State_Machine_TMR2_TMR1_2xEA_2020_09.mcppi" #define MCU "P16F887 Dip40" #define FOSC_INTERNE // not needed if FOSC= 4MHZ , because is the default value #define FOSC "4Mhz" // voir SQA_test_cde_2servo_16F887_2020_0916.scana //CONFIG1 : $2007 : 0x2CF4 //CONFIG2 : $2008 : 0x0700 #define Bavard //ac:pinout //ac:SQA_analyze // https://www.edaboard.com/threads/16f887-2-axis-joystick-drive-2-servomotors.394685/ // 2 axes joysticks drives 2 servos : // Servo motor control signals on RB0 and RB1 // Analogue inputs on RA0 and RA1 // MCU : PIC 16F887, internal fosc 4 MHz // Driving of 2 servomotors : // Timer2 drive State machine // one step to built the start pulse beginning at a minima of 1mS // the Timer1 elapsed time value comes from EA0 or EA1 to complete the total time SERVO ON // maxima is 2mS ! // - servomotor LOWER (360 ° turn) on PORTD.B0 (pin 19), // > Servomotor TOWER PRO MG995 (360 °), // - servomotor UPPER (180 °/270 ° turn) on PORTD.B1 (pin 20), // > Servomotor TOWER PRO MG996R (180 °/270 °), // global variables volatile unsigned int Consigne1=0; volatile unsigned int Consigne2=0; volatile unsigned int Value_Timer1 ; int Step=0; sbit Servo_Lower at PORTD.B0 ; sbit Servo_Upper at PORTD.B1 ; sbit Servo_Lower_dir at TRISD.B0 ; sbit Servo_Upper_dir at PORTD.B1 ; sbit SQA at PORTC.B3 ; sbit SQA_dir at TRISC.B3 ; int i,j,k; char CRam1[80]; char c1,cx; // void Toto_le_Rigolo() iv 0x0004 ics ICS_AUTO { //} void Interrupts() iv 0x0004 ics ICS_AUTO { //or //void interrupt () // OK //void Interrupt() // <- BAD if "Case sensitive" option is checkek for compiler ! //{ unsigned int TMR1_value; // temporary calculation value //TXREG='@'; // to test if interrupt fire if ((TMR2IE_bit) && (TMR2IF_bit)) { switch (Step) { case 0: // 1rst ms ON on Servo Lower SQA=1; Servo_Lower=1; Servo_Upper=0; TMR1ON_bit=0; TMR1IF_bit=0; TMR1IE_bit=0; Step++; break; case 1: Servo_Lower=1; Servo_Upper=0; // TON= 1ms + TMR1 time Value_Timer1= 65535-Consigne1; TMR1H= Value_Timer1>>8; TMR1L= Value_Timer1 & 0x00FF; TMR1IF_bit=0; TMR1IE_bit=1; TMR1ON_bit=1; Step++; break; case 2 : Servo_Lower=0; // 1rst ms ON on Servo UPPER Servo_Upper=1; TMR1IE_bit=0; TMR1ON_bit=0; TMR1IF_bit=0; Step++; break; case 3: Servo_Upper=1; // TON= 1ms + TMR1 time Servo_Lower=0; Value_Timer1= 65535-Consigne2; TMR1H= Value_Timer1>>8; TMR1L= Value_Timer1 & 0x00FF; TMR1IF_bit=0; TMR1IE_bit=1; TMR1ON_bit=1; Step++; break; case 4 : Servo_Lower=0; // 1rst ms ON on Servo UPPER Servo_Upper=0; TMR1IE_bit=0; TMR1ON_bit=0; TMR1IF_bit=0; SQA=0; Step++; break; case 19 : Step=0; break; default: Step++; break; } PR2 = 249; TMR2IF_bit = 0; } // ---------- TMR1 -------------------- if ( (TMR1IE_bit) && (TMR1IF_bit) ) { // handle timer 1 interrupt if (Step==2) Servo_Lower=0; if (Step==4) Servo_Upper=0; TMR1ON_bit=0; TMR1IE_bit=0; TMR1IF_bit = 0; } } void Init_Timer2() { // at Fosc=4MHz Actual Interrupt Time : 1 ms //Prescaler 1:1; Postscaler 1:4; TMR2 Preload = 249; T2CON = 0x1C; PR2 = 250; TMR2IE_bit = 1; INTCON = 0xC0; } //Timer1 at Fosc=4MHz //Prescaler 1:1; TMR1 Preload = 65036; Actual Interrupt Time : 500 us //Place/Copy this part in declaration section void Init_Timer1(){ T1CON = 0x01; TMR1IF_bit = 0; TMR1H = 0xFE; TMR1L = 0x0C; TMR1IE_bit = 0; INTCON= 0x00; } void CRLF1(void) { UART1_Write(13); UART1_Write(10); } void Print( char *T) { while(*(T)>0) { UART1_Write(*(T++)); } } void CPrint(const char *T1) { while(*(T1)>0) { UART1_Write(*(T1++)); } } void main() { #ifdef FOSC_INTERNE OSCCON=0; OSCCON.IRCF2=1; // 4MHz OSCCON.IRCF1=1; OSCCON.IRCF0=0; OSCCON.SCS=1; //OSCCON=0b01110001 ; // 8MHz (111) & SCS=1 (sinon 4 MHz par defaut) //OSCCON=0b01100001 ; // 4 MHz par defaut #endif ANSEL=0x03; TRISC = 0x00; TRISD = 0x00;t PORTC = 0x00; PORTD = 0x00; SQA_dir=0; SQA=0; ADC_Init(); UART1_Init(19200); // vider le registre de transmission if (UART1_Tx_Idle() == 1) UART1_Write(' '); CRLF1(); CPrint(" Compiler: MikroC 7.60 \r\n"); CPrint(" Directory : "Directory"\r\n"); CPrint(" Source : "Source"Version"Version"\r\n"); CPrint(" Test 2 servo , MCU" MCU" FOSC="FOSC"\r\n"); CPrint(" Servomotor LOWER 270° : TOWER PRO M996R (270°) \r\n"); CPrint(" Servomotor UPPER x360° : TOWER PRO MG995 (360°)\r\n"); CPrint(" Usage de Timer2 pour gerer une machine d'etat \r\n"); CRLF1(); Init_Timer1(); // sans interrupt PEIE_bit=1; GIE_bit=1; Init_Timer2(); // avec interrupt armée Step=0; // -------------- main loop --------------------------- while(1) { // consigne 0 à 1000µS + offset constant de 1ms généré par Timer2 // soit gamme de 1 à 2mS Consigne1 = ADC_Read(0); Consigne2 = ADC_Read(1); #ifdef Bavard CPrint(" Consigne1 Lower Servo :"); WordToStr(Consigne1 ,CRam1); Print(CRam1); CPrint(" Consigne2 Upper Servo :"); WordToStr(Consigne2 ,CRam1); Print(CRam1); CRLF1(); Delay_1sec(); // à modifier si besoin #else Delay_ms(20); #endif } } /* on terminal display Compiler: MikroC 7.60 Directory<NUL><SOH> Compiler: MikroC 7.60 Directory : C:\_MikroC\_MesProjets_MikroC\_16F877_2servomoteurs Source : Test_2_servo_16F887_using_State_Machine_TMR2_TMR1_2xEA_Version2020_0918 Test 2 servo , MCUP16F887 Dip40 FOSC=4Mhz Servomotor LOWER 270° : TOWER PRO M996R (270°) Servomotor UPPER x360° : TOWER PRO MG995 (360°) Usage de Timer2 pour gerer une machine d'etat Consigne1 Lower Servo : 164 Consigne2 Upper Servo : 167 Consigne1 Lower Servo : 167 Consigne2 Upper Servo : 167 Consigne1 Lower Servo : 183 Consigne2 Upper Servo : 182 Consigne1 Lower Servo : 170 Consigne2 Upper Servo : 172 Consigne1 Lower Servo : 163 Consigne2 Upper Servo : 165 Consigne1 Lower Servo : 172 Consigne2 Upper Servo : 168 Consigne1 Lower Servo : 183 Consigne2 Upper Servo : 183 */
Bonjour HexReader,You understand perfectly.
The compiler will not report a problem with Interrupt or interrupt case sensitivity turned on.
In C, myfunction, Myfunction and myfUNction are three completely different items when case sensitivity is on.
interrupt is recognised as an interrupt function - Interrupt is recognised as a valid function, but not as the special interrupt function.
I guess this may be why case sensitivity is turned off by default in mikroC, and why most mikroC users leave it turned off most of the time.
PWM1_high_time = ADC_Read(0)/4; // 0 = 0.5mS, 252 = 2.5mS
PWM2_high_time = ADC_Read(1)/4; // 0 = 0.5mS, 252 = 2.5mS
Thanks !Interrupt code would take a lot of explaining, sadly I do not have the patience, nor the teaching skills
If you just accept that the interrupt code works, then any adjustments that you might want to make are in these two lines:
Code:PWM1_high_time = ADC_Read(0)/4; // 0 = 0.5mS, 252 = 2.5mS PWM2_high_time = ADC_Read(1)/4; // 0 = 0.5mS, 252 = 2.5mS
Each line reads a number 0 to 1023 from ADC, then converts that number to 0 to 255 to control PWM pulse width.
If you do not want the full range 0.5ms to 2.5ms then manipulate the numbers to give - say...
.. set PWM1_high_time to values of 63 to 189 for 1ms to 2ms pulse width.
Not sure what it is that you want that is different to standard hobby servo.
maybe paulfjujo's code might suit you better? He is much better at understanding, explaining and teaching.
Thank you Paul for your availability !Hello Eric,
Does the program run OK ?
if not , what is the problem ?
What part of code needs more explanations ?
use personal MP to explain that, ( in French could be, better for us..)
or you can put here all your project in a zip
( *.cfg , *.mcpi, *.c, *.h ...) with your questions ..
Bonsoir Paul,Hello Eric,
Does the program run OK ?
if not , what is the problem ?
What part of code needs more explanations ?
use personal MP to explain that, ( in French could be, better for us..)
or you can put here all your project in a zip
( *.cfg , *.mcpi, *.c, *.h ...) with your questions ..