I have written code that makes LEDs blinks and moves a servo to several different directions. Here's the basic structure:
while(true){
//led on
//wait
//led off
//wait
}
while(true){
//servo to 45
//servo to 90
//servo to 270
}
I want both to run at the same time. The code above only turns on the LEDs, and infinitely since it's in the loop. The servo never works. I looked at other questions on here but I couldn't find anything relevant.
How can I make both the LEDs and servo work at the same time?
In general you cannot use two infinite loops. That's because it is senquentional program, so it cannot run second when until the first one is done. So if first loop is infinite, the second will never run.
To do some kind of 'multithreading', in simplest way is to use timers and interrupts.
In your case you want to run two different task. Blinking led and steering servos. When you use wait()/sleep()/delay(), the uC is simply stopping (except handling other things like interupts etc.). So you can set timers and in the interrupt blink led. Or better in the interrupt just set some flag, and in your main just check if flag has changed. Than just handle blink. So in general you will have in you main sth like this:
volatile uint8_t nowBlink = 0
ISR(TIMER1_OVF_vect)
{
// some timer handling and then:
nowBlink = 1
}
loop(){
if(nowBlink){
toggleLed();
nowBlink = 0;
}
setServo(123123);
}
Setting intterupt to 1 s, will blink your led with freq of 1 Hz, and then other parts of program will be done.
Here you have timers explained, and Here you have some libraries. Just read that and you should be master of arduino.
Best regards, voodoo16.
Don't use functions like delay_ms(), wait () etc. Try interrupt.
Use the struture like this :
int flag = 0;
void func_delay_50ms () interrupt
{
// set initial condition
flag ++;
}
void main
{
while (1)
{
if (flag == 4) // per 200ms
{
led = -led;
flag = 0;
}
if (!(flag % 2)) // per 100ms
{
servo ();
}
}
}
note : servo () should not block for a long time.
There are no really conturrent threads, And you should create an illusion to realize it.
(:з」∠) My poor English. pardon me.
Blinking a LED does not really require code on the MCU. You can use a timer and a PWM signal. https://www.arduino.cc/en/Tutorial/SecretsOfArduinoPWM
I wrote an Operating System for Arduino which supports multithreading in order to run multiple loops at once. Note that the servo has a range from 0-180. You can't turn in 270 degrees. You can find the source and further documentation here https://github.com/DrBubble/ArduinoOS.
This example code should do exactly what you want when running under the ArduinoOS.
#include "KernelInitializer.h"
#include "Servo.h"
#include "Led.h"
void setup()
{
KernelInitializer::InitializeKernel(mainThread);
}
void mainThread()
{
InitTask(secondThread);
while (true)
{
Led led(2); // replace 2 with the pin of your led
while (true)
{
led.TurnOn();
sleep(1000);
led.TurnOff();
sleep(1000);
}
}
}
void secondThread()
{
Servo servo(9); // replace 9 with the pin of your servo
while (true)
{
servo.SetValue(45);
sleep(1000);
servo.SetValue(90);
sleep(1000);
servo.SetValue(180);
sleep(1000);
}
}
You can simply use a goto statement
in both the loop.....you dont even need a loop if you use goto, like in assembly language.
c code for it is:
#include<stdio.h>
int main()
{
int count;
loop1:for(;;)
{
printf("Loop 1\n");
goto loop2;
}
loop2:for(;;)
{
printf("Loop 2\n");
goto loop1;
}
return 0;
}
Related
I would like to measure a pulse using the pic 18f4550 in capture mode, this pulse is generated by the pic microcontroller itself, for this I use a function which plays the role of the XOR logic gate (you find the function that I've used below). with RC0 and RC2 the inputs and RC6 the signal output. the pulse leaving RC6 enters ccp2 to be measured.
The problem I found is that the ccp2 cannot detect the impulse generated by the microcontroller. I don't know if there are any conditions to connect the pins of the microcontroller or something.
If anyone has an answer or a hint to fix this, I will be grateful!
and if you have any questions feel free to ask .thanks !!
UPDATE: I changed some instructions in the code, now the RC6 output provides a signal. but my LCD does not display anything. the RC6 output is present below.
UPDATE 2: the while(1) in the xor() function blocking the rest of my program, so the program never get out of xor() and my LCD wont display anything. when I don't use the while loop in xor () my RC6 produce anything, the same for the LCD.
I don't know where the problem is, I did everything in my power to find the bug . but the system still not working!!!
I will leave the program as it is, so new readers can understand what I am talking about.
#include <stdio.h>
#include <stdlib.h>
#include "osc_config.h"
#include "LCD_8bit_file.h"
#include <string.h>
unsigned long comtage,capt0,x;
char pulse[20];
char cosinus[20];
float period,dephTempo,deph,phi;
void init (){
IRCF0 =1; /* set internal clock to 8MHz */
IRCF1 =1;
IRCF2 =1;
PIE2bits.CCP2IE=1;
PIR2bits.CCP2IF=0;
CCPR2 =0; /*CCPR1 is capture count Register which is cleared initially*/
T3CONbits.RD16=1;
T3CKPS0=0;
T3CKPS1=0;
TMR3CS=0;
TMR3IF=0;
T3CCP2=0; /*Timer3 is the capture clock source for CCP2*/
}
void xor()
{
while(1)
{
if (PORTCbits.RC0==PORTCbits.RC2)
{
PORTCbits.RC6=0;
}
else if (PORTCbits.RC0!=PORTCbits.RC2)
{
PORTCbits.RC6=1;
}
}
}
void main()
{
TRISCbits.TRISC0=1;
TRISCbits.TRISC2=1;
TRISCbits.TRISC6=0;
xor();
LCD_Init();
while(1)
{
CCP2CON = 0b00000101;
PIR2bits.CCP2IF = 0;
TMR3ON = 0;
TMR3 = 0;
while (!PIR2bits.CCP2IF);
TMR3ON = 1;
CCP2CON = 0b00000100;
PIR2bits.CCP2IF = 0;
while (!PIR2bits.CCP2IF);
comtage = CCPR2;
dephTempo = (((float)comtage /30.518)/65536 );
sprintf(pulse,"%.3f ",dephTempo);
LCD_String_xy(0,0,"the pulse width is : ");
LCD_String_xy(2,9,pulse);
}
}
I have 2 questions.
The first: I have a problem in the behavior of this code; when I run it in Proteus the program make flasher "repeat the code in the main function"
what should I do?
This is the code:
#include <p18f452.h>
#include <delays.h>
#include <io.h>
void main ()
{
TRISC=0x00;
PORTC=0xff;
Delay1KTCYx(900);
PORTC=0x00;
Delay1KTCYx(900);
while(1)
{
}
}
The second question: what is the proper delay function I can use? and how can I measure the delay time?
Is the watchdog disabled in simulation ? If it is enabled it will cause the repetition of the program.
Try adding this line after the includes.
#pragma config WDT = OFF
You only have code to generate one flash. Move the flash and delays into the loop:
for(;;)
{
PORTC = 0xff;
Delay1KTCYx(900);
PORTC = 0x00;
Delay1KTCYx(900);
}
Measuring roughly can be made manually by timing N flashes with a stopwatch. It's of course easier to use a measurement intrument (an oscilloscope is nice for this) if you have it.
Also, since your duty cycle is 50%, you can simplify the code:
PORTC = 0;
for (;;)
{
PORTC = ~PORTC;
Delay1KTCYx(900);
}
This uses bitwise not (~) to invert the bits of PORTC, which will make them toggle from one to zero and vice versa. Setting the entire port to 0 before the loop makes sure all pins are at a known state.
i am currently doing a prototype which combine 2 sensors, the PIR motion sensor by cytron.
and a photodiode (tiny, with 3 legs, with the model unknown)
The prototype works in a way that, when there is no light, and there is motion, the led will turn on.
Else, it will turn off.
I have wrote codes to test the both sensors separately, it works quite fine.
I face problem of the output of led when i combine the 2 codes.
It is as shown in below:
// include
//==========================================================================
# include <pic.h>
# include <htc.h>
// configuration
//==========================================================================
__CONFIG (0x3F32);
// define
//==========================================================================
#define sensor RB3
#define led RA5
#define led2 RB7
#define light RB5
#define _XTAL_FREQ 4000000
#define delay ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))
// main function
//==========================================================================
void main(void)
{
// unsigned long delay_time=5000;
TRISA = 0b00000000;
TRISB = 0b01111111; //Configure Port B as Input
ADCON1 =0B00000110;
led=0;
led2=0;
int i;
while(1) //Infinity Loop
{
if(!light)
{
if(sensor)
{
for(i=5;i>0;i--)
{
led2=0;
led=1;
__delay_ms(10000);
}
}
else if(!sensor)
{
if (i>0)
{ for(i=5;i>0;i--)
{
led2=0;
led=1;
__delay_ms(10000);
}
}
else if(i<=0)
{
led=0;
led2=1;
}
}
}
else if(light)
{
led=0;
led2=1;
}
}
}
I appreciate your help in advance.
Please help.
Thank you.
You declare the variable i but then don't initialize it to a value (I don't think the C compiler initializes it to 0 either, I am not sure). If that was not the case, then imagine the following scenario:, that in the the very first beginning of execution:
it was (!light) and (!sensor), it starts comparing i>0 or i<=0 but what is i initially??
you only assume that the if (sensor) body has executed at least once to give i an initial value. I don't know the details of your program requirements or flow, but I see this as an unsafe and a hidden bug.
While I'm no expert at the PIC micro's I wonder whether the method you are using to access the RAx and RBx is the appropriate one i.e. "led = 0", rather than "led &= ~(1 << led)" or something in like that.
You also seem to not initialize the "int i" variable which I assume would lead to issues with the if statements.
Best regards.
How about something like:
while (1)
{
led_on = 0;
if (!light && !sensor)
{
if (led_on == 0)
{
/* Turn on LED... */
led_on = 1;
}
}
else if (led_on == 1)
{
/* Turn off LED... */
led_on = 0;
}
}
when I was working on pic24 family using assembly language if I needed to assign 2 ports consecutively it turned out that the second assignment would not work(unless you are using tristate buffers...I don't know the exact reason but that was the case...).Anyway...what I'm trying to say is that try to give a few mseconds delay after each led value assignments like:
for(i=5;i>0;i--)
{
led2=0;
_delay_ms(50);
led=1;
__delay_ms(10000);
}
So I did this code for Arduino in C. It is for controlling a stepper motor. But every time I have to wait until the microcontroller begins a new loop so that it can take the value for the new variables, how can I create an interrupt so it will do it in any time of the program?
#include <avr/io.h>
#define F_CPU 4000000UL
#include <util/delay.h>
#include "IO/ioconfig.h"
#include "leebotones/leebotonesA.h"
#include "leebotones/leebotonesB.h"
#include "rutina/avanza.h"
#include "rutina/retrocede.h"
char variableA = 0;
char variableB = 0;
int main(void){
ioconfig();
while(1) {
if (leebotonesA()==1) {
variableA++;
} //Fin de if leebotonesA.
if (leebotonesB()==1) {
if (variableA==0) {
variableB=1;
}
else {
variableB=0;
}
}
if (variableA==2) {
variableA=0;
PORTD=0x00;
_delay_ms(10000);
} //Fin de if variableA.
if (variableA==1 && variableB==0) {
avanza();
} //Fin de if leebotonesA.
if (variableA==1 && variableB==1) {
retrocede();
}
_delay_ms(25);
}//End of while
}// End of main
A hardware interrupt on the Arduino occurs when one of the interrupt pins receives a change of state. The function to use, if you have access to the Arduino library, is attachInterrupt.
Example code to listen for an interrupt (derived from the documentation I linked to, I added comments to help explain):
// The Arduino has an LED configured at pin 13
int pin = 13;
// Holds the current state of the LED to handle toggling
volatile int state = LOW;
void setup()
{
pinMode(pin, OUTPUT);
// First Parameter:
// 0 references the interrupt number. On the Duemilanove, interrupt 0
// corresponds to digital pin 2 and interrupt 1 corresponds to digital pin
// 3. There are only two interrupt pins for the Duemilanove and I believe
// the Uno too.
// Second Parameter:
// blink is the name of the function to call when an interrupt is detected
// Third Parameter:
// CHANGE is the event that occurs on that pin. CHANGE implies the pin
// changed values. There is also LOW, RISING, and FALLING.
attachInterrupt(0, blink, CHANGE);
}
void loop()
{
// Turns the LED on or off depending on the state
digitalWrite(pin, state);
}
void blink()
{
// Toggles the state
state = !state;
}
There is also a concept of Pin Change Interrupts that is supported on every pin. See the bottom part of introduction to interrupts for more info.
However, sometimes a hardware interrupt can be avoided by refactoring your code. For example, keep your loop() running quickly --- mostly just reading inputs, limit the use of delay() --- and in the loop, call a function when the targeted inputted value is detected.
MSTimer2 is an Arduino library function to let you set timer interrupts.
Another alternative to delay, rather than interrupts, is to set a timer and check it each time through the loop. http://arduino.cc/en/Tutorial/BlinkWithoutDelay explains the concepts. The Metro library http://arduino.cc/playground/Code/Metro implements this and is easy to use. I've used it instead of delay() so that I can check for a button push while my robot is moving.
Please help me with this code, it is making me crazy. This is a very simple program with 8-bit timer, cycling through all 8 leds (one-by-one). Am using ATSTK600 board.
My timers are working well, I think there is some problem with the loops (when I debug this program using avr studio-gcc, I can see all the leds working as I want but when I transfer it on board...leds don't blink). Am going crazy with this type of behavior.
Here is my code:
#include <avr/io.h>
#include <avr/interrupt.h>
volatile unsigned int intrs, i, j = 0;
void enable_ports(void);
void delay(void);
extern void __vector_23 (void) __attribute__ ((interrupt));
void enable_ports()
{
DDRB = 0xff;
TCCR0B = 0x03;
TIMSK0 = 0x01;
//TIFR0 = 0x01;
TCNT0 = 0x00;
//OCR0A = 61;
intrs = 0;
}
void __vector_23 (void)
{
for(i = 0; i<=8; i++)
{
while(1)
{
intrs++;
if(intrs >= 61)
{
PORTB = (0xff<<i);
intrs = 0;
break;
}
}
}
PORTB = 0xff;
}
int main(void)
{
enable_ports();
sei();
while(1)
{
}
}
Your interrupt routine is flawed. intrs counts only the number of times the loop has executed, not the number of timer interrupts as its name suggests. 61 iterations of that loop will take very little time. You will see nothing perceivable without an oscilloscope.
The following may be closer to what you need:
void __vector_23 (void)
{
intrs++;
if(intrs > 60)
{
intrs = 0;
PORTB = (0xff<<i);
i++ ;
if(i == 8 )
{
i = 0 ;
PORTB = 0xff;
}
}
}
Although setting the compare register OCR0A to 61 as in your commented out code would avoid the need for the interrupt counter and reduce unnecessary software overhead.
Are you sure that the code downloaded to the board is not optimized?
Have you attached volatile attribute to the PORTB identifier?
Is there a way for you to slow down the code (outside the debugger)? Any chance it's running but fast that you don't see it?
Can you verify that your intended code is in fact running (outside the debugger)?
When interrupt occurs, handler very quickly counts 62*9 times and finally sets PORTB to 0x00, so leds do only very short flash which is not visible. You see it in sumulator just because it runs slower and do not emulate visual dimming effect of fast port switching. Program has a design flaw: it tries to do full blinking cycle in single interrupt. That's wrong--only a single step should be performed in interrupt call. So handler should look like this:
void __vector_23 (void)
{
intrs++;
if(intrs >= 61)
{
PORTB = (0xff<<i);
intrs = 0;
i++;
if(i>8) i = 0;
}
}
Try this.
There is guidelin on interrupts handlers: Interrupt handler should be as fast and short as possible. Do not perform complex tasks in interrupts (cycle loop is one of them, if you get cycle in interrupt, try to remove it). Do not wait or delay in interrupts.
If you're seeing the behaviour you want when debugging with avr studio-gcc, then that gives you some confidence that your program is "good" (for some sense of the word "good"). So it sounds as though you need to focus on a different area: what is the difference between your debug environment and your stand-alone download?
When doing a stand-alone download, do you know if your program is running at all?
Are the LEDs blinking, or turning on at all? You don't explicitly say in your question, but that question could be very relevant to the debugging process. Does it look like the right behaviour, running at a different speed? If so, then your program is probably not doing some sort of initialisation that the debugger was doing.
When doing a stand-alone download, is the program being compiled with different settings compared to the debug version? Perhaps compiler optimisation settings are changing your program's timing characteristics.
(Your question would be better if you gave more detail about what the stand-alone download is doing. In general, it is hard for someone to debug a remote system when they're given few or no details about what is happening. Do all/some of the LEDs turn on at all?)