[ create a new paste ] login | about

Link: http://codepad.org/i8iowKl0    [ raw code | fork ]

C, pasted on Mar 20:
#include <htc.h>
#include <stdint.h>
#include <math.h>
#include <delay.c>

#define PIC_CLK 4000000 // Isn't redefining properly, had to change value in delay.h.
#define _XTAL_FREQ 4000000 // For __delay_us()
#define RADIUS_ROTOR_MM 215
#define LED_WIDTH_MM 5
#define LED_DUTY_CYCLE 10

__CONFIG (FOSC_INTRC_NOCLKOUT & WDTE_OFF & PWRTE_ON & MCLRE_ON & CP_OFF & CPD_OFF & BOREN_OFF & IESO_OFF & FCMEN_OFF & LVP_OFF & DEBUG_OFF);


/***********
 * Globals *
 ***********/

uint32_t TMR1_FREQ = 0;
float DELAY_H_PIXELS_US = 0;	
uint16_t NUMBER_H_PIXELS = 0;
float DELAY_H_PIXELS_US_ON = 0;
float DELAY_H_PIXELS_US_OFF = 0;
	
/***************
 * Initiatiors *
 ***************
 * Functions to set up the PIC the way we want it.
 */

void initAllPortsOut() {
	PORTA = PORTB = PORTC = PORTD = 0;	// Clear all bits in ports
	TRISA = TRISB = TRISC = TRISD = 0;	// Set all ports to output
	ANSEL = ANSELH = 0;					// Disable all analogue inputs.
}

void initComparator1() {
	CM1CON0bits.C1ON	= 1;	// Enable C1.
//	CM1CON0bits.C1OUT			// This bit is only readable - it is the actual output of the comparator module.
	CM1CON0bits.C1OE	= 1;	// Enable output on pin C1OUT (RA4). Make sure TRISA4 is set to 0 for output (already has been previously in code).
	CM1CON0bits.C1POL	= 0;	// Comparator inversion bit set. 0 = non inverted.
	CM1CON0bits.C1R		= 0;	// Comparator reference select bit. 0 = C1VIN+ (RA3) connects to C1VREF output (internal voltage ref). 0 = C1VIN+ connects to C1IN+ (RA3) pin
	CM1CON0bits.C1CH	= 0;	// 2 bits wide, comparator channel select bit. Select whether inverting input of comparator C1 comes from pin C12IN0-. C12IN1-... or C12IN4-. 00 = C12IN0- (RA0).
	TRISA0				= 1;
	TRISA3				= 1;	// Set C12IN0- (RA0) and C1IN+ (RA3) as analogue input. 12 = 1 and 2?
	ANSELbits.ANS0		= 1;
	ANSELbits.ANS3		= 1;	// Select RA0 and RA3 as analogue input. Setting the appropriate ANSEL bit high will cause all digital reads on the pin to be read as ‘0’ and allow analog functions on the pin to operate correctly.
	
	/*************************************************************************************************
	 * Use built in Vref circuit to  output a voltage appropriate for the schmitt trigger operation. *
	 *************************************************************************************************
	 * Calculated hysteresis given non inverting schmitt, low threshold voltage of 2.5, V high thr 2.7815, 
	 * high output voltage of 5, low voltage output of 0; Rin should be ~5.7K, Rf ~ 10K and Vref ~ 2.633V.
	 * See attached report for how VR was calculated.
	 */
	 
	 VRCONbits.VREN		= 1;	// CVREF circuit powered on and configured to connect to C1VIN+. It isn't however, since we previously set C1VIN+ to connect to C1IN+ pin.
	 VRCONbits.VROE		= 1; 	// CVREF voltage level is also output on the RA2/AN2/VREF-/CVREF/C2IN+ pin. Make sure TRISA2 is set to 0 for output (already has been previously in code). This gives us 'outside access' to Vref.
	 VRCONbits.VRR		= 1;	// CVREF Range Selection bit. 0 = high range, 1 = low. See datasheet.
	 VRCONbits.VRSS		= 0;	// CVREF Range Selection bit. 0 = Comparator Reference Source, CVRSRC = VDD - VSS.
	 VRCONbits.VR		= 13;	// CVREF Value Selection. 4 bits wide. When VRR = 1: CVREF = (VR<3:0>/24) * VDD. When VRR = 0: CVREF = VDD/4 + (VR<3:0>/32) * VDD.
}
	 
void initIntOscillator() {
	OSCCONbits.IRFC 	= 6;		// Internal oscillator frequency set. 3 bits wide, 100 = 1MHz, 11 = 500KHz
	OSCCONbits.OSTS		= 0;		// Use internal oscillator. 1 = ext osc.
	OSCCONbits.HTS		= 1;		// High frequency stability bit (8 MHz to 125 kHz). What do?
	OSCCONbits.LTS		= 0;		// Low frequency stability bit (31KHz). What do?
	OSCCONbits.SCS		= 1;		// System clock select. 1 = int, 0 = ext.
}	


void initTimer1() {
	T1CONbits.T1GINV	= 0; 	// Set T1 Gate active high or active low. 1 = high, 0 = low.
	T1CONbits.TMR1GE	= 0; 	// 1 = Timer1 is on if Timer1 gate is not active. 0 = Timer1 is on.
	T1CONbits.T1CKPS	= 3;	// Timer1 clock prescale, 2 bits wide. 00 = /1. 11 = /8
	T1CONbits.T1OSCEN	= 0; 	// LP oscillator enable for Timer1. Runs at 32.768KHz.
	T1CONbits.T1SYNC	= 0; 	// Sync external clock (dont think this applies but sync JIC). Inverted, 0 = sync.
	T1CONbits.TMR1CS	= 0; 	// 1 = External clock from T1CLI pin (RC0). 0 = Internal clock. Not sure what this should be when using LP osc!
	T1CONbits.TMR1ON	= 0; 	// 1 Enables timer, 0 stops it.
	TMR1H = TMR1L		= 0; 	// Clear whatever is in Timer1. Values are unknown on startup.
	
	/******************************
 	 * Calculate Timer1 Frequency *
	 ******************************
 	 * Unsigned 32bit integer required to deal with large _XTAL_FREQ number.
	 */
 	
	uint32_t freqTMR1 = _XTAL_FREQ/4;		
	switch(T1CONbits.T1CKPS) {									
		case 0 : break;
		case 1 : freqTMR1 = freqTMR1/2; break;
		case 2 : freqTMR1 = freqTMR1/4; break;
		case 3 : freqTMR1 = freqTMR1/8; break;
	}
	TMR1_FREQ = freqTMR1;
	
	T1CONbits.TMR1ON = 1; // Turn Timer1 On
}

void initCCP1CaptureRising() {
	CCP1CONbits.CCP1M	= 0x05;
	/* write to the CCP1CON register, specifically the CCP1M (Enhanced Capture/Compare/PWM mode
	 * select bits) selection, and set '0101 = Capture mode, every rising edge'. All other bits
	 * in register are not used.
	 */
	CCPR1 = 0;
}

void initCCP1Interrupt() {
	INTCONbits.GIE	= 1;	// Global interrupt enable. Enables all unmasked interrupts, must be set. Clears all interrupts also.
	INTCONbits.PEIE	= 1;	// Peripheral interrupt enable. Enables all unmasked peripheral interrupts. Clears all associated interrupts also.
	TRISC2			= 1;	// Pin CCP1 set to input.
	PIE1bits.CCP1IE	= 1;	// CCP1 interrupt enable bit, RC2.
}

void initDimensions() {
	/**********************************************
	 * Calculate the number of H-pixels available *
	 **********************************************
	 * Circumference/LED width will give us the number of independent
	 * horizontal pixel positions we have available to use for given 
	 * dimentions. Any fraction this sum produces can be truncated without 
	 * causing much of an issue. This gets sent to a global variable.
	 */
	 
	float numberPixelDivisions = (2*M_PI*RADIUS_ROTOR_MM)/LED_WIDTH_MM;
	NUMBER_H_PIXELS = (uint16_t)numberPixelDivisions;
	__delay_us(2);
}

/******************************************************************************************************/

void showMeTheLights() {
	int i = 0;
	int Array1[48]; // 48 is the max size an array can be on the PIC16F887. Use multiple arrays for more characters.

	Array1[0] = 0xFF; // Better way would to set up an array with 0x00, 0x01, 0x02... 0xFF and use the numbers to dictate which element to use.
	Array1[1] = 0x81;
	Array1[2] = 0x81;
	Array1[3] = 0x81;
	Array1[4] = 0x81;
	Array1[5] = 0x82;
	Array1[6] = 0x84;
	Array1[7] = 0x78; // This section outputs a 'D'
	
	Array1[8] = 0x00;
	Array1[9] = 0x00; // Char spacing
	
	Array1[10] = 0xFC;
	Array1[11] = 0x12;
	Array1[12] = 0x11;
	Array1[13] = 0x11;
	Array1[14] = 0x11;
	Array1[15] = 0x11;
	Array1[16] = 0x12;
	Array1[17] = 0xFC; // 'A'
	
	Array1[18] = 0x00;
	Array1[19] = 0x00; // Char spacing
	
	Array1[20] = 0xFF;
	Array1[21] = 0x02;
	Array1[22] = 0x04;
	Array1[23] = 0x08;
	Array1[24] = 0x10;
	Array1[25] = 0x20;
	Array1[26] = 0x40;
	Array1[27] = 0xFF; // 'N'
	

	while (i != 28) {
		PORTB = Array1[i];
		DelayBigUs((uint16_t)DELAY_H_PIXELS_US_ON);
		PORTB = 0;
		DelayBigUs((uint16_t)DELAY_H_PIXELS_US_OFF);
		i++;
	}
	PORTB = 0;
	
}

interrupt void math() {
	
	TMR1 = 0; // Restart Timer1 right away to get accurate timings.
	
	
	/**********************************************************
	 * Calculate the the time of one revolution (H scan rate) *
	 **********************************************************
	 * Float wont evaluate a full 32 bit number, have to be careful here when
	 * using high clock frequencies. 1/freqTMR1 gives time in seconds it takes 
	 * for 1 count of TMR1. Multiplying this by CCPR1 gives time in seconds    
	 * it takes for 1 revolution to occur. (float) cast on either CCPR1 or      
	 * TMR1_FREQ is absolutely neccessary - if performing maths with integers  
	 * even using a float type, the calculation is treated as an integers 
	 * only, and truncates the fractional part of the answer (gay).
	 */

	float revolutionTime_S = (float)CCPR1/TMR1_FREQ; 
	
	
	/************************************
	 * Calculate horizontal pixel delay *
	 ************************************
	 * Dividing the time it takes for 1 complete revolution by how many pixels
	 * we have available will give us the time it takes for the rotor to move
	 * from one pixel potition to the next.
	 */

	float horizontalDelay_US = revolutionTime_S/NUMBER_H_PIXELS;
	
	
	/**********************************************************
	 * Convert delay time to microseconds, reset timer & flag *
	 **********************************************************
	 * Convert the delay time in seconds to microseconds, and send that value
	 * to the specified global variable, then reset Timer1 and clear CCP1
	 * interrupt flag.
	 */
	
	float horizontalDelay_US = (horizontalDelay_US*1000000);	// meant to be 1M but delay is faulty. 1 sent to the delay = 4us.
	DELAY_H_PIXELS_US = (uint16_t)horizontalDelay_US;


	/********************************
	 * Combine delay and duty cycle *
	 ********************************/
	
	DELAY_H_PIXELS_US_ON = ((DELAY_H_PIXELS_US/100.0)*LED_DUTY_CYCLE);
	DELAY_H_PIXELS_US_OFF = ((DELAY_H_PIXELS_US/100.0)*(100 - LED_DUTY_CYCLE));
	;
	

/*	PORTB = CCPR1;
	PORTD = CCPR1 >> 8;
	__delay_ms(10000);
	PORTB = PORTD = 0;
	PORTB = (uint16_t)DELAY_H_PIXELS_US;
	PORTD = (uint16_t)DELAY_H_PIXELS_US >> 8;
	__delay_ms(10000);
	PORTB = PORTD = 0;
	PORTB = (uint16_t)DELAY_H_PIXELS_US_ON;
	PORTD = (uint16_t)DELAY_H_PIXELS_US_ON >> 8;
	__delay_ms(10000);
	PORTB = PORTD = 0;
	PORTB = (uint16_t)DELAY_H_PIXELS_US_OFF;
	PORTD = (uint16_t)DELAY_H_PIXELS_US_OFF >> 8;
*/
/*	The above code was to check whether numbers were being calculated correctly. They were accurate.
	Need to find good accurate delay function
*/

	showMeTheLights();
	PIR1bits.CCP1IF	= 0; // Clear interupt flag last.

}



void main() {
	initIntOscillator();
	initAllPortsOut();
	initCCP1CaptureRising();
	initCCP1Interrupt();
	initDimensions();
	initComparator1();
	initTimer1();
	while(1) {}
}


Create a new paste based on this one


Comments: