Split from: [TUT] Modularizing C Code: Managing large projects

Go To Last Post
7 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
/*
 * MAX7219.h
 *
 * Created: 19-02-2020 11:36:05
 *  Author: USER
 */ 


#ifndef MAX7219_H_
#define MAX7219_H_

#ifndef F_CPU
#define F_CPU									    16000000UL
#endif

#include <avr/io.h>

#define PIN_SCK                   					PORTB7
#define PIN_MOSI                  					PORTB5
#define PIN_SS                    					PORTB4

#define ON                        					1
#define OFF                       					0

#define MAX7219_LOAD1             					PORTB |= (1<<PIN_SS)
#define MAX7219_LOAD0             					PORTB &= ~(1<<PIN_SS)

#define MAX7219_MODE_DECODE       					0x09
#define MAX7219_MODE_INTENSITY    					0x0A
#define MAX7219_MODE_SCAN_LIMIT   					0x0B
#define MAX7219_MODE_POWER        					0x0C
#define MAX7219_MODE_TEST         					0x0F
#define MAX7219_MODE_NO_OP         					0x00


#define MAX7219_DIGIT0_UNIT							0x01		// For selecting LSB digit of current display
#define MAX7219_DIGIT1_TEN							0x02		// For selecting CSB digit of current display
#define MAX7219_DIGIT2_HUN							0x03		// For selecting MSB digit of currnet display
#define MAX7219_DIGIT3_FAULT						0x04		// For selecting fault, ampere & secnond leds
#define MAX7219_DIGIT4_MODE							0x05		// For selecting mode (MMAW, TIG & HF) leds
#define MAX7219_DIGIT5_2T_4T						0x06		// For selecting Opertion (2T & 4T) leds
#define MAX7219_DIGIT6_PARAMETER					0x07		// For selecting parameter leds (Pre flow, postflow, up slope etc. )
#define MAX7219_DIGIT7_PARAMETER					0x08		// Unsed pin

#define MAX7219_CHAR_BLANK							0xF
#define MAX7219_CHAR_NEGATIVE						0xA


void spiSendByte (char databyte);
void MAX7219_writeData(char data_register, char data);
void MAX7219_init(void);
void MAX7219_reset(void);
void MAX7219_data(unsigned char unit, unsigned char ten, unsigned char hundread, unsigned int dig4led, unsigned int dig5led, unsigned int dig3led);
void MAX7219_2T_4T(unsigned int T);
void MAX7219_display_current_process(unsigned int, unsigned int, unsigned int);
void MAX7219_voltage_display(unsigned int unit, unsigned int ten);
void MAX7219_blank_data(void);

char digitInUse = 6;                                            // For 7 digits

#endif /* MAX7219_H_ */

This is my MAX7219.h header file. I want to declare and initialize digitInUse = 6. But i when i do it shows an error saying that  multiple definition of `digitInUse'.  How can i solve this error. Following file is MAX7219.c  

/*
 * MAX7219.c
 *
 * Created: 19-02-2020 11:42:29
 *  Author: USER
 */ 

#include "MAX7219.h"

// digitsInUse = 6;

void spiSendByte (char databyte)
{
	// Copy data into the SPI data register
	SPDR = databyte;
	// Wait until transfer is complete
	while (!(SPSR & (1 << SPIF)));
}

void MAX7219_writeData(char data_register, char data)
{
	MAX7219_LOAD0;
	// Send the register where the data will be stored
	spiSendByte(data_register);
	// Send the data to be stored
	spiSendByte(data);
	MAX7219_LOAD1;
}

void MAX7219_init()
{
	DDRB |= (1 << PIN_SCK) | (1 << PIN_MOSI) | (1 << PIN_SS);

	// SPI Enable, Master mode
	SPCR |= (1 << SPE) | (1 << MSTR)| (1<<SPR1);
	MAX7219_writeData(MAX7219_MODE_DECODE, 0x07);
	
	// Scan limit runs from 0.
	MAX7219_writeData(MAX7219_MODE_SCAN_LIMIT, digitInUse);
	MAX7219_writeData(MAX7219_MODE_INTENSITY, 8);
	MAX7219_writeData(MAX7219_MODE_POWER, ON);
	MAX7219_writeData(MAX7219_MODE_TEST,OFF);
}

void MAX7219_reset(void)
{
	MAX7219_writeData(MAX7219_MODE_POWER, OFF);
	MAX7219_writeData(MAX7219_MODE_POWER, ON);
	MAX7219_writeData(MAX7219_MODE_DECODE, 0x07);
	MAX7219_writeData(MAX7219_MODE_SCAN_LIMIT, digitInUse);
	MAX7219_writeData(MAX7219_MODE_INTENSITY, 8);
	MAX7219_writeData(MAX7219_MODE_TEST,OFF);
}

void MAX7219_data(unsigned char unit, unsigned char ten, unsigned char hundread, unsigned int dig4led, unsigned int dig5led, unsigned int dig3led)
{
	MAX7219_writeData(MAX7219_DIGIT0_UNIT, unit);
	MAX7219_writeData(MAX7219_DIGIT1_TEN, ten);
	MAX7219_writeData(MAX7219_DIGIT2_HUN, hundread);
	MAX7219_writeData(MAX7219_DIGIT4_MODE, dig4led);
	MAX7219_writeData(MAX7219_DIGIT6_PARAMETER, dig5led);
	MAX7219_writeData(MAX7219_DIGIT3_FAULT,dig3led);
}

void MAX7219_2T_4T(unsigned int T)
{
	MAX7219_writeData(MAX7219_DIGIT5_2T_4T, T);
}

void MAX7219_display_current_process(unsigned int unit, unsigned int ten, unsigned int hundread)
{
	MAX7219_writeData(MAX7219_DIGIT0_UNIT, unit);
	MAX7219_writeData(MAX7219_DIGIT1_TEN, ten);
	MAX7219_writeData(MAX7219_DIGIT2_HUN, hundread);
}

void MAX7219_voltage_display(unsigned int unit, unsigned int ten)
{
	MAX7219_writeData(MAX7219_DIGIT3_FAULT, unit);
	MAX7219_writeData(MAX7219_DIGIT4_MODE, ten);
}

void MAX7219_blank_data()
{
	MAX7219_writeData(MAX7219_DIGIT0_UNIT, 0);
	MAX7219_writeData(MAX7219_DIGIT1_TEN, 0);
	MAX7219_writeData(MAX7219_DIGIT2_HUN, 0);
	MAX7219_writeData(MAX7219_DIGIT3_FAULT, 0b00000000);
	MAX7219_writeData(MAX7219_DIGIT4_MODE, 0b00000000);
	MAX7219_writeData(MAX7219_DIGIT5_2T_4T, 0b00000000);
	MAX7219_writeData(MAX7219_DIGIT6_PARAMETER, 0b00000000);
	// MAX7219_writeData(MAX7219_DIGIT4_MODE, 0);
}
Last Edited: Thu. Feb 20, 2020 - 12:39 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You shouldn't allocate storage in a H file. Reason being each time you include the H file, the variable gets declared again. Thus the error you see.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You cannot assign a value to it in the header! In the header just put:

extern char digitInUse;                                            // For 7 digits

The only thing "users" of this variable need to know is that it is a char - they don't need to be told what value it will have via the header. 

 

Then in just one .c file actually instantiate the variable with its initial value so in MAX7219.c use:

char digitInUse = 6;                                            // For 7 digits

That is what actually creates (technical term is "defines") the single copy of the variable. Nothing is created by the "extern" in the .h file as that is simply a "declaration" - it only declares that the variable exists and what type it is but does not create it.

 

Files using MAX7219.h just #include the header and then they can read/write the global variable that is "owned" by MAX7219.c

 

HOWEVER this is actually bad program design - why do you think it needs to be global? Why should other files be allowed access to change this? A better idea is to create it as:

static char digitInUse = 6;                                            // For 7 digits

within MAX7219.c and then have a function like:

char GetNumDigits() {
    return digitsInUse;
}

that is an "accessor" that will allow code outside of this driver to read what the value is but they cannot change it.

 

Oh and if your whole purpose of doing:

char digitInUse = 6;                                            // For 7 digits

in the .h file was so that a "user" can edit the .h file and change the number of digits then consider doing it in a different way. In the .h file have something like:

#define NUM_MAX7219_DIGITS 6

so the user can edit that then use:

char digitInUse = NUM_MAX7219_DIGITS; 

in the .c file.

 

Actually if you are going to follow this route you might want to have a max7219_config.h or something that is separate and is the "user editable" header then they won't need to edit the "main" header that has all the stuff that remains constant.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In below code i used switch case i want to make it seperate .h file and .c file but main problem i an not able define initial = CHECK_BUTTTON_PRESS; how can i do this any idea.

uint8_t initial = CHECK_BUTTTON_PRESS;

int button(unsigned int c,unsigned int j)					/* c is current and j is max limit */
{
	switch (initial)
	{
		case CHECK_BUTTTON_PRESS:
		{
			if(bit_is_clear(PINA,0))									 
			{
				incrementCheckMillis = millis();
				initial = INCREMENT;
			}
			if(bit_is_clear(PINA,1))
			{
				decrementCheckMillis = millis();
				initial = DECREMENT;
			}
			break;
		}
		
		case INCREMENT:													/* single press incremrnt */
		{
			if (millis() - incrementCheckMillis >= 100)
			{
				if(bit_is_clear(PINA,0))
				{
					c++;
					if(c > j)   						/* if c is greater j  */
					{
						c = j;
					}
					initial = CHECK_INC_LONG_PRESS;
					incrementCheckLongMillis = millis();
					
				}
			}
			break;
		}
		
		case CHECK_INC_LONG_PRESS:
		{
			if(bit_is_clear(PINA,0))
			{
				if(millis() - incrementCheckLongMillis >= 300)				/* if button is pressed and hold for 300ms */
				{
					initial = SPEED_INCREMENT;
					speedIncrementMillis = millis();
				}
			}
			else
			{
				initial = CHECK_BUTTTON_PRESS;
			}
			break;
		}
		
		case SPEED_INCREMENT:
		{
			if(bit_is_clear(PINA,0))
			{
				if(millis() - speedIncrementMillis >= 30)								/* increment count after every 10ms */
				{
					c++;
					if(c > j)
					{
						c = j;
					}
					speedIncrementMillis = millis();
					initial = SPEED_INCREMENT;
				}
			}
			else
			{
				initial = CHECK_BUTTTON_PRESS;
			}
			break;
		}

		case DECREMENT:
		{
			if(millis() - decrementCheckMillis >= 100)
			if(bit_is_clear(PINA,1))
			{
				c--;
				if(c < 1)
				{
					c = 1;
				}
				decrementCheckLongMillis = millis();
				initial = CHECK_DEC_LONG_PRESS;
			}
			break;
		}

		case CHECK_DEC_LONG_PRESS:
		{
			if(bit_is_clear(PINA,1))
			{
				if(millis() - decrementCheckLongMillis >= 300)
				{
					speedDecrementMillis = millis();
					initial = SPEED_DECREMENT;
				}
			}
			else
			{
				initial = CHECK_BUTTTON_PRESS;
			}
			break;
		}

		case SPEED_DECREMENT:
		{
			if(bit_is_clear(PINA,1))
			{
				if(millis() - speedDecrementMillis >= 30)			/* decrement count after every 20ms */
				{
					c--;
					if(c < 1)
					{
						c = 1;
					}
					speedDecrementMillis = millis();
					initial = SPEED_DECREMENT;
				}
			}
			else
			{
				initial = CHECK_BUTTTON_PRESS;
			}
			break;
		}
	}

	if(avgPulseCurrentShowFlag == RESET)					// If in Tigpulse Mode and peakCurrent is active
	{
	hunDigit = c/100;
	temp = c%100;
	tenDigit = temp/10;
	unitDigit = temp%10;
	}
	else
	{
		avgPulseCurrent = avg_current_display();
		hunDigit = avgPulseCurrent / 100;
		temp = avgPulseCurrent % 100;
		tenDigit = temp / 10;
		unitDigit = temp % 10;
	}
	
	return c;
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It seems to me that variable should be "inside" the function but as a "static" so it will remember the value from one call to button() to the next. Something like:

int button(unsigned int c,unsigned int j)					/* c is current and j is max limit */
{
    uint8_t initial = CHECK_BUTTTON_PRESS;

    switch (initial)
    {
        case CHECK_BUTTTON_PRESS:

If you haven't used "static" like this before you might read this code as if it is going to create and set "initial" to be CHECK_BUTTON_PRESS each time the function is called. But this is not the case. It acts more like a global - so it hods the "last value" on each subsequent call. Only the first time will it be initialised as CHECK_BUTTON_PRESS.

 

Moving it "inside" the function "encapsulates" it.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Personally, I'd suggest a function to debounce the buttons then feed that into another function to implement the button logic.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Wonder why this was split?? uc_coder's questions were valuable additional input to that "large project" tutorial as they are practical examples of applying the theory. Oh well.