As I've written before, I use a Mac for my GCB programming. At the moment the PPS Tool isn't available for the Mac. I recently ordered some PIC16F18877 processors for work as part of a potentially large project and today decided to have a look at them, and try and start to use them. A simple program I'd written for the 16F1825 which used interrupts, a serial LCD module and the millis() function by Chris Roper was loaded into my editor and compiled.
Millis() returned an error message that TMR0 did not work correctly with this processor as Chris has stated, so all references to millis() were removed, and the program re-compiled.
Success!
Well, no!
Although the program compiled perfectly well now, nothing appeared to work. The serial LCD refused to display anything and the button and buzzer did nothing either. Hmm. Why?
I looked at the datasheet and could see that the Serial TX function is assigned by PPS. As the Mac can't use the PPS tool, I fired up a VirtualPC and installed the PC build of GCB onto it and ran the PPS tool which gave me this:
'Generated by PIC PPS Tool for Great Cow Basic'PPS Tool version: 0.0.5.25'PinManager data: v1.75'Generated for 16f18877''Template comment at the start of the config file'#startupInitPPS,85#definePPSToolPart16f18877SubInitPPSUNLOCKPPS'Module: EUSARTRC6PPS=0x0010'TX > RC6LOCKPPSEndSub'Template comment at the end of the config file
Adding that into my code gave me a working Serial LCD. {Well it did once I counted the pins correctly and plugged the serial connection into the right pin...}
Next to look at the Interrupt.
Again the datasheet suggested this could be adjusted using PPS, so I went back to the VirtualPC and the PPS tool gave me this:
'Generated by PIC PPS Tool for Great Cow Basic'PPS Tool version: 0.0.5.25'PinManager data: v1.75'Generated for 16f18877''Template comment at the start of the config file'#startupInitPPS,85#definePPSToolPart16f18877SubInitPPSUNLOCKPPS'Module: EUSARTRC6PPS=0x0010'TX > RC6'Module: EXT_INTINTPPS=0x0002'RA2 > INTLOCKPPSEndSub'Template comment at the end of the config file
Now my interrupt worked too, along with the buzzer.
Looking at the generated PPS code I wondered how I could 'decode' the datasheet, into PPS code without needing to use the PPS tool I don't have easy access to.
For the 16F18877 the relevant pages in the manual are 241, 243 and 246. Page 241 lists the names of the input PPS funtions, page 243 lists the pin 'values' that need to be assigned to the function. For the external interrupt, the constant given on page 241 is INTPPS. The value for PortA.2 is given on page 243 as 0x02. In order to set the PPS for an external interrupt on PortA.2 the required code would be:
INTPPS=0x02
Just as given by the PPS tool.
Moving on to the Serial TX, page 246 tells us that the output pins for PPS are set using the command:
RxyPPS where the 'xy' is replaced by the pin notation of the required pin. So for pin PortC.6 this gives the command of: RC6PPS ('xy' being replaced by 'C6'). The instruction value for Serial TX is shown as 0x10 making the the code for Serial TX on PortC.6:
RC6PPS=0x10
Again, just as produced by the PPS tool.
Editing my code to read:
'Uses 16F18877, Serial LCD, PPS function mapping and interrupts for a button.'The interrupt triggers on a rising then falling edge to enable 'counting of buttons only when a button is pressed and released.'The button state is stored at startup to allow for buttons that'may idle high or low automatically.#Chip16F18877,32#Optionexplicit#ConfigCP=On#Include"Simple_Serial_LCD.h"'Simple_Serial_LCD.h provides a simple interface to an'attached serial LCD display. The ports used for the'serial interface should be defined in program code'for portability.#startupInitPPS,85'Set a startup routine with a high priority of 85.'Comms routines have a priority of 90, so setting this below that 'ensures PPS is set before any comms routine is attempted.'80 is the highest priority, 100 is 'normal' priority.#definePPSToolPart16f18877SubInitPPSUnlockPPS'Unlock PPS to allow changesRC6PPS=0x10'Assign PortC.6 to Serial TXINTPPS=0x02'Assign External Interrupt to PortA.2LockPPS'Lock PPS to prevent changesEndSub'*******************************************************************'*******************************************************************'*******************************************************************' Define the USART port#DefineUSART_BAUD_RATE9600#DefineUSART_BLOCKING#DefineSerOutPortportC.6'Pin 25#DefineButtonPortA.2'Pin 4#DefineBeeperPortC.3'Pin 18 'This connects directly to a 12V Piezo buzzer'the fact that a 12V buzzer is driven from a 5V pin'does not matter. It is loud enough to hear!DimTimeCountAsLongDimBeepCountAsByteDimPressedAsBitDimReset_TriggerAsBitDimTriggerAsBit'Set pin directionsDirSerOutPortOut'Pin 25DirBeeperOut'Pin 18DirButtonIn'Pin 4LetReset_Trigger=0LetTrigger=0LetTimeCount=0InitialiseTestSubTestDoSerLocate(0,0)HSerPrintTimeCountIfTrigger=1ThenSerLocate(1,0)HSerPrintTimeCountHSerPrint" "LetTrigger=0DoBip(1,25)EndIfIfReset_Trigger=1ThenSerLocate(1,11)HSerPrintTimeCountHSerPrint" "LetReset_Trigger=0DoBip(1,25)EndIfTimeCount++LoopEndSubSubInitialiseDoIfButton=PressedThenLetPressed=!ButtonLetTimeCount=0EndIfWait5mSTimeCount++LoopUntilTimeCount>125'Get the idle state of the button pinLetTimeCount=0'For the serial LCD to initialise, there must be a few'milliseconds of delay before using the serial LCD.'This is provided by the button test above.'Otherwise, add some delay here.ClearScreenSerLocate(0,0)HSerPrint" Hello 16F18877 "SerLocate(1,0)HSerPrint"& Fast Interrupt"'**********************************************************************'Interrupt setup'**********************************************************************'Option_Reg for rising/falling edge'INTEDG'INTEDG = 1 'Rising Edge'INTEDG = 0 'Falling EdgeLetINTEDG=Pressed'Interrupt on switch pressed state'INTE = 1 'Interrupt on Edge enabled'INTE = 0 'Interrupt on Edge disabled'INTF = 1 'Edge Interrupt happened'INTF = 0 'No Edge Interrupt'INTE = 1 'Interrupt on Edge enabled'INTE = 0 'Interrupt on Edge disabledLetINTE=1'Interrupt on Edge enabledLetINTF=0'Clear any interruptsOnInterruptExtInt0CallInterrupt_Sub'**********************************************************************'Interrupt setup'**********************************************************************Wait250mSClearScreenEndSubSubInterrupt_SubIfINTF=1ThenIfButton=PressedThen'Button pressedWait10mSIfButton=PressedThen'Still pressedLetTrigger=1LetINTEDG=!PressedEndIfEndIfIfButton<>PressedThen'Button releasedWait10mSIfButton<>PressedThen'Still releasedLetReset_Trigger=1LetINTEDG=PressedEndIfEndIf'Let INTF = 0 'Clear interruptEndIfEndSubSubDoBip(InNumberOfBipsAsByte,LengthOfBipsAsWord)ForBeepCount=1ToNumberOfBipsSoundBeep(1)'Beep onWaitLengthOfBipsmSSoundBeep(0)'Beep offWaitLengthOfBipsmSNextEndSubSubSoundBeep(InSoundAsBit)LetBeeper=Sound'Turn on or off the beeperEndSub
Gave me fully working code.
I don't imagine this comes close to describing the complexities of the PPS function assignments, in almost all cases I would recommend that if you have access to the PPS tool, that it is used, if you don't however, this may give some insight into how to generate working code for setting those functions.
In my case the '#Define PPSToolPart 16F18877' assignment seemed not to be required, as I was unsure of it's significance, I left it in for the sake of completeness. The PPS tool sets a StartUp Function to set the PPS assignments as soon as the processor starts. I copied this method to ensure the PPS functions are set before anything else executes.
The datasheet implies (if I read it correctly) that the Serial TX function defaults to PortC.6 during power on reset. For me, this didn't seem to be the case. Perhaps I didn't read that bit correctly?
Last edit: mkstevo 2019-01-21
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I have a new version of millis that should support your part.
I have not released it yet as I am still testing and documenting but I attach it here for you to try.
As I've written before, I use a Mac for my GCB programming. At the moment the PPS Tool isn't available for the Mac. I recently ordered some PIC16F18877 processors for work as part of a potentially large project and today decided to have a look at them, and try and start to use them. A simple program I'd written for the 16F1825 which used interrupts, a serial LCD module and the millis() function by Chris Roper was loaded into my editor and compiled.
Millis() returned an error message that TMR0 did not work correctly with this processor as Chris has stated, so all references to millis() were removed, and the program re-compiled.
Success!
Well, no!
Although the program compiled perfectly well now, nothing appeared to work. The serial LCD refused to display anything and the button and buzzer did nothing either. Hmm. Why?
I looked at the datasheet and could see that the Serial TX function is assigned by PPS. As the Mac can't use the PPS tool, I fired up a VirtualPC and installed the PC build of GCB onto it and ran the PPS tool which gave me this:
Adding that into my code gave me a working Serial LCD. {Well it did once I counted the pins correctly and plugged the serial connection into the right pin...}
Next to look at the Interrupt.
Again the datasheet suggested this could be adjusted using PPS, so I went back to the VirtualPC and the PPS tool gave me this:
Now my interrupt worked too, along with the buzzer.
Looking at the generated PPS code I wondered how I could 'decode' the datasheet, into PPS code without needing to use the PPS tool I don't have easy access to.
For the 16F18877 the relevant pages in the manual are 241, 243 and 246. Page 241 lists the names of the input PPS funtions, page 243 lists the pin 'values' that need to be assigned to the function. For the external interrupt, the constant given on page 241 is INTPPS. The value for PortA.2 is given on page 243 as 0x02. In order to set the PPS for an external interrupt on PortA.2 the required code would be:
Just as given by the PPS tool.
Moving on to the Serial TX, page 246 tells us that the output pins for PPS are set using the command:
RxyPPS where the 'xy' is replaced by the pin notation of the required pin. So for pin PortC.6 this gives the command of: RC6PPS ('xy' being replaced by 'C6'). The instruction value for Serial TX is shown as 0x10 making the the code for Serial TX on PortC.6:
Again, just as produced by the PPS tool.
Editing my code to read:
Gave me fully working code.
I don't imagine this comes close to describing the complexities of the PPS function assignments, in almost all cases I would recommend that if you have access to the PPS tool, that it is used, if you don't however, this may give some insight into how to generate working code for setting those functions.
In my case the '#Define PPSToolPart 16F18877' assignment seemed not to be required, as I was unsure of it's significance, I left it in for the sake of completeness. The PPS tool sets a StartUp Function to set the PPS assignments as soon as the processor starts. I copied this method to ensure the PPS functions are set before anything else executes.
The datasheet implies (if I read it correctly) that the Serial TX function defaults to PortC.6 during power on reset. For me, this didn't seem to be the case. Perhaps I didn't read that bit correctly?
Last edit: mkstevo 2019-01-21
Hi mkstevo ,
I have a new version of millis that should support your part.
I have not released it yet as I am still testing and documenting but I attach it here for you to try.
Cheers
Chris
I have just tested that using the 'new' millis(), and it does work just as it did on the 16F1825. Many thanks for the updated version.