C Programming Help

salguod

Well-Known Member
Joined
Oct 29, 2007
Messages
681
I'm not quite sure if this is the right place for this or if it is where many people know about C Programming, but here goes.

For the engineering module on my Uni course, we are in groups and have to produce a working prototype based around a microcontroller and C Programming. It just so happens that the other two people in the group cannot do it even though they are engineering students so it has been left to me, a design student, to produce the code for the model. I know very little if any so any help in writing the code would be greatly appreciated.

Our model is of one of those remote control cars which had the controller attached by a wire. A motor is used to drive the wheels and another motor is used for the steering in a rack and pinion type of arrangement, which I have been assured by the 2 engineers will work, but I'm sceptical about it. There are 4 buttons. One for forward, one for back, left and right. There are also 4 LEDs for headlights.

To go forward, the forward button must be pressed. To go back, the back button is pressed. To go forward and left, both forward and left must be pressed and so on for the remaining directions. If the left button is pressed on its own, nothing will happen. If the left and right buttons are pressed simultaneously, the LEDs will light, and press again to turn them off.

Here is the code so far and initial tests have shown it sort of works for forward and back but I don't know what to do to it now.

PHP:
//V1.0

#include <16f877a.h>
#device ICD=TRUE
#fuses HS,NOLVP,NOWDT,PUT
#use delay (clock=200000000)

#define LEFT PIN_B6           //input button
#define RIGHT PIN_B4          //input button
#define FORWARD PIN_B2        //input button
#define BACK PIN_B0           //input button
#define MOTORFWD PIN_D6       //output drive forward
#define MOTORBCK PIN_D4       //output drive backward
#define MOTORLEFT PIN_D2      //output steer left
#define MOTORRIGHT PIN_D0     //output steer right
#define LIGHTS PIN_C4         //output headlights

void main()
{

	if (FORWARD,0)
	output_low (MOTORFWD);

	if (BACK,0)
	output_low (MOTORBCK);

	if (FORWARD,0, LEFT,0)
	output_low (MOTORFWD);
   output_low (MOTORLEFT);

   if (FORWARD,0, RIGHT,0)
   output_low (MOTORFWD);
   output_low (MOTORRIGHT);


	if (BACK,0, LEFT,0)
   output_low (MOTORBCK);
   output_low (MOTORLEFT);


	if (BACK,0, RIGHT,0)
   output_low (MOTORBCK);
   output_low (MOTORRIGHT);

}

void headlights()
{
 while(input(LIGHTS));
 while(input(!LIGHTS));

 while(true)
  {
   HEADLIGHTS   light_one_led();
   wait_for_one_press();
  }
}

I can include a schematic of the circuit if that is helpful or more information on the microcontroller that we are using, but any help at all would be extremely helpful and appreciated.
 
looks a lot like my final term project i did in college.

all i can say it totally didn't look anything like what you wrote. and it's way to long since i did any hardware programming.

so, sorry to get your hopes up, but i can't help :D
 
Haha, fair enough. It would have been fine if we had done an easier project, but 2 engineers against one design student never has a pretty outcome. Thanks though.
 
:hmm: couple of things I find odd.


The comma operator in your ifs. You say "if (FORWARD,0)"... I assume FORWARD is a macro that returns 1 if the forward button is pressed? Trouble is, the result of anything before a comma is discarded, only the last bit is used as a result - hence the if will never be taken, the condition is always 0 (false).

If you want to do more than one thing inside an if, you can't just put two lines of code below the if. Only the first statement after the if is executed within the branch. Best practice is to always enclose your branches in curly braces {}.

"if (FORWARD,0, RIGHT,0)" - I assume you want to test for forward and right button being pressed? Consider using the && operator for logical AND.

I furthermore assume you want to be able to control your vehicle indefinitely - currently the main() procedure does one run, then stops. Maybe you're looking for a while (1) { ... }.

How do your motors react if you give signals multiple times? If I press forward and left at once for example, your code will first check if forward is pressed, then turn the motor forward, and check if forward and left is pressed, then turn the motor forward and left.

How do you stop your vehicle? Currently there is no code for what happens when no button is pressed.

The procedure headlights() is never called.
 
Everything you brought up there shows how little I know about what to do for this. We haven't been given any lectures on it at all, the books make little sense and the lecturers/people that run the lab are not very helpful at all. We have been told that it is very similar to BASIC, but C doesn't make much sense at all.

For some reason for this microcontroller, all the inputs are opposite of what they should be, so when the switch is pressed it returns with a 0 and when it is released it gives a 1, which is quite confusing from my point of view.

You're right with the assumption that we would like to be able to control the vehicle indefinitely, and the motors work fine with the first signal, but the second signal they are given, they sometimes continue what they are doing when the switch has been released, though the code was changed slightly from the one I posted but wasn't able to save it.

If you have any pointers or general tips, that would be great thanks!
 
Wish I could help but never did hardware programming. I was really good at Pascal/Visual Delphi in high school but since I started college I slowly started to forget it. I only did 2 semesters of some beginner(at a no knowledge level) C in my first year at Uni. But I'm sure there has to be guys here to help you out.
 
Oh deer. Let's start off simple then :lol:

The inputs... if they do the opposite of what you want then you can change their behavior in the macro definition at the top. For example, "#define LEFT PIN_B6" would result in LEFT being 0 iff the left button is pushed? Change it to "#define LEFT !PIN_B6" to invert that behavior, now LEFT will be 1/true iff the left button is pushed.

"output_low(MOTORFWD)" makes the car go forward, yes? How do you make it stop? I assume when no buttons are pushed the car should do nothing.
Let's simplify the task for now and assume you only have a forward button. Write a program that checks if the forward button is pushed, if it is then make the motor go forward, if it isn't then make the motor stop. Rinse and repeat.
As long as you don't get that simplified program working as it should there is no point in attempting more complicated stuff.
 
Bah, I had written something then the internet went and I lost it all... I'll try and remember all that I had written.

For the bit about the inputs being opposite, its actually everything on the microcontroller that is back to front as it were. If it is reading as a 1, then it is switched off, if it is a 0, then it is on. That is the way we were told as far as I can remember.

Would it work if I turned it into an IF/ELSE conditional statement? Where if none of the buttons were being pressed it would go to the else statement, which would state to turn everything off, and everything would then switch off?
 
That's the idea. Just remember to keep checking the buttons over and over to get that infinitely long control.
 
Thanks, I'll get back to you with what happens once I've given it a shot. Lab days are Thursdays so I should be able to give an update tomorrow evening sometime. Cheers!
 
Looks like narf has you covered on most counts so I'll just chime in with some ideas/suggestions.

1) If statements can be nested, and if you need to execute multiple statements as a result of a single if, you should enclose them in curly brackes:
Code:
// check for forward or back
if (FORWARD==0) output_low(MOTORFWD);
if (BACK==0) output_low(MOTORBCK);

// check for left or right. at this point, there is no need to output MOTORFWD or MOTORBCK, because the statements above should have already done that.
if (LEFT==0) {
   // if forward or back is pressed, go left
   if ((FORWARD==0)||(BACK==0)) output_low(MOTORLEFT);

   // if right is pressed, toggle lights
   if (RIGHT==0) headlights();
}
if (RIGHT==0) {
   // if forward or back is pressed, go right
  if ((FORWARD==0)||(BACK==0)) output_low(MOTORRIGHT);

  // no need to check for right+left here, because obviously that condition would already satisfy the LEFT+RIGHT check in the if above
}

Basically since you already checked for forward or back with the first two ifs at the start of your code, you only need to check if you need an additional left or right (or combination of both) on the third and fourth ifs.

A bunch of ifs isn't how I would go about implementing your controller software, though.

Personally, what i'd do is write an input function of some sort that takes the values from all four of your pins and returns a value corresponding to a pre-defined constant, so that your control program could be made a lot more elegant with a switch statement:

i.e.:
Code:
mixed input() {
   // code to read FORWARD, BACK, LEFT, RIGHT goes here
   return (some combined value);
}

now let's assume you wrote the function above to return a value that corresponds to the following constants:
_FWD
_BCK
_LEFT_FWD
_LEFT_BCK
_RIGHT_FWD
_RIGHT_BCK
_LIGHTS

...then you could write your check function as:

Code:
while (i=input()) {
     switch (i) {
     case _FWD:
          output_low(MOTORFWD);
          break;
     case _BCK:
          output_low(MOTORBCK);
          break;
     case _LEFT_FWD:
          output_low(MOTORFWD);
          output_low(MOTORLEFT);
          break;

     // .. case statements for other values


     default:
     // what to do when none of the conditions above are met (normally do nothing)
     }
}

Obviously that code isn't complete, and you'd still need to write your input function but I think you can see immediately that it's a better way of handling things.

HTH, and good luck with your project! :mrgreen:
 
Last edited:
Wow. Thanks for that Dr.Kamiya, that should definitely help move things along a bit. However, I'm not sure if the engineers would want to implement what you've done as they have something which sort of works already, but I shall try and persuade them.

We worked on it for about 2 hours today, I say we, but they took over and didn't want any input from me, so this is what they came up with. It does all what it needs to do in a very simple form (we tested it with LEDs instead of motors), but a flaw in it is that if you press the forward and backward button together, or the left and right together it will short circuit. They seem happy with it, and want to get it finished, especially since the deadline has been brought forward to next week instead of 3 weeks time.

PHP:
#include <16f877a.h>
#device icd=true
#fuses hs,nolvp,nowdt,put
#use delay(clock=20000000)

#define FORWARD PIN_B6 //MOTOR OUTPUT
#define BACKWARD PIN_B4 //MOTOR OUPUT
#define LEFT PIN_E0 //MOTOR OUTPUT
#define RIGHT PIN_E2  //MOTOR OUTPUT

#define PUSH_BUTTON PIN_B2 //FORWARD INPUT
#define PUSH_BUTTON2 PIN_B0 //BACKWARD INPUT
#define PUSH_BUTTON3 PIN_A2 //LEFT INPUT
#define PUSH_BUTTON4 PIN_A4 //RIGHT INPUT

#define GREEN_LED PIN_A5


void main()
{
while(true)
{if (input(PUSH_BUTTON))
output_high (FORWARD);
else
output_low (FORWARD);


if (input(PUSH_BUTTON2))
output_high (BACKWARD);
else
output_low (BACKWARD);


if (input(PUSH_BUTTON3))
output_high (LEFT);
else
output_low (LEFT);

if (input(PUSH_BUTTON4))
output_high (RIGHT);
else
output_low (RIGHT);

if (input(PUSH_BUTTON4))
output_high (GREEN_LED);
else
output_low (GREEN_LED);






}

}

We removed the LED headlights from the programme in the interest of simplicity, but this still doesn't seem right.

Thanks for the help though guys.
 
Silly engineers :lol: your initial program had nicely labelled buttons, now it's all numbered. I strongly recommend going back to calling the buttons by what they actually represent, ie rename PUSH_BUTTON2 to PUSH_BACKWARD or whatever. No need to add another layer of complications/things to go wrong.

To avoid short circuits, make sure your program never puts out backwards and forwards together. Here's an idea how:
PHP:
if (forward is pressed) {
  go forwards;
} else {
  stop going forwards;
  if (backward is pressed) {
    go backwards;
  } else {
    stop going backwards;
  }
}
This piece of code will go forwards if the forward button is pressed, and only go backwards if the forward button is not pressed and the backward button is pressed. In other words, if you press both buttons forwards will take precedence.
How exactly does your hardware handle stopping? Does every command to go in one direction require another command to stop going in that direction? The code above assumes it does, issueing a stop for each button that is not pressed.

Does your hardware provide debounced button inputs?
 
I don't think the hardware does provide debounced inputs.

The engineers are just being stubborn and have admitted that they shouldn't have done something as ambitious, since it is all falling apart and it is to be presented tomorrow. Coding hasn't really changed since the last update, the rapid prototyped model has apparently not worked, and I have no idea what they have done with the printed circuit board we had made. We have got a circuit which works on the bread board and we have been told that will be ok for the presentation.

Thanks for the help Narf and Dr.Kamiya, you may not have made much of an impact on the engineers and their code but you've helped me increase my knowledge on C. +rep to you both.
 
Without debounced buttons, "If the left and right buttons are pressed simultaneously, the LEDs will light, and press again to turn them off." will be hard to do. When the buttons bounce and there is no layer inbetween removing the bounce, your program will most likely be unable to distinguish bouncing from multiple manual presses.


Anyway, engineers trying to write programs usually is catastrophic.
 
Top