-1

I've been trying to program an atmega328p in Atmel Studio (it's fun), but when I tried to separate my keypad code into it's own c file, I got an error.

Error       'keypad' undeclared (first use in this function)    invisible_alarm C:\Users\kenkr\Documents\Atmel Studio\7.0\invisible_alarm\invisible_alarm\main.c    39

keypad is defined in a separate file, and I've ruled a few things out:

  • I didn't forget the h file (Using a symbol defined in keypad.h works)
  • The compiler isn't ignoring keypad.c (Errors in keypad.c appear in the compile output)
  • I didn't forget to add the .c/.h file to the project (They appear in the solution explorer)

I suspect the build order is messed up, but I'm not sure where build order is set in Atmel Studio, but that's just a guess. I put a sample of my files below. The only errors are from main.c referencing keypad.c.

// main.c
#define F_CPU 16000000
#define NULL 0

#include <util/delay.h>
#include <avr/io.h>
#include "lcd.h"
#include "keypad.h"

void example() {
    int header_example = KEY_1; // From keypad.h, no error
    uint16_t c_example = keypad; // from keypad.c, error
}
// ...
// keypad.h
#ifndef _KEYPAD_H_
#define _KEYPAD_H_

#define KEY_1 0
#define KEY_4 1
// ...

#endif
// keypad.c
#include <avr/io.h>
#include <util/delay.h>
#include "keypad.h"
#define NULL 0

uint16_t keypad = 0x0000;
// ...

Atmel Studio Solution Explorer

Kenkron
  • 573
  • 1
  • 3
  • 15
  • 3
    Your header file is missing an `extern uint16_t keypad;` or similar. – PiRocks Oct 12 '20 at 17:36
  • Oh. Thanks. I didn't realize you could define state in header files as well. If that's the case, maybe I can just put everything into a .h file. – Kenkron Oct 12 '20 at 17:42
  • No. You can't put everything into a .h file or at least you shouldn't. I recommend you read through some kind of c header file tutorial/explanation. – PiRocks Oct 13 '20 at 19:03
  • 1
    Does this answer your question? [How do I use extern to share variables between source files?](https://stackoverflow.com/questions/1433204/how-do-i-use-extern-to-share-variables-between-source-files) – PiRocks Oct 13 '20 at 19:03
  • @PiRocks Why not? There a lot of tutorials that say you *should* use .c files, but I've yet to see one give a good reason. – Kenkron Oct 14 '20 at 14:05
  • I though the whole reason we didn't just put everything in header files was because they only stored pre-compiler definitions and function definitions. Turns out, functions can be fully defined in .h files, so I figured state must be reserved for c files. Now I find out that's not true either, and now I don't know what the point of .c files are at all! – Kenkron Oct 14 '20 at 14:16
  • https://www.tutorialspoint.com/cprogramming/c_header_files.htm – PiRocks Oct 15 '20 at 02:11
  • Also read up about how `#include` works. Essentially it just copy pastes your .h file into your c file. The point of multiple c files is to break programs into multiple files, the point of header files is to share stuff between many c files. – PiRocks Oct 15 '20 at 02:13
  • I'm still not convinced. The link you provided shows a `main.c` including a `header.h`. There's no mention of a `header.c`, and if a header file can do anything a source file can do, I see no reason there *should* be a `header.c`. For me, putting everything in `keyboard.h` worked, and adding a .c file would just force me to write extra function declarations. – Kenkron Oct 16 '20 at 18:07
  • I found the answer: https://stackoverflow.com/questions/52928946/why-shouldnt-i-put-everything-in-header – Kenkron Oct 16 '20 at 18:15

1 Answers1

2

You need to declare the variable in the header file:

// keypad.h
#ifndef _KEYPAD_H_
#define _KEYPAD_H_

#include <stdint.h> // commonly needed for uint16_t

#define KEY_1 0
#define KEY_4 1
// ...

extern uint16_t keypad;

#endif
the busybee
  • 10,755
  • 3
  • 13
  • 30