If an example , I set a value of :
a = 50
How do I do a decrement whereby a always decreases by 2 ? An example :
48
46
44
42
40
Whereby the return results , I can use as a variable. Example in the case below , this method is to get temperature at random. But I would like it to decrease so that I can call this get temperature method even below for it to loop.
/* Retrieves current temperature. */
static int32_t get_temperature_sample(void)
{
/* For the sake of example, random data is used */
return rand() % 10 + 25;
}
/* Periodically called by Kaa SDK. */
static void example_callback(void *context)
{
time_t current_time = time(NULL);
/* Respect sample period */
if (difftime(current_time, last_sample_time) >= sample_period) {
int32_t temperature = get_temperature_sample();
printf("Sampled temperature: %i\n", temperature);
last_sample_time = current_time;
kaa_user_log_record_t *log_record = kaa_logging_data_collection_create();
log_record->temperature = temperature;
kaa_logging_add_record(kaa_client_get_context(context)->log_collector, log_record, NULL);
}
}
Like if the above codes , if I were to say that for my temperature. I wouldnt want it to be random as you can see it uses random. I want to set a value for my temperature and decrease like a constant until it reaches 0 in my print function shown below.
printf("Sampled temperature: %i\n", temperature);
last_sample_time = current_time;
Try something like this
static void get_temperature_sample(int *previous_temp)
{
*previous_temp -= 2; // This decrements the value and
// don't need a return value, because
// you are passing a pointer to
// the variable and hence modifying
// it's value directly
}
And when you call the function
int32_t temperature = 50; // Initial temperature
get_temperature_sample(&temperature);
You'll need to add a while somewhere in there depending on how you're tracking the temperature. But this will decrement the temp value whenever you call the function.
To decrement a, try using
a -=2;
it will help you..
Related
I am here to seek help from the community to develop a program in C language that would allow me to limit the inrush current of a DC motor while controlling the PWM at these terminals.
The motor in question is a 50W 24V and I want to limit the current to 2.5A.
For that, I developed an electronic board with a microcontroller from STMicroelectronics, the STM32F31C4T6.
The current measurement is done with an adc.
When I arrive in the function of the PID I am lost, I do not know how to limit the current and at the same time manage the PWM
Here is the beginning of the code I wrote, it just misses the PWM that I send at the beginning as an argument of the function :
#include "PID.h"
/* constants for PID */
const float Kp = 0.01; // The value for Proportional gain
const float Ki = 0.01; // The value for Integral gain
const float Kd = 0.001; // The value for Differential gain
const int Set_Point = 1950; // The ADC reference point we are aiming to regulate to
uint32_t tabDuty[50];
int i =0;
void PWM_Duty_Change(current)
{
/* Global Variables for PID */
float d_Temp = 0; // This stores the old ADC value
float i_Temp = 0; // This stores the accumulated Integral value
float PWM_Temp = 0;
//Local variables for PID
float iMax = 100; // Used to prevent integral wind-up
float iMin = -100; // Used to prevent integral wind-up
float Err_Value; // Holds the calculated Error value
float P_Term; // Holds the calculated Proportional value
float I_Term; // Holds the calculated Integral value
float D_Term; // Holds the calculated Differential value
int new_current_ADC_value; // Holds the new ADC value
float PWM_Duty; // Holds the new PWM value
new_current_ADC_value = current;
Err_Value = (Set_Point - new_current_ADC_value);
// This calculates Proportional value, Kp is
//multiplied with Err_Value and the result is assigned to P_Term
P_Term = Kp * Err_Value;
// Prepare Integral value, add the current error
//value to the integral value and assign the total to i_Temp
i_Temp += Err_Value;
// Prevents integral wind-up, limits i_Temp
//from getting too positive or negative
if (i_Temp > iMax)
{i_Temp = iMax;}
else if (i_Temp < iMin)
{i_Temp = iMin;}
// Calculates the Integral value, Ki is
//multiplied with i_Temp and the result is assigned to I_Term
I_Term = Ki * i_Temp;
// Calculates Differential value, Kd is multiplied with
//(d_Temp minus new_ADC_value) and the result is assigned to D_Term
// The new_ADC_value will become the old ADC value
//on the next function call, this is assigned to d_Temp so it can be used
D_Term = Kd * (d_Temp - Err_Value);
d_Temp = Err_Value;
/****** Now we have the P_Term, I_Term and D_Term *****/
PWM_Duty = PWM_Temp - (P_Term + I_Term + D_Term);
// PWM overflow prevention
if (PWM_Duty > 90)
{PWM_Duty = 90;}
else if (PWM_Duty < 10)
{PWM_Duty = 10;}
// Adjusts the PWM duty cycle
adjust_PWM(PWM_Duty);
// Assigns the current PWM duty cycle value to PWM_Temp
PWM_Temp = PWM_Duty;
}
If you need more information do not hesitate to ask me.
I thank you for all the help you can give me
I'm currently tracking the analog value of a photodetector coming into my system. The signal itself is cleaned, filtered (low pass and high pass), and amplified in hardware before coming into my system. The signal has a small amount of DC walk to it, which is giving me some trouble. I've attempted to just move the min up by 1% every 50 reads of the ADC,but it adds more noise than I'd like to my signal. Here's a snapshot of what I'm pulling in below (blue = signal, max/min average = green, red = min) The spikes in the red signal can be ignored that's something I'm doing to say when a certain condition is met.
Right now my function for tracking min is this:
//Determine is value is outside max or min
if(data > max) max = data;
if(data < min) min = data;
//Reset function to bring the bounds in every 50 cycles
if(rstCntr>=50){
rstCntr=0;
max = max/1.01;
min = min*1.01;
if(min <= 1200) min = 1200;
if(max >= 1900) max = 1900;
}
That works fine except when I do that 1% correction to make sure we are still tracking the signal it throws other functions off which rely on the average value and the min value. My objective is to determine:
On the negative slope of the signal
Data coming in is less than the average
Data coming in is 5% above the minimum
It is really #3 that is driving everything else. There is enough slack in the other two that they aren't that affected.
Any suggestions for a better way to track the max and min in real-time than what I'm doing?
EDIT: Per comment by ryyker: here is additional information and reproducible example code
Need more clearly described: I'm reading an analog signal approximately once every 2ms and determining whether that signal has crossed a threshold just above the minimum value of the analog signal. The signal has some DC walk in it which doesn't allow me to simply set the lowest value seen since power-on as the minimum value.
The question: On a reading-by-reading basis, how can I track the min of a signal that doesn't have a consistent minimum value?
int main(void) {
while (1)
{
//******************************************************************************
//** Process analog sensor data, calculate HR, and trigger solenoids
//** At some point this should probably be moved to a function call in System.c,
//** but I don't want to mess with it right now since it works (Adam 11/23/2022)
//******************************************************************************
//Read Analog Data for Sensor
data = ADC1_ReadChannel(7);
//Buffer the sensor data for peak/valley detection
for(int buf=3;buf>0;buf--){
dataBuffer[buf] = dataBuffer[buf-1];
}
dataBuffer[0] = data;
//Look for a valley
//Considered a valley is the 3 most recent data points are increasing
//This helps avoid noise in the signal
uint8_t count = 0;
for(int buf=0;buf<3;buf++) {
if(dataBuffer[buf]>dataBuffer[buf+1]) count++;
}
if(count >= 3) currentSlope = true; //if the last 3 points are increasing, we just passed a valley
else currentSlope = false; //not a valley
// Track the data stream max and min to calculate a signal average
// The signal average is used to determine when we are on the bottom end of the waveform.
if(data > max) max = data;
if(data < min) min = data;
if(rstCntr>=50){ //Make sure we are tracking the signal by moving min and max in every 200 samples
rstCntr=0;
max = max/1.01;
min = min*1.01;
if(min <= 1200) min = 1200; //average*.5; //Probably finger was removed from sensor, move back up
if(max >= 1900) max = 1900; //Need to see if this really works consistently
}
rstCntr++;
average = ((uint16_t)min+(uint16_t)max)/2;
trigger = min; //Variable is only used for debug output, resetting each time around
if(data < average &&
currentSlope == false && //falling edge of signal
data <= (((average-min)*.03)+min) && //Threshold above the min
{
FireSolenoids();
}
}
return 1;
}
EDIT2:
Here is what I'm seeing using the code posted by ryyker below. The green line is what I'm using as my threshold, which works fairly well, but you can see max and min don't track the signal.
EDIT3:
Update with edited min/max code. Not seeing it ever reach the max. Might be the window size is too small (set to 40 in this image).
EDIT4:
Just for extra clarity, I'm restating my objectives once again, hopefully to make things as clear as possible. It might be helpful to provide a bit more context around what the information is used for, so I'm doing that also.
Description:
I have an analog sensor which measures a periodic signal in the range of 0.6Hz to 2Hz. The signal's periodicity is not consistent from pulsewave to pulsewave. It varies +/- 20%. The periodic signal is used to determine the timing of when a valve is opened and closed.
Objective:
The valve needs to be opened a constant number of ms after the signal peak is reached, but the time it physically takes the valve to move is much longer than this constant number. In other words, opening the valve when the peak is detected means the valve opens too late.
Similar to 1, using the valley of the signal is also not enough time for the valve to physically open.
The periodicity of the signal varies enough that it isn't possible to use the peak-to-peak time from the previous two pulsewaves to determine when to open the valve.
I need to consistently determine a point on the negative sloped portion of the pulsewave to use as the trigger for opening the valve.
Approach:
My approach is to measure the minimum and maximum of the signal and then set a threshold above the minimum which I can use to determine the time the open the valve.
My thought is that by setting some constant percentage above the minimum will get me to a consistent location on the negative sloped which can be used to open the valve.
"On a reading-by-reading basis, how can I track the min of a signal that doesn't have a consistent minimum value?"
By putting each discrete signal sample through a moving window filter, and performing statistical operations on the window as it moves, standard deviation can be extracted (following mean and variance) which can then be combined with mean to determine the minimum allowed value for each point of a particular waveform. This assumes noise contribution is known and consistent.
The following implementation is one way to consider.
in header file or top of .c
//support for stats() function
#define WND_SZ 10;
int wnd_sz = WND_SZ;
typedef struct stat_s{
double arr[10];
double min; //mean - std_dev
double max; //mean + std_dev
double mean; //running
double variance;//running
double std_dev; //running
} stat_s;
void stats(double in, stat_s *out);
in .c (edit to change max and min)
// void stats(double in, stat_s *out)
// Used to monitor a continuous stream of sensor values.
// Accepts series of measurement values from a sensor,
// Each new input value is stored in array element [i%wnd_sz]
// where wnd_sz is the width of the sample array.
// instantaneous values for max and min as well as
// moving values of mean, variance, and standard deviation
// are derived once per input
void ISL_UTIL stats(double in, stat_s *out)
{
double sum = 0, sum1 = 0;
int j = 0;
static int i = 0;
out->arr[i%wnd_sz] = in;//array index values cycle within window size
//sum all elements of moving window array
for(j = 0; j < wnd_sz; j++)
sum += out->arr[j];
//compute mean
out->mean = sum / (double)wnd_sz;
//sum squares of diff between each element and mean
for (j = 0; j < wnd_sz; j++)
sum1 += pow((out->arr[j] - out->mean), 2);
//compute variance
out->variance = sum1 / (double)wnd_sz;
//compute standard deviation
out->std_dev = sqrt(out->variance);
//EDIT here:
//mean +/- std_dev
out->max = out->mean + out->std_dev;
out->min = out->mean - out->std_dev;
//END EDIT
//prevent overflow for long running sessions.
i = (i == 1000) ? 0 : ++i;
}
int main(void)
{
stat_s s = {0};
bool running = true;
double val = 0.0;
while(running)
{
//read one sample from some sensor
val = someSensor();
stats(val, &s);
// collect instantaneous and running data from s
// into variables here
if(some exit condition) break
}
return 0;
}
Using this code with 1000 bounded pseudo random values, mean is surrounded with traces depicting mean + std_dev and mean - std_dev As std_dev becomes smaller over time, the traces converge toward the mean signal:
Note: I used the following in my test code to produce data arrays of a signal with constant amplitude added to injected noise that diminishes in amplitude over time.
void gen_data(int samples)
{
srand(clock());
int i = 0;
int plotHandle[6] = {0};
stat_s s = {0};
double arr[5][samples];
memset(arr, 0, sizeof arr);
for(i=0; i < samples; i++)//simulate ongoing sampling of sensor
{
s.arr[i%wnd_sz] = 50 + rand()%100;
if(i<.20*samples) s.arr[i%wnd_sz] = 50 + rand()%100;
else if(i<.40*samples) s.arr[i%wnd_sz] = 50 + rand()%50;
else if(i<.60*samples) s.arr[i%wnd_sz] = 50 + rand()%25;
else if(i<.80*samples) s.arr[i%wnd_sz] = 50 + rand()%12;
else s.arr[i%wnd_sz] = 50 + rand()%6;
stats(s.arr[i%wnd_sz], &s);
arr[0][i] = s.mean;
arr[1][i] = s.variance;
arr[2][i] = s.std_dev;
arr[3][i] = s.min;
arr[4][i] = s.max;
}
//
Plotting algorithms deleted for brevity.
}
I am using C to program a microcontroller (NHS3152) to calculate resistance using this formula:
RES = (V1-V2)/I
I want to write a program that:
Updates the values of 3 Floats and 1 integer (V1, V2, I, RES)
Update uint8_t text[] = "Char to store values of V_1, V_2, I, Res"; with a string with the values of these 3 floats and 1 integer
Commits text to memory using the function: "Example1_Creating_an_NDEF..." (provided below)
The issue I am having is with Updating text with the values of the 3 floats and 1 integer. I am able to do it with sprintf, however I cannot use this function with my microcontroller (I dont know why it stops me from flashing it to memory)
The code bellow is an example of what i want to achieve in from point 2 above, in the real code the float and integer values are updated by getting values from sensors on the mircocontroller:
#include <stdio.h>
#include <stdint.h>
static volatile float V_1 = 5.0; // store value of Voltage 1
static volatile float V_2 = 2.0; // store value of voltage 2
static volatile int I = 5; // store current value
static volatile float RES; // calcualte resitance
int i=1;
uint8_t text[] = "Char to store values of V_1, V_2, I, Res";
int main(void)
{
printf( text);
printf("\n");
//updates values for ADC_1, ADC_2, I, Res,
while(i<=2){ // real while loop is infinite
V_1 ++ ; // Usually value updates from microcontroller sensor
V_2 ++ ;
I ++;
RES = (V_1-V_2)/I; // calculating resistance
sprintf((char *)text, "Updated Text V1: %6.2f V2: %6.2f I: %8.d resistance: %e", V_1, V_2,I, RES ); // what i want to do but without sprintf
printf( text);
printf("\n");
i++;
}
printf("END");
}
OUT:
Char to store values of V_1, V_2, I, Res
Updated Text V1: 6.00 V2: 3.00 I: 6 resistance: 5.000000e-01
Updated Text V1: 7.00 V2: 4.00 I: 7 resistance: 4.285714e-01
END
Here is the Code including the function Example1_Creating_an_NDEF.. from point 3. This working code manages to Commit the text to memory (it works). All i need is to be able to update the text without sprintf as i believe these functions aren't allowed when i'm not in debug mode.
#include "board.h"
// From ndeft2t
#include "ndeft2t/ndeft2t.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
uint8_t instance[NDEFT2T_INSTANCE_SIZE] __attribute__((aligned (4)));
uint8_t buffer[NFC_SHARED_MEM_BYTE_SIZE ] __attribute__((aligned (4)));
uint8_t locale[] = "en";
uint8_t text[] = "Char to store values of V_1, V_2, I, Res";
// I want to add these to the text message
static volatile float V_1 = 5.0;
static volatile float V_2 = 2.0;
static volatile int I = 5;
static volatile float Res = ;
static void Example1_Creating_an_NDEF_Message_with_a_single_record_of_type_TEXT (void)
{
Chip_NFC_Init(NSS_NFC); /* Is normally already called during board initialization. */
NDEFT2T_Init();
NDEFT2T_CreateMessage(instance, buffer, NFC_SHARED_MEM_BYTE_SIZE, true);
NDEFT2T_CREATE_RECORD_INFO_T recordInfo = {.shortRecord = true, .pString = locale};
if (NDEFT2T_CreateTextRecord(instance, &recordInfo)) {
/* The payload length to pass excludes the NUL terminator. */
if (NDEFT2T_WriteRecordPayload(instance, text, sizeof(text) - 1)) {
NDEFT2T_CommitRecord(instance);
}
}
NDEFT2T_CommitMessage(instance);
/* The return value of the commit function is ignored here. */
}
int main(void)
{
Board_Init();
//NDEFT2T_Init();
/* Optional feature: send the ARM clock to PIO0_1 */
Chip_IOCON_SetPinConfig(NSS_IOCON, IOCON_PIO0_1, IOCON_FUNC_1);
Chip_Clock_Clkout_SetClockSource(CLOCK_CLKOUTSOURCE_SYSTEM);
/* Blink & attach a message to Memory */
while (1) {
//updates values for V_1, V_2, I, Res,
V_1++;
V_2++;
I++;
RES = (V_1 - V_2)/RES;
// Update the text message to contain "(V_1, V_2, I, RES)"
LED_Toggle(LED_RED);
Example1_Creating_an_NDEF_Message_with_a_single_record_of_type_TEXT();
Chip_Clock_System_BusyWait_ms(500);
}
return 0;
}
EDIT: responding to KamilCuk's comment : Do you really need float? Does your mcu has floating point support? Consider using integers only.
The fucntions i use to get V1,V2 & I, all return an Integer (eg: V1=2931 12 bit converter so between 0 and 4096 ) however to convert the integer value to the real value i need to use the following conversion:
V1_real= (V1* 1.2) / 2825 + 0.09; // CONVERSION added line
Without conversion i Cannot calculate Res.
An acceptable compromise is to commit to memory the values V1, V2, I without converstion to real values. I can then calculate RES in a second momemnt, once i retrieve the data from the MCU ( i am using my phone as an NFC reader, the chip is an NFC tag)
So the question is:
How do i convert the message in text to a message containing the integers (V_1,V_2,I)? :
Something like:
uint8_t text[] = "Char to store values of V_1, V_2, I";
text = "Message with V_1: V_1value, V_2: V_2value, I: IValue
Below is the code i use to extract the value of V_1 & V_2:
void adc (void)
{
Chip_IOCON_SetPinConfig(NSS_IOCON, IOCON_ANA0_1, IOCON_FUNC_1);
Chip_ADCDAC_SetMuxADC(NSS_ADCDAC0, ADCDAC_IO_ANA0_1);
Chip_ADCDAC_SetInputRangeADC(NSS_ADCDAC0, ADCDAC_INPUTRANGE_WIDE);
Chip_ADCDAC_SetModeADC(NSS_ADCDAC0, ADCDAC_SINGLE_SHOT);
Chip_ADCDAC_StartADC(NSS_ADCDAC0);
//Getting the data
while (!(Chip_ADCDAC_ReadStatus(NSS_ADCDAC0) & ADCDAC_STATUS_ADC_DONE)) {
; /* Wait until measurement completes. For single-shot mode only! */
}
//Data V1 stored here
adcInput_1 = Chip_ADCDAC_GetValueADC(NSS_ADCDAC0);
// Usually i use this line to then conver it to the real value of V1
//adcInput_1= (adcInput_1 * 1.2) / 2825 + 0.09; // CONVERSION added line
//! [adcdac_nss_example_3]
}
Maybe someone has a better solution that allows me to actually arrive at having also RES calculated, knowing that:
RES= V1_real-V1_real/I_real
V1_real= (V1* 1.2) / 2825 + 0.09 and 0< V1 < 4000 (12 bit converter for V1)
V2_real= (V2* 1.2) / 2825 + 0.09 and 0< V2 < 4000
I_real = I*1e-12 0<I<4000
So I am having 2 global variables assigned value with time(NULL) value. Now after 5 sec, I want to have my previous Time value remain unchanged and only current Time value gets modified. I want to display the time duration. So I have written the code but not getting the right result. On one compiler (DevC++) I get the proper result as timDrn == 5 but with an online compiler I get both variables at the same value and timDrn == 0. So am I going right or wrong? I want prevTim to remain unchanged and curTim value to be increased by 5 with timeDrn = 5.
My results with a local compiler (DevC++)
prevTim = 1585569873
curTim = 1585569873
prevTim = 1585569873
curTim = 1585569878
time duration = 5
My results with an online compiler
prevTim = 1585569915
curTim = 1585569915
prevTim = 1585569915
curTim = 1585569915
time duration = 0
#include<stdio.h>
#include<time.h>
int prevTim ;
int curTim;
void delay(int number_of_seconds)
{
// Converting time into milli_seconds
int milli_seconds = 1000 * number_of_seconds;
// Storing start time
clock_t start_time = clock();
// looping till required time is not achieved
while (clock() < start_time + milli_seconds)
;
}
int main(void)
{
int itr ,timDrn ;
prevTim =time(NULL);
curTim = prevTim;
printf("prevTim = %d \n",prevTim);
printf("curTim = %d \n",curTim);
for(itr = 0 ;itr < 5 ;itr ++)
{
delay(1); //1 sec delay function
curTim =time(NULL);
}
timDrn =curTim - prevTim ;
printf("prevTim = %d \n",prevTim);
printf("curTim = %d \n",curTim);
printf("time duration = %d \n",timDrn);
return 0;
}
On the online compiler, the time at the end of the program is the same as when it started. So I guess your delay function probably returns immediately to avoid people putting very long delays and having their program run for ever on the website. Trust your local compiler. An online compiler is for convenience and basic testing, not for real work.
Also, delay doesn't exist in time.h, so I wonder how this compiles. Usually, one uses sleep.
The delay function incorrectly assumes clock returns time in milliseconds. The C standard does not specify this. Per C 2018 7.27.2.1 3:
To determine the time in seconds, the value returned by the clock function should be divided by the value of the macro CLOCKS_PER_SEC.
Delaying a program in this way is wasteful because it consumes processor time and is disrespectful in a submission to an online compiler. Although there is no standard C function to suspend program execution for a time, many systems provide a sleep function that will. (This is not wasteful because it requests the operating system to suspend program execution, so the processor can do other work or go into a low-power state.)
I'm writing a pong-type game in C, which will run on an ARM board over an LCD screen. Part of the requirements for the game is something called 'magic time'.
A "magic time" period occurs at random intervals between 5 and 10 seconds - i.e, between 5 and 10 seconds after the last "magic time" period, and lasts for a random duration of 2 to 10 seconds.
I don't really understand your question (do you execute this code every second via timer interrupt, or?), but there are some errors that I see on the first sight:
while (magicTime == true) {
magicTimeLength++;
magicTime == magicTimeLength;
}
Last line (magicTime == magicTimeLength;) don't do anything - it simply evaluates if magicTime is equal to the magicTimeLength, so you will enter dead-loop.
I think that you want to do this:
Init magicTimeOccurence with random value within 5 and 10.
Init magicTimeLength with random value within 2 and 10.
Every second, if magicTimeOccurence is greater than 0, decrease
its value by one.
Once magicTimeOccurence hits 0, decrease magicTimeLength value
by one.
Check if magicTimeLength is greater than 0. If it is, it is magic
time period (so, set the magicTime flag to true). Decrement
magicTimeLength.
If magicTimeLength, set magicTime to false and go to step 1.
You should initialize your timer0 interrupt with period of 1s. I think that you accomplished it with
/* Set timer 0 period */
T0PR = 0;
T0MR0 = SYS_GetFpclk(TIMER0_PCLK_OFFSET)/(TIMER0_TICK_PER_SEC);
but make sure that is triggered every second.
Here is sample code, it should show you what I mean.
/* In void InitTimer0Interrupt() */
...
T0TCR_bit.CE = 1; /* Counting Enable */
magicTimeOccurence = 5+(rand()%5);
magicTimeLength = 2+(rand()%8);
magicTime = false;
__enable_interrupt();
}
/* In void Timer0IntrHandler (void) */
void Timer0IntrHandler (void) {
/* clear interrupt */
T0IR_bit.MR0INT = 1;
VICADDRESS = 0;
if(magicTimeOccurence > 0)
{
magicTimeOccurence--;
}
else if(magicTimeLength > 0){
magicTime = true;
magicTimeLenght--;
}
else{
magicTime = false;
magicTimeOccurence = 5+(rand()%5);
magicTimeLength = 2+(rand()%8);
}
/* take action on timer interrupt */
}