Pages: [1]   Go Down
Author Topic: Can I write my own .c and .h files and use them with .pde main project?  (Read 710 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 11
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello,

I'm new on Arduino.
can I write my own .c and .h files and use them with main.pde project?

Here is what I did:
1/ I wrote funcion void tonTimer(T_TMR *t) and store it to file FC060.c
2/ I wrote line extern void tonTimer(T_TMR *t); and store it to file FC060.h
3/ I included #include "FC060.h" in file main.pde  and
    I called this function tonTimer(&tmr1);  but I got compiling error
undefined reference to 'tonTimer(T_TMR*)'
What's wrong ? Files FC060.c, FC060.h, main.pde are compiled OK when I delete line tonTimer(&tmr1);  

Code:
/*
file:      FC060.c
project:  
device:    
date:      
desc.:    software timer
*/

#include "FC060.h"
#include <avr/io.h>

T_TMR   tmr1;
T_TMR   tmr2;

void tonTimer(T_TMR *t)
{
  unsigned char sb   ;
  unsigned char value;
  unsigned char preset;
  
  sb     =  t-> sb;
  value  =  t-> value;
  preset =  t-> preset;
  
  if (sb==_BV(EN)){
     sb = (_BV(EN) || BV(RUN));
     value  = preset;
  }
  
  if (bit_is_set(sb,RUN)){
    if (TMR_BIT){
      value--;
      if (value==0){
         sb = _BV(CPL);
      }
    }
  }
  
  t-> sb = sb;
  t-> value = value;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
Code:
/*                                                            
file:      FC060.h                                            
project:                                                      
device:                                                        
date:                                                          
desc.:     header file for software timer                      
*/                                                            
                                                              
                                                              
#ifndef _FC060_H                                              
#define _FC060_H                                              
                                                              
#include <avr/io.h>                                            
                                                              
#define EN                     (0)                            
#define RUN                    (1)                            
#define CPL                    (2)                            
                                                              
#define TMR_BIT               (bit_is_set(ip,0))              
// uint8_t ip is defined in main skatch                        
                                                              
                                                              
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
                                                              
                                                              
// software timer data                                        
typedef struct {                                              
  unsigned char sb   ;  // holds flags                        
  unsigned char value;  // is value                            
  unsigned char preset;  // init value                        
} T_TMR;                                                      
                                                              
                                                              
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
                                                              
extern T_TMR   tmr1;                                          
extern T_TMR   tmr2;                                          
extern uint8_t ip  ;                                          
                                                              
extern void tonTimer(T_TMR *t);                                
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#endif _FC060_H                                                
Code:
// file main.pde
//

#include <avr/io.h>
#include "FC060.h"

uint8_t ip= 0;

//  void setup()
//
//
void setup()
{
  tmr1.sb    = _BV(EN);
  tmr1.preset = 20;
}

void loop()
{
   tonTimer( &tmr1);
}
[/size]
« Last Edit: February 12, 2011, 03:18:18 pm by frpr666 » Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 170
Posts: 12487
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


Please read the library tutorial - http://www.arduino.cc/en/Hacking/LibraryTutorial - as a library is often the best place to store reusable code.
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Newcastle, England
Offline Offline
Sr. Member
****
Karma: 2
Posts: 489
Always learning!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset


Please read the library tutorial - http://www.arduino.cc/en/Hacking/LibraryTutorial - as a library is often the best place to store reusable code.

Exactly what I would have put. Libraries are convenient to use, as other people can easily use them (should you choose to release them), and the functions that you can add are used in the same way as the standard ones are, so you do not need to add in lots of extra (non-hidden) code into the main sketch.

Onions.
Logged

My website: http://www.harryrabbit.co.uk/electronics/home.html Up and running now! (Feel free to look round!) smiley-grin

Ontario
Offline Offline
God Member
*****
Karma: 20
Posts: 835
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I have found myself with the same requirement.  I have wound up with 1,000s of lines of code crammed into a single sketch merely because it is inconvenient in Arduino to build code that is divided into logical modules.  Libraries appear to have to be C++ classes, and that is not what I want.  The modules I want to make are bog-standard C code and I know well how to build and link these in a conventional C environment.  I know that Arduino libraries are preferable in some cases, but that is not what I am trying to do.

Is there any provision in Arduino for conventional C modules, or is it necessary to go directly to the AVR toolchain to make this work?
Logged

Saint Petersburg, Russia
Offline Offline
Full Member
***
Karma: 2
Posts: 105
Amateur
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

What's wrong ?

Rename FC060.c to FC060.cpp
Logged

Left Coast, CA (USA)
Online Online
Brattain Member
*****
Karma: 332
Posts: 16566
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Is there any provision in Arduino for conventional C modules, or is it necessary to go directly to the AVR toolchain to make this work?

That is what the separate code tabs are for. There is a arrow button pointing right, near top of the IDE edit window that allows you to write or copy separate functions that will then be compiled along with your main sketch. You do have to use the proper file extension name.

Lefty
Logged

Ontario
Offline Offline
God Member
*****
Karma: 20
Posts: 835
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Rename FC060.c to FC060.cpp

I feel so dumb.  Thanks, and thanks Lefty.

I do a lot of debugging in a real C development environment, and establishing a system of CPP macros and such that allow the same file to be built in Arduino and UNIX has been a challenge.  This is an excellent step.  Thank you.
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 553
Posts: 46291
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

In order to support overloading, C++ performs an operation called name mangling. The result is that a function's real name is defined by the user-supplied function name, and the types of all the arguments.

C doesn't support overloading, so it doesn't play well when the C++ compiler has mangled the names.

The C++ compiler CAN compile C code without name mangling, so that the c extension can be used, if some compiler directives are added to the header file.

Quote
#ifdef __cplusplus
extern "C" {
#endif

// The C function declarations go here

#ifdef __cplusplus
}
#endif
The __cplusplus symbol is defined by the C++ preprocessor, but not by the C preprocessor, so, when the C++ compiler runs, it sees the extern "C" wrapper, but the C compiler does not.

The extern "C" directive tells the C++ compiler not to perform name mangling, since the functions in the block are to be called by C code, too.

Since the code in the .c file is compiled by the C compiler, which does not perform name mangling, the un-mangled names are what the C++ compiler needs to add to the symbol table for the linker to use.

Without the extern "C" directive, the mangled names are added to the symbol table by the C++ compiler, but not by the C compiler, so the linker can't find the function since the name in the symbol table (of the compiled function) doesn't match the name of the called function.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 11
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello,
the problem is solved. smiley It works after renaming *.c to *.cpp and after few mistakes correction. Now I know how to split large project.
@Vanyamba Thank you, that was what helped.
Edit1: @PaulS Thank you for the explanation, I try also your way, it works too. I will use it in the future, it seems to be clearer.
Here is the final working project

Code:
/*
file:      FC060.c
project:  
device:    
date:      
desc.:    software timer
*/

#include "FC060.h"
#include <avr/io.h>


T_TMR   tmr1;
T_TMR   tmr2;

void tonTimer(T_TMR *t)
{
  unsigned char sb   ;
  unsigned char value;
  unsigned char preset;
  
  sb     =  t->sb;
  value  =  t->value;
  preset =  t->preset;
  
  if (sb==_BV(EN)){
     sb = (_BV(EN) | _BV(RUN));
     value  = preset;
  }
  if ((TMR_BIT)&&
      (bit_is_set(sb,RUN))){
       value--;
       if (value==0){
         sb = _BV(CPL);
       }
  }

  t->sb = sb;
  t->value = value;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

Code:
/*
file:      FC060.h
project:  
device:    
date:      
desc.:     header file for software timer
*/


#ifndef _FC060_H
#define _FC060_H

#ifdef __cplusplus
extern "C" {
#endif

#include <avr/io.h>

#define EN                     (0)
#define RUN                    (1)
#define CPL                    (2)

#define TMR_BIT               (bit_is_set(ip,7))
// uint8_t ip is defined in main skatch


/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */


// software timer data
typedef struct {
  unsigned char sb   ;  // holds flags
  unsigned char value;  // is value
  unsigned char preset;  // init value
} T_TMR;


/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

extern T_TMR   tmr1;
extern T_TMR   tmr2;
extern uint8_t ip  ;

extern void tonTimer(T_TMR *t);
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

#ifdef __cplusplus
}
#endif

#endif _FC060_H

Code:
// file main.pde
//

#include <avr/io.h>
#include "FC060.h"

#define Q13 13          // here comes the output
#define Q13_1   (PORTB = 0b00100000)
#define Q13_0   (PORTB = 0b00000000)

#define INIT_TIMER_COUNT (6)
#define RESET_TIMER2 (TCNT2 = INIT_TIMER_COUNT)

volatile uint8_t int_counter = 0;
uint8_t ip, hf = 0;
uint8_t tmp;

//  void setup()
//
//
void setup()
{
  setupTMR2();
  Serial.begin(19200);      // open the serial port at 19200 bps:    
  Serial.flush();
  
  tmr1.sb    = _BV(EN);
  tmr1.value  = 0;
  tmr1.preset = 4;
  
  tmr2.sb    =  0;
  tmr2.value  = 0;
  tmr2.preset = 2;
}

void loop()
{
    // check interrupt activity
    tmp = int_counter;
    ip =  tmp & (~hf);
    hf =  tmp;
  
   tonTimer( &tmr1);
   tonTimer( &tmr2);
  
       if (bit_is_set(tmr1.sb, RUN)){
             Q13_1;
       }
       else {
             Q13_0;
       }

   if (bit_is_set(tmr1.sb, CPL)){
      tmr1.sb = 0;
      tmr2.sb = _BV(EN);
   }  

   if (bit_is_set(tmr2.sb, CPL)){
      tmr2.sb = 0;
      tmr1.sb = _BV(EN);
   }  

  

   if (TMR_BIT){
   Serial.print(0x00, BYTE);
   Serial.print(0x00, BYTE);
   Serial.print(tmr1.sb, BYTE);
   Serial.print(tmr1.value, BYTE);
   Serial.print(tmr1.preset, BYTE);  
   Serial.print(tmr2.sb, BYTE);
   Serial.print(tmr2.value, BYTE);
   Serial.print(tmr2.preset, BYTE);
   }
}

ISR(TIMER2_OVF_vect) {
  RESET_TIMER2;
  int_counter++;
};

void setupTMR2(){
  //   =   76543210
  DDRB = 0b00100000;
  
  // TIMER 2
  
  //Timer2 Settings: Timer Prescaler /64,
  TCCR2B |= ((1<<CS22) | (0<<CS21) | (0<<CS20));
  
  // Use normal mode
  TCCR2A |= (0<<WGM21) | (0<<WGM20);

  // Use internal clock - external clock not used in Arduino
  ASSR |= (0<<AS2);

  TIMSK2 |= (1<<TOIE2);  //Timer2 Overflow Interrupt Enable
  RESET_TIMER2;
  sei();
}
« Last Edit: February 13, 2011, 11:51:45 am by frpr666 » Logged

Pages: [1]   Go Up
Jump to: