EmbeddedRelated.com
Code Snippets

ADXL345 Driver

May 29, 20131 comment Coded in C for the Microchip PIC16
#define ADXL_SDA  PIN_C4
#define ADXL_SCL  PIN_C3
#define ADXL_CS   PIN_C0

#use i2c(master, sda=ADXL_SDA, scl=ADXL_SCL)

void init_adxl345() 
{
   output_float(ADXL_SCL);
   output_float(ADXL_SDA);
   output_high(ADXL_CS);
}

BOOLEAN adxl345_ready() 
{
   int1 ack;
   i2c_start();            // If the write command is acknowledged,
   ack = i2c_write(0x3a);  // then the device is ready.
   i2c_stop();
   return !ack;
}

void write_adxl345(BYTE address, BYTE data) 
{
   while(!adxl345_ready());
   i2c_start();
   i2c_write(0x3a);
   i2c_write(address);
   i2c_write(data);
   i2c_stop();
}

BYTE read_adxl345(BYTE address) 
{
   BYTE data;

   while(!adxl345_ready());
   i2c_start();
   i2c_write(0x3a);
   i2c_write(address);
   i2c_start();
   i2c_write(0x3b);
   data=i2c_read(0);
   i2c_stop();
   return(data);
}

int16 read_adxl345_axis(BYTE address) 
{
   BYTE msb,lsb;

   while(!adxl345_ready());
   i2c_start();
   i2c_write(0x3a);
   i2c_write(address);
   i2c_start();
   i2c_write(0x3b);
   lsb=i2c_read(1);
   msb=i2c_read(0);
   i2c_stop();
   return((msb<<8)|lsb);
}

LCD, 4 bit data mode

Fabien Le Mentec May 21, 2013 Coded in C for the ATMEGA328P
/* note: lcd model MC21605A6W */
/* note: DB0:3 and RW must be grounded */
/* note: see https://github.com/texane/lcmeter for usage */

#include <stdint.h>
#include <avr/io.h>

#define LCD_POS_DB 0x02
#define LCD_PORT_DB PORTD
#define LCD_DIR_DB DDRD
#define LCD_MASK_DB (0x0f << LCD_POS_DB)

#define LCD_POS_EN 0x06
#define LCD_PORT_EN PORTD
#define LCD_DIR_EN DDRD
#define LCD_MASK_EN (0x01 << LCD_POS_EN)

#define LCD_POS_RS 0x07
#define LCD_PORT_RS PORTD
#define LCD_DIR_RS DDRD
#define LCD_MASK_RS (0x01 << LCD_POS_RS)

static inline void wait_50_ns(void)
{
  __asm__ __volatile__ ("nop\n\t");
}

static inline void wait_500_ns(void)
{
  /* 8 cycles at 16mhz */
  __asm__ __volatile__ ("nop\n\t");
  __asm__ __volatile__ ("nop\n\t");
  __asm__ __volatile__ ("nop\n\t");
  __asm__ __volatile__ ("nop\n\t");
  __asm__ __volatile__ ("nop\n\t");
  __asm__ __volatile__ ("nop\n\t");
  __asm__ __volatile__ ("nop\n\t");
  __asm__ __volatile__ ("nop\n\t");
}

static inline void wait_50_us(void)
{
  /* 800 cycles at 16mhz */
  uint8_t x;
  for (x = 0; x < 100; ++x) wait_500_ns();
}

static inline void wait_2_ms(void)
{
  wait_50_us();
  wait_50_us();
  wait_50_us();
  wait_50_us();
}

static inline void wait_50_ms(void)
{
  /* FIXME: was _delay_ms(50), but not working */
  uint8_t x;
  for (x = 0; x < 25; ++x) wait_2_ms();
}

static inline void lcd_pulse_en(void)
{
  /* assume EN low */
  LCD_PORT_EN |= LCD_MASK_EN;
  wait_50_us();
  LCD_PORT_EN &= ~LCD_MASK_EN;
  wait_2_ms();
}

static void lcd_write_db4(uint8_t x)
{
  /* configured in 4 bits mode */

  LCD_PORT_DB &= ~LCD_MASK_DB;
  LCD_PORT_DB |= (x >> 4) << LCD_POS_DB;
  lcd_pulse_en();

  LCD_PORT_DB &= ~LCD_MASK_DB;
  LCD_PORT_DB |= (x & 0xf) << LCD_POS_DB;
  lcd_pulse_en();
}

static void lcd_write_db8(uint8_t x)
{
  /* configured in 8 bits mode */

  /* only hi nibble transmitted, (0:3) grounded */
  LCD_PORT_DB &= ~LCD_MASK_DB;
  LCD_PORT_DB |= (x >> 4) << LCD_POS_DB;
  lcd_pulse_en();
}

/* exported interface */

void lcd_setup(void)
{
  LCD_DIR_DB |= LCD_MASK_DB;
  LCD_DIR_RS |= LCD_MASK_RS;
  LCD_DIR_EN |= LCD_MASK_EN;

  LCD_PORT_DB &= ~LCD_MASK_DB;
  LCD_PORT_RS &= ~LCD_MASK_RS;
  LCD_PORT_EN &= ~LCD_MASK_EN;

  /* small delay for the lcd to boot */
  wait_50_ms();

  /* datasheet init sequence */

#define LCD_MODE_BLINK (1 << 0)
#define LCD_MODE_CURSOR (1 << 1)
#define LCD_MODE_DISPLAY (1 << 2)

  lcd_write_db8(0x30);
  wait_2_ms();
  wait_2_ms();
  wait_500_ns();

  lcd_write_db8(0x30);
  wait_2_ms();

  lcd_write_db4(0x32);
  wait_2_ms();

  lcd_write_db4(0x28);
  wait_2_ms();

  lcd_write_db4((1 << 3) | LCD_MODE_DISPLAY);
  wait_2_ms();

  lcd_write_db4(0x01);
  wait_2_ms();

  lcd_write_db4(0x0f);
  wait_2_ms();
}

void lcd_clear(void)
{
  /* clear lcd */
  lcd_write_db4(0x01);
  wait_2_ms();
}

void lcd_home(void)
{
  /* set cursor to home */
  lcd_write_db4(0x02);
  wait_2_ms();
}

void lcd_set_ddram(uint8_t addr)
{
  lcd_write_db4((1 << 7) | addr);
  wait_2_ms();
}

void lcd_goto_xy(uint8_t x, uint8_t y)
{
  /* assume 0 <= x < 8 */
  /* assume 0 <= y < 2 */

  /* from datasheet: */
  /* first line is 0x00 to 0x27 */
  /* second line is 0x40 to 0x67 */
  static const uint8_t row[] = { 0x00, 0x40 };
  lcd_set_ddram(row[y] | x);
}

void lcd_write(const uint8_t* s, unsigned int n)
{
  wait_50_ns();

  LCD_PORT_RS |= LCD_MASK_RS;
  for (; n; --n, ++s)
  {
    lcd_write_db4(*s);
    wait_2_ms();
  }
  LCD_PORT_RS &= ~LCD_MASK_RS;
}

Plotting 16-bit binary data

Stephen Friederichs May 17, 2013 Coded in Matlab
%Script to load and plot 16-bit accelerometer data
printf "Running acceleration data analysis script\r\n"

clear *	%Clear all variables

ts = (1/1000);	%1KHz sampling rate

%Path to TXT file with accelerometer samples
accel_data_path = "accel_data.txt";

%Open the acceleration data file as read-only, binary mode
file_accel_data = fopen(accel_data_path,"rb");

%Read unit16 samples from TXT file into an array
%count is # of samples, val is array of values
[val,count] = fread(file_accel_data,Inf,"uint16");

fclose(file_accel_data);

%Generate a time vector from t=0 to the end determined by count and sampling time
tmax = (count-1)*ts;
t=0:ts:tmax;

%Open figure 1
figure(1)

%Plot accelerometer samples
plot(t,val','1')

%Make the plot look pretty
title("Raw Sampled Accelerometer Data")
xlabel("Time (s)")
ylabel("Accelerometer Data")

%Save the plot to disk
print("plots/raw_accel_data.png")

10-bit A/D Data Sampling and Transmission

Stephen Friederichs May 17, 2013 Coded in C for the ATMega328P
/**@file endianness.c
   @brief Code to transmit 16-bit ADC samples in big or little-endian order
   @author Stephen Friederichs
   @date 5/12/13
   
   ADC Channels:
   0 - Accelerometer X axis (Vertical)
   1 - Accelerometer Y axis (Horizontal)
   2 - Accelerometer Z axis (Lateral)
   3 - Accelerometer 0G detect (Freefall detect)
   
   The heartbeat LED is on Port D, pin 7
*/   

/**@def F_CPU
   @brief Clock frequency = 8MHZ - this is set by fuses and registers, not by this define
   @note Always define this before including delay.h!
*/
#define F_CPU 8000000
	
/**@include io.h
   @brief Include for AVR I/O register definitions
*/
#include <avr/io.h>

/**@include stdint.h
   @brief Include for standard integer definitions (ie, uint8_t, int32_t, etc)
*/
#include <stdint.h>

/**@include delay.h
   @brief Include for delay functions such as _delay_ms() and _delay_us()
*/
#include <util/delay.h>

/* Basic bit manipulation macros - everyone should use these.  Please, steal these! Don't not use them and
 don't rewrite them yourself!
*/
#define SET(x,y) x |= (1 << y)
#define CLEAR(x,y) x &= ~(1<< y)
#define READ(x,y) ((0x00 == ((x & (1<<y))>> y))?0x00:0x01)
#define TOGGLE(x,y) (x ^= (1 << y))

int main(void)
{
	
	//Variable to count the number of times the timer interrupt has fired
	uint16_t ticks = 0;
	uint16_t accel_data = 0;
	uint8_t transmit_enable = 0x00;
	uint8_t * uart_data_pointer = &accel_data;
	
	/*Initialization Code*/
	
	/*	ATMega328 Datasheet Table 14-1 Pg 78
		Configure PD7 for use as Heartbeat LED
		Set as Output Low (initially)
	*/
	SET(DDRD,7);	//Direction: output
	CLEAR(PORTD,7);	//State: Lo

	/*	TCCR1A - ATMega328 Datasheet Section 16.11.2 pg 134 - TCCR1A
		No input capture used - bits 7:6 are 0
		No waveform generation used - bits 4:3 are 0
		Clock source select is bits 2:0 but are not yet set - wait until the 
		main loop is ready to start
	*/	
	TCCR1A = 0x00;
		
	/*	TCCR1C - ATMega328 Datasheet Section 16.11.3 pg 135 
		This register is only used for output compare.  
		There's no output compare in this application so this can be all 0's
	*/
	TCCR1C = 0x00;
		

	/*	TCCR1B
		
		Note: I've disabled the CKDIV8 fuse so that the clock source is 8MHz

		As per ATMega328 Datasheet Section 16.9.1 page 123, setting the timer 
		to Normal mode causes the counter to count up until it reaches 0xFFFF
		at which point it will overrun and start back at 0.  To configure this
		timer/counter to produce a period of 1ms we need to start counting 
		at a value that causes it to reach 65535 in 1ms. 
		
		What is that value?

		With a clock prescaler of 32 each count of the timer is roughly
		(1/8MHz)*32 = 1uS
		1ms / 1us /tick = 1000 ticks /ms
		The counter counts up to 65536, so to determine what value we have to
		start at we subtract 1000 from 65536:
		65536-1000 = 64536
	*/

	#define TIMER1_PERIOD 64536
		
	TCNT1 = TIMER1_PERIOD;

	//Configure ADC to read accelerometer data
	
	//ATMega328 - Section 24.9.1 Pg 254 - ADMUX Register

	/*ADC result - left-adjusted (Bit 5).  The ADC result is 10-bits wide.  
          In practice, the least-significant 2 bits are often too noisy to be
          of any use, so they are discarded. To support this, the ATMega328P is 
	  capable of storing the upper eight bits of the ADC result in the 
          ADCH register alone.  In this case, I want all 10 bits of the data 
          so I can show how to handle endianness in serial transmissions.  As 
          a result, the most significant two bits are stored in ADCH and the least 
          significant 8 are stored in ADCL.
	*/
	
	/*ADC Channel - I only care about one - the Y axis on the accelerometer 
          which is channel 1.*/
	
	ADMUX =		(0x01 << 6)  /*Reference - AVCC - 5V. */ 
			|(0x00 << 5) /* Right-adjust ADC result - refer to 
                                        Section 24.9.3.2 pg 256*/
			|(0x01 << 0); /*Channel set to X-Axis output on 
                                        accelerometer*/
	
	/*	ATMega328 Datasheet - Section 24.9.2 - ADCSRA - ADC Status
                and Control Register
		ADCEN - Bit 7 - Enable ADC - Obviously set this to 1
		ADCSC - Bit 6 - Start Converstion - Not yet: 0
		ADATE - Bit 5 - Auto-trigger ADC - I'll be manually triggering 
                                the ADC, so 0
		ADCIF - Bit 4 - ADC Interrupt Flag - Set when conversion 
                                completes.  Ignore.
		ADCIE - Bit 3 - ADC Interrupt Enable - Everything will be polled 
                        for this, so 0
		ADPS - Bits 2:0 - ADC Prescaler
	*/
	
	/*ATMega328 Section 24.4 Pg245 discusses what the prescaler should be set to:
	
	By default, the successive approximation circuitry requires an input clock 
        frequency between 50kHz and 200kHz to get maximum resolution.
	
	The ClkIO is 8MHz and the prescaler options are 2,4,8,16,32,64 and 128. 
        1MHz/8 = ~125KHz, so that seems good. That value is 3
	*/
	
	ADCSRA = (0x01 << 7)	//Enable ADC
		|(0x03);	//Set prescaler to 1/8 ClkIO - 125KHz
			  
	/*	ATMega328 Datasheet Section 24.9.5 Pg 257 - DIDR0
		This register allows digital input buffers on ADC pins to be
                disabled.  This saves power, so I'll do it
	*/
	
	DIDR0 = 0x01;	//Turn off digital filtering on ADC channel 0
	
	//Configure UART for 38400 8N1 Tx Communication
	
	//Step 1 - Baud rate
	/*	ATMega328 Datasheet Section 20.10 - Table 20-6 pg 192
		Baud rate settings for fosc of 8MHZ
		Choosing baud rate of 38.4K for minimum error
		U2Xn = 0 - Use standard (not double) data rate
		UBRRn = 12
	*/
	
	UBRR0 = 12;
	
 	/*	UCSR0A - UART 0 Control and Status Register A
		ATMega328 Datasheet Section 20.11.2 pg 194
		Bits 7:2 - Status bits
		Bit 1 - Double UART transmission speed - No: 0
		Bit 0 - Multi-Processor Communication Mode - No:0
	*/
	UCSR0A = 0x00;
	
	/*	UCSR0B - UART 0 Control and Status Register B
		ATMega328 Datasheet Section 20.11.3 pg 
		Bit 7 - Rx Complete Interrupt Enable - 0
		Bit 6 - Tx Complete Interrupt Enable - 0
		Bit 5 - USART Data Register Empty interrupt enable - 0
		Bit 4 - Receiver Enable - Set to 1
		Bit 3 - Transmitter Enable - Set to 1
		Bit 2 - Character Size Bit 2 - Set to 0 for 8 bits
		Bit 1 - 9th receive bit - Ignore
		Bit 0 - 9th transmit bit - Ignore
	*/
	UCSR0B = 0x00	| (1 << 3)
					| (1 << 4);
	
	/*	UCSR0C - UART 0 Control and Status Register C
		ATMega328 Datasheet Section 20.11.4 - Pg 196
		Bits 7:6 - Set to asynchronous (clockless) mode: 00
		Bits 5:4 - Parity setting - None : 00
		Bit 3 - Stop select - 1 : 0
		Bit 2:1 - Character size - 8 : 11
		Bit 0 - Clock polarity: Don't care : 0
	*/
	UCSR0C = 0x03 << 1;
	
	//Send a known pattern upon startup to verify the UART works
	UDR0 = 0xA5;
	
	//Wait until transmit is complete
	while(0x00 == READ(UCSR0A,6));
	
	UDR0 = 0x5A;
	
	while(0x00 == READ(UCSR0A,6));
	
	UDR0 = 0xA5;
	
	//Wait until transmit is complete
	while(0x00 == READ(UCSR0A,6));
	
	
	/*	Flash the LED for a second to show that initialization has successfully 
		occurred
	*/
	SET(PORTD,7);
	_delay_ms(1000);
	CLEAR(PORTD,7);
	
	/*	Start the timer/counter
		ATMega328 Datasheet Section 16.11.2 Pg 135 - TCCR1B
		No Waveform generation: bits 4:3 = 0
		No input capture: bits 7:6 = 0
		Clock select: ClkIO/8 - bits 2:0 = 010b = 0x02
	*/	
	TCCR1B = 0x02;	//This starts the counter/timer
	
	while(1)
	{
		/*	Timer overflow - Reading the accelerometer at a 1KHz rate 
                        and flash the heartbeat LED at a reasonable period as well
		*/
		if(READ(TIFR1,0))
		{
			/*	ATMega328 Datasheet Section 16.11.9 pg137
				Setting TIFR1 bit 1 clears the overflow flag 
			*/
			SET(TIFR1,0);	
				
			/*	Reload the timer/counter count value to the 
                                previous value so that the period remains the same
			*/
			TCNT1 = TIMER1_PERIOD;
			
			//Read accelerometer data via ADC
			SET(ADCSRA,6);	//Start ADC conversion
			
			/*      Wait until conversion finishes - this should never
                                be more than 25*(8000000/8)^-1 seconds, which is 
                                about 25us. Typical measured time is ~14.5us
                        */
			while(0x00 == READ(ADCSRA,4));	
	
			SET(ADCSRA,4);	//Clear the interrupt flag by setting it to 1
			
			//Clear acceleration data variable before loading new value
			accel_data = 0;
			
			/*      When reading the full 10-bits from the ADC the 
                                lower register must be read first
			*/
                        accel_data |= (uint16_t)ADCL;
			
			//Then the upper 2 bits
			accel_data |= (uint16_t)(ADCH << 8);
			
			/*      Transmission of data is toggled by transmitting a 
                                '0' (0x30) byte over serial
                        */
			if(0x01 == (READ(UCSR0A,7)))
			{
				if(0x30 == UDR0)
				{
					transmit_enable = 
                                             (0x00 == transmit_enable?0xFF:0x00);
				}
			}
											
			if(0xFF == transmit_enable)
			{
#ifdef BIG_ENDIAN
				//Send high byte...
				UDR0 = uart_data_pointer[1];
				while(0x00 == READ(UCSR0A,6));
			
				//...then low byte
				UDR0 = uart_data_pointer[0];
				while(0x00 == READ(UCSR0A,6));
#else
				//Send low byte...
				UDR0 = uart_data_pointer[0];
				while(0x00 == READ(UCSR0A,6));

				//...then high byte
				UDR0 = uart_data_pointer[1];
				while(0x00 == READ(UCSR0A,6));
#endif
			}			
			//Blink Heartbeat LED
			/*	
			The timer period is 1ms. To keep everything simple the LED will toggle
			every 512 ticks - roughly every .5s.  
			*/
			
			ticks++;
			//If true, the current ticks is a multiple of 512
			//So blink the heartbeat LED
			if(0x8000 == (ticks <<  7))
			{
				TOGGLE(PORTD,7);
			}
		}
		
		//Main Loops
	
	}

}

Software SPI

May 6, 20131 comment Coded in ASM for the Microchip PIC16
#include<p16f877a.inc>

#define	s_data_o	PORTC,5 ;serial data out
#define	s_data_i	PORTC,4	;serial data in
#define	s_clock		PORTC,3 ;clock out

	udata_shr
tx_reg	res	1
rx_reg	res	1

	code

;************************
;Configure I/O Ports
;Load data in WREG
;Call soft_spi_write
;************************
soft_spi_write
	global	soft_spi_write
	banksel	tx_reg
	movwf	tx_reg  	;store W = tx_reg
	banksel	PORTC 		;Bank 0
	bsf	STATUS,C 	;Set Carry Flag=1
send_next_bit
	rlf	tx_reg,F	;rotate left
	movf	tx_reg,F	;Check wheter 8 bit transmitted or not
	btfsc	STATUS,Z 	;If no ,send next bit
	return			;if yes,return

	bcf	s_data_o	;data line low
	btfsc	STATUS,C	;check the bit in carry,      	
	bsf	s_data_o	;if high,s_data_o =1
	fill	(nop),3
	bsf	s_clock		;s_clock=1	|		     _
	fill	(nop),5		;		|clock high to low _| |_		
	bcf	STATUS,C	;clear carry	|
	bcf	s_clock 	;S_clock=0  	|
	fill	(nop),3
	goto	send_next_bit	; looping process...........

;**************************************************
;Configure I/O Ports
;Call soft_spi_read	
;This fuction returns the received data is in WREG
;**************************************************
soft_spi_read			;subroutine for receive
	global	soft_spi_read
	movlw	0x01		;eight bit reception
	movwf	rx_reg
read_next_bit
	rlf	rx_reg,f	;rotating the rx_reg register to store the received bit
	bsf	s_clock 
	fill	(nop),5
	btfsc	s_data_i
	bsf	rx_reg,0	;receiving the data
	bcf	s_clock 
	fill	(nop),3
	btfss	STATUS,C	;testing whether the reception is compleate or not
	goto	read_next_bit	;if not compleated do the process again
	movf	rx_reg,W	;restore data in WREG
	return

	end

Interfacing SM630

May 6, 2013 Coded in C for the Microchip PIC16
#define cmd_add_fingerprint	0x40
#define cmd_search_fingerprint 0x44
#define cmd_packet	0x10
#define data_packet	0x20
#define res_packet	0x30

#define res_rcv_correct 0x01
#define res_rcv_error	0x02
#define res_opr_success	0x31
#define res_finger_detected	0x32
#define res_timeout	0x33
#define res_process_fail 0x34
#define res_para_error	0x35
#define res_fingerprint_found 0x39
#define res_fingerprint_unfound 0x3A

#use rs232(baud=57600,xmit=PIN_C6,rcv=PIN_C7,bits=8,parity=n,stop=1,stream=Finger,timeout=1000)//,force_sw)

int8 cmd_buffer[10],response_buffer[15];

int8 find_checksum(int8 total_byte)
{
	int8 byte_count;
	int16 check_sum=0;
	for(byte_count=0;byte_count<total_byte;byte_count++)
	{
		check_sum+=cmd_buffer[byte_count];
	}
	
	return(make8(check_sum,0));
}

void cmd_to_sm630(int8 total_byte)
{
	int8 byte_count;
	for(byte_count=0;byte_count<total_byte;byte_count++)
	{
		fputc(cmd_buffer[byte_count],Finger);
		delay_us(10);
	}		
}

void response_from_sm630(int8 total_byte)
{
	int8 byte_count;
	while(fgetc(Finger)!=0x4D);
	response_buffer[0]=0x4D;
	for(byte_count=1;byte_count<total_byte;byte_count++)
	{
		response_buffer[byte_count]=fgetc(Finger);
	}			
}		
	

int8 add_finger(int16 finger_id)
{
	cmd_buffer[0]=0x4D; //Packet Head
	cmd_buffer[1]=0x58; //Packet Head
	cmd_buffer[2]=cmd_packet; //Command Packet
	cmd_buffer[3]=0x03; //3 byte length
	cmd_buffer[4]=cmd_add_fingerprint; //Add finger Print cmd
	cmd_buffer[5]=make8(finger_id,1);//Higher byte of finger print id
	cmd_buffer[6]=make8(finger_id,0);//Lower byte of finger print id
	cmd_buffer[7]=find_checksum(7);//Check sum of 7 bytes
	
	cmd_to_sm630(8);
	response_from_sm630(6); //Read 6 bytes
	
	if(response_buffer[4] == res_rcv_correct)
	{
		
		response_from_sm630(7); //Read 6 bytes
		if(response_buffer[5] == res_opr_success)
		{
			//Display Press finger again
			//lcd_goto(2,1);
			//lcd_send_byte("  Press again   ");
			response_from_sm630(7); //Read 6 bytes
		}
	}
	return (response_buffer[5]);		
}	

int8 search_finger(int16& result_id,int16 num_fingerprint)
{
	output_low(PIN_A5);
	cmd_buffer[0]=0x4D; //Packet Head
	cmd_buffer[1]=0x58; //Packet Head
	cmd_buffer[2]=cmd_packet; //Command Packet
	cmd_buffer[3]=0x05; //5 byte length
	cmd_buffer[4]=cmd_search_fingerprint; //Search finger Print cmd
	cmd_buffer[5]=0x00; //Higher byte of Starting id
	cmd_buffer[6]=0x00; //Lower byte of Starting id
	cmd_buffer[7]=make8(num_fingerprint,1);//Higher byte of number of  fingerprints searched
	cmd_buffer[8]=make8(num_fingerprint,0);//Lower byte of number of  fingerprints searched
	cmd_buffer[9]=find_checksum(9);//Check sum of 9 bytes
	
	cmd_to_sm630(10);
	response_from_sm630(6); //Read 6 bytes
	if(response_buffer[4] == res_rcv_correct)
	{
		response_from_sm630(7); //Read 7 bytes
		if(response_buffer[5] == res_opr_success)
		{
				delay_ms(10);
				response_from_sm630(6); //Read 6 bytes
				//disp_response(6);
				if(response_buffer[5] == res_fingerprint_found)
				{
					response_buffer[0]=fgetc(Finger);
					response_buffer[1]=fgetc(Finger);
					result_id=make16(response_buffer[0],response_buffer[1]);
				}
		
	
		}

	}
	else
		response_buffer[5]=response_buffer[4];		
	return (response_buffer[5]);	
		

}

Interfacing SIM300

May 6, 2013 Coded in C for the Microchip PIC16
#use rs232(baud=19200,xmit=pin_C6,rcv=pin_C7,parity=n,bits=8,stop=1,stream=GSM,timeout=100)
 
int8 sms_buffer[40],ph_number[15]; 
 

 
void sync()
 {
	fprintf(GSM,"AT\n\r");
	delay_ms(100);
	fprintf(GSM,"AT\n\r");
	delay_ms(100);
	fprintf(GSM,"AT\n\r");
	delay_ms(100);
	fprintf(GSM,"AT\n\r");
	delay_ms(100);
}

void dial_modem()
{
	int8 i=0;
	fputc('A',GSM);
	fputc('T',GSM);
	fputc('D',GSM);
	fputc(' ',GSM);
	
	while(ph_number[i] !='\0' && i<16)
	{
		fputc(ph_number[i],GSM);
		i++;
	}
	fputc(';',GSM);
	fputc(0x0D,GSM);
	fputc(0x0A,GSM);
} 

void hang_call()
{
	fputc('A',GSM);
	fputc('T',GSM);
	fputc('H',GSM);
	fputc(0x0D,GSM);
	fputc(0x0A,GSM);
}
void set_text_mode()
{
	sync();
	fprintf(GSM,"AT+CMGF=1\n\r");
	
}
int1 get_sms(int8 intex_no)
{
	int8 count=0;
	set_text_mode();
	delay_ms(100);
	fprintf(GSM,"AT+CMGR=%u\n\r",intex_no);
	while(fgetc(GSM)!=0x0A);
	if(fgetc(GSM)=='+')
	{	
		
		while(fgetc(GSM)!='"');
		while(fgetc(GSM)!='"');
		while(fgetc(GSM)!='"');
		do
		{
			ph_number[count]=fgetc(GSM);
			count++;
		}while(ph_number[count-1] !='"' && count<15);
		ph_number[count-1]='\0';
		while(fgetc(GSM)!=0x0A);
		count=0;
		do
		{
			sms_buffer[count]=fgetc(GSM);
			count++;
		}while(sms_buffer[count-1] !=0x0D && count<24);
		sms_buffer[count-1]='\0';
		delay_ms(500);
		sync();	
		fprintf(GSM,"AT+CMGD=%u\n\r",intex_no);//delete sms
		
	}
	else
	{
		count=24;
	}	
	if(count>=24)
		return 0;
	else
	{
		return 1;	
	}	
		
}
void send_sms()
{
	int8 array_index;
	set_text_mode();
	delay_ms(100);
	fprintf(GSM,"AT+CMGS=");
	fputc('"',GSM);
	array_index=0;
	while(ph_number[array_index] !='\0')
	{
		fputc(ph_number[array_index],GSM);
		array_index++;
	}
	fputc('"',GSM);
	fputc(0x0D,GSM);
	fputc(0x0A,GSM);
	while(fgetc(GSM) !=' ');
	array_index=0;
	while(sms_buffer[array_index] !='\0')
	{
		fputc(sms_buffer[array_index],GSM);
		array_index++;
	}
	fputc(0x1A,GSM);// Ctrl-Z
	delay_ms(100);
}		

int8 read_strength()
{
	int8 rssi[3],rssi_byte;
	//output_low(PIN_A5);
	fprintf(GSM,"AT+CSQ\n\r");
	while(fgetc(GSM) !=' ');
	//output_high(PIN_A5);
	rssi[0]=fgetc(GSM) & 0x0F;
	rssi[1]=fgetc(GSM) & 0x0F;
	rssi_byte=rssi[0]*10;
	rssi_byte=rssi_byte+rssi[1];
	return rssi_byte;
}

soft Real Time Clock implementation

April 25, 2013 Coded in C
typedef struct t_smalltm{
  u16 year;
  u8 mon;
  u8 day;
  u8 hour;
  u8 min;
  u8 sec;
} t_smalltm;

t_smalltm rtc;

//**************************************************************
// call this function every 1 sec. from timer interrupt.
// for fast code execution rtc will be placed in internal RAM.
//**************************************************************
void realTimeClock(void)
 {u8 rest;

  if (++rtc.sec==60)        // sec
   {
    rtc.sec=0;
    if (++rtc.min==60)      // min
     {
      rtc.min=0;
      if (++rtc.hour==24)   // hour
       {
        rtc.hour=0;
        rtc.day++;          // day
        rest=rtc.year%4;
        if ((((rest==0 && rtc.year%100!=0) || rtc.year%400==0)
			      && rtc.mon==2 && rtc.day==30)
           || (rest && rtc.mon==2 && rtc.day==29)
           || ((rtc.mon==4 || rtc.mon==6 || rtc.mon==9 || rtc.mon==11) 
			      && rtc.day==31)
           || (rtc.day==32))
             {
              rtc.day=1;
              if (++rtc.mon==13)   // mon
                rtc.mon=1, rtc.year++; // HAPPY NEW YEAR !  :)
             }
        }
      }
    }
 }
//**************************************************************
// read RTC function
void getRTC(t_smalltm* stm)
 {
  disableInterrupts();     // evite erronated read
                           // because realTimeClock is called from interrupt
  memcpy(stm,&rtc,sizeof(t_smalltm));
  enableInterrupts();
 }
//**************************************************************
// set RTC function
void setRTC(u16 year, u8 mon, u8 day, u8 hour, u8 min, u8 sec)
 {
  disableInterrupts();
  rtc.year=year;
  rtc.mon=mon;
  rtc.day=day;
  rtc.hour=hour;
  rtc.min=min;
  rtc.sec=sec;
  enableInterrupts();
 }

Stack Implementation with data hiding

Stephen Friederichs April 20, 20131 comment Coded in C
/**@file stack.h
   @brief This header file contains the public types, variables and methods associated with the stack implementation in stack.c.  None of the internal implementation details are exposed.  This allows the implementation to vary while the public interface remains the same.
			
   @author Stephen Friederichs
   @date 4/28/13
   @note This compiles in Cygwin using GCC 4.5.3
*/   

#ifndef __STACK_H__
#define __STACK_H__

/**@include stdint.h
   @brief Include for standard integer definitions (ie, uint8_t, int32_t, etc)
*/
#include <stdint.h>

/**@include stdlib.h
   @brief Include stdlib for malloc and free definition
*/
#include <stdlib.h>   

/**@include stddef.h
   @brief Include stddef.h for definition of size_t
*/
#include <stddef.h>

/**@typedef stack
   @brief Define the type for a stack handle
   
   There are two fundamental aspects of data hiding in C used here.
   
   The first is that you can define a type as a pointer to a struct WITHOUT 
   having defined the struct.  The struct is defined in the source file alone 
   and no implementation details are exposed in the header file. 
   
   The second aspect of this typedef is that stack_t is defined as a
   pointer to a const st_stack struct. Const correctness is tricky in C but 
   for this usage the stack_t type points to a constant struct - changes to the
   struct are NOT ALLOWED when the stack_t type is used.  
   
   Is this tough security?  No.  This only ensures the compiler complains if 
   someone tries to dereference a stack_t type and mess with the data inside 
   (of course, they don't know what any of the data inside the struct IS due 
   to the fact it's hidden in the source file).  An unscrupulous person could
   cast to a void pointer and do whatever they want with it.  Or edit the 
   header file to remove the const. And of course, if they have the source they
   know exactly what's inside the struct and can do whatever they want.  
   
   Definitely read the Wikipedia article on const correctness to get this all 
   straight in your head: http://en.wikipedia.org/wiki/Const-correctness
  
*/
typedef const struct st_stack * stack_t;

/**@typedef stack_element_t
   @brief Define the type of the stack elements - bytes in this case
*/
typedef uint8_t stack_element_t;

/**@fn stack_init
   @brief Initializes the stack and returns a pointer to the stack struct
   @param[in] size The number of elements that can be stored on the stack
   @return A pointer to the stack or NULL if the initialization failed.
*/

stack_t stack_init(size_t size);

/**@fn stack_push
   @brief Push an element on to the stack
   @param[in] stack  A pointer to the stack to which we are pushing data
   @param[in] element The data to push to the stack
   
   @return Status of the call
   @retval -1 The supplied pointer doesn't point to a stack
   @retval -2 The stack is full
   @retval 0 The call succeeded
*/

int stack_push(stack_t stack, stack_element_t element);

/**@fn stack_pop
   @brief Remove an element from the stack
   @param[in] element Pointer to an element variable to hold the received data
   
   @note The element argument is a const pointer to an element.  This means that the function will not change the address of the pointer, but the value of the element can change (this is the entire point of the function call).

   @return Status of the call
   @retval -1 Call failed - not a valid stack 
   @retval -2 Call failed - stack empty
   @retval 0 Call succeeded
*/
int stack_pop(stack_element_t const * element);

/**@fn stack_destroy
   @brief This stack no longer pleases me and I wish it gone.  Or the program is exiting.  Either way, free the memory associated with the stack.
   @param[in] stack The stack which should no longer exist.
	
   @return Status of the call
   @retval -1 Call failed - not a valid stack
   @retval 0 Call succeeded
*/

int stack_destroy(stack_t stack);

#endif

/*---------------------------------------------------------------------------*/

#ifdef STACK_IMPLEMENTATION_1

/**@file stack.c
   @brief This file implements a basic stack in C but uses C's scope system and typing to hide the internal implementation of the stack and only allow to publicly-advertised functions and variables. This stack implementation uses an array to hold the data and grows up.

   @note Implementation 1			
   @author Stephen Friederichs
   @date 4/20/13
*/   

/**@include stack.h
   @brief stack.h contains all of the types and includeds that allow this stack implementation uses.	
*/    
/* 	This file doesn't actually exist - it's all of the above definitions
	To avoid errors, comment it out
*/
//#include <stack.h>

/**@def STACK_CANARY_VALUE
   @brief Value that the canary in the stack struct must be set to for the stack to be considered a value stack object
*/

#define STACK_CANARY_VALUE 0x31

/**@struct st_stack
   @brief Struct containing the internal variables for the stack implementation
*/
struct st_stack
{
	uint8_t canary;	/**< A value that will be initialized to a specific value to show signify that the pointer points to a stack and that the stack is a valid stack object. This can't protect against any malicious intent but should at least serve as an indication that someone might have tried to modify the internals of the stack object itself*/
										
	stack_element_t * array;/**< Pointer to the array where the stack data is stored*/
																			
	size_t head; /**< Index of the most recently added element in the stack*/
	size_t size; /**< The maximum size of the stack*/

};

/**@fn _stack_valid
   @brief Returns 1 if the stack object is valid
   @param[in] stack Pointer to the stack 
   @return Validity of the object
   @retval 1 Valid object
   @retval 0 Invalid object
   @note This function can only be called from within this file.
*/

static int _stack_valid( stack_t stack)
{
	return (STACK_CANARY_VALUE == stack->canary)?1:0;
}

/**@fn stack_init 
	See above
*/

stack_t stack_init(size_t size)
{

	struct st_stack * new_stack = malloc(sizeof(st_stack));
	
	if(NULL == new_stack)
	{
		return NULL;		
	}
	

	new_stack->array = malloc(sizeof(st_element)*size));
	
	if(NULL == new_stack->array)
	{
		/*	Allocation of the array failed, so free the memory associated with the stack 
			object before returning
		*/
		free(new_stack);
		return NULL;	
	}
	
	new_stack->head = 0;	/*	This stack grows up so it starts at element 0*/
	new_stack->size = size	
	
	new_stack->canary = STACK_CANARY_VALUE;	/*	Initialize the stack's canary
												to the appropriate value*/
	/*	Return a pointer to the new stack object - appropriately cast  
		to the const type to avoid warnings
	*/
	return (stack_t)new_stack;	
	
}

/**@fn stack_push
	See above
*/

int stack_push(stack_t stack, stack_element_t element)
{
	/*	The passed pointer is a pointer to a const stack,
		so generate a non-const pointer
	*/
	st_stack * stack_pointer = (st_stack *)stack;
	
	if(!_stack_valid(stack))
	{
		return -1;	/*	Object is not a stack*/
	}
	if(stack->head == (stack->size-1))
	{
		return -2;	/*	Stack is full*/
	}
	
	/*	All checks passed, add element*/
	stack_pointer->array[++head] = element;
	
	return 0;
}

/**@fn stack_pop
	See above		
*/

int stack_pop(stack_t stack, stack_element const * element)
{
	stack_element popped_element;
	
	/*	The passed pointer is a pointer to a const stack,
		so generate a non-const pointer
	*/
	st_stack * stack_pointer = (st_stack*)stack;
	
	if(!_stack_valid(stack))
	{
		return -1;	/*	Pointer doesn't point to a stack*/
	}
	
	/*	Check to see if the stack is empty*/
	if(0 == stack->head)
	{
		return -2;	/*	Stack is empty, cannot pop*/
	}
	

	*popped_element = stack->array[stack_pointer->head--];
	
	return 0;
}

/**@fn stack_destroy
	See above
*/

int stack_destroy(stack_t stack)
{
	/*	The passed pointer is a pointer to a const stack,
		so generate a non-const pointer
	*/
	st_stack stack_pointer = (st_stack*)stack;
	
	if(!_stack_valid(stack))
	{
		return -1;	/*	Signal failure - not a stack object*/
	}

	/*	Clear the canary - if the pointer to this struct is reused after the
		stack is destroyed, the canary will be invalid and the call wil fail
	*/
	stack_pointer->canary = 0x00;
	
	free(stack->array);
	
	free(stack);
	
	return 0;
}

/*	Don't allow the use of the STACK_CANARY_VALUE outside of this vile*/
#undef STACK_CANARY_VALUE

#else	//STACK_IMPLEMENTATION_2

/**@file stack.c
   @brief This file implements a basic stack in C but uses C's scope system  and typing to hide the internal implementation of the stack and only allow to publicly-advertised functions and variables. This stack implementation uses an array to hold the data and grows down.

   @note Implementation 2			
   @author Stephen Friederichs
   @date 4/20/13
*/   

/**@include stack.h
   @brief stack.h contains all of the types and includes that allow this stack implementation uses.	
*/    
/*	This file doesn't actually exist - it would if this weren't one huge file
	So comment this out to ensure no compilation errors
*/
//#include <stack.h>

/**@def STACK_CANARY_VALUE
   @brief Value that the canary in the stack struct must be set to for the stack to be considered a value stack object
*/

#define STACK_CANARY_VALUE 0x32

/**@struct st_stack
   @brief Struct containing the internal variables for the stack implementation
*/
struct st_stack
{
	uint8_t canary;	/**< A value that will be initialized to a specific value to show signify that the pointer points to a stack and that the stack is a valid stack object. This won't protect against any truly malicious intent but might indicate that someone tried to modify the internals of the object themselves.*/
										
	stack_element_t * array; /**< Pointer to the array where the stack data is stored*/
																			
	size_t head; /**< Index of the most recently added element in the stack*/
	size_t size; /**< The maximum size of the stack*/

};

/**@fn _stack_valid
   @brief Returns 1 if the stack object is valid
   @param[in] stack Pointer to the stack 
   @return Validity of the object
   @retval 1 Valid object
   @retval 0 Invalid object
   @note This function can only be called from within this file.
*/

static int _stack_valid( stack_t stack)
{
	/*	Ensure we don't try to dereference a NULL pointer
		Obviously if the pointer is NULL it's not a valid stack
	*/
	if(NULL == stack)
        {
        	return 0;
	}
  
        return (STACK_CANARY_VALUE == stack->canary)?1:0;
}

/**@fn stack_init 
	See above
*/

stack_t stack_init(size_t size)
{
	struct st_stack * new_stack = malloc(sizeof(st_stack));
	
	if(NULL == new_stack)
	{
		return NULL;		
	}
	
	new_stack->array = malloc(sizeof(st_element)*size));
	
	if(NULL == new_stack->array)
	{
		/*	Allocation failed, so free the memory associated with the stack 
			object before returning
		*/
		free(new_stack);
		return NULL;	
	}
	
	new_stack->head = size;	/*	This stack grows down so it starts at the 
								highest element*/
	new_stack->size = size	
	
	new_stack->canary = STACK_CANARY_VALUE;	

	return (stack_t)new_stack;	
	
}

/**@fn stack_push
	See above
*/

int stack_push(stack_t stack, stack_element_t element)
{
	/*	The passed pointer is a pointer to a const stack,
		so generate a non-const pointer
	*/
	st_stack * stack_pointer = (st_stack *)stack;
	
	if(!_stack_valid(stack))
	{
		return -1;	/*	Object is not a stack*/
	}
	if(0 == stack->head)
	{
		return -2;	/*	Stack is full*/
	}
	
	/*	All checks passed, add element*/
	stack_pointer->array[--head] = element;
	
	/*	Return success*/
	return 0;
}

/**@fn stack_pop
	See above		
*/

int stack_pop(stack_t stack, stack_element const * element)
{
	stack_element popped_element;
	
	/*	The passed pointer is a pointer to a const stack,
		so generate a non-const pointer so we can modify
		the head variable.
	*/
	st_stack * stack_pointer = (st_stack *)stack;
	
	if(!_stack_valid(stack))
	{
		return -1;	/*	Pointer doesn't point to a stack*/
	}
	
	/*	Check to see if the stack is empty*/
	if(stack->size == stack->head)
	{
		return -2;	/*	Stack is empty, cannot pop*/
	}
	
	*popped_element = stack->array[stack_pointer->head--];
	
	/*	Signal success*/
	return 0;
}

/**@fn stack_destroy
	See above
*/

int stack_destroy(stack_t stack)
{
	/*	The passed pointer is a pointer to a const stack,
		so generate a non-const pointer so the canary can
		be cleared later
	*/
	st_stack * stack_pointer = (st_stack *)stack;
	
	if(!_stack_valid(stack))
	{
		return -1;	/*	Signal failure - not a stack object*/
	}

	/*	Clear the canary - if the pointer to this struct is reused after the
		stack is destroyed, the canary will be invalid and the call wil fail
	*/
	stack_pointer->canary = 0x00;
	
	free(stack->array);
	
	free(stack);
	
	/*	Return success*/
	return 0;
}

/*	Don't allow the use of the STACK_CANARY_VALUE outside of this vile*/
#undef STACK_CANARY_VALUE

#endif

Arithmetic Operations

April 15, 2013 Coded in ASM for the Microchip PIC16
UDATA
HIBYTE	RES	1	
LOBYTE	RES	1
COUNTX	RES	1
MULCND	RES	1
MULPLR	RES	1
BCD	RES	2
ACCaLO	res	1
ACCaHI	res	1
ACCbLO	res	1
ACCbHI	res	1
ACCcLO	res	1
ACCcHI	res	1
ACCdLO	res	1
ACCdHI	res	1
R2	res	1
R1	res	1
R0	res	1
TEMPX	res	1
L_temp	res	1
H_temp	res	1
w_save	res	1
RandHi	res	1
RandLo	res	1
parity	res	1

;*************************************************************************
; Multiplication MULPLR(8 bit) x MULCND(8 bit) -->HIBYTE(msb),LOBYTE(lsb)*  
; a) Load the multiplier in the location MULPLR				 *
; b) Load the multiplicant in the location MULCND			 *
; c) Call Mpy8x8						         * 
; d) Msb is in the location HIBYTE					 *
; e) Lsb is in the location LOBYTE					 *
;*************************************************************************
Mpy8x8	 	 	 
 	clrf	HIBYTE	 
 	clrf	LOBYTE	 
 	clrf	COUNTX	 
 	bsf	COUNTX, 3
		 
 	movf	MULCND, W	 
LoopX
	bcf	STATUS, C	 
 	btfsc	MULPLR, 0	 
 	addwf	HIBYTE, f	 
 	rrf	HIBYTE, f	 
 	rrf	LOBYTE, f	 
 	bcf	STATUS, C	 
 	rrf	MULPLR, f	 
 	decfsz	COUNTX, f	 
 	goto	LoopX	 
 	return	
;*******************************************************************
;Multiplication: ACCb(16 bits)*ACCa(16 bits) -> ACCb,ACCc (32 bits)*	
;(a) Load the 1st operand in location ACCaLO & ACCaHI (16 bits)	   *	
;(b) Load the 2nd operand in location ACCbLO & ACCbHI (16 bits)    *
;(c) CALL Mpy_16bit						   * 
;(d) The 32 bit result is in location (ACCbHI,ACCbLO,ACCcHI,ACCcLO)*
;*******************************************************************
Mpy_16bit
	movlw	.16 		; for 16 shifts
	movwf	temp
	movf	ACCbHI,W	; move ACCb to ACCd
	movwf	ACCdHI
	movf	ACCbLO,W
	movwf	ACCdLO
	clrf	ACCbHI
	clrf	ACCbLO
Mloop
	rrf	ACCdHI, F	 ;rotate d right
	rrf	ACCdLO, F
	btfsc	STATUS,C	 ;need to add?
	call	Add_16bit
	rrf	ACCbHI, F
	rrf	ACCbLO, F
	rrf	ACCcHI, F
	rrf	ACCcLO, F
	decfsz	temp, F 	;loop until all bits checked
	goto	Mloop
	return 	 

;******************************************************************
;This routine convert the hex value present in the WREG to decimal* 
;and store the results in the reg: BCD and BCD+1  		  *
;******************************************************************
BinBCD	 	 	 
 	clrf	BCD	 
	clrf	BCD+1
Again1
	addlw	0x9C	;subtract 100 and check for borrow
 	btfss	STATUS, C	 
 	goto	add100	 
 	incf	BCD+1, f
	goto	Again1
add100	 
	addlw	0x64
Again
	addlw	0xF6	;subtract 10 and check for borrow
 	btfss	STATUS, C	 
 	goto	SwapBCD	 
 	incf	BCD, f
	goto	Again
 	 	 	 
SwapBCD
	addlw	0x0A	 
 	swapf	BCD, f	 
 	iorwf	BCD, f	 
 	return	 	 

;***************************************************************
;This routine find the square of the number present in the WREG*
;The hex result is stored in WREG and the decimal result is    *  
;stored in GPRs BCD and BCD+1                                  * 
;***************************************************************
square
	movwf	COUNTX	 
	movlw	0x01
	movwf	TEMPX
	clrw
r_square	
	addwf	TEMPX,W
	incf	TEMPX,F
	incf	TEMPX,F
	decfsz	COUNTX,F
	goto	r_square
	movwf	w_save
	call	BinBCD	
	movf	w_save,W
	return
;*******************************************************************
;This routine find the square root of a number which is stored in  *
;WREG.The result is stored in WREG.If the number hasn't a finite   * 
;square root this function returns an error value EE in WREG       *
;*******************************************************************
square_root
	movwf	w_save
	movlw	0x01
	movwf	TEMPX
	movwf	COUNTX
loop
	movf	TEMPX,W
	subwf	w_save,f
	btfsc	STATUS,Z
	goto	zero
	btfss	STATUS,C
	goto	no_root
	incf	COUNTX,F
	incf	TEMPX,F
	incf	TEMPX,F
	goto	loop
zero
	movf	COUNTX,W
	return
no_root
	movlw	0XEE
	return
	
;********************************************************************
; Binary To BCD Conversion Routine				    *
; This routine converts a 16 Bit binary Number to a 5 Digit	    *
; BCD Number.							    *
; The 16 bit binary number is input in locations ACCaHI and         *
; ACCaLO with the high byte in ACCaHI.				    *
; The 5 digit BCD number is returned in R0, R1 and R2 with R0	    *
; containing the MSD in its right most nibble.			    *
;********************************************************************
Hex_to_Dec	 	 	 
 	bcf	STATUS, C	 
 	clrf	COUNTX	 
 	bsf	COUNTX, 4	;set count to 16
 	clrf	R0	 
 	clrf	R1	 
 	clrf	R2	 
Loop16a
	rlf	ACCaLO, f	 
 	rlf	ACCaHI, f	 
 	rlf	R2, f	 
 	rlf	R1, f	 
 	rlf	R0, f	 
 	decfsz	COUNTX, f	 
 	goto	Adjdec	 
 	return	 	 
Adjdec
	movlw	R2	;load as indirect address pointer
 	movwf	FSR	 
 	call	AdjBCD	 
  	incf	FSR, f	 
 	call	AdjBCD	 
 	incf	FSR, f	 
 	call	AdjBCD	 
 	goto	Loop16a	 
 	 	 	 
AdjBCD
	movf	INDF, w	 
 	addlw	0x03	 
 	movwf	TEMPX	 
 	btfsc	TEMPX,3;test if result > 7
 	movwf	INDF	 
 	movf	INDF, w	 
 	addlw	0x30	 
 	movwf	TEMPX	 
 	btfsc	TEMPX, 7	;test if result > 7
 	movwf	INDF	;save as MSD
 	return	 	 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Division : ACCb(16 bits) / ACCa(16 bits) -> ACCd(16 bits) with  ;
; Remainder in ACCc (16 bits)					  ;
; (a) Load the Denominator in location ACCaHI & ACCaLO ( 16 bits );
; (b) Load the Numerator in location ACCbHI & ACCbLO ( 16 bits )  ;
; (c) CALL Division						  ;
; (d) The 16 bit result is in location ACCdHI & ACCdLO		  ;
; (e) The 16 bit Remainder is in locations ACCcHI & ACCcLO	  ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Division
	clrf	COUNTX
	bsf	COUNTX,4 ; set count = 16
	clrf	ACCcHI
	clrf	ACCcLO
	clrf	ACCdLO
	clrf	ACCdHI
divLoop
	bcf	STATUS,C
	rlf	ACCbLO,F
	rlf	ACCbHI,F
	rlf	ACCcLO,F
	rlf	ACCcHI,F
	movf	ACCaHI,W
	subwf	ACCcHI,W ; check if a>c
	btfss	STATUS,Z
	goto	notz
	movf	ACCaLO,W
	subwf	ACCcLO,W ; if msb equal then check lsb
notz
	btfss	STATUS,C ; carry set if c>a
	goto	nosub	 ; if c < a
subca
	movf	ACCaLO,W ; c-a into c
	subwf	ACCcLO, F
	movf	ACCaHI,W
	subwf	ACCcHI, F
	bsf	STATUS,C ; shift a 1 into d (result)
nosub
	rlf	ACCdLO,F
	rlf	ACCdHI,F
	decfsz	COUNTX,F
	goto	divLoop
	
	return
;*******************************************************************
; Random Number Generator					   *
; This routine generates a 16 Bit Pseudo Sequence Random Generator *
; It is based on Linear shift register feedback. The sequence	   *
; is generated by (Q15 xorwf Q14 xorwf Q12 xorwf Q3 )		   *
; The 16 bit random number is in location RandHi(high byte)	   *
; & RandLo (low byte)						   *
; Before calling this routine, make sure the initial values	   *
; of RandHi & RandLo are NOT ZERO				   *
; A good chiose of initial random number is 0x3045		   *
;*******************************************************************
Random16
	rlf	RandHi,W
	xorwf	RandHi,W
	movwf	w_save
	rlf	w_save, F ; carry bit = xorwf(Q15,14)
	swapf	RandHi, F
	swapf	RandLo,W
	movwf	w_save
	rlf	w_save, F 
	xorwf	RandHi,W ; LSB = xorwf(Q12,Q3)
	swapf	RandHi, F
	andlw	0x01
	rlf	RandLo, F
	xorwf	RandLo, F
	rlf	RandHi, F
	return

;**********************************************************************
; BCD To Binary Conversion					      *   
; This routine converts a 5 digit BCD number to a 16 bit binary	      *
; number.							      *  
; The input 5 digit BCD numbers are asumed to be in locations	      *
; R0, R1 & R2 with R0 containing the MSD in its right most nibble.    *
; The 16 bit binary number is output in registers ACCaHI & ACCaLO     *
; ( high byte & low byte repectively ).				      *
; The method used for conversion is :				      *	
; input number X = abcde ( the 5 digit BCD number )		      *
; X = abcde = 10[10[10[10a+b]+c]+d]+e				      *	
;**********************************************************************
Dec_to_Hex
	clrf	ACCaHI
	movf	R0,W
	andlw	0x0F
	movwf	ACCaLO
	call	mpy10a ; result = 10a+b
	swapf	R1,W
	call	mpy10b ; result = 10[10a+b]
	movf	R1,W
	call	mpy10b ; result = 10[10[10a+b]+c]
	swapf	R2,W
	call	mpy10b ; result = 10[10[10[10a+b]+c]+d]
	movf	R2,W
	andlw	0x0F
	addwf	ACCaLO, F
	btfsc	STATUS,C
	incf	ACCaHI, F ; result = 10[10[10[10a+b]+c]+d]+e
	return		 ; BCD to binary conversion done

mpy10b
	andlw	0x0F
	addwf	ACCaLO, F
	btfsc	STATUS,C
	incf	ACCaHI, F
mpy10a
	bcf	STATUS,C ; multiply by 2
	rlf	ACCaLO,W
	movwf	L_temp
	rlf	ACCaHI,W ; (H_temp,L_temp) = 2*N
	movwf	H_temp
	bcf	STATUS,C ; multiply by 2
	rlf	ACCaLO, F
	rlf	ACCaHI, F
	bcf	STATUS,C ; multiply by 2
	rlf	ACCaLO, F
	rlf	ACCaHI, F
	bcf	STATUS,C ; multiply by 2
	rlf	ACCaLO, F
	rlf	ACCaHI, F ; (H_byte,L_byte) = 8*N
	movf	L_temp,W
	addwf	ACCaLO, F
	btfsc	STATUS,C
	incf	ACCaHI, F
	movf	H_temp,W
	addwf	ACCaHI, F
	return		 ; (H_byte,L_byte) = 10*N
;*********************************************************************************************
;This routine is used to find the parity bit(ODD or EVEN)an 8 bit no:stored in the WREG.     *
;The parity bit is stored in the LSB of parity reg.To find EVEN parity make the EVEN_PARITY  *
;definition TRUE.To find ODD parity make the EVEN_PARITY definition FALSE.  		     *	
;*********************************************************************************************
find_parity
	movwf	TEMPX
	swapf	TEMPX,W
	xorwf	TEMPX,W
	movwf	parity
	rrf	parity, F
	rrf	parity, F
	xorwf	parity,W
	andlw	0x03
	addlw	0x01
	movwf	TEMPX
	rrf	TEMPX,F
	rrf	TEMPX,W
	movwf	parity
	#if	EVEN_PARITY
	xorlw	0x01
	movwf	parity
	#endif
	return

;************************************************************************
; Subtraction : ACCb(16 bits) - ACCa(16 bits) -> ACCb(16 bits)		*
; (a) Load the 1st operand in location ACCaLO & ACCaHI ( 16 bits )	*
; (b) Load the 2nd operand in location ACCbLO & ACCbHI ( 16 bits )	*
; (c) CALL Sub_16bit							*
; (d) The result is in location ACCbLO & ACCbHI ( 16 bits )		*
;************************************************************************
Sub_16bit
	call	Neg_16bit
	call	Add_16bit
	return		

;************************************************************************	
; Addition : ACCb(16 bits) + ACCa(16 bits) -> ACCb(16 bits)		*		
; (a) Load the 1st operand in location ACCaLO & ACCaHI ( 16 bits )	*
; (b) Load the 2nd operand in location ACCbLO & ACCbHI ( 16 bits )	*
; (c) CALL Add_16bit							*
; (d) The result is in location ACCbLO & ACCbHI ( 16 bits )		*
;************************************************************************
Add_16bit
	movf	ACCaLO,W
	addwf	ACCbLO, F ; add lsb
	btfsc	STATUS,C ; add in carry
	incf	ACCbHI, F
	movf	ACCaHI,W
	addwf	ACCbHI, F ; add msb
	return 
;************************************************************************
; 2's Compliment: negate ACCa ( -ACCa -> ACCa )				*
; (a) Load the operand in location ACCaLO & ACCaHI ( 16 bits )		*
; (b) CALL Neg_16bit							*
; (c) The result is in location ACCaLO & ACCaHI ( 16 bits )		*
;************************************************************************
Neg_16bit
	comf	ACCaLO, F ; 
	incf	ACCaLO, F
	btfsc	STATUS,Z
	decf	ACCaHI, F
	comf	ACCaHI, F
	return