Basic PIC Programming issues - microcontroller

I am writing PIC code in C and encountered the following problems:
When I write my delay as _delay_ms(500), my code doesn't compile, it says it didn't recognize this instruction. I am using MPLAB.
I want to write a program that would count how many time the push button is pressed then return that value and display it using LED's. I know how to display it, but not how to make the program to wait for the push of the push button on the pickit.
main()
{
TRISA=0;//Sets all ports on A to be outputs
TRISB=1;//Sets all ports on B to be inputs
for(;;){
if(PORTBbits.RB0==1){//When the button is pressed the LED is off
PORTAbits.RA1 =0;
count=count+1;
}
else{
PORTAbits.RA1=1;
count = count +1;
}
if (count > 20){//if count =20 aka 20 button presses the LED turns on
PORTAbits.RA0=1;
}
else{
PORTAbits.RA0=0;
}
}
}

There are a few issues:
Assuming you're using a PIC24 or a dsPIC, you need to include libpic30.h
Before you include libpic30.h you need to #define FCY to be your instruction rate so that the delay takes the correct number of cycles. See the comments in the libpic30.h file for details.
The function is __delay_ms not _delay_ms. Note that there are two underscores at the beginning.
The name is all lower case, not Delay_ms as in your comment.

You need to add delay in your code when you detect a key is pressed. As you are saying the _delay_ms(500) is not recognized, You can try something like following:
unsigned char x;
// Just waste a few cycles to create delay
for (x = 0; x < 100; x++)
{
// No operation instruction
Nop();
}
You can create your own delay function with specific number of iterations of this for loop. Measure the exact delay created by this function using a profiler if you need. IMO any arbitrary delay, like say 100 iterations as stated above shall work.

Related

In this code can you please explain what is happening after the draw(n -1) function

#include <stdio.h>
#include <cs50.h>
void draw(int n);
int main(void)
{
int height = get_int("number:");
draw(height);
}
void draw(int n)
{
if(n <= 0)
{
return;
}
draw(n - 1);
for(int i = 0 ; i < n ; i++)
{
printf("#");
}
printf("\n");
}
Iam learing recursion topic, suppose the user input 4 when the compiler completes the if part the value of n is '0' and returning when i debug , but then the for loop starts the value of 'n' becomes '1' and also 'i' doesn't change it constantly 0 why is that iam expected n becomes 0 after the if draw(n - 1) completes.
I will try to make this explanation as simple as I can. First things first, To begin with, when using recursion, you would be noticing the calling of a method within itself with a different argument. In your case it is the draw method.
Now each time, a draw method is called inside another draw method, the outer method(in this case the draw that is called first) stops its flow of execution till the completion of the inner draw.
So when you called draw(4), it ran all the code till it reached line 5 in draw method, and called draw(3). Your for loop of draw(4) is not executed yet. This will continue till draw(1) calls a draw(0). At this stage, draw(0) will return out and the draw(1) will continue its for loop from where it left. So you would find that here n=1, leading to the first print of # and then a new line after it. Once the operation completes in here, it continues with where it left for draw(2). Which is the for loop in draw(2) where the value of n=2. And here it does two print of # and then a new line. This continues.
Now for the question why i is always 0, it is to do with what we call scopes in programming, you can see that each time the i is declared fresh in the loop and assigned a value 0. This means, each time a for loop is hit, the value of i is reinitialised to 0. If you had a global var i out side of your draw method, you would have had the value of i being retained.
I did try my best to put things in as simple form as possible but feel free to let me know if you needed more clarity.

Arduino: while (Serial.available()==0) gives input

I am trying to input GPS coordinate into the serial monitor to use in my drone project
However, whenever I try to input GPS coordinate, it automatically writes one of the GPS coordinates without my input. For example, GPS latitude is shown as 0.00, but the program waits for GPS Longitude info.
For a detailed situation please look at the picture attached.
int GPSNumCor;
void setup() {
// put your setup code here, to run once:
Serial.begin (115200);
Serial.print("What is the number of your GPS Coordinate? ");
while (Serial.available() == 0);
GPSNumCor = Serial.parseInt();
Serial.println(GPSNumCor);
delay (200);
float GPSLat[GPSNumCor], GPSLon[GPSNumCor];
for (int i = 0; i < GPSNumCor; i++)
{
if (i == 0)
{
Serial.println("What is your 1st GPS Coordinate");
}
if (i == 1)
{
Serial.println("What is your 2nd GPS Coordinate");
}
if (i == 2)
{
Serial.println("What is your 3rd GPS Coordinate");
}
if (i > 2)
{
Serial.print("What is your ");
Serial.print(i + 1);
Serial.println(" th GPS Coordinate");
}
delay(200);
Serial.print ("Latitude: ");
while (Serial.available() == 0);
GPSLat[i] = Serial.parseFloat();
Serial.println(GPSLat[i]);
Serial.print("Longitude: ");
while (Serial.available() == 0);
GPSLon[i] = Serial.parseFloat();
Serial.println(GPSLon[i]);
}
}
It has to wait for all input until I make an input to the program, but it does not wait.
I know while (Serial.available()==0) is a way to go, but I do not know why it would not work.
First, there's no reason to use while (Serial.available() == 0);. The parseFloat function you are about to use waits for data to be available and, if it didn't, merely checking for zero wouldn't be sufficient anyway because that would stop waiting as soon as a single character was available.
So here's why that while loop is a bad idea:
If you really do need to wait for the input before calling parseFloat, this won't do it. It only waits until at least one character is received and the coordinates may be more than one character.
The parseFloat function doesn't return until it has read an entire float anyway. So it already waits for you.
But that's not your problem. Think about the input stream, say it's "11.0<newline>22.0newline44.0". Where is the code to read the spaces between those numbers? When parseFloat tries to read a space, it returns a zero, as the documentation says. That's why you're getting zeroes -- you don't have any code to do anything with the separators between the floats.
Think about how parseFloat must work when it reads "12.34newline". First it reads the 1 and has no idea whether that's the whole number of not, so it keeps checking. Then it reads the "2.34" and still has no idea it has the whole number. Not until it sees the newline does it know that 12.34 is the correct float to return. But it does not consume the newline. Why? Because that might mean something.
With the code you showed, your next call to parseFloat will then try to read the newline and see that this is not a valid character to be part of a floating point number. So, as the documentation says, it will return zero.
Look closely at parseFloat's documentation to find out how to correctly match the delimiters in your serial stream. The parseFloat function has the ability to behave differently, consuming and ignoring delimeters rather than returning zero.
I don't know how it work, I just add Serial.read() in every time I want to read.
If u don't want to add Serial.read(), u can also use old version like 1.6.0, it still work fine but it don't work when u make like C# Serial app.
Just add Serial.read(), it work fine every place.
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
}
void loop() {
// put your main code here, to run repeatedly:
while(Serial.available()==0){}
int r=Serial.parseInt();
Serial.println(r);
Serial.read(); // it work fine
while(Serial.available()==0){}
int g=Serial.parseInt();
Serial.println(g);
Serial.read();
}
In the Serial Monitor window, in the drop-down menu on the bottom-right, change from "Newline" to "No line ending" and that will solve the problem (by preventing the Serial Monitor from automatically entering zero value(s)).
Both the parseInt() and parseFloat() have a hard time reading other data types (this also includes white spaces such as new lines) than the ones specified, and as a result they automatically return zero.
Reference: This page on Programming electronics offers valuable, detailed explanations (look for a paragraph with bold text):
https://www.programmingelectronics.com/parseint/

Arduino Function Execution Time

I have an Arduino and an APC220 wireless transceiver. I'm writing a library that reads in data from the APC using the SoftwareSerial class. I originally started with the (incorrect) code below that was causing a seg fault because the i variable is incremented even when there is no data available to read. In cases where it happened to work (by chance when the data was immediately available), this function took approximately 6 milliseconds to execute. When I put the i++; statement in its proper place (above the closing brace immediately above it), the function takes over 270 ms to run. Speed is crucial for this function, so I'm wondering what it is about that statement's placement that causes such a dramatic increase in time.
For the code below, buff is declared as char buff[10]; and sSerial is an instance of SoftwareSerial
unsigned long updateLocation(Marker* marker) {
this->sSerial->print('~');
//initiate request from vision system
this->sSerial->flush();
this->sSerial->print('#');
this->sSerial->print(marker->num);
this->sSerial->print('*');
this->sSerial->flush();
unsigned long start = millis();
int state = 0, i = 0;
while((millis() - start) < 600) {
if(this->sSerial->available()) {
buff[i] = this->sSerial->read();
if(buff[i] == ',') {
buff[i] = 0;
switch(state) {
case 0:
i = -1;
state++;
break;
case 1:
marker->x = atof(buff);
i = -1;
state++;
break;
case 2:
marker->y = atof(buff);
i = -1;
state++;
break;
case 3:
marker->theta = atof(buff);
i = -1;
return (millis() - start);
break;
default:
return 0;
break;
}
}
// Correct location for i++; takes 270 ms to execute
}
// Incorrect location for i++; Takes 6 ms to execute
i++;
}
this->sSerial->print('~');
this->sSerial->flush();
return 0;
}
Assuming that there's data ready and waiting from sSerial, there's no effective difference in the placement of i++.
You said yourself, in most cases the data isn't ready. With the incorrect placement of i++, i quickly grows to greater than the size of buff which causes the segfault.
With the correct placement, your code blocks for up to 600ms waiting for enough data to come in to reach case 3 and return. On average, you're seeing that it takes 270ms for that to happen.
You can test this theory yourself by timing the same function operating directly on a string rather than reading in from serial.
You may want to a) increase your baud rate b) check to see if there's a more efficient software serial implementation you can use c) switch to hardware serial. If you are only using hardware serial currently for debugging output, you can switch that around. Use an FTDI adapter ($6-10 on eBay) to pipe software serial to USB and reserve the hardware serial for your time sensitive function.
You might also be able to reconfigure your code so it doesn't block the whole time waiting. You can read in what's available, store it in a global and go back to your main loop to do something else until there's data available again.
edit: I see now that the APC220 is 9600 baud max. That's pretty slow, so the bottle neck may not be software serial (but you should test it). If the bottle neck is simply the baud rate, you will need to look at optimizing your code not to block waiting for input if there are other things your system can work on while it's waiting.

Calculating the average of Sensor Data (Capacitive Sensor)

So I am starting to mess around with Capacitive sensors and all because its some pretty cool stuff.
I have followed some tutorials online about how to set it up and use the CapSense library for Arduino and I just had a quick question about this code i wrote here to get the average for that data.
void loop() {
long AvrNum;
int counter = 0;
AvrNum += cs_4_2.capacitiveSensor(30);
counter++;
if (counter = 10) {
long AvrCap = AvrNum/10;
Serial.println(AvrCap);
counter = 0;
}
}
This is my loop statement and in the Serial it seems like its working but the numbers just look suspiciously low to me. I'm using a 10M resistor (brown, black, black, green, brown) and am touching a piece of foil that both the send and receive pins are attached to (electrical tape) and am getting numbers around about 650, give or take 30.
Basically I'm asking if this code looks right and if these numbers make sense...?
The language used in the Arduino environment is really just an unenforced subset of C++ with the main() function hidden inside the framework code supplied by the IDE. Your code is a module that will be compiled and linked to the framework. When the framework starts running it first initializes itself then your module by calling the function setup(). Once initialized, the framework enters an infinite loop, calling your modules function loop() on each iteration.
Your code is using local variables in loop() and expecting that they will hold their values from call to call. While this might happen in practice (and likely does since that part of framework's main() is probably just while(1) loop();), this is invoking the demons of Undefined Behavior. C++ does not make any promises about the value of an uninitialized variable, and even reading it can cause anything to happen. Even apparently working.
To fix this, the accumulator AvrNum and the counter must be stored somewhere other than on loop()'s stack. They could be declared static, or moved to the module outside. Outside is better IMHO, especially in the constrained Arduino environment.
You also need to clear the accumulator after you finish an average. This is the simplest form of an averaging filter, where you sum up fixed length blocks of N samples, and then use that average each Nth sample.
I believe this fragment (untested) will work for you:
long AvrNum;
int counter;
void setup() {
AvrNum = 0;
counter = 0;
}
void loop() {
AvrNum += cs_4_2.capacitiveSensor(30);
counter++;
if (counter == 10) {
long AvrCap = AvrNum/10;
Serial.println(AvrCap);
counter = 0;
AvrNum = 0;
}
}
I provided a setup(), although it is redundant with the C++ language's guarantee that the global variables begin life initialized to 0.
your line if (counter = 10) is invalid. It should be if (counter == 10)
The first sets counter to 10 and will (of course) evaluate to true.
The second tests for counter equal to 10 and will not evaluate to true until counter is, indeed, equal to 10.
Also, kaylum mentions the other problem, no initialization of AvrNum
This is What I ended up coming up with after spending some more time on it. After some manual calc it gets all the data.
long AvrArray [9];
for(int x = 0; x <= 10; x++){
if(x == 10){
long AvrMes = (AvrArray[0] + AvrArray[1] + AvrArray[2] + AvrArray[3] + AvrArray[4] + AvrArray[5] + AvrArray[6] + AvrArray[7] + AvrArray[8] + AvrArray[9]);
long AvrCap = AvrMes/x;
Serial.print("\t");
Serial.println(AvrCap);
x = 0;
}
AvrArray[x] = cs_4_2.capacitiveSensor(30);
Serial.println(AvrArray[x]);
delay(500);

how to recheck file in Arduino SD card

I am trying to create a list of files on my SD card this is easy enough to do once but the moment I run the program more than once the list become either shortened or the program say there is no files at all.
To make this as easy as possible I am using the SD example that comes with the arduino SD library and just putting the setup part ( that would normally run once ) in the loop part.
Heres what I have with that.
#include <SD.h>
File root;
void setup()
{
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}
Serial.print("Initializing SD card...");
// On the Ethernet Shield, CS is pin 4. It's set as an output by default.
// Note that even if it's not used as the CS pin, the hardware SS pin
// (10 on most Arduino boards, 53 on the Mega) must be left as an output
// or the SD library functions will not work.
pinMode(10, OUTPUT);
if (!SD.begin(10)) {
Serial.println("initialization failed!");
return;
}
Serial.println("initialization done.");
}
void loop()
{
Serial.println("hit any key then enter to run the list");
while(!Serial.available())
{;}
Serial.read();
root = SD.open("/");
printDirectory(root, 0);
Serial.println("done!");
// nothing happens after setup finishes.
}
void printDirectory(File dir, int numTabs) {
while(true) {
File entry = dir.openNextFile();
if (! entry) {
// no more files
//Serial.println("**nomorefiles**");
break;
}
for (uint8_t i=0; i<numTabs; i++) {
Serial.print('\t');
}
Serial.print(entry.name());
if (entry.isDirectory()) {
Serial.println("/");
printDirectory(entry, numTabs+1);
} else {
// files have sizes, directories do not
Serial.print("\t\t");
Serial.println(entry.size(), DEC);
}
}
}
But then I get this weird output after running it
Initializing SD card...initialization done.
hit any key then enter to run the list
HFBVYRG.TXT 7
THBVFG.TXT 7
WAZXDSQ.TXT 7
QAZXSW.TXT 21
WSXZAQ.TXT 7
1478523.TXT 7
QWSDFRE.TXT 7
ZXCVBNM.TXT 7
MKOLIJY.TXT 7
done!
hit any key then enter to run the list
HFBVYRG.TXT 7
THBVFG.TXT 7
WAZXDSQ.TXT 7
QAZXSW.TXT 21
WSXZAQ.TXT 7
1478523.TXT 7
QWSDFRE.TXT 7
ZXCVBNM.TXT 7
MKOLIJY.TXT 7
done!
hit any key then enter to run the list
HFBVYRG.TXT 7
THBVFG.TXT 7
WAZXDSQ.TXT 7
QAZXSW.TXT 21
done!
hit any key then enter to run the list
done!
hit any key then enter to run the list
done!
hit any key then enter to run the list
done!
hit any key then enter to run the list
////////////////////////////////////////////////////////////////////////////////////
as you can see it gets shorter and shorter then just stops altogether.
Does anyone have any ideas why ?
I have tried playing around with pointers and closing and reopening the file but I have come up with nothing.
Any ideas would be greatly appreciated.
No good can come from mismatched open()'s and close()'s. You open the root directory every pass through the loop:
root = SD.open("/");
but never
root.close();
First, fix this error and also check that when you open the root that you succeed before trying to print a listing:
root = SD.open("/");
if(root) {
printDirectory(root, 0);
Serial.println("done!");
root.close();
}
else {
Serial.println("failed to open directory");
}
Second, close the files that are opened in the directory walk
void printDirectory(File dir, int numTabs) {
while(true) {
File entry = dir.openNextFile();
...
entry.close();
}
return;
}
Lastly, consider not blocking in the loop(). Other things can happen outside your loop() and they will be blocked indefinitely depending on how long you wait to hit a key. A more typical code pattern is to spin wildly through the loop() as opposed to blocking waiting for user input. For example:
boolean bNeedPrompt = true;
void loop() {
// Show the prompt once, then mark as displayed so that text does not
// continuously scroll on the screen
if(bNeedPrompt) {
Serial.println("hit any key then enter to run the list");
bNeedPrompt = false;
}
if(Serial.available()) {
Serial.read();
// do action
// set flag so that prompt will display again
bNeedPrompt = true;
}
return;
}
jdr5ca's answer addresses a lot of the problems with your setup - by not closing files you are going to be leaking resources which won't end well. It is particularly important on such a low memory setup as the Arduino, which has only 2k RAM for the original chips, so worth bearing in mind throughout your code.
Short answer for your remaining question: it won't be entirely predictable, but low memory is likely the cause of your problem. Read on for more details.
I've had some similar experiences with the SD library recently, though not with such an obvious cause. I found that if the free memory on my system got below about 500 bytes (a quarter of the total RAM) then the SD library starts to behave very oddly when trying to list directories.
I saw similar things to you, for example:
list entries under root directory and find two sub-directories
list entries in one of those sub-directories, worked fine
list entries under root directory and now I find only one sub-directory! The one I had listed the contents of has vanished!
I could still list the contents of the sub-directory fine, ie. it is still there!
resetting the Arduino and starting again gave the same results, again showing that the files were still present on SD card
I think all of this comes down to SD library being both quite memory hungry (#include SD.h uses up 500 bytes off the bat!), and not handling low memory errors particularly obviously.
So if things are acting strangely then:
check your memory usage (see eg. freeRam() from http://playground.arduino.cc/Code/AvailableMemory)
reduce your memory usage where ever possible. In rough order:
remove libraries you don't need
get rid of any hard coded strings that you don't need (eg. in calls to Serial.print())
for hard coded strings you do need make them as short as possible, and store them in flash (eg. Serial.print(F("String in flash"));) rather than RAM
you can't stick format strings (eg. for snprintf) in flash currently, so avoid using those and just build up the output manually (it is more long handed but saves memory)
make sure you are using appropriate variable types everywhere (ie. the smallest sized type that will suit your purposes) - especially important if you have any arrays, for obvious reasons!

Resources