I'm trying to control DC motor speed. As of right now, to my limited understanding, I suppose I'm able to control the motor with just high and low by setting and clearing bits. The goal is to have the motor run at its 50% or 70% of the max speed, preferrably while gradually increasing and decreasing the speed. Please see the following piece of code and the circuit diagram for the current system configuration.
Here's the motor's datasheet:
https://www.ti.com/lit/ds/symlink/drv8801.pdf
The board I'm using is:
ATmega64A
Atmel AVR 8-bit Microcontroller
#define MOTOR_CON PORTA
#define DC_ENABLE_ON sbi(PORTA, 3)
#define DC_ENABLE_OFF cbi(PORTA, 3)
#define DC_PHASE_ON sbi(PORTA, 2)
#define DC_PHASE_OFF cbi(PORTA, 2)
#define DC_MODE_ON sbi(PORTA, 1)
#define DC_MODE_OFF cbi(PORTA, 1)
void MotorSpeedSwingUp(void)
{
DC_ENABLE_ON;
}
void MotorSpeedSwingDn(void)
{
DC_ENABLE_OFF;
}
void MotorForwardPhase(void)
{
DC_PHASE_ON;
DC_MODE_OFF;
}
void MotorReversePhase(void)
{
DC_PHASE_OFF;
DC_MODE_OFF;
}
void MotorRun(void)
{
if(motor_swing_flag == TRUE)
{
motor_swing_flag = FALSE;
MotorSpeedSwingUp();
}
else
{
motor_swing_flag = TRUE;
MotorSpeedSwingDn();
}
}
void MotorBrake(void)
{
DC_PHASE_OFF;//Forward
DC_ENABLE_OFF;
DC_MODE_ON;
}
Many thanks for helping!
The concept of PWM control is to repeat ON and OFF in a very
short cycle as shown in Figure 9-3 and so on. The ratio of ON time
in the cycle is called "duty cycle" and is proportional to the motor
rotation speed as enhzflep comments.
Let's suppose the cycle is 200usec and we want to have the motor
rotate at 70% speed. Then we should repeat the following sequence:
Enable the motor.
Wait 140usec.
Disable the motor.
Wait 60usec.
Assuming your C compiler supports usleep() function, would you please
try something like (not tested):
#define CYCLE 200 // 200usec for 1 cycle
#include <unistd.h>
/*
* have the motor run at "duty" speed for "duration" seconds
* 0.0 <= duty <= 1.0
*/
void PwmRun(double duty, int duration)
{
if (duty < 0.) duty = 0.; // lower limit of "duty"
if (duty > 1.) duty = 1.; // upper limit of "duty"
int ontime = (int)(CYCLE * duty); // PWM on time
int offtime = (int)(CYCLE * (1. - duty)); // PWM off time
for (int t = 0; t < duration * 1000000; t += CYCLE) {
if (ontime > 0) DC_ENABLE_ON;
usleep(ontime);
if (offtime > 0) DC_ENABLE_OFF;
usleep(offtime);
}
}
// example to run the motor at 70% speed for 3 seconds
PwmRun(0.7, 3);
It will be easy to modify the code to gradually increase the speed
from 50% to 70%.
Related
I have to write a C code so that the RGB LED on the board breaths. My code is blinking not breathing. My teacher said that varying brightness is achieved by varying duty-cycle so in that case I can't use pwm. Please help me to understand this code.
#include <stdint.h>
#include <stdlib.h>
#define SYSCTL_RCGC2_R (*((volatile unsigned long *)0x400FE108))
#define SYSCTL_RCGC2_GPIOF 0x00000020 //port F clock gating control
#define GPIO_PORTF_DATA_R (*((volatile unsigned long *)0x400253FC))
#define GPIO_PORTF_DIR_R (*((volatile unsigned long *)0x40025400))
#define GPIO_PORTF_DEN_R (*((volatile unsigned long *)0x4002551C))
void delay (double sec);
int cond;
int main(void){
SYSCTL_RCGC2_R = SYSCTL_RCGC2_GPIOF;
GPIO_PORTF_DIR_R=0x0E;
GPIO_PORTF_DEN_R=0x0E;
cond=0;
while(1){
GPIO_PORTF_DATA_R = 0x02;
delay(12.5);
GPIO_PORTF_DATA_R = 0x00;
delay(0);
GPIO_PORTF_DATA_R = 0x02;
delay(2.5);
GPIO_PORTF_DATA_R = 0x00;
delay(10);
GPIO_PORTF_DATA_R = 0x02;
delay(5);
GPIO_PORTF_DATA_R = 0x00;
delay(7.5);
GPIO_PORTF_DATA_R = 0x02;
delay(7.5);
GPIO_PORTF_DATA_R = 0x00;
delay(5);
GPIO_PORTF_DATA_R = 0x02;
delay(12.5);
GPIO_PORTF_DATA_R = 0x00;
delay(0);
GPIO_PORTF_DATA_R = 0x02;
delay(7.5);
GPIO_PORTF_DATA_R = 0x00;
delay(5);
GPIO_PORTF_DATA_R = 0x02;
delay(5);
GPIO_PORTF_DATA_R = 0x00;
delay(7.5);
}
return 0;
}
void delay(double sec){
int c=1, d=1;
for(c=1;c<=sec;c++)
for(d=1;d<= 4000000;d++){}
}
There are two ways you can drive LEDs: either with constant current through some general-purpose I/O, or with repeated duty cycle from PWM. PWM meaning pulse-width modulation and it will happen with pulses that are too fast for the human eye to notice, could be anywhere from some 100Hz up to 10kHz or so.
The main advantage of PWM is that you easily can control current. Which is case of RGB means color intensity of the 3 individual LEDs. Most smaller LEDs are rated at 20mA so that's usually the maximum current you are aiming for, corresponding to 100% duty cycle.
The correct way to achieve this is to use PWM.
But what your current code does is to "bit bang" simulate PWM by pulling GPIO pins. That's very crude and inefficient. Normally microcontrollers have a timer and/or PWM hardware peripheral built in, where you just provide a duty cycle and the hardware takes care of everything from there. In this case you would set up 3 PWM hardware channels which should ideally be clocked at the same time.
LEDs are diodes with different forward voltage depending on chemistry. So you very likely have different forward voltages per each of the 3 colors. You have to check the datasheet of the RGB and look for luminous intensity experessed in candela. In this case very likely millicandela, mcd. Lets assume that your green led has 300mcd but the red and blue have 100mcd. They are somewhat linear, or you can probably get away with assuming they are. So a crude equation in this case is to give the green LED 3 times less current than the others, in order to get an even mix of colors. Once you have compensated for that, you can give your 3 PWM channels a RGB code and hopefully get the corresponding color.
As a side note, the delay function in your code is completely broken in many ways. The loop iterator for such busy-delays must be volatile or any half-decent compiler will simply remove the delay when optimizations are enabled. And there is no reason to use floating point either.
If you are doing it with your delay function and your delay resolution is in seconds as suggested in the code of course it will "blink" - the frequency needs to be faster than human visual perception - say for example about 50Hz, then to get a smooth variation you might divide that up into say 20 levels, requiring a millisecond delay.
In any case your delay() function defeats itself by taking a floating point number of seconds but comparing it with an integer loop counter - it will only ever work in whole seconds.
So given a function delayms( unsigned millisec ) (which I discuss later) then:
#define BREATHE_UPDATE_MS 100
#define BREATHE_MINIMUM 0
#define PWM_PERIOD_MS 20
unsigned tick = 0 ;
unsigned duty_cycle = 0 ;
unsigned cycle_start_tick= 0 ;
unsigned breath_update_tick = 0 ;
int breathe_dir = 1 ;
for(;;)
{
// If in PWM "mark"...
if( tick - cycle_start_tick < duty_cycle )
{
// LED on
GPIO_PORTF_DATA_R |= 0x02 ;
}
// else PWM "space"
else
{
// LED off
GPIO_PORTF_DATA_R &= ~0x02 ;
}
// Update tick counter
tick++ ;
// If PWM cycle complete, restart
if( tick - cycle_start_tick >= PWM_PERIOD_MS )
{
cycle_start_tick = tick ;
}
// If time to update duty-cycle...
if( tick - breath_update_tick > BREATHE_UPDATE_MS )
{
breath_update_tick = tick ;
duty_cycle += breathe_dir ;
if( duty_cycle >= PWM_PERIOD_MS )
{
// Breathe in
breathe_dir = -1 ;
}
else if( duty_cycle == BREATHE_MINIMUM )
{
// Breathe out
breathe_dir = 1 ;
}
}
delayms( 1 ) ;
}
Change BREATHE_UPDATE_MS to breathe faster, change BREATHE_MINIMUM to "shallow breathe" - i.e. not dim to off.
If your delay function truly results in a delay resolution in seconds then approximately and rather crudely:
void delayms( unsigned millisec )
{
for( int c = 0; c < millisec; c++ )
{
for( volatile int d = 0; d < 4000; d++ ) {}
}
}
However that suggests to me a rather low core clock rate, so you may need to adjust that. Note the use of volatile to prevent the removal of the empty loop by the optimiser. The problem with this delay is that you will need to calibrate it to the clock speed of your target and its timing is likely to differ in any case depending on what compiler you use and what compiler options you use. It is generally a poor solution.
In practice using a "busy-loop" delay for this is ill-advised and crude and it would be better to use the Cortex-M SYSTICK:
volatile uint32_t tick = 0 ;
void SysTick_Handler(void)
{
tick++ ;
}
... removing the tick and tick++ from the original; code. Then you don't need a delay in the loop above because all the timing is pegged to the value of tick. However should you want a delay for other reasons then:
delayms( uint32_t millisec )
{
uint32_t start = tick ;
while( tick - start < millisec ) ;
}
Then you would initialise the SYSTICK at start-up thus:
int main (void)
{
SysTick_Config(SystemCoreClock / 1000) ;
...
}
This assumes that you are using the CMSIS, but your code suggests that you are not doing that (or even using a vendor supplied register header). You will in that case need to get down and dirty with the SYSTICK and NVIC registers if you (or your tutor) insists on that. The source for SysTick_Config() is as follows:
__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
{
return (1UL); /* Reload value impossible */
}
SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */
NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
SysTick->VAL = 0UL; /* Load the SysTick Counter Value */
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
return (0UL); /* Function successful */
}
I have a simple question about how to read rotary encoder input.
If I understand this image correctly, then every turn triggers a rise on pin A. Then, you have to check pin B, which is high if the encoder is turning clockwise and low if the encoder is turning counter clockwise.
I've tried to write my own code and not using any libraries, because I thought this would be really simple, but it turned out it was not.
This is the code I've written:
#define rotary_A 2
#define rotary_B 3
void setup()
{
pinMode(rotary_A, INPUT);
pinMode(rotary_B, INPUT);
attachInterrupt(digitalPinToInterrupt(rotary_A), rotary_spin, RISING);
Serial.begin(9600);
}
void rotary_spin()
{
if (digitalRead(rotary_B) == HIGH)
Serial.println("+");
else
Serial.println("-");
}
I was expecting to get + when I turn it clockwise and - when I turn it counter clockwise. However, I'm getting several outputs for each turn, like there were several interrupts triggered in rapid succession. For example, when I turn the encoder clockwise:
-
-
+
+
and counter clockwise:
+
+
-
-
-
-
The outputs are different every time, but the last character is always the right one.
What am I getting wrong? Is it not that simple or are there different types of encoders?
The question implies that there should only be a single interrupt per revolution. But encoders typically generate more than a single cycle per revolution--some in the thousands. That is probably why the interrupts seem to occur more rapidly than expected.
In a zero-latency interrupt environment, the code should work. But if the phase B pin is sampled too long after the phase A pin goes high, it will fail. This might occur if the next phase A rising edge occurs while Serial.println is still executing in the previous interrupt.
A simple test to see if this is the case is to turn the encoder very, very slowly. If this results in correct data, the problem is probably interrupt latency. Serial.println can then be replaced with something much quicker, like illuminating LEDs, to see if that resolves latency issues.
For actual use, you would need to make sure that the worse-case latency between phase A going high and phase B being sampled is adequate for the maximum rate of encoder rotation.
Final note: The code should be able to adequately detect direction, but cannot be used to increment/decrement a counter to track position. That requires more than one interrupt per cycle.
check this repository of mine on Github.
https://github.com/KingZuluKing/Rotary-Encoder-Peripheral-System
It has to be something like this, more details inside the repo.
void encode_Rotor_func()
{
lcd.clear();
Vol_Knob_stat=digitalRead(Vol_Knob);
if(Vol_Knob_stat==0)
{
Vol_Dir_stat=digitalRead(Vol_Dir);
if(Vol_Dir_stat==0 && deciBells<=9)
{
deciBells++;
lcd.setCursor(0, 0);
lcd.print("VOLUME= .");
lcd.setCursor(7, 0);
lcd.print(deciBells);
lcd.setCursor(10, 0);
lcd.print("dB's");
}
else if(Vol_Dir_stat==1 && deciBells >=-79)
{
deciBells--;
lcd.setCursor(0, 0);
lcd.print("VOLUME= .");
lcd.setCursor(7, 0);
lcd.print(deciBells);
lcd.setCursor(10, 0);
lcd.print("dB's");
}
else{
do something else etc.. etc....
}
}
}
I made a small sketch that makes clear how to interpret the encoder accordingly to the image sequence in your post:
Try this code with the equivalent pins CLK and DT connected to A2 and A1 receptively.
// Rotary Encoder Inputs
#define CLK A2
#define DT A1
int counter = 0;
String currentDir ="";
unsigned char currentPairBit = 0b0; // 8 bits
unsigned char lastPairBit = 0b0; // 8 bits
void setup() {
Serial.begin(9600); // opens serial port, sets data rate to 9600 bps
DDRC = 0b00000000; // Set Analog(C) encoder pins as inputs
}
void loop() {
while(true) { // while cycle is faster than loop!
// reads the analog states!
currentPairBit = PINC >> 1 & 0b11; // Gets A2(PC2) and A1(PC1) bits on C (analog input pins) (>> 1 = Jumps pin 0)
if ((lastPairBit & 0b11) != currentPairBit) {
lastPairBit = lastPairBit << 2 | currentPairBit;
// Bit Pairs Cyclic Sequence:
// 1. 2. 3. 4. 5.
// 11 | 01 | 00 | 10 | 11 for CCW
// 11 | 10 | 00 | 01 | 11 for CW
if (lastPairBit == 0b01001011 || lastPairBit == 0b10000111) {
if (lastPairBit == 0b01001011) {
currentDir = "CCW";
counter--;
} else {
currentDir = "CW";
counter++;
}
Serial.print("Direction: ");
Serial.print(currentDir);
Serial.print(" | Counter: ");
Serial.println(counter);
}
}
}
}
Then check the Serial Monitor to see how fast it is. Note that you should avoid the delay() function in your code or any other that interrupts the cycle by too much time. Consider using a second auxiliary Arduino for anything else than counting.
Resulting Serial Output:
I am using an ADM00308 development board from MicroChip. The board has a PIC16F883 processor. The code example can be downloaded from their website. I am using a nanotec steppermotor ST4118m0706 with a step 1.8 degree. I've calculated the max speed of the stepper motor:
from this website
RPMmax = 24V/(2⋅0,032mh⋅0,5A) = 3,75n/s (3,75⋅60 = 225rpm)
Minimum time per step = (2⋅0,032mh⋅0,5)/24V = 0,00133 seconds.
So in theory, the stepper motor should be able to handle 225rpm without oscillating. Now the software.
The code example provides a variable speed up to around 45rpm. This is too slow, since my target is 130rpm. Here is the original code:
Pulse width, Max speed and scan
// Prescale: Must change both values together - PRESCALE Divisor and BIT MASK */
// 1 = 0b00000000, 2 = 0b00010000, 4 = 0b00100000, 8 = 0b00110000
//#define REF_PWM_PRESCALE 8
//#define REF_PWM_PRESCALE_MASK 0b00110000
// The Rollover Count is the period of the timer.
// The timer period = 0 - Rollover Count.
//#define REF_PWM_PERIOD = ((float) ((1.0 / (((float)_XTAL_FREQ) / 4.0)) * (REF_PWM_PRESCALE * REF_RWM_ROLLOVER_COUNT)))
//#define REF_FREQ ((float) (1.0 / REF_PERIOD) )
// Set minimum speed by (65535 - MAX_SPEED_COUNT) * usec per bit
// 12 msec =
#define MIN_MOTOR_PULSEWIDTH (0.015)
#define MAX_SPEED_COUNT ((unsigned int) (65535.0 - ((float) ((MIN_MOTOR_PULSEWIDTH / (1.0 / (((float)_XTAL_FREQ) / 4.0))) / (ROTATION_PRESCALE * 2)))))
#define SPEED_INPUT_SPAN ((unsigned int) 900)
#define SPEED_INPUT_COUNTS_PER_BIT ((unsigned int) (MAX_SPEED_COUNT / SPEED_INPUT_SPAN))
#define ROTATION_ROLLOVER_COUNT (MAX_SPEED_COUNT + 100)
#define ROTATION_PRESCALE 8
#define ROTATION_PRESCALE_MASK 0b00110000
#define ROTATION_PERIOD = ((float) ((1.0 / (((float)_XTAL_FREQ) / 4.0)) * (ROTATION_PRESCALE * ROTATION_ROLLOVER_COUNT)))
#define ROTATION_FREQ ((float) (1.0 / ROTATION_PERIOD) )
SpeedUpdate
FaultTypeEnum SpeedUpdate(void)
{
FaultTypeEnum Fault;
unsigned int Speed;
Fault = NO_FAULT;
if (SpeedInput < 65)
{
/* open/shorted(GND) speed input */
Speed = 0;
Fault = SPEED_INPUT_LOW;
}
else if (SpeedInput < 100)
{
Speed = 0;
Fault = NO_FAULT;
}
else if (SpeedInput > 950)
{
Speed = 0;
Fault = SPEED_INPUT_HIGH;
}
else if (SpeedInput > 900)
{
/* open/shorted(VDD) speed input */
Speed = MAX_SPEED_COUNT;
Fault = NO_FAULT;
}
else
{
Speed = (SpeedInput - 100) * SPEED_INPUT_COUNTS_PER_BIT;
Fault = NO_FAULT;
}
RotationTimerRolloverCount = MAX_SPEED_COUNT - Speed;
/* setup the next timer reload value */
T1CON = 0b00000000; /* Temporarily pause the PWM timer */
/* use variables to reload timer faster in interrupt routine */
RotationTimerReloadHi = (unsigned )(RotationTimerRolloverCount >> 8);
RotationTimerReloadLo = (unsigned short) RotationTimerRolloverCount;
T1CON = 0b00000001 | ROTATION_PRESCALE_MASK; // Re-enable PWM timer, set prescale
return Fault;
}
Timer
/* Rotation Timer. Must be fast. */
if (PIR1bits.TMR1IF)
{
PIR1bits.TMR1IF = 0;
TMR1H = RotationTimerReloadHi;
TMR1L = RotationTimerReloadLo;
/* Calculate next stepper rotation state */
/* HOLD switch sets min_rotation_state = max_rotation_state */
/* SINGLE STEP switch sets min_rotation_state = max_rotation_state */
if (System.Bits.Stop)
{
/* no current output */
RotationData.All = ROTATION_STOP;
}
else
{
/* update stepper driver with last calculated data */
PORTB = ((PORTB & 0b11000000) | RotationData.All);
I managed to change the speed to 146rpm by changing:
#define MIN_MOTOR_PULSEWIDTH (0.015)
to for testing
#define MIN_MOTOR_PULSEWIDTH (0.006)
The stepper rotates at a speed of 98rpm with the potentio completely rotated to the left. Lowering the value to 0.004 will get a speed of 146rpm with good torque on a 24v supply(torque will suffer on a 12v supply). Lowering the value even more, will oscillate the motor (you can hear the motor but it doesn't rotate anymore). Which is strange since the max rpm is supposed to be 225rpm. However, the main problem is that I can't seem to reach a rpm of 130. Changing the value to 0.005, 0.0045, etc doesn't increase the speed more than 98 until 0.004. It also seems that the potentiometer has some kind of presets. By turning the potentiometer, it changes from 146rpm to 98rpm, to 73rpm, etc. It doesn't change the speeds fluently, if you get my point. Hence I am getting the idea it's programmed in presets, which I also tried to change.
Firmware and information can be downloaded on the original site
I am programming a sensor mote (XM1000) I am using Contiki Operating System to program this devices ( I am using terminal to view the outputs and GEdit to write my 'C' code in. This sensor mote has a temprature, light and humidity sensor on board as well as 3 LED lights.
Below I have two sets of code. The first set of code functions and gives me the sensor readings for the values for temprature, light and humidity.
The second set of code functions. it turns the LED lights on/off and makes them blinking regularly on the sensor node XM1000, it counts how many times the LED has blinked and output the count to the console.
The problem I am having is creating a if statement to meet these following conditions and I am struggling to combine the two codes together. So this is what I want to achieve:
• If the temperature exceeds over 26 Degrees then turn on LED Light 1 for 5 seconds, else if the temperature is equal to and below 26 Degrees then turn off LED Light 1.
• If the Humidity exceeds over 40% then turn on LED Light 2 for 5 seconds, else if the humidity is equal to and below 40% then turn off LED Light 2.
• If the Light intensity exceeds over 510 nanometres then turn on LED Light 3 for 5 seconds, else if the light intensity is equal to and below 510nm then turn off LED Light 3.
First Set of Code: It measures the temprature, light and humidity and outputs the results on a terminal window.
#include "contiki.h" //Contiki Header File
#include "dev/light-sensor.h" //Light Sensor Header File
#include "dev/sht11-sensor.h" //Temperature and Humidity Header File
#include <stdio.h> /* for printf() */ // standard input/output library needed to write to the standard output
static struct etimer timer; //Process Requires a Timer
int light=0, temp=0, humid=0;
//To Start
/*___________________________________________________*/
PROCESS(sensor_reading_process, "Sensor Reading Process");
AUTOSTART_PROCESSES(&sensor_reading_process);
/*___________________________________________________*/
//PROCESS BEGINS
PROCESS_THREAD(sensor_reading_process, ev, data)
{
PROCESS_BEGIN();
SENSORS_ACTIVATE(light_sensor); //Activate the Light Sensor
SENSORS_ACTIVATE(sht11_sensor);//Activate Temp/Humidity Sensor
etimer_set(&timer, CLOCK_CONF_SECOND);//Configuring Timer 1SEC
while(1) { //Start of While Loop
PROCESS_WAIT_EVENT_UNTIL(ev==PROCESS_EVENT_TIMER);//Wait4Time
// This is how we get the Sensor Values for light, temp, hum
light = light_sensor.value(LIGHT_SENSOR_PHOTOSYNTHETIC);
temp = sht11_sensor.value(SHT11_SENSOR_TEMP);
humid = sht11_sensor.value(SHT11_SENSOR_HUMIDITY);
printf("Light=%d, Temp=%d, Humid=%d\n", light, temp, humid);
//Above Line if Print Plus Values
etimer_reset(&timer); //Reset the Timer
}
PROCESS_END(); //End of Process
}
The second code:
#include "contiki.h"
#include "leds.h" // LED HEADER FILE
#include <stdio.h> /* for printf() */
static struct etimer timer;
/*____________________________________________________*/
PROCESS(led_blinking_process, "LED Blinking Process");
PROCESS(LED_process, "LED process");
AUTOSTART_PROCESSES(&LED_process);
/*____________________________________________________*/
PROCESS_THREAD(LED_process, ev, data)
{
static int count = 0;
PROCESS_BEGIN();
etimer_set(&timer, CLOCK_CONF_SECOND/2); // 0.5S timer
leds_init(); // initialise the LEDs
while(1) {
PROCESS_WAIT_EVENT_UNTIL(ev==PROCESS_EVENT_TIMER); // wait for timer event
count++; // count the blinking times
process_start(&led_blinking_process, NULL); // to blink the BLUE Led
printf("Count: %d\n", count); // output the counter number to console
etimer_reset(&timer); // reset the timer
}
PROCESS_END();
}
CODE FOR LED LIGHTS
/*____________________________________________________*/
PROCESS_THREAD(led_blinking_process, ev, data)
{
PROCESS_BEGIN();
leds_toggle(LEDS_BLUE); // Blinking the Blue LED
PROCESS_END();
}
Please note both codes work when I run them , I am just trying to combine them , use a if statement so i can meet my functions I have stated above.
Thanks in advance for any help or contributions!
Here's what I think it will look like, give or take a little hacking. I've structured the code as a single loop, that just polls all three sensors at 5 second intervals. So every 5 seconds, the on/off status of all three lights might change. I figure for watering a lawn, you don't really need split-second precision in terms of knowing when it got hot, or dark, or whatever.
Based on your replies in the comments section of the OP, there might have to be some computation done involving the return values of the sensor readings. I figure it's probably easier to do the computation at compile time, so the code is biased that way.
#include <stdio.h> /* for printf() */
#include "contiki.h"
#include "leds.h"
#include "dev/light-sensor.h"
#include "dev/sht11-sensor.h"
PROCESS(Led_management_process, "LED Management Process");
AUTOSTART_PROCESSES(&Led_management_process);
static struct etimer Timer;
/* Per the online docs at http://www.advanticsys.com/wiki/index.php?title=TestCM5000
T = -39.6 + 0.01 × SO(T)
So, solving for SOt gives:
*/
#define degreesC(n) (n)
#define TEMP_D1 degreesC(-39.6)
#define TEMP_D2 degreesC(0.01)
#define TEMP_THRESHOLD(tempC) (int)(((((double)(tempC))-(TEMP_D1))/(TEMP_D2)))
#define TARGET_TEMP_READING TEMP_THRESHOLD(degreesC(26))
#define LIGHT_LED LEDS_GREEN
#define HUM_LED LEDS_BLUE
#define TEMP_LED LEDS_RED
PROCESS_THREAD(Led_management_process, ev, data)
{
static int humidity_led_on = 0;
static int light_led_on = 0;
static int temp_led_on = 0;
PROCESS_BEGIN();
SENSORS_ACTIVATE(light_sensor);
SENSORS_ACTIVATE(sht11_sensor);
leds_init();
unsigned int cycle = 0;
while (1) {
printf("%8u:", cycle);
/* This part is questionable, since I don't know if the
sensors are guaranteed to return ints (vs. floats or
something) and I don't know what units they use. */
int temp = sht11_sensor.value(SHT11_SENSOR_TEMP);
if (temp > TARGET_TEMP_READING) {
printf(" TEMP warm- ");
if (!temp_led_on) {
printf("toggle LED");
temp_led_on = 1;
leds_toggle(TEMP_LED);
}
else {
printf("LED is ok ");
}
}
else {
printf(" TEMP cold- ");
if (temp_led_on) {
printf("toggle LED");
temp_led_on = 0;
leds_toggle(TEMP_LED);
}
else {
printf("LED is ok ");
}
}
/* Code for humidity */
/* Code for light */
printf("\n");
/* Sleep 5 seconds */
etimer_set(&Timer, CLOCK_CONF_SECOND * 5);
PROCESS_WAIT_EVENT_UNTIL(ev==PROCESS_EVENT_TIMER);
etimer_reset(&Timer);
++cycle;
}
PROCESS_END();
}
Im trying to create an embedded c code to control a dc motor with the PIC32MX460F512L microcontroller. Ive Configured the system clock at 80MHz, and the peripheral clock at 10MHz, Am using Timer 1 for pulsing the PWM with a given duty cycle, and Timer 2 for measuring the motor run time. I have a header file(includes.h) that contains system configuration information eg clock. Ive created most of the functions but some are a bit challenging. For example, initializing the LEDS and the functions for forward, backward movements and stop, I wanted the dc motor to run in forward direction for 4 sec at 70% duty cycle, then stop for 1 sec then reverse for 3 sec at 50% duty cycle and then stop for 1 sec and then forward again for 3 sec at 40% duty cycle, stop for 1 sec and finally forward for 5 sec at 20% duty cycle. Any suggestions for the forward, stop, and reverse functions
#include <stdio.h>
#include <stdlib.h>
#include <includes.h>
void main()
{
// Setting up PIC modules such as Timers, IOs OCs,Interrupts, ...
InitializeIO();
InitializeLEDs();
InitializeTimers();
while(1) {
WaitOnBtn1();
Forward(4.0,70);
Stop(1.0);
Backward(3.0,50);
Stop(2);
Forward(3.0,40);
Stop(1.0);
Backward(2.0,20);
LEDsOFF();
}
return;
}
void InitializeIO(){
TRISAbits.TRISA6 = 1;
TRISAbits.TRISA7 = 1;
TRISGbits.TRISG12 = 0;
TRISGbits.TRISB13 = 0;
LATGbits.LATB12 = 0;
LATGbits.LATB13 = 0;
return;
}
void InitializeLEDs(){
//code to initialize LEDS
}
void InitializeTimers(){
// Initialize Timer1
T1CON = 0x0000; // Set Timer1 Control to zeros
T1CONbits.TCKPS=3; // prescale by 256
T1CONbits.ON = 1; // Turn on Timer
PR1= 0xFFFF; // Period of Timer1 to be full
TMR1 = 0; // Initialize Timer1 to zero
// Initialize Timer2
T2CON = 0;
T2CONbits.TCKPS = 7; // prescale by 256
T2CONbits.T32 = 1; // use 32 bits timer
T2CONbits.ON = 1;
PR2 = 0xFFFFFFFF; // Period is set for 32 bits
TMR2 = 0;
}
void WaitOnBtn1(){
// wait on Btn1 indefinitely
while(PORTAbits.RA6 == 0);
// Turn On LED1 indicating it is Btn1 is Pushed
LATBbits.LATB10 = 1;
return;
}
void Forward(float Sec, int D){
int RunTime = (int)(Sec*39000); // convert the total
time to number of Tics
TMR2 = 0;
//LEDs
LATGbits.LATG12 = 1; // forward Direction
LATBbits.LATB12 = 0;
LATBbits.LATB13 = 0;
LATBbits.LATB11 = 1;
// Keep on firing the PWM as long as Run time is not
elapsed
while (TMR2 < RunTime){
PWM(D);
}
return;
}
void PWM(int D){
TMR1 = 0;
int Period = 400;
while (TMR1< Period) {
if (TMR1 < Period*D/100){
LATGbits.LATG13 = 1;
}
else{
LATGbits.LATG13 = 0;
}
}
Functions, not methods, to be precise.
So what is exactly the question?
What I can say from a quick look on a source code:
LEDs initialisation should be done as you did in InitializeIO() function. Simply set proper TRISx bits to 0 to configure LED pins as output.
For the PWM and motor control functions you should take some time and try to understand how builtin PWM peripheral works. It is a part of OC (Output Compare) and it is very easy to use. Please, take look on following link http://ww1.microchip.com/downloads/en/DeviceDoc/61111E.pdf
and this one for the minimal implementation using builtin peripheral libraries https://electronics.stackexchange.com/questions/69232/pic32-pwm-minimal-example
Basically you need to set up OC registers to "make" OC module acts like PWM. You need to allocate one of the timers to work with OC module (it will be used for base PWM frequency) and that's it.
All you need after that is to set PWM duty cycle value by setting timer PRx register, you don't need to swap bits like in your PWM routine.
To stop it simple stop it simply disable the timer.
To run it again run the timer.
To change direction (it depends of your driver for the motor) I guess you need just to toggle direction pin.
I hope it helps...