/***** crc16.h *****///Tested#define CRC16_DNP0x3D65// DNP, IEC 870, M-BUS, wM-BUS, ...#define CRC16_CCITT0x1021// X.25, V.41, HDLC FCS, Bluetooth, ...//Other polynoms not tested#define CRC16_IBM0x8005// ModBus, USB, Bisync, CRC-16, CRC-16-ANSI, ...#define CRC16_T10_DIF0x8BB7// SCSI DIF#define CRC16_DECT0x0589// Cordeless Telephones#define CRC16_ARINC0xA02B// ACARS Aplications#define POLYNOMCRC16_XXX // Define the used polynom from one of the aboves// It calculates the new crc16 with the newByte. Variable crcValue is the actual or initial value (0).unsigned int crc16(unsigned int crcValue, unsigned char newByte);/***** crc16.c *****/#include "crc16.h"unsigned int crc16(unsigned int crcValue, unsigned char newByte) {unsigned char i;for (i = 0; i < 8; i++) {if (((crcValue & 0x8000) >> 8) ^ (newByte & 0x80)){crcValue = (crcValue << 1) ^ POLYNOM;}else{crcValue = (crcValue << 1);}newByte <<= 1;} return crcValue;}/***** EXAMPLE *****/unsigned int exampleOfUseCRC16 (unsigned char *Data, usigned char len){unsigned int crc;unsigned char aux = 0;crc = 0x0000; //Initialization of crc to 0x0000 for DNP//crc = 0xFFFF; //Initialization of crc to 0xFFFF for CCITTwhile (aux < len){crc = crc16(crc,Data[aux]);aux++;}return (~crc); //The crc value for DNP it is obtained by NOT operation//return crc; //The crc value for CCITT}
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 codeint32_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;}
/** * @file SPI.h * Control's for the SPI*/#ifndef FILE_SPI_H#define FILE_SPI_Hclass SPI{public:/** * @brief Init for SPI * @details * @param void * @return void */static void _Init(void);/** * @brief Send data to Display * @details * @param unsigned char msg - Message send to Display * @return void */static void LCD_DataOut(unsigned char msg);/** * @brief Send data to Display * @details Display mode must be set * @param char* msg - Message send to Display * @param int Length - Length of message send to Display * @return void */static void LCD_DataOut(char *msg, int Length);/** * @brief Send command to Display * @details * @param unsigned char msg - Message send to Display * @return void */static void LCD_CommOut(unsigned char msg);private:typedef enum {ModeIdle, ModeLCD, ModeMem} SPI_Modes;static SPI_Modes SPI_Mode;/** * It configures SPI in a mode to communicate to the selected device * @param Mode This defines the mode to configure. */static void ConfigSPI(SPI_Modes Mode);/** * It performs data exchange via SPI for a given number of inputs and outputs * @param TXpointer to transmit buffer or 0. if 0 then a dummy byte is sent (0x81) * @param RXpointer to receive buffer or 0 * @param IOcount total number of receive and transmit bytes */static void DoSPI_IO(char* TX, char* RX, int IOcount);};#############################################/** * @file SPI.c * Control's for the SPI*/#include "SPI.h"#include "msp430.h"#define ArrayLength(array) (sizeof(array)/sizeof(array[0]))/// Macro to set a bit y in variable x#define SETB(x,y) (x |= (1 << y))/// Macro to reset a bit y in variable x#define CLRB(x,y) (x &= ~(1 << y))SPI::SPI_Modes SPI::SPI_Mode;/** * @brief Init for SPI * @details * @param void * @return void */void SPI::_Init(void){SPI_Mode = ModeIdle;}/** * @brief Send data to Display * @details Display mode must be set * @param unsigned char msg - Message send to Display * @return void */void SPI::LCD_DataOut(unsigned char msg) //Data Output Serial Interface{ConfigSPI(ModeLCD);CLRB(P3OUT,4);//Chip Select = Active, CS = 0SETB(P2OUT,7);//A0 = Data, A0 = 1 /* Software delay for selection line to settle */ __delay_cycles(25);while (UCBUSY & UCB0STAT);// Wait until SPI is no longer busyUCB0TXBUF = msg;// Transmit Messagewhile (UCBUSY & UCB0STAT); // Wait until SPI is no longer busySETB(P3OUT,4);//after 1 byte, Chip Select = inactive, CS =1}/** * @brief Send data to Display * @details Display mode must be set * @param char* msg - Message send to Display * @param int Length - Length of message send to Display * @return void */void SPI::LCD_DataOut(char *msg, int Length) //Data Output Serial Interface{ConfigSPI(ModeLCD);CLRB(P3OUT,4);//Chip Select = Active, CS = 0SETB(P2OUT,7);//A0 = Data, A0 = 1 /* Software delay for selection line to settle */ __delay_cycles(25);DoSPI_IO(msg, 0, Length);SETB(P3OUT,4);//after 1 byte, Chip Select = inactive, CS =1}/** * @brief Send command to Display * @details Display mode must be set * @param unsigned char msg - Message send to Display * @return void */void SPI::LCD_CommOut(unsigned char msg) //Command Output Serial Interface{ConfigSPI(ModeLCD);CLRB(P3OUT,4);//Chip Select = Active, CS = 0CLRB(P2OUT,7);//A0 = Command, A0 = 0 /* Software delay for selection line to settle */ __delay_cycles(25);while (UCBUSY & UCB0STAT);// Wait until SPI is no longer busyUCB0TXBUF = msg;// Transmit Messagewhile (UCBUSY & UCB0STAT);// Wait until SPI is no longer busySETB(P3OUT,4);//after 1 byte, Chip Select = inactive, CS = 1}/** * It configures SPI in a mode to communicate to the selected device * @param Mode This defines the mode to configure. */void SPI::ConfigSPI(SPI_Modes Mode){if(SPI_Mode == Mode)return;switch(Mode){case ModeLCD:/******************************************************* * USCI - SPI configuration for LCD * *******************************************************/ UCB0CTL1 = UCSWRST; // **Reset USCI state machine**// UCMST = Master Mode Selected// UCCKPH = Data is captured on the first UCLK edge and changed on the following edge.// ~UCCKPL = The inactive state is low.// UCMSB = MSB first// UCSYNC = Synchronous mode// 8 bit data, 3 pin SPIUCB0CTL0 = UCMST+UCCKPH+UCMSB+UCSYNC;UCB0CTL1 |= UCSSEL_2; // SMCLK clock source UCB0BR0 |= 0x03; // SPI Clk = SMCLK / 3 = 1 MHz UCB0BR1 = 0; UCB0CTL1 &= ~UCSWRST; // **Initialize USCI state machine** break;case ModeMem:/******************************************************* * USCI - SPI configuration for Memory * *******************************************************/ UCB0CTL1 = UCSWRST; // **Reset USCI state machine**// UCMST = Master Mode Selected// UCCKPH = Data is captured on the first UCLK edge and changed on the following edge.// ~UCCKPL = The inactive state is low.// UCMSB = MSB first// UCSYNC = Synchronous mode// 8 bit data, 3 pin SPIUCB0CTL0 = UCMST+UCCKPH+UCMSB+UCSYNC;UCB0CTL1 |= UCSSEL_2; // SMCLK clock source UCB0BR0 |= 0x01; // SPI Clk = SMCLK / 1 = 3 MHz UCB0BR1 = 0; UCB0CTL1 &= ~UCSWRST; // **Initialize USCI state machine** break;case ModeIdle:default:Mode = ModeIdle;break;}SPI_Mode = Mode;}/** * It performs data exchange via SPI for a given number of inputs and outputs * @param TXpointer to transmit buffer or 0. if 0 then a dummy byte is sent (0x81) * @param RXpointer to receive buffer or 0 * @param IOcount total number of receive and transmit bytes */void SPI::DoSPI_IO(char* TX, char* RX, int IOcount){volatile int dummy = 0x81;if((TX == 0) && (RX == 0)) return;while(IOcount > 0){if(UCB0IFG & UCTXIFG){if(TX == 0)UCB0TXBUF = dummy;// dummy writeelse{UCB0TXBUF = *TX++;IOcount--;}}if(UCB0IFG & UCRXIFG){if(RX == 0)dummy = UCB0RXBUF;// dummy readelse{*RX++ = UCB0RXBUF;IOcount--;}}}while (UCBUSY & UCB0STAT);// Wait until SPI is no longer busydummy = UCB0RXBUF;// dummy read to empty any remaining data in RX buffer}
/* 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 0char 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 0x07char hook_state;char input_state;int notdone=1;#define ON 0x02#define OFF 0x03char std_state;static char state_machine_active=0;/* plug all of the other interrupt vectors */#ifdef SDCCvoid 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"); }
clcclear allclose alls1 = serial('COM26', 'BaudRate', 57600);set(s1,'Terminator',35); fopen(s1);V=[];val='';time=200;count=0;f=0; % ********************************************************************** % Read Serial valuestictt=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);endendhold offfclose(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_SEC26L#define MAX_SLOPE2000L#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 sensorinx = 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 dataprintf "Running acceleration data analysis script\r\n"clear *%Clear all variablests = (1/1000);%1KHz sampling rate%Path to TXT file with accelerometer samplesaccel_data_path = "accel_data.txt";%Open the acceleration data file as read-only, binary modefile_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 timetmax = (count-1)*ts;t=0:ts:tmax;%Open figure 1figure(1)%Plot accelerometer samplesplot(t,val','1')%Make the plot look prettytitle("Raw Sampled Accelerometer Data")xlabel("Time (s)")ylabel("Accelerometer Data")%Save the plot to diskprint("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 fireduint16_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 78Configure PD7 for use as Heartbeat LEDSet as Output Low (initially)*/SET(DDRD,7);//Direction: outputCLEAR(PORTD,7);//State: Lo/*TCCR1A - ATMega328 Datasheet Section 16.11.2 pg 134 - TCCR1ANo input capture used - bits 7:6 are 0No waveform generation used - bits 4:3 are 0Clock 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;/*TCCR1BNote: I've disabled the CKDIV8 fuse so that the clock source is 8MHzAs per ATMega328 Datasheet Section 16.9.1 page 123, setting the timer to Normal mode causes the counter to count up until it reaches 0xFFFFat which point it will overrun and start back at 0. To configure thistimer/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 = 1uS1ms / 1us /tick = 1000 ticks /msThe counter counts up to 65536, so to determine what value we have tostart at we subtract 1000 from 65536:65536-1000 = 64536*/#define TIMER1_PERIOD 64536TCNT1 = 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 RegisterADCEN - Bit 7 - Enable ADC - Obviously set this to 1ADCSC - Bit 6 - Start Converstion - Not yet: 0ADATE - Bit 5 - Auto-trigger ADC - I'll be manually triggering the ADC, so 0ADCIF - Bit 4 - ADC Interrupt Flag - Set when conversion completes. Ignore.ADCIE - Bit 3 - ADC Interrupt Enable - Everything will be polled for this, so 0ADPS - 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 - DIDR0This 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 192Baud rate settings for fosc of 8MHZChoosing baud rate of 38.4K for minimum errorU2Xn = 0 - Use standard (not double) data rateUBRRn = 12*/UBRR0 = 12; /*UCSR0A - UART 0 Control and Status Register AATMega328 Datasheet Section 20.11.2 pg 194Bits 7:2 - Status bitsBit 1 - Double UART transmission speed - No: 0Bit 0 - Multi-Processor Communication Mode - No:0*/UCSR0A = 0x00;/*UCSR0B - UART 0 Control and Status Register BATMega328 Datasheet Section 20.11.3 pg Bit 7 - Rx Complete Interrupt Enable - 0Bit 6 - Tx Complete Interrupt Enable - 0Bit 5 - USART Data Register Empty interrupt enable - 0Bit 4 - Receiver Enable - Set to 1Bit 3 - Transmitter Enable - Set to 1Bit 2 - Character Size Bit 2 - Set to 0 for 8 bitsBit 1 - 9th receive bit - IgnoreBit 0 - 9th transmit bit - Ignore*/UCSR0B = 0x00| (1 << 3)| (1 << 4);/*UCSR0C - UART 0 Control and Status Register CATMega328 Datasheet Section 20.11.4 - Pg 196Bits 7:6 - Set to asynchronous (clockless) mode: 00Bits 5:4 - Parity setting - None : 00Bit 3 - Stop select - 1 : 0Bit 2:1 - Character size - 8 : 11Bit 0 - Clock polarity: Don't care : 0*/UCSR0C = 0x03 << 1;//Send a known pattern upon startup to verify the UART worksUDR0 = 0xA5;//Wait until transmit is completewhile(0x00 == READ(UCSR0A,6));UDR0 = 0x5A;while(0x00 == READ(UCSR0A,6));UDR0 = 0xA5;//Wait until transmit is completewhile(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/counterATMega328 Datasheet Section 16.11.2 Pg 135 - TCCR1BNo Waveform generation: bits 4:3 = 0No input capture: bits 7:6 = 0Clock select: ClkIO/8 - bits 2:0 = 010b = 0x02*/TCCR1B = 0x02;//This starts the counter/timerwhile(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 pg137Setting 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 ADCSET(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 valueaccel_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 bitsaccel_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 byteUDR0 = 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 byteUDR0 = 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 toggleevery 512 ticks - roughly every .5s. */ticks++;//If true, the current ticks is a multiple of 512//So blink the heartbeat LEDif(0x8000 == (ticks << 7)){TOGGLE(PORTD,7);}}//Main Loops}}
#include<p16f877a.inc>#defines_data_oPORTC,5 ;serial data out#defines_data_iPORTC,4;serial data in#defines_clockPORTC,3 ;clock outudata_shrtx_regres1rx_regres1code;************************;Configure I/O Ports;Load data in WREG;Call soft_spi_write;************************soft_spi_writeglobalsoft_spi_writebankseltx_regmovwftx_reg ;store W = tx_regbankselPORTC ;Bank 0bsfSTATUS,C ;Set Carry Flag=1send_next_bitrlftx_reg,F;rotate leftmovftx_reg,F;Check wheter 8 bit transmitted or notbtfscSTATUS,Z ;If no ,send next bitreturn;if yes,returnbcfs_data_o;data line lowbtfscSTATUS,C;check the bit in carry, bsfs_data_o;if high,s_data_o =1fill(nop),3bsfs_clock;s_clock=1| _fill(nop),5;|clock high to low _| |_bcfSTATUS,C;clear carry|bcfs_clock ;S_clock=0 |fill(nop),3gotosend_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 receiveglobalsoft_spi_readmovlw0x01;eight bit receptionmovwfrx_regread_next_bitrlfrx_reg,f;rotating the rx_reg register to store the received bitbsfs_clock fill(nop),5btfscs_data_ibsfrx_reg,0;receiving the databcfs_clock fill(nop),3btfssSTATUS,C;testing whether the reception is compleate or notgotoread_next_bit;if not compleated do the process againmovfrx_reg,W;restore data in WREGreturnend
/**@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 definitionsTo 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 = sizenew_stack->canary = STACK_CANARY_VALUE;/*Initialize the stack's canaryto 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_pushSee 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_popSee 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_destroySee 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 thestack 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 fileSo 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 pointerObviously 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 = sizenew_stack->canary = STACK_CANARY_VALUE;return (stack_t)new_stack;}/**@fn stack_pushSee 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_popSee 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 modifythe 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_destroySee 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 canbe 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 thestack 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
UDATAHIBYTERES1LOBYTERES1COUNTXRES1MULCNDRES1MULPLRRES1BCDRES2ACCaLOres1ACCaHIres1ACCbLOres1ACCbHIres1ACCcLOres1ACCcHIres1ACCdLOres1ACCdHIres1R2res1R1res1R0res1TEMPXres1L_tempres1H_tempres1w_saveres1RandHires1RandLores1parityres1;*************************************************************************; 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 clrfHIBYTE clrfLOBYTE clrfCOUNTX bsfCOUNTX, 3 movfMULCND, W LoopXbcfSTATUS, C btfscMULPLR, 0 addwfHIBYTE, f rrfHIBYTE, f rrfLOBYTE, f bcfSTATUS, C rrfMULPLR, f decfszCOUNTX, f gotoLoopX 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_16bitmovlw.16 ; for 16 shiftsmovwftempmovfACCbHI,W; move ACCb to ACCdmovwfACCdHImovfACCbLO,WmovwfACCdLOclrfACCbHIclrfACCbLOMlooprrfACCdHI, F ;rotate d rightrrfACCdLO, FbtfscSTATUS,C ;need to add?callAdd_16bitrrfACCbHI, FrrfACCbLO, FrrfACCcHI, FrrfACCcLO, Fdecfsztemp, F ;loop until all bits checkedgotoMloopreturn ;******************************************************************;This routine convert the hex value present in the WREG to decimal* ;and store the results in the reg: BCD and BCD+1 *;******************************************************************BinBCD clrfBCD clrfBCD+1Again1addlw0x9C;subtract 100 and check for borrow btfssSTATUS, C gotoadd100 incfBCD+1, fgotoAgain1add100 addlw0x64Againaddlw0xF6;subtract 10 and check for borrow btfssSTATUS, C gotoSwapBCD incfBCD, fgotoAgain SwapBCDaddlw0x0A swapfBCD, f iorwfBCD, 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 * ;***************************************************************squaremovwfCOUNTX movlw0x01movwfTEMPXclrwr_squareaddwfTEMPX,WincfTEMPX,FincfTEMPX,FdecfszCOUNTX,Fgotor_squaremovwfw_savecallBinBCDmovfw_save,Wreturn;*******************************************************************;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_rootmovwfw_savemovlw0x01movwfTEMPXmovwfCOUNTXloopmovfTEMPX,Wsubwfw_save,fbtfscSTATUS,ZgotozerobtfssSTATUS,Cgotono_rootincfCOUNTX,FincfTEMPX,FincfTEMPX,FgotoloopzeromovfCOUNTX,Wreturnno_rootmovlw0XEEreturn;********************************************************************; 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 bcfSTATUS, C clrfCOUNTX bsfCOUNTX, 4;set count to 16 clrfR0 clrfR1 clrfR2 Loop16arlfACCaLO, f rlfACCaHI, f rlfR2, f rlfR1, f rlfR0, f decfszCOUNTX, f gotoAdjdec return AdjdecmovlwR2;load as indirect address pointer movwfFSR callAdjBCD incfFSR, f callAdjBCD incfFSR, f callAdjBCD gotoLoop16a AdjBCDmovfINDF, w addlw0x03 movwfTEMPX btfscTEMPX,3;test if result > 7 movwfINDF movfINDF, w addlw0x30 movwfTEMPX btfscTEMPX, 7;test if result > 7 movwfINDF;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 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;DivisionclrfCOUNTXbsfCOUNTX,4 ; set count = 16clrfACCcHIclrfACCcLOclrfACCdLOclrfACCdHIdivLoopbcfSTATUS,CrlfACCbLO,FrlfACCbHI,FrlfACCcLO,FrlfACCcHI,FmovfACCaHI,WsubwfACCcHI,W ; check if a>cbtfssSTATUS,ZgotonotzmovfACCaLO,WsubwfACCcLO,W ; if msb equal then check lsbnotzbtfssSTATUS,C ; carry set if c>agotonosub ; if c < asubcamovfACCaLO,W ; c-a into csubwfACCcLO, FmovfACCaHI,WsubwfACCcHI, FbsfSTATUS,C ; shift a 1 into d (result)nosubrlfACCdLO,FrlfACCdHI,FdecfszCOUNTX,FgotodivLoopreturn;*******************************************************************; 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 *;*******************************************************************Random16rlfRandHi,WxorwfRandHi,Wmovwfw_saverlfw_save, F ; carry bit = xorwf(Q15,14)swapfRandHi, FswapfRandLo,Wmovwfw_saverlfw_save, F xorwfRandHi,W ; LSB = xorwf(Q12,Q3)swapfRandHi, Fandlw0x01rlfRandLo, FxorwfRandLo, FrlfRandHi, Freturn;**********************************************************************; 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_HexclrfACCaHImovfR0,Wandlw0x0FmovwfACCaLOcallmpy10a ; result = 10a+bswapfR1,Wcallmpy10b ; result = 10[10a+b]movfR1,Wcallmpy10b ; result = 10[10[10a+b]+c]swapfR2,Wcallmpy10b ; result = 10[10[10[10a+b]+c]+d]movfR2,Wandlw0x0FaddwfACCaLO, FbtfscSTATUS,CincfACCaHI, F ; result = 10[10[10[10a+b]+c]+d]+ereturn ; BCD to binary conversion donempy10bandlw0x0FaddwfACCaLO, FbtfscSTATUS,CincfACCaHI, Fmpy10abcfSTATUS,C ; multiply by 2rlfACCaLO,WmovwfL_temprlfACCaHI,W ; (H_temp,L_temp) = 2*NmovwfH_tempbcfSTATUS,C ; multiply by 2rlfACCaLO, FrlfACCaHI, FbcfSTATUS,C ; multiply by 2rlfACCaLO, FrlfACCaHI, FbcfSTATUS,C ; multiply by 2rlfACCaLO, FrlfACCaHI, F ; (H_byte,L_byte) = 8*NmovfL_temp,WaddwfACCaLO, FbtfscSTATUS,CincfACCaHI, FmovfH_temp,WaddwfACCaHI, Freturn ; (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_paritymovwfTEMPXswapfTEMPX,WxorwfTEMPX,Wmovwfparityrrfparity, Frrfparity, Fxorwfparity,Wandlw0x03addlw0x01movwfTEMPXrrfTEMPX,FrrfTEMPX,Wmovwfparity#ifEVEN_PARITYxorlw0x01movwfparity#endifreturn;************************************************************************; 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_16bitcallNeg_16bitcallAdd_16bitreturn;************************************************************************; 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_16bitmovfACCaLO,WaddwfACCbLO, F ; add lsbbtfscSTATUS,C ; add in carryincfACCbHI, FmovfACCaHI,WaddwfACCbHI, F ; add msbreturn ;************************************************************************; 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_16bitcomfACCaLO, F ; incfACCaLO, FbtfscSTATUS,ZdecfACCaHI, FcomfACCaHI, Freturn