View previous topic :: View next topic |
Author |
Message |
BLL
Joined: 11 Nov 2006 Posts: 181 Location: Birmingham, UK
|
|
Posted: Fri Feb 21, 2020 3:33 am |
|
|
Hi both
I did not know about the 400 Hz mode - my googling always talked about the 20ms gap. I have looked at your example. I would need to use timer1 as the 1840 doesn't have a timer3 and, as you say, tickle the values for my clock frequency.
Thanks again for the help.
Brian |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19589
|
|
Posted: Fri Feb 21, 2020 3:43 am |
|
|
Yes, your chip uses Timer1 for the CCP.
Use 400Hz mode. Seriously every modern RC uses this. If it doesn't work
you can go slower, but the servo will run better (smoother, faster updates,
and often give more torque), with the faster updates. This is the
required rate for 'digital servos'. |
|
|
BLL
Joined: 11 Nov 2006 Posts: 181 Location: Birmingham, UK
|
|
Posted: Fri Feb 21, 2020 5:19 am |
|
|
Hi Ttelmah
I have now reworked your example to use timer1 for the CCP and timer2 for the off time and using 400Hz. It is a miniature digital servo I am using, mainly because I can program its speed. It needs to run slowly between the 2 pulse values of 33% and 59%.
Unfortunately, I am not at home until April, so I can't program the PIC and try it until then!
Thanks again for your help - I have learned a lot!
Brian |
|
|
BLL
Joined: 11 Nov 2006 Posts: 181 Location: Birmingham, UK
|
|
Posted: Fri Apr 10, 2020 2:28 pm |
|
|
Hi all,
Now back at home, I have been playing with the 1840 to drive the servo and, hey, it works perfectly!
Now to the next problem:
The 1840 must also flash a pair of leds as an aircraft strobe.
Up to this point, I have done this in the for loop within main. This works, but any other polling of inputs has to wait until the current strobe cycle has finished.
Here is the code I used in the for loop within main:
Code: |
output_low(Strobes);
delay_ms(150);
output_high(Strobes);
delay_ms(150);
output_low(Strobes);
delay_ms(150);
output_high(Strobes);
delay_ms(1000);
|
I then had the idea to use timer0. At 16 MHz and setup_timer_0(T0_INTERNAL|T0_DIV_256);
This should overflow every 16 and a bit us, so a delay of 150 ms needs about 9 overflows and 1000 ms needs about 61.
So my interrupt function looks like this:
Code: |
#INT_TIMER0
void delay_pulse(void)
{
delay_counter++;
if(delay_1 == true)
{
if(delay_counter >= 9 && get_timer0() == 254)
{
delay_counter = 0;
delay_1 = false;
delay_2 = true;
output_high(Strobes);
set_timer0(254);
return;
}
}
if(delay_2 == true)
{
if(delay_counter >= 9 && get_timer0() == 254)
{
delay_counter = 0;
output_low(Strobes);
delay_2 = false;
delay_3 = true;
set_timer0(254);
return;
}
}
if(delay_3 == true)
{
if(delay_counter >= 9 && get_timer0() == 254)
{
delay_counter = 0;
output_high(Strobes);
delay_3 = false;
delay_4 = true;
set_timer0(254);
return;
}
}
if(delay_4 == true)
{
if(delay_counter >= 61 && get_timer0() == 254)
{
delay_counter = 0;
output_high(Strobes);
delay_4 = false;
set_timer0(254);
return;
}
}
} |
It is called from within the main loop by:
Code: |
if(LPulseCount < 650) //when strobe switch selected on transmitter
{
delay_counter = 0;
output_low(Strobes);
enable_interrupts(INT_TIMER0);
enable_interrupts(GLOBAL); |
At this point, only delay_1 is true; the rest are false.
It appears as thought the interrupt function is not being called at all.
I thought I now understood timers, but obviously not!!
The LEDs come on and stay on.
Can anyone shed light on my failings please?
Thanks
Brian |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Apr 10, 2020 8:21 pm |
|
|
The following program will interrupt at approximately a 150ms interval. Code: |
#include <12F1840.h>
#use delay(internal=16M)
#define LED_PIN PIN_A2
#int_timer0
void t0_isr(void)
{
static int8 count = 0;
count++;
if(count == 9)
{
count = 0;
output_toggle(LED_PIN);
}
}
//=========================
void main(void)
{
output_low(LED_PIN);
setup_timer_0(T0_INTERNAL | T0_DIV_256);
clear_interrupt(INT_TIMER0);
enable_interrupts(INT_TIMER0);
enable_interrupts(GLOBAL);
while(TRUE);
} |
|
|
|
BLL
Joined: 11 Nov 2006 Posts: 181 Location: Birmingham, UK
|
|
Posted: Sat Apr 11, 2020 7:05 am |
|
|
Hi PCM Programmer
Thank you for your sample code. As expected, it works fine.
In order to get the double flash, followed by a long pause, I have modified the code as follows:
Code: |
#INT_TIMER0
void t0_isr(void)
{
count++;
//end of a cycle
if(count >= 75)
{
count = 0;
output_low(Strobes);
return;
}
// toggle state every 160 ms approx
if(count == 9 || count == 18 || count == 27)
output_toggle(Strobes);
}
|
I then notice some irregularities in the LED flashing. Within this PIC, I am also using timer1 and 2 to control a servo, so I don't know if this might be the cause of the problem.
I am turning on/off the strobes by enabling/disabling INT0.
It appears not to be possible to prioritise interrupts, as on PIC18 devices.
Any suggestions please?
Thanks again for your help.
Brian |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9269 Location: Greensville,Ontario
|
|
Posted: Sat Apr 11, 2020 8:59 am |
|
|
Couple of comments.....
Could you use just one timer as the 'main heartbeat' ? Within the ISR have a counter for RC servo position and another for strobes ?
There's a SW RTC in the code library that uses this approach for 'time'.
http://www.ccsinfo.com/forum/viewtopic.php?t=26177
A lot depends on what else the PIC has to do. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Apr 11, 2020 10:56 am |
|
|
You could do it like temtronic says, or you could do it like I have below.
It's better just to lay everything out. It's easier to understand.
Code: |
#include <12F1840.h>
#use delay(internal=16M)
#define LED_PIN PIN_A2
#define LED_DELAY 9 // 9 * 16.384 = 147.5 ms
// 256/9 = 28.44 so allowable max count = 28
int8 count = 0;
// One interrupt every 16.384 ms.
#int_timer0
void t0_isr(void)
{
count++;
if(count == LED_DELAY) output_high(LED_PIN);
if(count == 2 * LED_DELAY) output_low(LED_PIN);
if(count == 3 * LED_DELAY) output_high(LED_PIN);
if(count == 4 * LED_DELAY) output_low(LED_PIN);
if(count == 10 * LED_DELAY) count = 0;
// 10-4 = 6. (6 +1) * 147.5ms = 1032 ms between LED blink intervals
}
//=========================
void main(void)
{
output_low(LED_PIN);
setup_timer_0(T0_INTERNAL | T0_DIV_256);
clear_interrupt(INT_TIMER0);
enable_interrupts(INT_TIMER0);
enable_interrupts(GLOBAL);
while(TRUE);
} |
|
|
|
BLL
Joined: 11 Nov 2006 Posts: 181 Location: Birmingham, UK
|
|
Posted: Sat Apr 11, 2020 11:04 am |
|
|
What a clever idea - I hadn't thought of that.
I have now binned timer0 and controlled the strobes from inside timer1.
It's simple and works brilliantly!
Thank you so much for your suggestion.
Brian |
|
|
|