I have made a program that runs and I am able to enter in three variables, length, external diameter and internal diameter. After I enter in internal diameter the program freezes and a window pops up saying the program has stopped responding. The program's purpose is to calculate area, volume, mass, weight etc. of a cylindrical pipe given a number of variable inputs.
Any help would be appreciated.
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#define PI 3.14159
#define ACC_GRAVITY 9.81 /* metres/sec^2 */
#define FALSE 0
#define TRUE !FALSE
int main(void)
{
/* define the required variables */
float length;
float ext_diam, int_diam;
float ext_rad, int_rad;
float volume;
float weight;
float area;
float mass;
float width;
float flag_1, flag_2, thickness, percent;
double no_sheets;
/* define some constants - could use #define */
const float density_convert = 1.0E3;
const float mm_to_metres = 1.0E-3;
const float density = 8.03; /* grams per cm^3 */
/* prompt and get values */
printf("input the length of pipe in metres: ");
scanf("%f", &length);
do
{
flag_1 = FALSE;
flag_2 = FALSE;
printf("intput the external diameter of the pipe in milimeters: ");
scanf("%f", &ext_diam);
printf("ext_diam: %f\n", ext_diam);
printf("intput the internal diameter of the pipe in milimeters: ");
scanf("%f", int_diam);
printf("int_diam: %f\n", int_diam);
if (ext_diam < int_diam)
{
printf("external diameter must be greater than the internal diameter\n");
flag_1 = TRUE;
}
else
{
percent = thickness / ext_diam * 100.0;
if(percent > 2.5 )
{
/* do calculations - conversions, area of pipe cross-section, volume
** of pipe, mass and weight of pipe */
ext_diam = ext_diam * mm_to_metres;
int_diam = int_diam * mm_to_metres;
ext_rad = ext_diam / 2.0;
int_rad = int_diam / 2.0;
area = (PI * ext_rad * ext_rad) - (PI * int_rad * int_rad);
volume = area * length;
mass = volume * density * density_convert;
weight = mass * ACC_GRAVITY;
}
else
{
printf("Width of pipe too small\n");
flag_2 = TRUE;
}
}
} while(ext_diam > 0.0);
/* output the results */
printf("area of cylinder: %f m^2\n", area);
printf("volume of steel needed: %f m^3\n", volume);
printf("mass of steel needed: %f kg\n", mass);
printf("weight of steel needed: %f newtons\n", weight);
/* compute number of sheets of steel needed - 10m is max length of a
** sheet */
no_sheets = trunc (length / 10.0) + 1;
printf("number of 10m long sheets needed: %d\n", no_sheets);
/* assume width of sheets is based on the average of the internal and
** external diameters */
width = 2.0 * PI * (ext_rad + int_rad) / 2.0;
printf("width of sheets: %f m\n",width);
system("pause");
return 0;
}
There are some issues with your code:
scanf("%f", int_diam);, scanf needs a pointer to the variable, this will work
scanf("%f", &int_diam);
In the line
percent = thickness / ext_diam * 100.0;
thickness is not initialized the first time it is used (did you forget a passage?)
Not sure if the termination when ext_diam is <= 0 is intended.
Finally, there are multiple double-to-float conversions (e.g. area calculus) which might cause loss of data
Change scanf("%f", int_diam); to scanf("%f", &int_diam);
Also, your do while loop seems to go into an infinite loop. Since it depends on the external diameter, either change the loop condition, or ensure that external diameter will reach a value <=0 inside the loop. Your do while loop will only terminate when user enters a non-positive value for ext_diam.
Also, assuming thickness refers to the thickness of the pipe, add this equation before you use this variable thickness=ext_diam-int_diam;, or any other formula you use to calculate the thickness.
Related
I am making a physics-based where balls (gdi+ ellipses) will collide. There are 4 conditions I need to program to make the collisions work correctly. To do this I'm using if statements.
I noticed when debugging that in some cases, the code inside the if block is NOT executed as if the condition was not met - however - changing the code inside that if block will still alter the way my program works.
I've extensively debugged to ensure this is what's happening. I've also switched up the way I'm writing my if statements to ensure the logic is correct, but the problem persists.
When the game is started, I add a couple of balls to a vector.
/**
* Start a new game
*/
void CGame::NewGame()
{
this->mBalls.clear();
shared_ptr<CBall> cueBall = make_shared<CBall>(this);
cueBall->SetX(410.0);
cueBall->SetY(379.0 - (25 / 2) - 110);
cueBall->SetVelocityX(0);
cueBall->SetVelocityY(160.0);
this->mGameItems.push_back(cueBall);
shared_ptr<CBall> ball1 = make_shared<CBall>(this);
ball1->SetX(420.0);
ball1->SetY(379.0 - (25 / 2));
this->mGameItems.push_back(ball1);
}
They are then drawn on the screen by iterating through the vector CGame.mGameItems and calling a Draw function on each one.
/**
* Draw the ball with as a circle
* \param graphics The GDI+ graphics context to draw on
*/
void CBall::Draw(Gdiplus::Graphics* graphics)
{
SolidBrush colorBrush(Color(255, 1000, 1000, 1000));
graphics->FillEllipse(&colorBrush, Rect(this->GetX(), this->GetY(), this->diameter, this->diameter));
}
The redrawing and updating of the window is done in CChildView::OnPaint.
/** This function is called to draw in the window.
*
* This function is called in response to a drawing message
* whenever we need to redraw the window on the screen.
* It is responsible for painting the window.
*/
void CChildView::OnPaint()
{
CPaintDC paintDC(this); // device context for painting
CDoubleBufferDC dc(&paintDC); // device context for painting
Graphics graphics(dc.m_hDC); // Create GDI+ graphics context
mGame.OnDraw(&graphics);
// TODO: Add your message handler code here
// Do not call CWnd::OnPaint() for painting messages
if (mFirstDraw)
{
mFirstDraw = false;
SetTimer(1, FrameDuration, nullptr);
/*
* Initialize the elapsed time system
*/
LARGE_INTEGER time, freq;
QueryPerformanceCounter(&time);
QueryPerformanceFrequency(&freq);
mLastTime = time.QuadPart;
mTimeFreq = double(freq.QuadPart);
}
/*
* Compute the elapsed time since the last draw
*/
LARGE_INTEGER time;
QueryPerformanceCounter(&time);
long long diff = time.QuadPart - mLastTime;
double elapsed = double(diff) / mTimeFreq;
mLastTime = time.QuadPart;
mGame.Update(elapsed);
}
To handle collisions of the objects, a function calls a function called Update() on a CGame object which uses the following code to check if a collision happened.
/** Handle updates for animation
* \param elapsed The time since the last update
*/
void CGame::Update(double elapsed)
{
// Collisions of balls
for (shared_ptr<CBall> ball1 : this->GetBalls())
{
for (shared_ptr<CBall> ball2 : this->GetBalls())
{
double centerXBall1 = ball1->GetX() + ball1->GetDiameter() / 2;
double centerYBall1 = ball1->GetY() + ball1->GetDiameter() / 2;
double centerXBall2 = ball2->GetX() + ball2->GetDiameter() / 2;
double centerYBall2 = ball2->GetY() + ball2->GetDiameter() / 2;
double distance = sqrt((pow((centerXBall2 - centerXBall1), 2) +
pow((centerYBall2 - centerYBall1), 2)));
if (ball1 != ball2 && (distance <= ball1->GetDiameter() || distance <= ball2->GetDiameter()))
{
// The slope of the line that passes through the center of both
// balls
double slopeThroughCenters =
(centerYBall2 - centerYBall1) / (centerXBall2 -
centerXBall1);
// The angle between a vertical and the deflection direction of
// ball 1
double angleOfVelocity1 = 0.0;
// The angle between a horizontal line and the deflection
// direction of ball 2
double angleOfVelocity2 = 0.0;
double complimentaryAngle = atan(slopeThroughCenters);
if (centerXBall1 > centerXBall2 && centerYBall1 > centerYBall2)
{
angleOfVelocity1 = PI / 2 - complimentaryAngle;
angleOfVelocity2 = (PI / 2 - complimentaryAngle) + PI / 2;
}
double initialVelocityBall1 = sqrt(pow(ball1->GetVelocityX(), 2) +
pow(ball1->GetVelocityY(), 2));
double initialVelocityBall2 = sqrt(pow(ball2->GetVelocityX(), 2) +
pow(ball2->GetVelocityY(), 2));
double finalVelocityBall1 = ((ball1->GetMass() - ball2->GetMass()) * initialVelocityBall1) /
(ball1->GetMass() + ball2->GetMass());
double finalVelocityBall2 = (2 * ball1->GetMass() * initialVelocityBall1) /
(ball1->GetMass() + ball2->GetMass());
double velocityXBall1 = finalVelocityBall2 * cos(angleOfVelocity1);
double velocityYBall1 = finalVelocityBall2 * sin(angleOfVelocity1);
double velocityXBall2 = finalVelocityBall2 * cos(angleOfVelocity2);
double velocityYBall2 = finalVelocityBall2 * sin(angleOfVelocity2);
ball1->SetVelocityX(velocityXBall1);
ball1->SetVelocityY(velocityYBall1);
ball2->SetVelocityX(velocityXBall2);
ball2->SetVelocityY(velocityYBall2);
}
}
}
for (auto ball : this->mBalls)
{
ball->Update(elapsed);
}
}
When I run the debugger, the if block:
if (centerXBall1 > centerXBall2 && centerYBall1 > centerYBall2)
{
angleOfVelocity1 = PI / 2 - complimentaryAngle;
angleOfVelocity2 = PI - complimentaryAngle;
}
Doesn't seem to be executed, however, if I change the variable's values, for example,
angleOfVelocity1 = PI;
angleOfVelocity2 = PI;
My program actually changes according to the values of those variables. How is this possible if the debugger shows that the if block isn't executed in the first place?
Sorry if my code isn't minimalistic and concise enough, but I did not want to leave out anything important for solving this problem.
This question already has answers here:
Why does division result in zero instead of a decimal?
(5 answers)
Integer division always zero [duplicate]
(1 answer)
Closed 5 years ago.
I'm calculating angles using an IMU which as you may know involves a lot of maths. In-order to get angles at any moment, a time stamp of each reading is applied which is used to determine the refresh rate/update rate which i used in the equation.
The idea is to get a value which i can use as the rate relative to a whole second(1000 ms),i do-: 1 / (1000 / TimeStamp difference) / gyro Scale value which results in a very small decimal when done by hand, doing this with C++ yields 0 every time which is confusing because its in the exact order i should do it in.
Thanks in advance;
Kelvin
#include "stdafx.h"
typedef struct {
double Accel_X; /*!< Accelarometer value X axis */
double Accel_Y; /*!< Accelarometer value Y axis */
double Accel_Z; /*!< Accelarometer value Z axis */
double Gyroscope_X; /*!< Gyroscope value X axis */
double Gyroscope_Y; /*!< Gyroscope value Y axis */
double Gyroscope_Z; /*!< Gyroscope value Z axis */
__int16 Temperature; /*!< Temperature in degrees */
__int32 TimeStamp; /*!< Time in Ms when measurement was taken */
bool isPopulated; /*!< Indicates if the current instance has been populated */
} MPU6050_Raw_Result_Calib;
MPU6050_Raw_Result_Calib LatestResultRaw_Calib[2];
float xAngle;
double gyroScale = 65.5;
double calc()
{
double actualRate;
if (!LatestResultRaw_Calib[0].isPopulated && !LatestResultRaw_Calib[1].isPopulated)
return 0;
__int16 refreshRate = LatestResultRaw_Calib[0].TimeStamp - LatestResultRaw_Calib[1].TimeStamp;
actualRate = 1 / (1000 / refreshRate) / gyroScale;
xAngle += LatestResultRaw_Calib[0].Gyroscope_X * actualRate;
return xAngle;
}
int main()
{
LatestResultRaw_Calib[0].Gyroscope_X = 1;
LatestResultRaw_Calib[0].isPopulated = true;
LatestResultRaw_Calib[0].TimeStamp = 1565;
LatestResultRaw_Calib[1].Gyroscope_X = 15;
LatestResultRaw_Calib[1].isPopulated = true;
LatestResultRaw_Calib[1].TimeStamp = 1500;
while (1)
{
printf("%f ", calc());
}
}
In your equations and definitions, use a double format ie. 1.0, 1565.0, and so on
I realize issue has been asked many times, but after reading many many similar questions I am still unable to understand and solve this issue. I am a novice coder and am still learning, and for many days i have been unable to solve this issue.
I am using a demo code library from arduino and trying to compile it in c++ Atmel Studio 7 (compiling for a custom board i made based on ATSAMD21). Here is my relevant code (removed all unrelated parts):
#include <Arduino.h>
#include <Wire.h>
#include "Kalman.h" // Source: https://github.com/TKJElectronics/KalmanFilter
//Beginning of Auto generated function prototypes by Atmel Studio
uint8_t i2cWrite(uint8_t registerAddress, uint8_t data, bool sendStop);
uint8_t i2cWrite(uint8_t registerAddress, uint8_t data, uint8_t length, bool sendStop);
uint8_t i2cRead(uint8_t registerAddress, uint8_t data, uint8_t nbytes);
//End of Auto generated function prototypes by Atmel Studio
#define RESTRICT_PITCH // Comment out to restrict roll to ±90deg instead - please read: http://www.freescale.com/files/sensors/doc/app_note/AN3461.pdf
Kalman kalmanX; // Create the Kalman instances
Kalman kalmanY;
/* IMU Data */
double accX, accY, accZ;
double gyroX, gyroY, gyroZ;
int16_t tempRaw;
double gyroXangle, gyroYangle; // Angle calculate using the gyro only
double compAngleX, compAngleY; // Calculated angle using a complementary filter
double kalAngleX, kalAngleY; // Calculated angle using a Kalman filter
uint32_t timer;
uint8_t i2cData[14]; // Buffer for I2C data
// TODO: Make calibration routine
#if defined(ARDUINO_SAMD_ZERO) && defined(SERIAL_PORT_USBVIRTUAL)
// Required for Serial on Zero based boards
#define Serial SERIAL_PORT_USBVIRTUAL
#endif
void setup() {
Serial.begin(115200);
Wire.begin();
//TWBR = ((F_CPU / 400000L) - 16) / 2; // Set I2C frequency to 400kHz
i2cData[0] = 7; // Set the sample rate to 1000Hz - 8kHz/(7+1) = 1000Hz
i2cData[1] = 0x00; // Disable FSYNC and set 260 Hz Acc filtering, 256 Hz Gyro filtering, 8 KHz sampling
i2cData[2] = 0x00; // Set Gyro Full Scale Range to ±250deg/s
i2cData[3] = 0x00; // Set Accelerometer Full Scale Range to ±2g
while (i2cWrite(0x19, *i2cData, 4, false)); // Write to all four registers at once
while (i2cWrite(0x6B, 0x01, true)); // PLL with X axis gyroscope reference and disable sleep mode
while (i2cRead(0x75, *i2cData, 1));
if (i2cData[0] != 0x68) { // Read "WHO_AM_I" register
Serial.print(F("Error reading sensor"));
while (1);
}
//delay(100); // Wait for sensor to stabilize
/* Set kalman and gyro starting angle */
while (i2cRead(0x3B, *i2cData, 6));
accX = (i2cData[0] << 8) | i2cData[1];
accY = (i2cData[2] << 8) | i2cData[3];
accZ = (i2cData[4] << 8) | i2cData[5];
// Source: http://www.freescale.com/files/sensors/doc/app_note/AN3461.pdf eq. 25 and eq. 26
// atan2 outputs the value of -π to π (radians) - see http://en.wikipedia.org/wiki/Atan2
// It is then converted from radians to degrees
#ifdef RESTRICT_PITCH // Eq. 25 and 26
double roll = atan2(accY, accZ) * RAD_TO_DEG;
double pitch = atan(-accX / sqrt(accY * accY + accZ * accZ)) * RAD_TO_DEG;
#else // Eq. 28 and 29
double roll = atan(accY / sqrt(accX * accX + accZ * accZ)) * RAD_TO_DEG;
double pitch = atan2(-accX, accZ) * RAD_TO_DEG;
#endif
kalmanX.setAngle(roll); // Set starting angle
kalmanY.setAngle(pitch);
gyroXangle = roll;
gyroYangle = pitch;
compAngleX = roll;
compAngleY = pitch;
timer = micros();
}
void loop() {
/* Update all the values */
while (i2cRead(0x3B, *i2cData, 14));
accX = ((i2cData[0] << 8) | i2cData[1]);
accY = ((i2cData[2] << 8) | i2cData[3]);
accZ = ((i2cData[4] << 8) | i2cData[5]);
tempRaw = (i2cData[6] << 8) | i2cData[7];
gyroX = (i2cData[8] << 8) | i2cData[9];
gyroY = (i2cData[10] << 8) | i2cData[11];
gyroZ = (i2cData[12] << 8) | i2cData[13];
double dt = (double)(micros() - timer) / 1000000; // Calculate delta time
timer = micros();
// Source: http://www.freescale.com/files/sensors/doc/app_note/AN3461.pdf eq. 25 and eq. 26
// atan2 outputs the value of -π to π (radians) - see http://en.wikipedia.org/wiki/Atan2
// It is then converted from radians to degrees
#ifdef RESTRICT_PITCH // Eq. 25 and 26
double roll = atan2(accY, accZ) * RAD_TO_DEG;
double pitch = atan(-accX / sqrt(accY * accY + accZ * accZ)) * RAD_TO_DEG;
#else // Eq. 28 and 29
double roll = atan(accY / sqrt(accX * accX + accZ * accZ)) * RAD_TO_DEG;
double pitch = atan2(-accX, accZ) * RAD_TO_DEG;
#endif
double gyroXrate = gyroX / 131.0; // Convert to deg/s
double gyroYrate = gyroY / 131.0; // Convert to deg/s
#ifdef RESTRICT_PITCH
// This fixes the transition problem when the accelerometer angle jumps between -180 and 180 degrees
if ((roll < -90 && kalAngleX > 90) || (roll > 90 && kalAngleX < -90)) {
kalmanX.setAngle(roll);
compAngleX = roll;
kalAngleX = roll;
gyroXangle = roll;
} else
kalAngleX = kalmanX.getAngle(roll, gyroXrate, dt); // Calculate the angle using a Kalman filter
if (abs(kalAngleX) > 90)
gyroYrate = -gyroYrate; // Invert rate, so it fits the restriced accelerometer reading
kalAngleY = kalmanY.getAngle(pitch, gyroYrate, dt);
#else
// This fixes the transition problem when the accelerometer angle jumps between -180 and 180 degrees
if ((pitch < -90 && kalAngleY > 90) || (pitch > 90 && kalAngleY < -90)) {
kalmanY.setAngle(pitch);
compAngleY = pitch;
kalAngleY = pitch;
gyroYangle = pitch;
} else
kalAngleY = kalmanY.getAngle(pitch, gyroYrate, dt); // Calculate the angle using a Kalman filter
if (abs(kalAngleY) > 90)
gyroXrate = -gyroXrate; // Invert rate, so it fits the restriced accelerometer reading
kalAngleX = kalmanX.getAngle(roll, gyroXrate, dt); // Calculate the angle using a Kalman filter
#endif
gyroXangle += gyroXrate * dt; // Calculate gyro angle without any filter
gyroYangle += gyroYrate * dt;
//gyroXangle += kalmanX.getRate() * dt; // Calculate gyro angle using the unbiased rate
//gyroYangle += kalmanY.getRate() * dt;
compAngleX = 0.93 * (compAngleX + gyroXrate * dt) + 0.07 * roll; // Calculate the angle using a Complimentary filter
compAngleY = 0.93 * (compAngleY + gyroYrate * dt) + 0.07 * pitch;
// Reset the gyro angle when it has drifted too much
if (gyroXangle < -180 || gyroXangle > 180)
gyroXangle = kalAngleX;
if (gyroYangle < -180 || gyroYangle > 180)
gyroYangle = kalAngleY;
uint32_t time = millis();
/* Print Data */
#if 1 // Set to 1 to activate
Serial.print(accX); Serial.print("\t");
Serial.print(accY); Serial.print("\t");
Serial.print(accZ); Serial.print("\t");
Serial.print(gyroX); Serial.print("\t");
Serial.print(gyroY); Serial.print("\t");
Serial.print(gyroZ); Serial.print("\t");
Serial.print(time); Serial.print("\t");
Serial.print("\t");
#endif
#if 0
Serial.print(roll); Serial.print("\t");
Serial.print(gyroXangle); Serial.print("\t");
Serial.print(compAngleX); Serial.print("\t");
Serial.print(kalAngleX); Serial.print("\t");
Serial.print("\t");
Serial.print(pitch); Serial.print("\t");
Serial.print(gyroYangle); Serial.print("\t");
Serial.print(compAngleY); Serial.print("\t");
Serial.print(kalAngleY); Serial.print("\t");
#endif
#if 1 // Set to 1 to print the temperature
Serial.print("\t");
double temperature = (double)tempRaw / 340.0 + 36.53;
Serial.print(temperature); Serial.print("\t");
#endif
Serial.print("\r\n");
//delay(2);
}
const uint8_t IMUAddress = 0x68; // AD0 is logic low on the PCB
const uint16_t I2C_TIMEOUT = 1000; // Used to check for errors in I2C communication
uint8_t i2cWrite(uint8_t registerAddress, uint8_t data, bool sendStop) {
return i2cWrite(registerAddress, &data, 1, sendStop); // INVALID CONVERSION ERROR HERE
}
uint8_t i2cWrite(uint8_t registerAddress, uint8_t *data, uint8_t length, bool sendStop) {
Wire.beginTransmission(IMUAddress);
Wire.write(registerAddress);
Wire.write(data, length);
uint8_t rcode = Wire.endTransmission(sendStop); // Returns 0 on success
if (rcode) {
Serial.print(F("i2cWrite failed: "));
Serial.println(rcode);
}
return rcode; // See: http://arduino.cc/en/Reference/WireEndTransmission
}
uint8_t i2cRead(uint8_t registerAddress, uint8_t *data, uint8_t nbytes) {
uint32_t timeOutTimer;
Wire.beginTransmission(IMUAddress);
Wire.write(registerAddress);
uint8_t rcode = Wire.endTransmission(false); // Don't release the bus
if (rcode) {
Serial.print(F("i2cRead failed: "));
Serial.println(rcode);
return rcode; // See: http://arduino.cc/en/Reference/WireEndTransmission
}
Wire.requestFrom(IMUAddress, nbytes, (uint8_t)true); // Send a repeated start and then release the bus after reading
for (uint8_t i = 0; i < nbytes; i++) {
if (Wire.available())
data[i] = Wire.read();
else {
timeOutTimer = micros();
while (((micros() - timeOutTimer) < I2C_TIMEOUT) && !Wire.available());
if (Wire.available())
data[i] = Wire.read();
else {
Serial.println(F("i2cRead timeout"));
return 5; // This error value is not already taken by endTransmission
}
}
}
return 0; // Success
}
The above code gives error in the i2cWrite function at line 195 Col 54:
invalid conversion from 'uint8_t* {aka unsigned char*}' to 'uint8_t {aka unsigned char}' -fpermissive
Note that i modified the above code first and added an *asterisk to i2cWrite/i2cRead array on lines 43, 46, 55, 83. If i don't add those then the same exact error on ALL those lines as well. Since the original code didn't have those *references maybe I wasn't supposed to add those pointers...?
I am trying to learn about pointers and references, but struggling. For the life of me i cannot understand how to solve this error. I've tried various & and * but for the life of me can't understand and correct this issue. I just cant seem to understand how/where my code is trying to assign a uint8_t* to uint8_t.
Per other topics, do i need to cast or use volatile or const to any of these variables? I don't think so but again i'm a beginner.
I'd be very grateful for anyone to point me in the right direction or help me understand a solution. In Arduino i can compile and run this code, but not in Atmel Studio. Any help is much appreciated.
EDIT: I've updated the code and removed the comments so that the error and line numbers match up with my post. Apologies for confusion on the line #s.
You need to declare the function before calling it.
In the definition of i2cWrite, it cannot see the declaration of the overload that receives a pointer as argument. Because of that, the compiler is assuming you are calling the function recursively, in which has a argument with wrong type.
This is a problem:
uint8_t i2cWrite(uint8_t registerAddress, uint8_t data, bool sendStop) {
return i2cWrite(registerAddress, &data, 1, sendStop); // Returns 0 on success
}
As shown by the first line, i2cWrite takes 3 arguments: uint8_t, uint8_t, and bool. But then you call it with 4 arguments: uint8_t, uint8_t *, int, bool.
Then after that you declare another function called i2cWrite that takes 4 arguments. This is not allowed .
It's hard to say but I'm guessing that you wanted these functions to have different names, the 3-argument one and the 4-argument one.
Thanks to both answers. The solution was simply my function prototypes at the very beginning were slightly different. The 2nd i2cWrite declaration was missing the derefernce *asterisk. That fixed it right up.
I used gnuplot in a cpp code. I take the code from a guide. I tun this code without error,but the graphics can not be show.
Code :
#define GNUPLOT "gnuplot -persist"
int main(int argc, char **argv)
{
FILE *gp;
gp = popen(GNUPLOT,"w"); /* ’gp’ is the pipe descriptor */
if (gp==NULL)
{
printf("Error opening pipe to GNU plot. Check if you have it! \n");
return 0;
}
fprintf(gp, "set samples 2000\n");
fprintf(gp, "plot cos(x) \n");
fprintf(gp, "rep sin(x) \n");
fclose(gp);
return 0;
}
EDIT 1
I tried examples from another guide. I compile and run without error them, but the graph does not appear. I use linux os.
Code2 :
#include <stdio.h>
#include <plot.h>
#include <math.h>
#define SIZE 100.0 /* nominal size of user coordinate frame */
#define EXPAND 2.2 /* expansion factor for elliptical box */
void draw_boxed_string (plPlotter *plotter,
char *s, double size, double angle)
{
double true_size, width;
pl_ftextangle_r (plotter, angle); /* set text angle (degrees) */
true_size = pl_ffontsize_r (plotter, size); /* set font size */
width = pl_flabelwidth_r (plotter, s); /* compute width of string */
pl_fellipserel_r (plotter, 0.0, 0.0,
EXPAND * 0.5 * width, EXPAND * 0.5 * true_size,
angle); /* draw surrounding ellipse */
pl_alabel_r (plotter, 'c', 'c', s); /* draw centered text string */
}
int main()
{
plPlotter *plotter;
plPlotterParams *plotter_params;
int i;
/* set a Plotter parameter */
plotter_params = pl_newplparams ();
pl_setplparam (plotter_params, "PAGESIZE", "letter");
/* create a Postscript Plotter that writes to standard output */
if ((plotter = pl_newpl_r ("ps", stdin, stdout, stderr,
plotter_params)) == NULL)
{
fprintf (stderr, "Couldn't create Plotter\n");
return 1;
}
if (pl_openpl_r (plotter) < 0) /* open Plotter */
{
fprintf (stderr, "Couldn't open Plotter\n");
return 1;
}
/* specify user coor system */
pl_fspace_r (plotter, -(SIZE), -(SIZE), SIZE, SIZE);
pl_pencolorname_r (plotter, "blue"); /* use blue pen */
pl_fillcolorname_r (plotter, "white"); /* set white fill color */
pl_filltype_r (plotter, 1); /* fill ellipses with fill color */
/* choose a Postscript font */
pl_fontname_r (plotter, "NewCenturySchlbk-Roman");
for (i = 80; i > 1; i--) /* loop through angles */
{
double theta, radius;
theta = 0.5 * (double)i; /* theta is in radians */
radius = SIZE / pow (theta, 0.35); /* this yields a spiral */
pl_fmove_r (plotter, radius * cos (theta), radius * sin (theta));
draw_boxed_string (plotter, "GNU libplot!", 0.04 * radius,
(180.0 * theta / M_PI) - 90.0);
}
if (pl_closepl_r (plotter) < 0) /* close Plotter */
{
fprintf (stderr, "Couldn't close Plotter\n");
return 1;
}
if (pl_deletepl_r (plotter) < 0) /* delete Plotter */
{
fprintf (stderr, "Couldn't delete Plotter\n");
return 1;
}
return 0;
}
You should run ./plot > a.ps not only ./plot
I'm very new to Arduino. I have much more experience with Java and ActionScript 3. I'm working on building a light meter out of an Arduino Uno and a TAOS TSL235R light-to-frequency converter.
I can only find a tuturial using a different sensor, so I am working my way through converting what I need to get it all to work (AKA some copy and paste, shamefully, but I'm new to this).
There are three parts: this is the first tutorial of the series Arduino and the Taos TSL230R Light Sensor: Getting Started.
The photographic conversion: Arduino and the TSL230R: Photographic Conversions.
At first, I could return values for the frequency created by the TSL235R sensor, but once I tried to add the code for photographic conversions I only get zero returned, and none of the funcions outside of the main loop seem to fire being that my Serial.Println() doesn't return anything.
I am more concerned with making the functions fire than if my math is perfect. In ActionScript and Java there are event listeners for functions and such, do I need to declare the function for it to fire in C/C++?
Basically, how can I make sure all my functions fire in the C programming language?
My Arduino Sketch:
// TSL230R Pin Definitions
#define TSL_FREQ_PIN 2
// Our pulse counter for our interrupt
unsigned long pulse_cnt = 0;
// How often to calculate frequency
// 1000 ms = 1 second
#define READ_TM 1000
// Two variables used to track time
unsigned long cur_tm = millis();
unsigned long pre_tm = cur_tm;
// We'll need to access the amount of time passed
unsigned int tm_diff = 0;
unsigned long frequency;
unsigned long freq;
float lux;
float Bv;
float Sv;
// Set our frequency multiplier to a default of 1
// which maps to output frequency scaling of 100x.
int freq_mult = 100;
// We need to measure what to divide the frequency by:
// 1x sensitivity = 10,
// 10x sensitivity = 100,
// 100x sensitivity = 1000
int calc_sensitivity = 10;
void setup() {
attachInterrupt(0, add_pulse, RISING); // Attach interrupt to pin2.
pinMode(TSL_FREQ_PIN, INPUT); //Send output pin to Arduino
Serial.begin(9600); //Start the serial connection with the copmuter.
}//setup
void loop(){
// Check the value of the light sensor every READ_TM ms and
// calculate how much time has passed.
pre_tm = cur_tm;
cur_tm = millis();
if( cur_tm > pre_tm ) {
tm_diff += cur_tm - pre_tm;
}
else
if( cur_tm < pre_tm ) {
// Handle overflow and rollover (Arduino 011)
tm_diff += ( cur_tm + ( 34359737 - pre_tm ));
}
// If enough time has passed to do a new reading...
if (tm_diff >= READ_TM ) {
// Reset the ms counter
tm_diff = 0;
// Get our current frequency reading
frequency = get_tsl_freq();
// Calculate radiant energy
float uw_cm2 = calc_uwatt_cm2( frequency );
// Calculate illuminance
float lux = calc_lux_single( uw_cm2, 0.175 );
}
Serial.println(freq);
delay(1000);
} //Loop
unsigned long get_tsl_freq() {
// We have to scale out the frequency --
// Scaling on the TSL230R requires us to multiply by a factor
// to get actual frequency.
unsigned long freq = pulse_cnt * 100;
// Reset pulse counter
pulse_cnt = 0;
return(freq);
Serial.println("freq");
} //get_tsl_freq
void add_pulse() {
// Increase pulse count
pulse_cnt++;
return;
Serial.println("Pulse");
}//pulse
float calc_lux_single(float uw_cm2, float efficiency) {
// Calculate lux (lm/m^2), using standard formula
// Xv = Xl * V(l) * Km
// where Xl is W/m^2 (calculate actual received uW/cm^2, extrapolate from sensor size
// to whole cm size, then convert uW to W),
// V(l) = efficiency function (provided via argument) and
// Km = constant, lm/W # 555 nm = 683 (555 nm has efficiency function of nearly 1.0).
//
// Only a single wavelength is calculated - you'd better make sure that your
// source is of a single wavelength... Otherwise, you should be using
// calc_lux_gauss() for multiple wavelengths.
// Convert to w_m2
float w_m2 = (uw_cm2 / (float) 1000000) * (float) 100;
// Calculate lux
float lux = w_m2 * efficiency * (float) 683;
return(lux);
Serial.println("Get lux");
} //lux_single
float calc_uwatt_cm2(unsigned long freq) {
// Get uW observed - assume 640 nm wavelength.
// Note the divide-by factor of ten -
// maps to a sensitivity of 1x.
float uw_cm2 = (float) freq / (float) 10;
// Extrapolate into the entire cm2 area
uw_cm2 *= ( (float) 1 / (float) 0.0136 );
return(uw_cm2);
Serial.println("Get uw_cm2");
} //calc_uwatt
float calc_ev( float lux, int iso ) {
// Calculate EV using the APEX method:
//
// Ev = Av + Tv = Bv + Sv
//
// We'll use the right-hand side for this operation:
//
// Bv = log2( B/NK )
// Sv = log2( NSx )
float Sv = log( (float) 0.3 * (float) iso ) / log(2);
float Bv = log( lux / ( (float) 0.3 * (float) 14 ) ) / log(2);
return( Bv + Sv );
Serial.println("get Bv+Sv");
}
float calc_exp_tm ( float ev, float aperture ) {
// Ev = Av + Tv = Bv + Sv
// need to determine Tv value, so Ev - Av = Tv
// Av = log2(Aperture^2)
// Tv = log2( 1/T ) = log2(T) = 2^(Ev - Av)
float exp_tm = ev - ( log( pow(aperture, 2) ) / log(2) );
float exp_log = pow(2, exp_tm);
return( exp_log );
Serial.println("get exp_log");
}
unsigned int calc_exp_ms( float exp_tm ) {
unsigned int cur_exp_tm = 0;
// Calculate mS of exposure, given a divisor exposure time.
if (exp_tm >= 2 ) {
// Deal with times less than or equal to half a second
if (exp_tm >= (float) int(exp_tm) + (float) 0.5 ) {
// Round up
exp_tm = int(exp_tm) + 1;
}
else {
// Round down
exp_tm = int(exp_tm);
}
cur_exp_tm = 1000 / exp_tm;
}
else if( exp_tm >= 1 ) {
// Deal with times larger than 1/2 second
float disp_v = 1 / exp_tm;
// Get first significant digit
disp_v = int( disp_v * 10 );
cur_exp_tm = ( 1000 * disp_v ) / 10;
}
else {
// Times larger than 1 second
int disp_v = int( (float) 1 / exp_tm);
cur_exp_tm = 1000 * disp_v;
}
return(cur_exp_tm);
Serial.println("get cur_exp_tm");
}
float calc_exp_aperture( float ev, float exp_tm ) {
float exp_apt = ev - ( log( (float) 1 / exp_tm ) / log(2) );
float apt_log = pow(2, exp_apt);
return( apt_log );
Serial.println("get apt_log");
}
That is a lot of code to read, where should I start.
In your loop() you are assigning frequency but printing freq
// get our current frequency reading
frequency = get_tsl_freq();
-- snip --
Serial.println(freq);
in get_tsl_freq() you are creating a local unsigned int freq that hides the global freq and using that for calculation and returning the value, maybe that is also a source of confusion for you. I do not see a reason for frequency and freq to be globals in this code. The function also contains unreachable code, the control will leave the function on return, statements after the return will never be executed.
unsigned long get_tsl_freq() {
unsigned long freq = pulse_cnt * 100; <-- hides global variable freq
// re-set pulse counter
pulse_cnt = 0;
return(freq); <-- ( ) not needed
Serial.println("freq"); <-- Unreachable
}
Reading a bit more I can suggest you pick up a C++ book and read a bit. While your code compiles it is not technically valid C++, you get away with it thanks to the Arduino software that does some mangling and what not to allow using functions before they are declared.
On constants you use in your calculations
float w_m2 = (uw_cm2 / (float) 1000000) * (float) 100;
could be written as
float w_m2 = (uw_cm2 / 1000000.0f) * 100.0f;
or even like this because uw_cm2 is a float
float w_m2 = (uw_cm2 / 1000000) * 100;
You also seem to take both approaches to waiting, you have code that calculates and only runs if it has been more than 1000 msec since it was last run, but then you also delay(1000) in the same code, this may not work as expected at all.