How to setup Eccp2 With a timer and ZeroCross.
I need to figure out how to open-close an output with comparison the timer and eecp2.
I need to make a motor to work from 25% up to 75%.
I have include Eccp2 and Timer1 and Ext_INT Libraries from mplab. I have set ECCP2 to compare timer1. Also Ext_Int to falling Edge in input INT0.
So the first thing in my main which i'm trying to do is to set interupt everytimer i get zerocross. I dont know if i explain it well...
I mean every time that the input in INT0 is in Ground.
INT0_SetInterruptHandler(ZeroCrossCallback);
Second i found a code which i dont know exactly what its doing...
void ZeroCrossCallback() {
if (!PORTBbits.INT0) {
TMR1_WriteTimer(0);
CCP2CONbits.CCP2M = 9;
EXT_INT0_risingEdgeSet();
} else {
CCP2CONbits.CCP2M = 0;
EXT_INT0_fallingEdgeSet();
}
}
And last I need to set my motor to work from 25% up to 75%
Img
Related
As a C beginner, I struggle alot to solve this problem of mine :
I am working on a project where I basicly have to program a PIC (microchip) in C using the mikroC platform.
What I'm trying to achieve is with only one switch/button, I'll have to switch from three different "modules" (as I call them "modules", they correspond to different lighting effects created by LEDs) depending on the time spent pressing the switch/button. In my case, after 500 ms module 1 is up, after 1500 ms module 2 goes up and after 3500 ms module 3 is up (and the whole thing has to be in an infinitely repeating loop since I have to be able to change a module at ANYTIME during the operation).
My only problem is getting the timer/clock to start runnning at the beginning of the program and keep counting time until it reaches a stop signal (like the end of a loop or something).
This may not be appropriate to ask to this community but here I am nonetheless.
I am concious that this is more of a 'algorithmics/logic' problem than anything but I have been trying for the last week without any clue on how to get past this problem...
No results since the code isn't ready at all.
There is a mikroC library for handling button presses. The following example (from the link.) provides a skeletal example of detecting a button push...
bit oldstate; // Old state flag
void main() {
ANSEL = 0; // Configure AN pins as digital I/O
ANSELH = 0;
C1ON_bit = 0; // Disable comparators
C2ON_bit = 0;
TRISB0_bit = 1; // set RB0 pin as input
TRISC = 0x00; // Configure PORTC as output
PORTC = 0xAA; // Initial PORTC value
oldstate = 0;
do {
if (Button(&PORTB, 0, 1, 1)) { // Detect logical one
oldstate = 1; // Update flag
}
if (oldstate && Button(&PORTB, 0, 1, 0)) { // Detect one-to-zero transition
PORTC = ~PORTC; // Invert PORTC
oldstate = 0; // Update flag
}
} while(1); // Endless loop
}
There is also a collection of MicroE Examples which include timer examples such as these, and this one. Each of these provide code base examples that might be adapted to create a function that can be wrapped around sections in the button press code to obtain time durations.
I hope this helps.
When the button gets pressed, you need to initialize timer module of respective microcontroller check the interrupt flag, and put it in a loop. increment the value until the button is released, and after that compare the resultant value with the specified limits, this was you can decide for how long a button is pressed, and consecutively you will be able to switch your output. This is the only way if you want to precisely monitor the delay without interrupting the current execution of the program.
Arduino drone project, whenever output is "loaded" ("open-circuit" signal-in pin to ESC or even a cap to ground), the input "steering" command starts to glitch (go to really low values << 1000).
The motor speed is a function of both the steering command, as well as the throttle. (In this test-case with just one motor as seen in the code below, unMotorSpeed = unThrottleIn +/- unSteeringIn)
When hooked up to a scope, the physical input signals (steering and throttle coming from the receiver) are great, and I even swapped the input pins to make sure there wasn't a problem between the receiver and the arduino. The problem seems to be coming from the software, but it just doesn't make sense, since when there isn't a "load" attached, the input and output values are all fine and clean. (I put "load" in quotes because sometimes it's essentially an open circuit --> super high impedance input signal to the electronic speed controller (ESC), which I don't even ground to complete a circuit).
Would anyone be able to check out the code and see if I'm missing something?
At this point, a somewhat quick workaround would be to simply not write those new glitchy values to the motor and keep the old speed values for whenever the new speed is significantly lower than the old speed (and these are at over 50khz, so clearly a huge jump in just one step is a bit crazy).
Note: In the code, the total output of unMotorSpeed leaves from the servoThrottle pin. Just the original naming that I didn't end up changing... it's clear if you read the code and see all the variables.
UPDATE: Weird thing is, I just ran my setup without any changes and EVERYTHING WORKED...I reflashed the arduino multiple times to make sure it wasn't some lucky glitch, and it kept on working, with everything set up. Then I dropped my remote on the ground and moved a few of the wires on the breadboard around, and things went back to their wonky ways after putting the setup back together. Idk what to do!
// --> starting code found at: rcarduino.blogspot.com
// See related posts -
// http://rcarduino.blogspot.co.uk/2012/01/how-to-read-rc-receiver-with.html
with.html
#include <Servo.h>
// Assign your channel in pins
#define THROTTLE_IN_PIN 3
#define STEERING_IN_PIN 2
// Assign your channel out pins
#define THROTTLE_OUT_PIN 9
//#define STEERING_OUT_PIN 9
// Servo objects generate the signals expected by Electronic Speed Controllers and Servos
// We will use the objects to output the signals we read in
// this example code provides a straight pass through of the signal with no custom processing
Servo servoThrottle;
//Servo servoSteering;
// These bit flags are set in bUpdateFlagsShared to indicate which
// channels have new signals
#define THROTTLE_FLAG 1
#define STEERING_FLAG 2
// holds the update flags defined above
volatile uint8_t bUpdateFlagsShared;
// shared variables are updated by the ISR and read by loop.
// In loop we immediatley take local copies so that the ISR can keep ownership of the
// shared ones. To access these in loop
// we first turn interrupts off with noInterrupts
// we take a copy to use in loop and the turn interrupts back on
// as quickly as possible, this ensures that we are always able to receive new signals
volatile uint16_t unThrottleInShared;
volatile uint16_t unSteeringInShared;
// These are used to record the rising edge of a pulse in the calcInput functions
// They do not need to be volatile as they are only used in the ISR. If we wanted
// to refer to these in loop and the ISR then they would need to be declared volatile
uint32_t ulThrottleStart;
uint32_t ulSteeringStart;
//uint32_t ulAuxStart;
void setup()
{
Serial.begin(9600);
// attach servo objects, these will generate the correct
// pulses for driving Electronic speed controllers, servos or other devices
// designed to interface directly with RC Receivers
servoThrottle.attach(THROTTLE_OUT_PIN);
// using the PinChangeInt library, attach the interrupts
// used to read the channels
attachInterrupt(digitalPinToInterrupt(THROTTLE_IN_PIN), calcThrottle,CHANGE);
attachInterrupt(digitalPinToInterrupt(STEERING_IN_PIN), calcSteering,CHANGE);
}
void loop()
{
// create local variables to hold a local copies of the channel inputs
// these are declared static so that thier values will be retained
// between calls to loop.
static uint16_t unThrottleIn;
static uint16_t unSteeringIn;
static uint16_t difference;
static uint16_t unMotorSpeed; // variable that stores overall motor speed
static uint8_t bUpdateFlags; // local copy of update flags
// check shared update flags to see if any channels have a new signal
if(bUpdateFlagsShared)
{
noInterrupts(); // turn interrupts off quickly while we take local copies of the shared variables
// take a local copy of which channels were updated in case we need to use this in the rest of loop
bUpdateFlags = bUpdateFlagsShared;
// in the current code, the shared values are always populated
// so we could copy them without testing the flags
// however in the future this could change, so lets
// only copy when the flags tell us we can.
if(bUpdateFlags & THROTTLE_FLAG)
{
unThrottleIn = unThrottleInShared;
}
if(bUpdateFlags & STEERING_FLAG)
{
unSteeringIn = unSteeringInShared;
}
// clear shared copy of updated flags as we have already taken the updates
// we still have a local copy if we need to use it in bUpdateFlags
bUpdateFlagsShared = 0;
interrupts(); // we have local copies of the inputs, so now we can turn interrupts back on
// as soon as interrupts are back on, we can no longer use the shared copies, the interrupt
// service routines own these and could update them at any time. During the update, the
// shared copies may contain junk. Luckily we have our local copies to work with :-)
}
//Serial.println(unSteeringIn);
// do any processing from here onwards
// only use the local values unAuxIn, unThrottleIn and unSteeringIn, the shared
// variables unAuxInShared, unThrottleInShared, unSteeringInShared are always owned by
// the interrupt routines and should not be used in loop
// the following code provides simple pass through
// this is a good initial test, the Arduino will pass through
// receiver input as if the Arduino is not there.
// This should be used to confirm the circuit and power
// before attempting any custom processing in a project.
// we are checking to see if the channel value has changed, this is indicated
// by the flags. For the simple pass through we don't really need this check,
// but for a more complex project where a new signal requires significant processing
// this allows us to only calculate new values when we have new inputs, rather than
// on every cycle.
///// if-else chain commented out to determine/prove problem with steering signal --> buggy!
if(unSteeringIn < 1400) // if steering joystick moved left
{
difference = 1400 - unSteeringIn;
if(unThrottleIn - difference >= 0)
unMotorSpeed = unThrottleIn - difference;
}
else if(unSteeringIn > 1550) //if steering joystick moved right (needs to be tweaked, but works for now)
{
difference = unSteeringIn - 1600;
if(unThrottleIn + difference < 2000)
unMotorSpeed = unThrottleIn + difference;
}
else
{
unMotorSpeed = unThrottleIn;
}
//Serial.println(unMotorSpeed);
//Serial.println(unSteeringIn);
//Serial.println(unThrottleIn);
if(bUpdateFlags)
{
//Serial.println(servoThrottle.readMicroseconds());
if(servoThrottle.readMicroseconds() != unMotorSpeed)
{
servoThrottle.writeMicroseconds(unMotorSpeed);
Serial.println(unMotorSpeed);
}
}
bUpdateFlags = 0;
}
// simple interrupt service routine
void calcThrottle()
{
// if the pin is high, its a rising edge of the signal pulse, so lets record its value
if(digitalRead(THROTTLE_IN_PIN) == HIGH)
{
ulThrottleStart = micros();
}
else
{
// else it must be a falling edge, so lets get the time and subtract the time of the rising edge
// this gives use the time between the rising and falling edges i.e. the pulse duration.
unThrottleInShared = (uint16_t)(micros() - ulThrottleStart); // pulse duration
// use set the throttle flag to indicate that a new throttle signal has been received
bUpdateFlagsShared |= THROTTLE_FLAG;
}
}
void calcSteering()
{
if(digitalRead(STEERING_IN_PIN) == HIGH)
{
ulSteeringStart = micros();
}
else
{
unSteeringInShared = (uint16_t)(micros() - ulSteeringStart); // pulse duration
bUpdateFlagsShared |= STEERING_FLAG;
}
}
You should read the documentation of AttachInterrupt() - in the section "About Interrupt Service Routines" it gives information on how certain functions behave when called from an interrupt. For micros() it states:
micros() works initially, but will start behaving erratically after 1-2 ms.
I believe that means after the ISR has been running for more than 1ms, rather than just 1 ms in general, so may not apply in this case, but you might need to consider how you are doing the timing in the ISR. That's a problem with Arduino - terrible documentation!
One definite problem which may be a cause is the fact that unSteeringInShared is non-atomic. It is a 16 bit value on 8 bit hardware so requires multiple instructions to read and write and the process can be interrupted. It is therefore possible to read one byte of the value in the loop() context and then have both bytes changed by the interrupt context before you read the second byte, so you then up with two halves of two different values.
To resolve this problem you could either disable interrupts while reading:
noInterrupts() ;
unSteeringIn = unSteeringInShared ;
interrupts() ;
Or you can spin-lock the read:
do
{
unSteeringIn = unSteeringInShared ;
} while( unSteeringIn != unSteeringInShared ) ;
You should do the same for unThrottleInShared too, although why you do not see any problem with that is unclear - this is perhaps not the problem you are currently observing, but is definitely a problem in any case.
Alternatively if 8 bit resolution is sufficient you could encode the input as an atomic 8 bit value thus:
uint8_t unSteeringInShared ;
...
int32_t timeus = micros() - ulSteeringStart - 1000 ;
if( timeus < 0 )
{
unSteeringInShared = 0 ;
}
else if( timeus > 1000 )
{
unSteeringInShared = 255;
}
else
{
unSteeringInShared = (uint8_t)(time * 255 / 1000) ;
}
Of course changing your scale from 1000 to 2000 to 0 to 255 will need changes to the rest of the code. For example to convert a value x in the range 0 to 255 to a a servo pulse width:
pulsew = (x * 1000 / 256) + 1000 ;
I am trying to get an Arduino UNO to read a 64cpr quadrature encoder. I specifically want to use Timer1 to measure of the frequency (and hence speed) of one of the encoder signals.
I ultimately want to store 10 measurements in an array to compute a moving average filter, but one thing at a time. I first need to be able to measure the clock cycles between two rising edges.
Here's what I've got so far. Any help or comments are appreciated:
#include <avr/io.h>
#include <avr/interrupt.h>
const int inputCapture = 8;
void setup(){
sei();
TCNT1 = 0;
TCCR1B = (1<<CS10)|(1<<ICES1); // No prescaling
TIFR1 = 1<<ICF1;
pinMode(inputCapture, INPUT);
Serial.begin(9600);
}
ISR(TIMER1_CAPT1_vect){
thisStep = ICR1;
TCNT1 = 0;
}
void loop(){
Serial.println(thisStep);
}
Right now I'm not even jumping into the ISR, which I don't understand. I think I have set everything up correctly. Interrupts are enabled. ICES1 should default to 0, or falling edge trigger, which is fine (just want to measure one period). I'm picking a pin on port B to receive the (input) signal, which should be fine. From Atmel's documentation, I think Timer1 is connected.
Any thoughts? Thanks in advance!
(I'll gladly post code if someone can point out how to paste it in here without using the 4 space indentation system that doesn't work)
Hello folks
After ~9Hours racking by brains, I can't find an answer or find where my calculations are going wrong... but they are.
I have a circuit built using a microchip 18F2550 microcontroller.
I am using this circuit to measure the delay between 2 signals and am using the 2 CCP registers in capture mode.
This all works and the result is sent to the PC (over USB serial) all dandy, but the results are wrong.
I have to apply a gain of ~16000 to any results to get somewhere near the delay presented to the pins.
I have the delay set in the line
Timer1 is set as an internal
Timer3 is disabled
relevant interrupts are enabled
and the main routine runs continuously.
When I get a rising edge detection on the CCP1 pin, the interrupt is configured to reset timer1 to zero as well as the overflow counter
#INT_CCP1
void ccp1_isr() // Captures the rising edge of CCP1 pin.
{
if(timing==FALSE){ // only do this on the edge, any bouncing will reset timers etc.
set_timer1(0);
T1_Overflow = 0;
Pulse_Time = 0;
timing = 1; // Set flag to indicate timing.
output_high(BLUE_LED);
}
}
the timing flag ensures the times cannot be reset by another pulse on the CCP1 pin.
Timer1 should then be reset and start counting as normal. Every time it rolls around by 65535 (16bit device) another interrupt is fired after which the amount of overflows are incremented.
#INT_TIMER1
void isr()
{
T1_Overflow++;
}
Finally, when the input pin on CCP2 goes high, the CCP_2 interrupt is triggered. This captures the value of the CCP register (which is the value of Timer0 at the time the interrupt was fired) and the overflow register.
#INT_CCP2
void ccp2_isr()
{
if(timing == TRUE){ // only output this when preceded by CCP1
if(Count_Done == FALSE) // do this once only
{
Count_Done = TRUE; // and also flag to the main routine to output data to the terminal.
Pulse_time = CCP_2;
Pulse_Overflow = T1_Overflow;
measureCount++; // increment the number of measures.
}
output_low(BLUE_LED);
timing = FALSE;
}
}
CCP1 can now start responding to the inputs again.
The idea of this is that every time I get a pulse of one input at CCP1 followed by CCP2, a string is sent to the terminal with a counter, the number of overflows and the time left in the timer.
while(TRUE) // do forever while connected
{
usb_task(); // keep usb alive
if(Count_Done == TRUE)
{
printf(usb_cdc_putc, "%lu , %lu , %lu \r\n",measureCount, pulse_time, pulse_overflow);
Count_Done = FALSE;
}
so, I should get an output to the terminal of something like "1,61553,35" for a ~12ms delay between CCP1 and CCP2.
The problem is that these are the results I am getting for a 200ms pulse provided to the circuit. (Verified twice)
so where am I going wrong.
I have a 48MHZ Clock with no prescaler which implies a cycle every 20ns.
Divide by for 4 instructions per cycle for the clock which implies 5.2ns every cycle
16 bit timer which implies rollover every 65535*5.2ns = 341us per rollover.
when you do the calculations (0.000341*pulse_overflow)+pulse_time*(5.2*(10^-9))
then the above data gives 0012.27ms and not the 200ms provided.
Can anyone point out where I am going wrong with these calculations???
Your error is in "Divide by for 4 instructions per cycle for the clock which implies 5.2ns every cycle"
The counter ticks once every 4 cycles, not 4 times per cycle. So, the correct calculations are:
2.08333E-08 s/cycle of osc
8.33333E-08 s/tick of timer
0.005461333 s/rollover
You are off by a factor of 16.
I have problems with successful pic programming work.. As i'm new in pic programming i started with lighting up 8-segment display LED one by one. Everything went well except RB4 output LED didn't light up (its not broken because i checked it with 5v through resistor). I thought its a problem but not so major so i went on. Next aim was to light up all segments of display right up after stratup with code:
#include <htc.h>
void main()
{
TRISB=0X00;
PORTB=0X00;
TRISA = 1;
while(1)
{
PORTB=0XFF;
}
}
This wasn't successful - only 2 segments light up in startup and then immediately disappeared and then none of LED lighted up afterwards.
I went even further after that problem - i wanted to turn on output when switch is pressed (High Input) and another time it was unsuccessful. RB7 LED was on all the time. Switch pressing didn't do anything. Code :
#include <htc.h>
void main()
{
TRISB=0X00;
PORTB=0X00;
TRISA = 1;
while(1)
{
if (RA4 == 1) //Even tried TRISA4 ==1 //RB0 Dont light up, RB7 do light up all the time
{
RB0 = 1;
}
else
{
RB7 = 1;
}
}
}
Can somebody please tell why i have these problems? Any solutions?
Btw - fuses were : WDT OFF, BODEN ON, MCLRE OFF, Code protect OFF, PWRTE OFF, LVP ON, CPD OFF
Im using K150 PIC Programmer
1 : PIC pins
2 : Circuit
I don't know what's going on with the first snippet. The second one fails because
TRISA = 1
sets only RA0 as input. The rest of A pins (including RA4) are still output. You need something like
TRISA = 0x10;
RB4 is influenced by LVP. In the "CONFIG – CONFIGURATION WORD REGISTER":
LVP: Low-Voltage Programming Enable bit
1 = RB4/PGM pin has PGM function, low-voltage programming enabled
0 = RB4/PGM is digital I/O, HV on MCLR must be used for programming
which I'm guessing is why RB4 did not light up.
Reading RA4, clearly you need to set TRISA4. Though I think it's in that state at power-up. RA4's full name is RA4/T0CKI/CMP2. At power-up the T0CS bit of the OPTION register is '1', which is:
T0CS: TMR0 Clock Source Select bit
1 = Transition on RA4/T0CKI/CMP2 pin
0 = Internal instruction cycle clock (CLKOUT)
so clearing that might help.
The comparator stuff seems to wake up with the CMCON register all zeros, which puts CM2=CM1=CM0=0, which is "reset". It's not clear to me how that affects RA4. But it might be worth setting the comparators "off", ie CM2=CM1=CM0=1.
As far as the other effects you are seeing are concerned, I dunno :-( It would be interesting to see what the little fragments of code compile to.