Why Arduino Code Works but C Code does Not

Hi,
So I am trying to use C code to control a motor based on the contents of a string(I believe that this is called "bare-metal" but I could be mistaken.)
When I upload my C code, it does not work. However, I wrote and uploaded an equivalent code using the Arduino language, and that works. I believe that the issue with that D2, D3, and D4 are not being written as HIGH in the C code, because I am not measuring any power from there. I checked and those pins' pinModes are OUTPUT, so that is not the issue.

For context, I am using an Arduino Nano and am using this datasheet. To control the motor, I am using a DRV8833. I added the Arduino code and C code below, as well as the pin connections. I appreciate any advice you could give me.

Pins
Nano|DRV8833|Motor|IR sensor
GND-----------------------------GND
5V --------------------------------VCC
5 ----------------------------------D0
2 --------IN1
7 --------IN2
VIN -----VCC
GND----GND
----------OUT1---------Red
-----------OUT2 --------Black

Arduino:

#include <Arduino.h>

void control(bool A, bool B, bool C, int act){//control motors
  int true_act = digitalRead(5);//to read the IR sensor. 1 if positive, 0 otherwise
  if((act == 2) || (true_act == act)){
    if(A){
      digitalWrite(2, HIGH);//turn motor on
      Serial.print("A");
    }else{
      digitalWrite(2, LOW);//turn motor off
      Serial.print("a");
    }
    if(B){
      digitalWrite(3, HIGH);//turn motor on
      Serial.print("B");
    }else{
      digitalWrite(3, LOW);//turn motor off
      Serial.print("b");
    }
    if(C){
      digitalWrite(4, HIGH);//turn motor on
      Serial.print("C");
    }else{
      digitalWrite(4, LOW);//turn motor off
      Serial.print("c");
    }
    delay(5000);
    Serial.println("");
  }
}


void setup(){
  Serial.begin(57600);
  delay(100);
  Serial.println("Starting setup()");
  //pinModes
  pinMode(2, OUTPUT); pinMode(3, OUTPUT); pinMode(4, OUTPUT);//for D2, D3, D4 being output
  pinMode(5, INPUT);//for D5 being input
  pinMode(6, OUTPUT); pinMode(7, OUTPUT); pinMode(8, OUTPUT);
  digitalWrite(6, LOW); digitalWrite(7, LOW); digitalWrite(8, LOW);

  char* code = "2abc";
  int L = 4;//number of characters in code
  int activation = -1;//if activation = 2, then do it regardless of the IR sensor. If 0 or 1, do it when the IR sensor matches
  bool motorA = false; bool motorB = false; bool motorC = false;
  //code processing
  Serial.println("Processing code");
  for(int i = 0; i < L; i++){
    Serial.print("Character ");
    Serial.print(" is ");
    Serial.print(" is: ");
    Serial.println(*(code + i));
    switch(*(code + i)){
      case 'a':
        motorA = true;
        break;
      case 'b':
        motorB = true;
        break;
      case 'c':
        motorC = true;
        break;
      case '2':
        if(activation != -1){
          control(motorA, motorB, motorC, activation);
        }
        activation = 2; 
        motorA = false; motorB = false; motorC = false;
        break;
      case '1':
        if(activation != -1){
          control(motorA, motorB, motorC, activation);
        }
        activation = 1; 
        motorA = false; motorB = false; motorC = false;
        break;
      case '0':
        if(activation != -1){
          control(motorA, motorB, motorC, activation);
        }
        activation = 0; 
        motorA = false; motorB = false; motorC = false;
        break;
    }
  }
  if(activation != -1){
    control(motorA, motorB, motorC, activation);
  }
  activation = -1; 
  motorA = false; motorB = false; motorC = false;
}
void loop(){
  setup(); //for debugging purposes
}

C code:

#include <Arduino.h>
#include <stdbool.h>
#define F_CPU 20000000L


void control(bool A, bool B, bool C, int act){//control motors
  int true_act = ((PIND & (1 << PD5)) > 0);//to read the IR sensor. 1 if positive, 0 otherwise
  if((act == 2) || (true_act == act)){
    if(A){
      PORTD |= (1 << PD2);//turn motor on
    }else{
      PORTD &= ~(1 << PD2);//turn motor off
    }
    if(B){
      PORTD |= (1 << PD3);//turn motor on
    }else{
      PORTD &= ~(1 << PD3);//turn motor off
    }
    if(C){
      PORTD |= (1 << PD4);//turn motor on
    }else{
      PORTD &= ~(1 << PD4);//turn motor off
    }
    delay(5000);
  }
}


//1 is output, 0 is input
//DATASHEET: https://docs.arduino.cc/resources/datasheets/A000005-datasheet.pdf
void setup(){
  //pinModes
  DDRD |= ((1 << PD2) | (1 << PD3) | (1 << PD4));//mask for D2, D3, D4 being output
  DDRD &= ~(1 << PD5);//mask for D5 being input
  DDRD |= ((1 << PD6) | (1 << PD7));//mask for D6, D7, D8 being output. We will use these as ground for the motors
  DDRB |= (1 << PB0);//pin D8 is the start of the B register
  PORTD &= ~(1 << PD6); PORTD &= ~(1 << PD7); PORTB &= ~(1 << PB0);

  char* code = "2abc";
  int L = 4;//number of characters in code
  int activation = -1;//if activation = 2, then do it regardless of the IR sensor. If 0 or 1, do it when the IR sensor matches
  bool motorA = false; bool motorB = false; bool motorC = false;
  //code processing
  for(int i = 0; i < L; i++){
    switch(*(code + i)){
      case 'a':
        motorA = true;
        break;
      case 'b':
        motorB = true;
        break;
      case 'c':
        motorC = true;
        break;
      case '2':
        if(activation != -1){
          control(motorA, motorB, motorC, activation);
        }
        activation = 2; 
        motorA = false; motorB = false; motorC = false;
        break;
      case '1':
        if(activation != -1){
          control(motorA, motorB, motorC, activation);
        }
        activation = 1; 
        motorA = false; motorB = false; motorC = false;
        break;
      case '0':
        if(activation != -1){
          control(motorA, motorB, motorC, activation);
        }
        activation = 0; 
        motorA = false; motorB = false; motorC = false;
        break;
    }
  }
}

/*
void loop(){
  setup(); //for debugging purposes
}
*/

Sorry I do not follow word schematics. From what little bit I understand there are some problems. Post an annotated schematic showing exactly how you have wired it. Show all power sources, ground, power,etc. Post links to technical information on each of the hardware items such as the motor.

2 Likes

Why do you think C and arduino code are any different?
Could you add the compiler error log?

So the problem is solved.

Why did you post a question on the forum? You have what you need, yes?

Use the Arduino code. Ask a question on the forum only when you have not already solved the problem yourself.

In principle, you should be able to set the registers directly without the Arduino API. However, the code you show is not equivalent, I see a lot of differences. Perhaps the differences are not important, but it makes it hard for us to tell.

Also "does not work" doesn't give us much to go on. What did you do? What did you expect to happen? What actually happened?

The C code doesn't seem to ever set the outputs HIGH, so if that is what you found, it is what I would expect. Actually, the C code doesn't compile in the IDE, so perhaps you can explain how you ran it.

The Arduino API provides tested and ready to use functions. If you are writing your own versions, it is wasy to make mistakes. Put the code into macros or functions (static inline). Test the functions independently to verify they work as you expect. When you have tested them, put them into an include file and then include in your project.

In the code below you comparing a signed and unsigned values

the result is an undefined behaviour

1 Like

Gee, what a bunch of unhelpful responses...

You C code is missing these lines after the switch:

  if(activation != -1){
    control(motorA, motorB, motorC, activation);
  }
  activation = -1; 
  motorA = false; motorB = false; motorC = false;

the way I'm thinking the code works, when you read '2' from the string, the 2 case will NOT call control(), because activation is still -1. Then it sets activation to 2, and the code under the switch will call control(). But in the C version, you'll never call control...

(You could keep the Serial.print() calls in the "direct port access" version, and it might help show what's going on.)

1 Like

I was just about to post that. I modified the code and it sets the outputs high as expected. The logic of the code does not really makes sense to me. Is activation==2 supposed to run for 5 seconds, or does it start the motor and subsequent command turn it off?

Anyway here is the code

#include <Arduino.h>
#include <stdbool.h>

// #define F_CPU 20000000L

//control motors
void control(bool A, bool B, bool C, int act)
{
  int true_act = ((PIND & (1 << PD5)) > 0);  //to read the IR sensor. 1 if positive, 0 otherwise

  Serial.print (A);
  Serial.print (" ");
  Serial.print (B);
  Serial.print (" ");
  Serial.print (C);
  Serial.print (" ");
  Serial.print (act);
  Serial.print (" ");
  Serial.print (true_act);
  Serial.println();

  if ((act == 2) || (true_act == act))
  {
    if (A)
    {
      PORTD |= (1 << PD2);  //turn motor on
    }
    else
    {
      PORTD &= ~(1 << PD2);  //turn motor off
    }
    if (B)
    {
      PORTD |= (1 << PD3);  //turn motor on
    }
    else
    {
      PORTD &= ~(1 << PD3);  //turn motor off
    }
    if (C)
    {
      PORTD |= (1 << PD4);  //turn motor on
    }
    else
    {
      PORTD &= ~(1 << PD4);  //turn motor off
    }
    delay(500);
  }
}


//1 is output, 0 is input
//DATASHEET: https://docs.arduino.cc/resources/datasheets/A000005-datasheet.pdf
void parse_code ()
{
  //pinModes
  DDRD |= ((1 << PD2) | (1 << PD3) | (1 << PD4));  //mask for D2, D3, D4 being output
  DDRD &= ~(1 << PD5);                             //mask for D5 being input
  DDRD |= ((1 << PD6) | (1 << PD7));               //mask for D6, D7, D8 being output. We will use these as ground for the motors

  DDRB |= (1 << PB0);                              //pin D8 is the start of the B register

  PORTD &= ~(1 << PD6);
  PORTD &= ~(1 << PD7);

  PORTB &= ~(1 << PB0);

  const char* code = "2abc";
  int L = 4;            //number of characters in code
  int activation = -1;  //if activation = 2, then do it regardless of the IR sensor. If 0 or 1, do it when the IR sensor matches
  bool motorA = false;
  bool motorB = false;
  bool motorC = false;
  //code processing
  for (int i = 0; i < L; i++)
  {
    switch (*(code + i))
    {
      case 'a':
        motorA = true;
        break;
      case 'b':
        motorB = true;
        break;
      case 'c':
        motorC = true;
        break;
      case '2':
        if (activation != -1)
        {
          control(motorA, motorB, motorC, activation);
        }
        activation = 2;
        motorA = false;
        motorB = false;
        motorC = false;
        break;
      case '1':
        if (activation != -1)
        {
          control(motorA, motorB, motorC, activation);
        }
        activation = 1;
        motorA = false;
        motorB = false;
        motorC = false;
        break;
      case '0':
        if (activation != -1)
        {
          control(motorA, motorB, motorC, activation);
        }
        activation = 0;
        motorA = false;
        motorB = false;
        motorC = false;
        break;
    } // switch
  }

  if(activation != -1)
  {
    control(motorA, motorB, motorC, activation);
  }
  activation = -1; 
  motorA = false; motorB = false; motorC = false;
  
}

void setup ()
{
  Serial.begin (9600);
  Serial.println ("Running");

  parse_code();
}

void loop()
{
  // 
}

1 Like

@westfw and @bobcousins thank you for answers, that was the issue! Don't know how I missed that! And sorry that I didn't give a lot of details on what was supposed to happen, it was late at night where I was posting this. When activation = 2, it was supposed to turn on the appropriate motors for five seconds regardless if digitalRead(5) was HIGH or LOW.

Also while I know Arduino would have been easier, I also wanted to try setting the registers directly using C. I learned that one could do this and decided it would be fun to try.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.