char bcdToAscii( unsigned char bcdNibble )
{
char result;
if( bcdNibble < 10 )
{// valid BCD input. ( [0,9] is the valid range for BCD input. )
result = (char)( bcdNibble + 48 ); // +48 is applicable to [0,9] input range.
}// end if
else
{// invalid input
result = '0';
}// end else
return( result );
}// end bcdToAscii()
unsigned char asciiToBcd( char asciiByte )
{/* Converts an input ASCII character (expected within the [ '0' - '9' ] range) into its BCD counterpart. */
unsigned char result;
if(
asciiByte >= '0'
&& asciiByte <= '9'
)
{// range check passed.
result = (unsigned char)(asciiByte - 48); // -48 offset gives the decimal value of the ASCII character.
}
else
{// range check failed.
result = 0;
}// end else
return( result );
}// end asciiToBcd()
//This macros defines an alpha value between 0 and 1
#define DSP_EMA_I32_ALPHA(x) ( (uint16_t)(x * 65535) )
int32_t dsp_ema_i32(int32_t in, int32_t average, uint16_t alpha){
int64_t tmp0; //calcs must be done in 64-bit math to avoid overflow
tmp0 = (int64_t)in * (alpha) + (int64_t)average * (65536 - alpha);
return (int32_t)((tmp0 + 32768) / 65536); //scale back to 32-bit (with rounding)
}
//here is a function that uses the averaging code
int32_t my_avg_func(void){
static int32_t average = 0;
int32_t adc_value;
adc_value = read_the_adc_value();
average = dsp_ema_i32(adc_value, average, DSP_EMA_I32_ALPHA(0.1));
return average;
}
/*
k164_js.c
Purpose: New firmware for the k164 dtmf decoder board and
the AT89C2051-24PC The source code was compiled with sdcc.
URLs:
http://www.digikey.com/product-detail/en/AT89C2051-24PU/AT89C2051-24PU-ND/1118880
http://www.electronics123.com/kits-and-modules/Telephone-Call-Logger-Kit-16k.html
http://www.kitsrus.com/pdf/k164.pdf
Compile: sdcc k164_js.c ; packihx k164_js.ihx > k164_js.hex
Simulate: s51 k164_js.hex
Copyright (C) 2009 Nu Tech Software Solutions, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
AUTHOR: Sean Mathews <coder at f34r.com> 1/27/2009
*/
#include <at89x051.h>
#define STATUS_LED P3_5
#define HOOK_LED P3_4
#define LOOP_STATUS P3_3
#define STD_STATUS P3_7
#define MODE_SWITCH P1_5
/* UART parameters */
#define CpuClk 20275200 // 20.2752 MHz clock chip on the k164 board
#define Baudrate 9600 // UART - 9600,N,8,1 baud used by current firmware
#define Timer1ReloadValue (256-(2*CpuClk/32/12/Baudrate))
#define F34R_MODE 0
char szVERSION[] = "V1.0";
/*
To determine the value that must be placed in TH1 to generate a given baud rate, we may use the following equation (assuming PCON.7 is clear).
TH1 = 256 - ((Crystal / 384) / Baud)
If PCON.7 is set then the baud rate is effectively doubled, thus the equation becomes:
TH1 = 256 - ((Crystal / 192) / Baud)
make this next macro work and we wont hvae to hard code the values ...
*/
#define InterruptRate 10000 // how oftin to hit our interrupt per second
#define Timer0H 0xBE //(char)((0xFF00 & (65536 - (InterruptRate / 12 * 1000))) >> 8)
#define Timer0L 0x00 //(char)(0x00FF & (65536 - (InterruptRate / 12 * 1000)))
/* prototypes */
void hw_init();
char getchar( void );
void myputchar( char c );
void doevents();
void myputs(char *);
void itoa(int value, char* string, int radix);
void uitoa(unsigned int value, char* string, int radix);
void send_version(void);
void send_hello(void);
void send_help(void);
#define UNKNOWN 0x01
#define OFFHOOK 0x02
#define ONHOOK 0x03
#define VERSION 0x04
#define EGGS 0x05
#define RESET 0x06
#define SEND_HELP 0x07
char hook_state;
char input_state;
int notdone=1;
#define ON 0x02
#define OFF 0x03
char std_state;
static char state_machine_active=0;
/* plug all of the other interrupt vectors */
#ifdef SDCC
void mydummyISR (void) interrupt 12 _naked {
}
#endif
/* Serial interrupt to track incoming key strokes */
void serial_isr(void) interrupt 4 {
if (RI != 0)
{
RI = 0;
if(SBUF == '?')
hook_state = UNKNOWN;
if(SBUF == 'V' || SBUF == 'v')
input_state = VERSION;
if(SBUF == 'R' || SBUF == 'r')
input_state = RESET;
if(SBUF == '!')
input_state = EGGS;
if(SBUF == 'H' || SBUF == 'h')
input_state = SEND_HELP;
}
return;
}
/*-------------------------------------------------------------------------
integer to string conversion
Written by: Bela Torok, 1999 in the public domain
bela.torok@kssg.ch
usage:
uitoa(unsigned int value, char* string, int radix)
itoa(int value, char* string, int radix)
value -> Number to be converted
string -> Result
radix -> Base of value (e.g.: 2 for binary, 10 for decimal, 16 for hex)
---------------------------------------------------------------------------*/
#define NUMBER_OF_DIGITS 16 /* space for NUMBER_OF_DIGITS + '\0' */
void uitoa(unsigned int value, char* string, int radix)
{
unsigned char index, i;
index = NUMBER_OF_DIGITS;
i = 0;
do {
string[--index] = '0' + (value % radix);
if ( string[index] > '9') string[index] += 'A' - ':'; /* continue with A, B,.. */
value /= radix;
} while (value != 0);
do {
string[i++] = string[index++];
} while ( index < NUMBER_OF_DIGITS );
string[i] = 0; /* string terminator */
}
void itoa(int value, char* string, int radix)
{
if (value < 0 && radix == 10) {
*string++ = '-';
uitoa(-value, string, radix);
}
else {
uitoa(value, string, radix);
}
}
/* setup UART */
void hw_init() {
LOOP_STATUS = 1; //set our loop status pin to an input
STD_STATUS = 1; //set our std status pin to an input
MODE_SWITCH = 1; //set the "ECHO" switch input on the K164 board to input
EA = 0; // disable all interrupts
PCON |= 0x80; // SMOD = 1 double speed clock for our baud rate interrupt
TH1 = TL1 = Timer1ReloadValue; // timer 1 mode 1 reload value 9600 baud as calculated in our macro
TMOD &= 0x0f; /* Set timer 1 */
TMOD |= 0x20; /* Set timer 1 as Gate=0 Timer, mode 2 */
TR1 = 1; // turn on serial timer Timer 1
SCON = 0x40; // init port as 8-bit UART with variable baudrate
SCON |= 0x10; // Enabling serial reception
// SCON |= 0x02; // Setting TI bit
ES = 1; // Enable Serial Interrupt */
/* Timer 0 setup */
TMOD &= 0xf0; /* Set timer 0 */
TMOD |= 0x01; /* Set timer 0 16 bit timer */
/* configure generic timer 0 reset value */
TH0 = Timer0H;
TL0 = Timer0L; // reload with 35711 for 1Hz
TR0 = 1; // turn on timer 0
ET0 = 1; // Enable timer 0 interrupt
RI = 0;
TI = 1;
EA = 1; // enable all interrupts
}
/* setup FIRMWARE */
void fw_init() {
/* initialize our state machine to ON HOOK */
hook_state = UNKNOWN;
input_state = UNKNOWN;
std_state = UNKNOWN;
/* Turn off our LED's we just started */
HOOK_LED = 0;
STATUS_LED = 0;
}
/* read a character from UART */
char getchar( void ) {
while(!RI);
RI = 0;
return(SBUF);
}
/* send a character to UART port */
void myputchar( char c ) {
while(!TI);
TI =0;
SBUF = c;
}
void myputs(char *sz) {
while(*sz) myputchar(*sz++);
}
/* Timer 0 interrupt the state machines main interrupt */
void timer_isr(void) interrupt 1 {
static int suppressfirst=1;
static int x=0;
static int counter=0;
char buffer[17];
/* configure generic timer 0 reset value */
TH0 = Timer0H;
TL0 = Timer0L;
/* every 1 second do our event routine */
if(x++>50) {
x=0;
doevents();
}
/* we need to control this or we will be trying to send out serial data from two threads */
if(state_machine_active) {
if( input_state == VERSION ) {
send_version();
input_state = UNKNOWN;
}
if( input_state == SEND_HELP ) {
send_help();
input_state = UNKNOWN;
}
if( input_state == EGGS ) {
myputs("! Jack Edin 1961-2012 rip - Logic Unlimited !\r\n");
myputs("! Sean Mathews - NuTech.com !\r\n");
input_state = UNKNOWN;
}
if( input_state == RESET ) {
notdone=0;
input_state = UNKNOWN;
}
/* check state of the hook line it seems to be inverted */
if(!LOOP_STATUS) {
HOOK_LED = 1; /* ON NPN Transistor base*/
if( hook_state != OFFHOOK ) {
counter++;
if(counter>10) { // 100ms
hook_state = OFFHOOK;
if(!suppressfirst) {
myputs("OFFHOOK\r\n");
} else {
suppressfirst=0;
}
}
}
} else {
HOOK_LED = 0; /* OFF NPN Transistor base*/
counter=0;
if( hook_state != ONHOOK ) {
hook_state = ONHOOK;
if(!suppressfirst) {
myputs("ONHOOK\r\n");
} else {
suppressfirst=0;
}
}
}
/* check state of the STD pin on the MT8870CE chip */
if(STD_STATUS) {
if( std_state != ON ) {
std_state = ON;
if(MODE_SWITCH==F34R_MODE) {
myputs("TONE ");
}
switch(P1 & 0x0f) {
case 10:
buffer[0]='0';
buffer[1]=0;
break;
case 11:
buffer[0]='*';
buffer[1]=0;
break;
case 12:
buffer[0]='#';
buffer[1]=0;
break;
default:
itoa(P1 & 0x0f,buffer,10);
break;
}
myputs(buffer);
if(MODE_SWITCH==F34R_MODE) {
myputs("\r\n");
}
}
} else {
if( std_state != OFF ) {
std_state = OFF;
}
}
}
}
/* Event routine for periodic processing */
void doevents() {
static char flipflop=0;
/* one second event handler. Future use...*/
/* flash the status led every 1 second */
if(MODE_SWITCH!=F34R_MODE) {
STATUS_LED = !STATUS_LED;
} else {
flipflop = !flipflop;
if(flipflop)
STATUS_LED = !STATUS_LED;
}
}
/* MAIN */
void main(void) {
notdone=1;
/* first setup our states and any other startup code so
when our hardware calls our routines they are ready */
fw_init();
/* ok now setup our hardware and start the interrupts */
hw_init();
/* tell the world we are up and running */
send_hello();
/* let the state machine go */
state_machine_active=1;
/* ... */
while (notdone) { }
// disable all interrupts
EA = 0;
// jump to 0
((void (code *)(void)) 0) ();
}
void send_hello() {
myputs("\r\n! K164mh Telephone DTMF Decoder ");
myputs(szVERSION);
myputs(" written for my good friend Jack Edin 1961-2012 rip!\r\n");
}
void send_version() {
myputs(szVERSION);
myputs("\r\n");
}
void send_help() {
myputs("\r\n! Every line that starts with a ! is considered informational\r\n!and is not part of any call logging.\r\n");
myputs("! The state messages are ONHOOK [%1], OFFHOOK, TONE %1\r\n");
myputs("! The tones can also be on the ONHOOK line if the device is in inbound calls mode\r\n");
myputs("! K164mh commands: \r\n! ? = Information\r\n! V = Version\r\n! R = Reset\r\n! H = This info\r\n");
}
clc
clear all
close all
s1 = serial('COM26', 'BaudRate', 57600);
set(s1,'Terminator',35);
fopen(s1);
V=[];
val='';
time=200;
count=0;
f=0;
% **********************************************************************
% Read Serial values
tic
tt=toc;
while(tt<time)
val=fscanf(s1);
tt=toc;
%########################################################################
A=[];
B=[];
C=[];
b=[];
x=[];
j=1;
if(j<numel(val))
while(val(j)~='$')
a=val(j);
b=[b,a];
j=j+1;
end
A=[A,str2num(b)];
j=j+1;
b=[];
while(val(j)~='*')
a=val(j);
b=[b,a];
j=j+1;
end
B=[B,str2num(b)];
j=j+1;
b=[];
while(val(j)~='#')
a=val(j);
b=[b,a];
j=j+1;
end
C=[C,str2num(b)];
i=j;
b=[];
f=f+i;
end
x=[x,round(toc)];
if(~(isempty(A)&&isempty(B)&&isempty(C)))
subplot(1,2,1)
plot(x,A,'--rs','LineWidth',2,'MarkerEdgeColor','k','MarkerFaceColor','r','MarkerSize',5);
hold on % if u want this in different graph remove hold on and add "figure" command before each graph;
plot(x,B,'--rs','LineWidth',2,'MarkerEdgeColor','k','MarkerFaceColor','g','MarkerSize',5);
grid on;
subplot(1,2,2)
plot(x,(B/(A+B))*100,'--rs','LineWidth',2,'MarkerEdgeColor','k','MarkerFaceColor','m','MarkerSize',5);
hold on
plot(x,C,'--rs','LineWidth',2,'MarkerEdgeColor','k','MarkerFaceColor','b','MarkerSize',5);
grid on;
pause(.01);
end
end
hold off
fclose(s1);
// Linear regression of samples in a circular sample
// buffer. Uses only integer arithmetic, optimized for
// computation on 16bit microcontroller with hardware
// multiplier. The linear regression computation is
// simplified considerably by subtracting out the rolling
// average of the buffer samples.
// This computation assumes the samples arrive at
// regular intervals, and this sampling rate is known.
// Usage :
// 1. call lr_Init() to initialize gnLRDenominator,
// gnNumSamples and gnSampleIndex
// 2. get first sample value and initialize gZBuffer
// with this value
// 3. for each subsequent incoming sample
// gZBuffer[gnSampleIndex] = lr_GetNewZSample();
// gZAverage = lr_CalculateAverage(gZBuffer,gnNumSamples);
// gSlope = lr_CalculateSlope(gZBuffer, gnNumSamples, gnSampleIndex, gZAverage);
// gnSampleIndex++;
// if (gnSampleIndex >= gnNumSamples) gnSampleIndex = 0;
//
typedef signed long s32;
#define MAX_Z_SAMPLES 80
#define SENSOR_SAMPLES_PER_SEC 26L
#define MAX_SLOPE 2000L
#define CLAMP(x,min,max) {if ((x) <= (min)) (x) = (min); else if ((x) >= (max)) (x) = (max);}
s32 gnLRDenominator;
int gnSampleIndex, gnNumSamples;
s32 gZBuffer[MAX_Z_SAMPLES];
s32 gZAverage;
s32 gSlope;
void lr_Init(int numSamples) {
s32 zSample, sumT, sumT2;
int inx;
sumT = -(numSamples * (numSamples-1L))/2L;
sumT2 = (numSamples * (numSamples-1L)*(2L*numSamples-1L))/6L;
gnLRDenominator = (numSamples*sumT2) - (sumT*sumT);
gnSampleIndex = 0;
gnNumSamples = numSamples;
zSample = lr_GetNewZSample(); // get a sample from the sensor
inx = gnNumSamples;
while (inx--) gZBuffer[inx] = zSample; // fill the ZBuffer with first sample value
}
s32 lr_CalculateAverage(s32* pZBuffer, int numSamples ) {
int inx;
s32 accumulator, average;
inx = numSamples;
accumulator = 0;
while (inx--) {
accumulator += pZBuffer[inx];
}
accumulator = (accumulator >= 0 ? accumulator +numSamples/2 : accumulator - numSamples/2);
average = accumulator/numSamples; // rounded up average
return average;
}
/// Linear regression of samples in buffer to calculate slope.
s32 lr_CalculateSlope(s32* pZBuffer, int numSamples, int currentSampleIndex, int zAverage) {
int inx,tRelative;
s32 z, sumZT,slope;
sumZT = 0;
inx = numSamples;
while (inx--) {
z = pZBuffer[inx] - zAverage; // subtract out the average value to simplify the arithmetic
tRelative = inx - currentSampleIndex; // time origin is the current sample in window
if (tRelative > 0) {
tRelative -= numSamples;
}
sumZT += ((s32)tRelative*z);
}
slope = (sumZT*(s32)(SENSOR_SAMPLES_PER_SEC*numSamples))/gnLRDenominator;
CLAMP(slope,-MAX_SLOPE,MAX_SLOPE);
return slope;
}
/**
* @file
* Software timer facility.
*
* This module implements an unlimited number of 8-bit down-counting 10ms and
* 100ms timers. Timers are actually held in various places by the application
* code and are registered with this module for service from the system's
* timekeeping interrupt.
*
* A down-counting timer starts out set to a time interval and is
* automatically decremented via the system's periodic interrupt. Check for a
* zero value to know when the timer has expired:
*
* <pre>uint8_t my_timer = 10;
* timer_register_100ms(&my_timer);
*
* for (;;)
* {
* if (my_timer == 0)
* {
* do_something();
* my_timer = 10;
* }
* }</pre>
*
* Down-counting timers are restricted to 8 bits so that they can be
* atomically manipulated outside interrupt code on 8-bit architectures
* without resorting to disable interrupts.
*
* @warning All variables used as timers must be declared
* <code>volatile</code>, because they are modified from an interrupt
* context that may not be understood by the compiler. GCC in
* particular is known to optimize away timer variables that aren't
* declared <code>volatile</code>.
*
* <h2>Configuration</h2>
* The number of available 10ms and 100ms timer slots is set using
* {@link MAX_100MS_TIMERS} and {@link MAX_10MS_TIMERS}.
*/
#include <stdlib.h> /* for NULL */
#include <stdint.h> /* uint8_t, etc. */
#include <stdbool.h> /* bool type, true, false */
#include "timer.h"
/** Maximum number of 100ms timers that can be registered. */
#define MAX_100MS_TIMERS 10
/** Maximum number of 10ms timers that can be registered. */
#define MAX_10MS_TIMERS 10
/** The polling frequency for the 10ms timers is scaled by this factor to
service the 100ms timers. */
#define PRESCALE_100MS 10
/* ------------------------------------------------------------------------ */
/** 10ms timer array. These are pointers to the actual timers elsewhere in
the application code. */
static volatile uint8_t *timers_10ms [MAX_10MS_TIMERS];
/** 100ms timer array. These are pointers to the actual timers elsewhere in
the application code. */
static volatile uint8_t *timers_100ms [MAX_100MS_TIMERS];
bool timer_register_10ms (volatile uint8_t *t)
{
uint8_t k;
for (k = 0; k < MAX_10MS_TIMERS; ++k)
{
if (NULL == timers_10ms[k])
{
/* Success--found an unused slot */
timers_10ms[k] = t;
return false;
}
}
/* Failure */
return true;
}
bool timer_register_100ms (volatile uint8_t *t)
{
uint8_t k;
for (k = 0; k < MAX_100MS_TIMERS; ++k)
{
if (NULL == timers_100ms[k])
{
/* Success--found an unused slot */
timers_100ms[k] = t;
return false;
}
}
/* Failure */
return true;
}
void timer_poll (void)
{
static uint8_t prescaler = PRESCALE_100MS;
volatile uint8_t *t;
uint8_t k;
/* Service the 10ms timers */
for (k = 0; k < MAX_10MS_TIMERS; ++k)
{
t = timers_10ms[k];
/* First NULL entry marks the end of the registered timers */
if (t == NULL)
{
break;
}
if (*t > 0)
{
-- *t;
}
}
/* Now divide the frequency by 10 and service the 100ms timers every 10th
time through. */
if (--prescaler == 0)
{
prescaler = PRESCALE_100MS;
for (k = 0; k < MAX_100MS_TIMERS; ++k)
{
t = timers_100ms[k];
if (t == NULL)
{
break;
}
if (*t > 0)
{
-- *t;
}
}
}
}
/* Header file */
#if !defined(TIMER_H)
#define TIMER_H
/**
* @file
*/
#include <stdbool.h>
#include <stdlib.h>
/**
* Registers a 10-millisecond timer for service.
*
* @param[in] t pointer to the variable used for timing
*
* @retval true if registration failed
* @retval false if registration succeeded (normal return)
*/
bool timer_register_10ms (volatile uint8_t *t);
/**
* Registers a 100-millisecond timer for service.
*
* @param[in] t pointer to the variable used for timing
*
* @retval true if registration failed
* @retval false if registration succeeded (normal return)
*/
bool timer_register_100ms (volatile uint8_t *t);
/**
* Maintains all registered timers.
*
* This function should be called from a stable 10-millisecond time base,
* preferably from an interrupt.
*/
void timer_poll (void);
#endif /* TIMER_H */
%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")
/**@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
}
}
#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
/**@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
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