#include <pic18.h>
#include <htc.h>
#include <conio.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#define CLK_20MHZ 0
#define CLK_48MHZ 1
#define CLK_64MHZ 0
//Nothing in place for 20MHZ and 50 micro res. All other combos supported.
#define FIFTY_MICRO_RES 1
#define HUNDRED_MICRO_RES 0
__CONFIG(1,USBOSC & CPUDIV1 & PLLDIV12 & HS & FCMDIS & IESODIS);
__CONFIG(2,VREGDIS & PWRTDIS & BORDIS & WDTDIS);
__CONFIG(3,PBDIGITAL & LPT1DIS & MCLRDIS & ICPORTDIS & DEBUGDIS);
__CONFIG(4,STVREN & LVPDIS & XINSTDIS & DEBUGDIS);
__CONFIG(5,UNPROTECT);
__CONFIG(6,UNPROTECT);
__CONFIG(7,UNPROTECT);
// Data Structures
struct rowData
{
unsigned char frameType; //0x01 = rowData
unsigned int offTime; //time off in ms
unsigned int onTime[24];
};
struct performanceData
{
unsigned long num_loops;
unsigned long micros;
};
//keeps track of timer2 with 50 or 100us resolution
unsigned int fifty_micros = 0;
//keeps track of timer0 with approx 3ms resolution
unsigned long micros = 0;
// Global variables
struct performanceData pData;
struct rowData rData;
unsigned char * p; //pointer for serial communication
unsigned char count;
unsigned char numSet;
unsigned char toWriteA;
unsigned char toWriteB;
unsigned char toWriteC;
unsigned char toWriteD;
int i;
// Interrupt service routine that is called every time a timer fires
void interrupt isr(void) {
if(TMR2IF){
//This is run every 50 or 100uS
#if HUNDRED_MICRO_RES
fifty_micros+=2;
#endif
#if FIFTY_MICRO_RES
fifty_micros++;
#endif
TMR2IF=0; // clear event flag
} else {
if (TMR0IF) {
//Run every 3ms or so
//20MHz
#if CLK_20MHZ
micros += 3277;
#endif
#if CLK_48MHZ
micros += 2731;
#endif
#if CLK_64MHZ
micros += 2048;
#endif
TMR0IF=0;
}
}
}
void init(void){
ADCON1 =0x06 ; // Changes PORTA to digital
CMCON = 0x07 ; // Disable analog comparators
//Configure ports, all output except for RC7
TRISA = 0x00 ;
TRISB = 0X00 ;
TRISC = 0b10000000 ; //Set RC7 input for USART, all others output
71
TRISD = 0X00 ;
TRISE = 0X00 ;
PEIE = 1; //Peripheral interrupt enabled
/***** Timer 2 Code ****
* Prescale ratio set at 1:16
* Timer2 module activated
* Postscale ratio set at 1:10
*/
#if CLK_20MHZ
T2CON = 0b00000101;
//Set timer period to 97.6 = 122, works out to be ˜100uS
//after ISR is run. OLD: 123, 125, 130 - micros too low,
//120, 122, 123 to high. 124=dead on for 6.510215s
//PR2 = 124;
PR2 = 124;
#endif
#if CLK_48MHZ
#if HUNDRED_MICRO_RES
T2CON = 0b00000111; //1:16 prescaler
PR2 = 74;
#endif
#if FIFTY_MICRO_RES
T2CON = 0b00000101; //1:4 prescaler
PR2 = 149;
#endif
#endif
#if CLK_64MHZ
T2CON = 0b00000111;
#if HUNDRED_MICRO_RES
PR2 = 99;
#endif
#if FIFTY_MICRO_RES
PR2 = 49;
#endif
#endif
//Timer0 Setup
#if CLK_20MHZ
T0CON = 0b11000101; //1:64 prescaler
#endif
#if CLK_48MHZ
T0CON = 0b11000110; //1:128 prescaler
#endif
#if CLK_64MHZ
72
T0CON = 0b11000110; //1:128 prescaler
#endif
ei(); // Global interrupts enabled
//Setup USART (Serial Port) for 19200bps
#if CLK_20MHZ
SPBRG = 64;
#endif
#if CLK_48MHZ
SPBRG = 155;
#endif
#if CLK_64MHZ
SPBRG = 207;
#endif
BRGH = 1; //Set to high speed mode
TX9 = 0;
SYNC = 0;
SPEN = 1;
TXEN = 1; //enable transmitter
CREN = 1;
}
void turnOnPorts()
{
//Dummy Data for Testing
for (i = 0; i < 24; i++) {
if (i % 2 == 0)
{
rData.onTime[i] = 60000;
}
else
{
rData.onTime[i] = 30000;
}
}
//initialize variables
count = 0;
toWriteA = 0x0f;
toWriteB = 0xff;
toWriteC = 0x0f;
toWriteD = 0xff;
count = 0;
//Loop through onTime data. If any is = 0,
//indicate that pin should be turned off.
while (count < 24)
{
if(rData.onTime[count] == 0) {
if (count < 8)
{
toWriteB -= (1<<count);
}
if (count >= 8 && count < 16)
{
toWriteD -= (1<<(count-8));
}
if (count >= 16 && count < 20)
{
//PORTA0-PORTA3
toWriteA -= (1<<(count-16));
}
if (count >= 20)
{
//PORTC0-PORTC3
toWriteC -= (1<<(count-20));
}
}
count++;
}
//Keep track of how many are turned off already
for (i = 0; i < 24; i++) {
if (rData.onTime[i] == 0x0000)
{
numSet++;
}
}
//Write the calculated values to the ports
PORTA = toWriteA;
PORTB = toWriteB;
PORTC = toWriteC;
PORTD = toWriteD;
}
void turnOffPorts()
{
//Keep track of performance for debugging and optimizations
pData.num_loops = 0;
numSet = 0;
//Initialize
toWriteA = 0x0f;
toWriteB = 0xff;
toWriteC = 0x0f;
toWriteD = 0xff;
//About 1uS has passed since the ports were initialized.
//Set to 0 for performance testing with the stopwatch function.
TMR2 = 0;
fifty_micros = 0;
74
//Performance sensitive loop
while(numSet < 24)
{
count = 0;
while (count < 24)
{
if((rData.onTime[count] != 0x0000) &&
(rData.onTime[count] <= fifty_micros))
{
numSet++;
rData.onTime[count] = 0x0000;
if (count < 8)
{
toWriteB -= (1<<count);
}
if (count >= 8 && count < 16)
{
toWriteD -= (1<<(count-8));
}
if (count >= 16 && count < 20)
{
//PORTA0-PORTA3
toWriteA -= (1<<(count-16));
}
if (count >= 20)
{
//PORTC0-PORTC3
toWriteC -= (1<<(count-20));
}
}
count++;
}
PORTA = PORTA & toWriteA;
PORTB = PORTB & toWriteB;
PORTC = PORTC & toWriteC;
PORTD = PORTD & toWriteD;
pData.num_loops++; //performance measure.
}
//Comments regarding different optimizations tried
//START w/ nested for loops:
//t = 15.3014mS, micros 15400, shifter=74
//
//ONE LOOP:
//t = 15.328, micros 15400, shifter = 79
//WITH 2 SUBPORTS and nested ifs
//t = 15.185, micros 15400, shifter = 78
//WITH 2 subport and non-nested ifs
//t=15.249, micros 15300, shifter = 78
//WITH 2 subport and non-nested ifs and count shifter instead of j
//t=15.324, micros 15400, shifter = 79
pData.micros = micros;
//48MHZ = 263 loops, 15.2466s = 0.05797ms
75
//64MHZ = 351 loops, 15.1642s = 0.0432ms
//64MHZ = 347 loops, 15.1359s = 0.0436ms @ 50uS resolution
//64MHZ = 413 loops, 15.1479s = 0.0367ms @ 50uS and changing
// fifty_micros variable to int rather than long
//48MHZ = 308 loops, 15.1769s = 0.0492ms @ 50uS and
// the int rather than long
}
//Serial USART functions -- grabbed from Hi-Tech C examples folder
void putch(unsigned char byte)
{
/* output one byte */
while(!TXIF) /* set when register is empty */
continue;
TXREG = byte;
}
unsigned char getch() {
/* retrieve one byte */
while(!RCIF) /* set when register is not empty */
continue;
return RCREG;
}
//Writes contents of rData to the serial port
void writeRowDataInfo()
{
p = &rData;
i = 0;
while(i < sizeof(rData))
{
putch(*p);
i++;
p++;
}
}
void writePerformanceData()
{
p = &pData;
i = 0;
while(i < sizeof(pData))
{
putch(*p);
i++;
p++;
}
}
//Reads serial port to fill in rData
void readRowDataInfo()
{
putch(0x06); //Send ACK character so that PC knows to start sending data.
p = &rData;
i = 0;
while(i < sizeof(rData))
{
*p = getch();
p++;
i++;
}
}
main()
{
//Initializes ports, timers, usart
init();
//Turn off timer2, turn on timer0, clear micros counter
TMR0ON = 1;
TMR0IE = 1;
TMR2ON = 0;
TMR2IE = 0;
TMR0 = 0; //Reset timer 0
while(1) {
micros = 0;
//Read next row from serial port
readRowDataInfo();
//Turn on all pins required
turnOnPorts();
//Turn off pins when the timing is correct (performance sensitive area)
turnOffPorts();
//Wait for offTime period
while (micros < rData.offTime)
{
//busy loop
}
}
}
That code is very specific for a PIC processor, and quite a bit of effort would be required to modify it to run on any other type of processor.
What other processor did you have in mind?
I have a program that works but maybe there are problems at the time of so for a commitment to this code
if you have code for a PIC18 have a look at Microchip curiosity nano development boards which include several PIC18 boards.
Because your code is so PIC18 specific if you do have to use an Arduino the simplest approach is probably to get a specification of the product and implement it from scratch.
Here you go. All you have to do is convert the PIC-specific code to AVR code. Looks like most of it is timers, Serial, and maybe an analog to digital converter.
Note: The code appears to be using 24 output pins. This will need something with more pins than an UNO/Nano. Perhaps an Arduino MEGA?
byte TMR2IF = 0;
byte TMR0IF = 0;
// #include <pic18.h>
// #include <htc.h>
// #include <conio.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#define CLK_20MHZ 0
#define CLK_48MHZ 1
#define CLK_64MHZ 0
//Nothing in place for 20MHZ and 50 micro res. All other combos supported.
#define FIFTY_MICRO_RES 1
#define HUNDRED_MICRO_RES 0
//__CONFIG(1, USBOSC & CPUDIV1 & PLLDIV12 & HS & FCMDIS & IESODIS);
//__CONFIG(2, VREGDIS & PWRTDIS & BORDIS & WDTDIS);
//__CONFIG(3, PBDIGITAL & LPT1DIS & MCLRDIS & ICPORTDIS & DEBUGDIS);
//__CONFIG(4, STVREN & LVPDIS & XINSTDIS & DEBUGDIS);
//__CONFIG(5, UNPROTECT);
//__CONFIG(6, UNPROTECT);
//__CONFIG(7, UNPROTECT);
// Data Structures
struct rowData
{
unsigned char frameType; //0x01 = rowData
unsigned int offTime; //time off in ms
unsigned int onTime[24];
};
struct performanceData
{
unsigned long num_loops;
unsigned long microseconds;
};
//keeps track of timer2 with 50 or 100us resolution
unsigned int fifty_microseconds = 0;
//keeps track of timer0 with approx 3ms resolution
unsigned long microseconds = 0;
// Global variables
struct performanceData pData;
struct rowData rData;
unsigned char * p; //pointer for serial communication
unsigned char count;
unsigned char numSet;
unsigned char toWriteA;
unsigned char toWriteB;
unsigned char toWriteC;
unsigned char toWriteD;
int i;
// Interrupt service routine that is called every time a timer fires
void TimerISR(void)
{
if (TMR2IF)
{
//This is run every 50 or 100uS
#if HUNDRED_MICRO_RES
fifty_microseconds += 2;
#endif
#if FIFTY_MICRO_RES
fifty_microseconds++;
#endif
TMR2IF = 0; // clear event flag
}
else
{
if (TMR0IF)
{
//Run every 3ms or so
//20MHz
#if CLK_20MHZ
microseconds += 3277;
#endif
#if CLK_48MHZ
microseconds += 2731;
#endif
#if CLK_64MHZ
microseconds += 2048;
#endif
TMR0IF = 0;
}
}
}
void init(void)
{
// ADCON1 = 0x06 ; // Changes PORTA to digital
// CMCON = 0x07 ; // Disable analog comparators
//Configure ports, all output except for RC7
// TRISA = 0x00 ;
// TRISB = 0X00 ;
// TRISC = 0b10000000 ; //Set RC7 input for USART, all others output
// 71;
// TRISD = 0X00 ;
// TRISE = 0X00 ;
// PEIE = 1; //Peripheral interrupt enabled
/***** Timer 2 Code ****
Prescale ratio set at 1:16
Timer2 module activated
Postscale ratio set at 1:10
*/
#if CLK_20MHZ
T2CON = 0b00000101;
//Set timer period to 97.6 = 122, works out to be ˜100uS
//after ISR is run. OLD: 123, 125, 130 - microseconds too low,
//120, 122, 123 to high. 124=dead on for 6.510215s
//PR2 = 124;
PR2 = 124;
#endif
#if CLK_48MHZ
#if HUNDRED_MICRO_RES
T2CON = 0b00000111; //1:16 prescaler
PR2 = 74;
#endif
#if FIFTY_MICRO_RES
// T2CON = 0b00000101; //1:4 prescaler
// PR2 = 149;
#endif
#endif
#if CLK_64MHZ
T2CON = 0b00000111;
#if HUNDRED_MICRO_RES
PR2 = 99;
#endif
#if FIFTY_MICRO_RES
PR2 = 49;
#endif
#endif
//Timer0 Setup
#if CLK_20MHZ
T0CON = 0b11000101; //1:64 prescaler
#endif
#if CLK_48MHZ
// T0CON = 0b11000110; //1:128 prescaler
#endif
#if CLK_64MHZ
// 72
T0CON = 0b11000110; //1:128 prescaler
#endif
interrupts(); // ei(); // Global interrupts enabled
//Setup USART (Serial Port) for 19200bps
#if CLK_20MHZ
SPBRG = 64;
#endif
#if CLK_48MHZ
// SPBRG = 155;
#endif
#if CLK_64MHZ
SPBRG = 207;
#endif
// BRGH = 1; //Set to high speed mode
// TX9 = 0;
// SYNC = 0;
// SPEN = 1;
// TXEN = 1; //enable transmitter
// CREN = 1;
}
void turnOnPorts()
{
//Dummy Data for Testing
for (i = 0; i < 24; i++)
{
if (i % 2 == 0)
{
rData.onTime[i] = 60000;
}
else
{
rData.onTime[i] = 30000;
}
}
//initialize variables
count = 0;
toWriteA = 0x0f;
toWriteB = 0xff;
toWriteC = 0x0f;
toWriteD = 0xff;
count = 0;
//Loop through onTime data. If any is = 0,
//indicate that pin should be turned off.
while (count < 24)
{
if (rData.onTime[count] == 0)
{
if (count < 8)
{
toWriteB -= (1 << count);
}
if (count >= 8 && count < 16)
{
toWriteD -= (1 << (count - 8));
}
if (count >= 16 && count < 20)
{
//PORTA0-PORTA3
toWriteA -= (1 << (count - 16));
}
if (count >= 20)
{
//PORTC0-PORTC3
toWriteC -= (1 << (count - 20));
}
}
count++;
}
//Keep track of how many are turned off already
for (i = 0; i < 24; i++)
{
if (rData.onTime[i] == 0x0000)
{
numSet++;
}
}
//Write the calculated values to the ports
// PORTA = toWriteA;
PORTB = toWriteB;
PORTC = toWriteC;
PORTD = toWriteD;
}
void turnOffPorts()
{
//Keep track of performance for debugging and optimizations
pData.num_loops = 0;
numSet = 0;
//Initialize
toWriteA = 0x0f;
toWriteB = 0xff;
toWriteC = 0x0f;
toWriteD = 0xff;
//About 1uS has passed since the ports were initialized.
//Set to 0 for performance testing with the stopwatch function.
// TMR2 = 0;
fifty_microseconds = 0;
// 74;
//Performance sensitive loop
while (numSet < 24)
{
count = 0;
while (count < 24)
{
if ((rData.onTime[count] != 0x0000) &&
(rData.onTime[count] <= fifty_microseconds))
{
numSet++;
rData.onTime[count] = 0x0000;
if (count < 8)
{
toWriteB -= (1 << count);
}
if (count >= 8 && count < 16)
{
toWriteD -= (1 << (count - 8));
}
if (count >= 16 && count < 20)
{
//PORTA0-PORTA3
toWriteA -= (1 << (count - 16));
}
if (count >= 20)
{
//PORTC0-PORTC3
toWriteC -= (1 << (count - 20));
}
}
count++;
}
// PORTA = PORTA & toWriteA;
PORTB = PORTB & toWriteB;
PORTC = PORTC & toWriteC;
PORTD = PORTD & toWriteD;
pData.num_loops++; //performance measure.
}
//Comments regarding different optimizations tried
//START w/ nested for loops:
//t = 15.3014mS, microseconds 15400, shifter=74
//
//ONE LOOP:
//t = 15.328, microseconds 15400, shifter = 79
//WITH 2 SUBPORTS and nested ifs
//t = 15.185, microseconds 15400, shifter = 78
//WITH 2 subport and non-nested ifs
//t=15.249, microseconds 15300, shifter = 78
//WITH 2 subport and non-nested ifs and count shifter instead of j
//t=15.324, microseconds 15400, shifter = 79
pData.microseconds = microseconds;
//48MHZ = 263 loops, 15.2466s = 0.05797ms
// 75;
//64MHZ = 351 loops, 15.1642s = 0.0432ms
//64MHZ = 347 loops, 15.1359s = 0.0436ms @ 50uS resolution
//64MHZ = 413 loops, 15.1479s = 0.0367ms @ 50uS and changing
// fifty_microseconds variable to int rather than long
//48MHZ = 308 loops, 15.1769s = 0.0492ms @ 50uS and
// the int rather than long
}
//Serial USART functions -- grabbed from Hi-Tech C examples folder
void putch(unsigned char c)
{
(void) c;
/* output one byte */
// while (!TXIF) /* set when register is empty */
// continue;
// TXREG = c;
}
unsigned char getch()
{
/* retrieve one byte */
// while (!RCIF) /* set when register is not empty */
// continue;
// return RCREG;
return 0;
}
//Writes contents of rData to the serial port
void writeRowDataInfo()
{
p = (byte *) &rData;
size_t i = 0;
while (i < sizeof(rData))
{
putch(*p);
i++;
p++;
}
}
void writePerformanceData()
{
p = (byte *) &pData;
size_t i = 0;
while (i < sizeof(pData))
{
putch(*p);
i++;
p++;
}
}
//Reads serial port to fill in rData
void readRowDataInfo()
{
putch(0x06); //Send ACK character so that PC knows to start sending data.
p = (byte *) &rData;
size_t i = 0;
while (i < sizeof(rData))
{
*p = getch();
p++;
i++;
}
}
void setup()
{
//Initializes ports, timers, usart
init();
//Turn off timer2, turn on timer0, clear microseconds counter
// TMR0ON = 1;
// TMR0IE = 1;
// TMR2ON = 0;
// TMR2IE = 0;
// TMR0 = 0; //Reset timer 0
}
void loop()
{
microseconds = 0;
//Read next row from serial port
readRowDataInfo();
//Turn on all pins required
turnOnPorts();
//Turn off pins when the timing is correct (performance sensitive area)
turnOffPorts();
//Wait for offTime period
while (microseconds < rData.offTime)
{
//busy loop
}
}
This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.