About 3 years ago i was working on a project that needed a 7 segment display. At that time i was just learning PIC 8-bit mcu's, MPLABX, XC8 and C in general. A lot at once. I put a Mock up of what I wanted together and wrote some code. Took me a few weeks but I had it working.
I used MCC, and the code was generated across 4-5 files. Below I'll try to pull all the related code out of each file so that I'm not uploading 20 pages of code for what could have been much simpler.
At the time I thought the 7 segment code could be portable.
The mock up used a PIC16F1564, and the hardware was entirely my own design on a protoboard. It mostly worked as expected.
Fast forward to today, I'm trying to make a small timer for my Son who is making a board game. I thought I would try a PIC16F54, mainly because it was cheap, and also i'd never used an external crystal in a project, so more to learn, perfect.
I've built the hardware, and the hardware works. I can display any number I want, and the multiplexing works perfectly.
I dont have a schematic to show, because I drew up the schematic in KICAD, then printed it, and by the time I was finished building and testing the hardware, it changed a little. I could change the KICAD files and I will if someone here thinks they need to see my schematic. But i'm pretty sure this is a programming issue.
I've taken my functional code and pasted it into my new program. It wont compile.
Code from Working Board (PIC16F1564)
Entire Program from Timer. This wont compile, only since I've added the code relating to the 7 segment. It specifically chokes on the function pointer array. I've highlighted it below.
The compiler output is here. The line #'s it is referencing in the errors relate to the correct numbers in the code above.
Any thoughts or ideas on how to overcome this?
Appreciation to anyone who took the time to even look at all this
I used MCC, and the code was generated across 4-5 files. Below I'll try to pull all the related code out of each file so that I'm not uploading 20 pages of code for what could have been much simpler.
At the time I thought the 7 segment code could be portable.
The mock up used a PIC16F1564, and the hardware was entirely my own design on a protoboard. It mostly worked as expected.
Fast forward to today, I'm trying to make a small timer for my Son who is making a board game. I thought I would try a PIC16F54, mainly because it was cheap, and also i'd never used an external crystal in a project, so more to learn, perfect.
I've built the hardware, and the hardware works. I can display any number I want, and the multiplexing works perfectly.
I dont have a schematic to show, because I drew up the schematic in KICAD, then printed it, and by the time I was finished building and testing the hardware, it changed a little. I could change the KICAD files and I will if someone here thinks they need to see my schematic. But i'm pretty sure this is a programming issue.
I've taken my functional code and pasted it into my new program. It wont compile.
Code from Working Board (PIC16F1564)
C:
//snippet from pin_manager.h
#define SEG7A_SetHigh() do { LATCbits.LATC1 = 1; } while(0)
#define SEG7A_SetLow() do { LATCbits.LATC1 = 0; } while(0)
#define SEG7G_SetHigh() do { LATCbits.LATC0 = 1; } while(0)
#define SEG7G_SetLow() do { LATCbits.LATC0 = 0; } while(0)
#define SEG7F_SetHigh() do { LATAbits.LATA2 = 1; } while(0)
#define SEG7F_SetLow() do { LATAbits.LATA2 = 0; } while(0)
#define SEG7D_SetHigh() do { LATAbits.LATA1 = 1; } while(0)
#define SEG7D_SetLow() do { LATAbits.LATA1 = 0; } while(0)
#define SEG7E_SetHigh() do { LATAbits.LATA0 = 1; } while(0)
#define SEG7E_SetLow() do { LATAbits.LATA0 = 0; } while(0)
#define SEG7B_SetHigh() do { LATCbits.LATC4 = 1; } while(0)
#define SEG7B_SetLow() do { LATCbits.LATC4 = 0; } while(0)
#define SEG7C_SetHigh() do { LATCbits.LATC2 = 1; } while(0)
#define SEG7C_SetLow() do { LATCbits.LATC2 = 0; } while(0)
void seg7set0(); // following 11 functions are prototypes for each 7-seg setting called in pin_manager.c
void seg7set1();
void seg7set2();
void seg7set3();
void seg7set4();
void seg7set5();
void seg7set6();
void seg7set7();
void seg7set8();
void seg7set9();
void seg7setclear();
//snippet from pin_manager.c
void seg7set0()
{
SEG7A_SetLow();
SEG7B_SetLow();
SEG7C_SetLow();
SEG7D_SetLow();
SEG7E_SetLow();
SEG7F_SetLow();
SEG7G_SetHigh();
}
void seg7set3() // establish function for activating #3 on 7-seg
{
SEG7A_SetLow();
SEG7B_SetLow();
SEG7C_SetLow();
SEG7D_SetLow();
SEG7E_SetHigh();
SEG7F_SetHigh();
SEG7G_SetLow();
}
void seg7set1() // establish function for activating #1 on 7-seg
{
SEG7A_SetHigh();
SEG7B_SetLow();
SEG7C_SetLow();
SEG7D_SetHigh();
SEG7E_SetHigh();
SEG7F_SetHigh();
SEG7G_SetHigh();
}
void seg7set2() // function for activating #2 on 7-seg
{
SEG7A_SetLow();
SEG7B_SetLow();
SEG7C_SetHigh();
SEG7D_SetLow();
SEG7E_SetLow();
SEG7F_SetHigh();
SEG7G_SetLow();
}
void seg7set4()
{
SEG7A_SetHigh();
SEG7B_SetLow();
SEG7C_SetLow();
SEG7D_SetHigh();
SEG7E_SetHigh();
SEG7F_SetLow();
SEG7G_SetLow();
}
void seg7set5()
{
SEG7A_SetLow();
SEG7B_SetHigh();
SEG7C_SetLow();
SEG7D_SetLow();
SEG7E_SetHigh();
SEG7F_SetLow();
SEG7G_SetLow();
}
void seg7set6()
{
SEG7A_SetLow();
SEG7B_SetHigh();
SEG7C_SetLow();
SEG7D_SetLow();
SEG7E_SetLow();
SEG7F_SetLow();
SEG7G_SetLow();
}
void seg7set7()
{
SEG7A_SetLow();
SEG7B_SetLow();
SEG7C_SetLow();
SEG7D_SetHigh();
SEG7E_SetHigh();
SEG7F_SetHigh();
SEG7G_SetHigh();
}
void seg7set8()
{
SEG7A_SetLow();
SEG7B_SetLow();
SEG7C_SetLow();
SEG7D_SetLow();
SEG7E_SetLow();
SEG7F_SetLow();
SEG7G_SetLow();
}
void seg7set9()
{
SEG7A_SetLow();
SEG7B_SetLow();
SEG7C_SetLow();
SEG7D_SetLow();
SEG7E_SetHigh();
SEG7F_SetLow();
SEG7G_SetLow();
}
void seg7setclear()
{
SEG7A_SetHigh();
SEG7B_SetHigh();
SEG7C_SetHigh();
SEG7D_SetHigh();
SEG7E_SetHigh();
SEG7F_SetHigh();
SEG7G_SetHigh();
}
//main.c I've put the entire main.c code here, just in case the reasoning for "why i did something" one way or the other is present.
void main(void)
{
// initialize the device
SYSTEM_Initialize();
// When using interrupts, you need to set the Global and Peripheral Interrupt Enable bits
// Use the following macros to:
// Enable the Global Interrupts
INTERRUPT_GlobalInterruptEnable();
// Enable the Peripheral Interrupts
INTERRUPT_PeripheralInterruptEnable();
// Disable the Global Interrupts
//INTERRUPT_GlobalInterruptDisable();
// Disable the Peripheral Interrupts
//INTERRUPT_PeripheralInterruptDisable();
void (*seg7set[11])(); // array to hold pointers for each 7 segment vaule
seg7set[0] = seg7set0;
seg7set[1] = seg7set1; // calling the functions defined in pin_manager.h for each 7 segment value
seg7set[2] = seg7set2;
seg7set[3] = seg7set3;
seg7set[4] = seg7set4;
seg7set[5] = seg7set5;
seg7set[6] = seg7set6;
seg7set[7] = seg7set7;
seg7set[8] = seg7set8;
seg7set[9] = seg7set9;
seg7set[10]= seg7setclear;
unsigned int DutyCycle; // duty cycle of power circuit
int p; // p will be the 7-segment value
unsigned int PrevResult; // previous result of power current reading
char ADCsel=2; // flip flop for selection of ADC channel
unsigned int current; // current power of circuit
char ADCsw; // flip flop for determining if ADC channel should be switched
int displaysw; // flip flop for switching digit display
while (1)
{
// Add your application code
if (ADCclk>520) // number here sets the sample rate, consider reducing the number to account for the time
{
ADCON0bits.GO = 1;
// PrevResult = ((ADRESH << 8) + ADRESL);
if (ConversionComplete==1) // read the pot which is the setting, this variable declared in ADC1.c
{
if (ADCsel==1) // set to read DutyCycle
{
DutyCycle = ((ADRESH << 8) + ADRESL); // get the value from the ADC and set it to DutyCycle
ADCsw=1; // Toggle the ADC switch
ADCON0bits.CHS = channel_AN7; // Set ADC channel to read Pot
ConversionComplete = 0;
ADCclk=0; // reset ConversionComplete and ADCclk
}
if (ADCsel==2) // sets ADC channel to read current feedback circuit
{
current = ((ADRESH << 8) + ADRESL); // get the value from the ADC and set it to current.
ADCsw=1;
// toggle ADC selector to read current
ADCON0bits.CHS = channel_AN3; // Set ADC channel to read Current
ConversionComplete = 0;
ADCclk=0;
}
if(ADCsw==1)
{
if(ADCsel==1) // if ADCsel is set to read pot, switch to read current and toggle the switch
{
ADCsel=2;
ADCsw=0;
}
}
if(ADCsw==1)
{
if(ADCsel==2) // if ADCsel is set to read current, switch to read pot and toggle the switch
{
ADCsel=1;
ADCsw=0;
}
}
}
}
if (digitsel>1)
{
seg7set[10](); // clear 7 segment display to prevent ghosting
if (IO_RA5_PORT==1)
{
IO_RA5_SetLow();
p=(current*10 / 1024); //get tens value from adc reading
seg7set[p]();
}
else if (IO_RA5_PORT==0)
{
IO_RA5_SetHigh();
p=((current*25 / 256)%10); //get ones value from adc reading
seg7set[p]();
}
digitsel=0;
}
PWM1DCL = DutyCycle;
PWM1DCH = (DutyCycle >> 8);
PWM1LDCON = 0x80;
// p = (current*10 / 1024); //Multiplying current by 10, so that integer math works, and gives an integer value between 0 and 9. Needs adjustment yet for proper rounding (add one half of a point)
//p is the value to display on 7 segment display
//seg7set[p](); // calling the 7 segment value specified by p
}
}
Entire Program from Timer. This wont compile, only since I've added the code relating to the 7 segment. It specifically chokes on the function pointer array. I've highlighted it below.
Code:
/*
* File: Main1.c
* Author: Travis
*
* Created on May 18, 2020, 1:30 PM
*/
// CONFIG
#pragma config OSC = XT // Oscillator selection bits (RC oscillator)
#pragma config WDT = OFF // Watchdog timer enable bit (WDT enabled)
#pragma config CP = OFF // Code protection bit (Code protection off)
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
#define _XTAL_ 4000000
#include <xc.h>
#define SEG7A_SetLow() RB0=0
#define SEG7A_SetHigh() RB0=1
#define SEG7B_SetLow() RB1=0
#define SEG7B_SetHigh() RB1=1
#define SEG7C_SetLow() RB2=0
#define SEG7C_SetHigh() RB2=1
#define SEG7D_SetLow() RB3=0
#define SEG7D_SetHigh() RB3=1
#define SEG7E_SetLow() RB4=0
#define SEG7E_SetHigh() RB4=1
#define SEG7F_SetLow() RB5=0
#define SEG7F_SetHigh() RB5=1
#define SEG7G_SetLow() RB6=0
#define SEG7G_SetHigh() RB6=1
void seg7set0(); // following 11 functions are prototypes for each 7-seg setting called in pin_manager.c
void seg7set1();
void seg7set2();
void seg7set3();
void seg7set4();
void seg7set5();
void seg7set6();
void seg7set7();
void seg7set8();
void seg7set9();
void seg7setclear();
void seg7set0()
{
SEG7A_SetLow();
SEG7B_SetLow();
SEG7C_SetLow();
SEG7D_SetLow();
SEG7E_SetLow();
SEG7F_SetLow();
SEG7G_SetHigh();
}
void seg7set3() // establish function for activating #3 on 7-seg
{
SEG7A_SetLow();
SEG7B_SetLow();
SEG7C_SetLow();
SEG7D_SetLow();
SEG7E_SetHigh();
SEG7F_SetHigh();
SEG7G_SetLow();
}
void seg7set1() // establish function for activating #1 on 7-seg
{
SEG7A_SetHigh();
SEG7B_SetLow();
SEG7C_SetLow();
SEG7D_SetHigh();
SEG7E_SetHigh();
SEG7F_SetHigh();
SEG7G_SetHigh();
}
void seg7set2() // function for activating #2 on 7-seg
{
SEG7A_SetLow();
SEG7B_SetLow();
SEG7C_SetHigh();
SEG7D_SetLow();
SEG7E_SetLow();
SEG7F_SetHigh();
SEG7G_SetLow();
}
void seg7set4()
{
SEG7A_SetHigh();
SEG7B_SetLow();
SEG7C_SetLow();
SEG7D_SetHigh();
SEG7E_SetHigh();
SEG7F_SetLow();
SEG7G_SetLow();
}
void seg7set5()
{
SEG7A_SetLow();
SEG7B_SetHigh();
SEG7C_SetLow();
SEG7D_SetLow();
SEG7E_SetHigh();
SEG7F_SetLow();
SEG7G_SetLow();
}
void seg7set6()
{
SEG7A_SetLow();
SEG7B_SetHigh();
SEG7C_SetLow();
SEG7D_SetLow();
SEG7E_SetLow();
SEG7F_SetLow();
SEG7G_SetLow();
}
void seg7set7()
{
SEG7A_SetLow();
SEG7B_SetLow();
SEG7C_SetLow();
SEG7D_SetHigh();
SEG7E_SetHigh();
SEG7F_SetHigh();
SEG7G_SetHigh();
}
void seg7set8()
{
SEG7A_SetLow();
SEG7B_SetLow();
SEG7C_SetLow();
SEG7D_SetLow();
SEG7E_SetLow();
SEG7F_SetLow();
SEG7G_SetLow();
}
void seg7set9()
{
SEG7A_SetLow();
SEG7B_SetLow();
SEG7C_SetLow();
SEG7D_SetLow();
SEG7E_SetHigh();
SEG7F_SetLow();
SEG7G_SetLow();
}
void seg7setclear()
{
SEG7A_SetHigh();
SEG7B_SetHigh();
SEG7C_SetHigh();
SEG7D_SetHigh();
SEG7E_SetHigh();
SEG7F_SetHigh();
SEG7G_SetHigh();
}
Void (*seg7set[11])(); // array to hold pointers for each 7 segment vaule
seg7set[0] = seg7set0;
seg7set[1] = seg7set1; // calling the functions defined in pin_manager.h for each 7 segment value
seg7set[2] = seg7set2;
seg7set[3] = seg7set3;
seg7set[4] = seg7set4;
seg7set[5] = seg7set5;
seg7set[6] = seg7set6;
seg7set[7] = seg7set7;
seg7set[8] = seg7set8;
seg7set[9] = seg7set9;
seg7set[10]= seg7setclear;
void main(void) {
TRISA = 0b1010; //RA3 gets tri-stated to turn off AN1 and AN2,
//RA1 must be high imp. its connected straight to ground
TRISB = 0b00000000; //All PortB Pins are I/O
OPTION = 000111; //Options - Prescaler set at 1:256
char currentclk = 0;
char previousclk = 0;
int dotflash = 0;
int ansel = 0;
// char charsel = 1;
RA3=1; //Anode 1 and 2 - tristate this pin to turn off
RB7=1; //Anode 3 start on Anode 3, or the if statement flow doesnt work
while(1) {
previousclk = currentclk; // clock
currentclk = TMR0;
if (previousclk > currentclk) //advance item clocks here
{
dotflash++;
ansel++;
}
if (dotflash==4000) //4000 cycles is approx 1s
{
if (RA0==1) RA0=0;
else if (RA0==0) RA0=1;
dotflash=0;
}
if (ansel>15)
{
if (RB7==1)
{
RB7=0;
TRISA = 0b0010;
RA3=1;
}
else if (RA3==1)
{
RA3=0;
}
else if (RA3==0)
{
TRISA = 0b1010;
RB7=1;
}
ansel=0;
}
// TRISA = 0b1010;
//RA0=1; //Dot Anode
RB0=0;
RB1=0;
RB2=0;
RB3=1;
RB4=0;
RB5=0;
RB6=0;
}
return;
}
Code:
CLEAN SUCCESSFUL (total time: 4ms)
make -f nbproject/Makefile-default.mk SUBPROJECTS= .build-conf
make[1]: Entering directory 'C:/Users/Travis/MPLABXProjects/BensTimer.X'
make -f nbproject/Makefile-default.mk dist/default/production/BensTimer.X.production.hex
make[2]: Entering directory 'C:/Users/Travis/MPLABXProjects/BensTimer.X'
"C:\Program Files (x86)\Microchip\xc8\v2.05\bin\xc8-cc.exe" -mcpu=16F54 -c -fno-short-double -fno-short-float -O0 -fasmfile -maddrqual=ignore -xassembler-with-cpp -mwarn=-3 -Wa,-a -DXPRJ_default=default -msummary=-psect,-class,+mem,-hex,-file -ginhx032 -Wl,--data-init -mno-keep-startup -mno-osccal -mno-resetbits -mno-save-resetbits -mno-download -mno-stackcall -std=c99 -gdwarf-3 -mstack=compiled:auto -o build/default/production/Main1.p1 Main1.c
::: advisory: (2049) C99 compliant libraries are currently not available for baseline or mid-range devices, or for enhanced mid-range devices using a reentrant stack; using C90 libraries
Main1.c:158:8: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
Void (*seg7set[11])(); // array to hold pointers for each 7 segment vaule
^
Main1.c:158:1: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
Void (*seg7set[11])(); // array to hold pointers for each 7 segment vaule
^
Main1.c:158:6: error: function cannot return function type 'int ()'
Void (*seg7set[11])(); // array to hold pointers for each 7 segment vaule
^
Main1.c:159:1: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
seg7set[0] = seg7set0;
^
Main1.c:159:1: error: array initializer must be an initializer list
Main1.c:160:1: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
seg7set[1] = seg7set1; // calling the functions defined in pin_manager.h for each 7 segment value
^
Main1.c:160:1: error: array initializer must be an initializer list
Main1.c:161:1: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
seg7set[2] = seg7set2;
^
Main1.c:161:1: error: array initializer must be an initializer list
Main1.c:162:1: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
seg7set[3] = seg7set3;
^
Main1.c:162:1: error: array initializer must be an initializer list
Main1.c:163:1: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
seg7set[4] = seg7set4;
^
Main1.c:163:1: error: array initializer must be an initializer list
Main1.c:164:4: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
seg7set[5] = seg7set5;
^
Main1.c:164:4: error: array initializer must be an initializer list
Main1.c:165:4: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
seg7set[6] = seg7set6;
^
Main1.c:165:4: error: array initializer must be an initializer list
Main1.c:166:4: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
seg7set[7] = seg7set7;
^
Main1.c:166:4: error: array initializer must be an initializer list
Main1.c:167:4: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
seg7set[8] = seg7set8;
^
Main1.c:167:4: error: array initializer must be an initializer list
Main1.c:168:4: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
seg7set[9] = seg7set9;
^
Main1.c:168:4: error: array initializer must be an initializer list
Main1.c:169:4: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
seg7set[10]= seg7setclear;
^
Main1.c:169:4: error: array initializer must be an initializer list
13 warnings and 12 errors generated.
(908) exit status = 1
nbproject/Makefile-default.mk:106: recipe for target 'build/default/production/Main1.p1' failed
make[2]: Leaving directory 'C:/Users/Travis/MPLABXProjects/BensTimer.X'
nbproject/Makefile-default.mk:90: recipe for target '.build-conf' failed
make[1]: Leaving directory 'C:/Users/Travis/MPLABXProjects/BensTimer.X'
nbproject/Makefile-impl.mk:39: recipe for target '.build-impl' failed
make[2]: *** [build/default/production/Main1.p1] Error 1
make[1]: *** [.build-conf] Error 2
make: *** [.build-impl] Error 2
BUILD FAILED (exit value 2, total time: 961ms)
Any thoughts or ideas on how to overcome this?
Appreciation to anyone who took the time to even look at all this