Movatterモバイル変換


[0]ホーム

URL:


EmbeddedRelated.com
Code Snippets
The 2026 Embedded Online Conference
   Code Snippets

CRC-16 Calculation

Dr. Maykel Alonso January 16, 20138 comments Coded inC
/***** 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}

Binary Coded Decimal (BCD) - ASCII Converter

Dr Cagri Tanriover February 12, 2013 Coded inC
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()

Exponential Moving Average

February 13, 20133 comments Coded inC
//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;}

bitbang (software) SPI implementation

Fabien Le Mentec March 28, 2013 Coded inC for theatmega328p
#include <stdint.h>#include <avr/io.h>/* default pins */#define SOFTSPI_CLK_DDR DDRD#define SOFTSPI_CLK_PORT PORTD#define SOFTSPI_CLK_MASK (1 << 3)#define SOFTSPI_MOSI_DDR DDRD#define SOFTSPI_MOSI_PORT PORTD#define SOFTSPI_MOSI_MASK (1 << 4)#ifndef SOFTSPI_DONT_USE_MISO#define SOFTSPI_DONT_USE_MISO 0#endif#if (SOFTSPI_DONT_USE_MISO == 0)#define SOFTSPI_MISO_DDR DDRD#define SOFTSPI_MISO_PIN PIND#define SOFTSPI_MISO_MASK (1 << 5)#endifstatic void softspi_setup_master(void){  SOFTSPI_CLK_DDR |= SOFTSPI_CLK_MASK;  SOFTSPI_MOSI_DDR |= SOFTSPI_MOSI_MASK;#if (SOFTSPI_DONT_USE_MISO == 0)  SOFTSPI_MISO_DDR |= SOFTSPI_MISO_MASK;#endif}static inline void softspi_clk_low(void){  SOFTSPI_CLK_PORT &= ~SOFTSPI_CLK_MASK;}static inline void softspi_clk_high(void){  SOFTSPI_CLK_PORT |= SOFTSPI_CLK_MASK;}static inline void softspi_mosi_low(void){  SOFTSPI_MOSI_PORT &= ~SOFTSPI_MOSI_MASK;}static inline void softspi_mosi_high(void){  SOFTSPI_MOSI_PORT |= SOFTSPI_MOSI_MASK;}static inline void softspi_write_bit(uint8_t x, uint8_t m){  /* dac7554 samples at clock falling edge */  /* 5 insns per bit */  softspi_clk_high();  if (x & m) softspi_mosi_high(); else softspi_mosi_low();  softspi_clk_low();}static void softspi_write_uint8(uint8_t x){  /* transmit msb first, sample at clock falling edge */  softspi_write_bit(x, (1 << 7));  softspi_write_bit(x, (1 << 6));  softspi_write_bit(x, (1 << 5));  softspi_write_bit(x, (1 << 4));  softspi_write_bit(x, (1 << 3));  softspi_write_bit(x, (1 << 2));  softspi_write_bit(x, (1 << 1));  softspi_write_bit(x, (1 << 0));}static inline void softspi_write_uint16(uint16_t x){  softspi_write_uint8((uint8_t)(x >> 8));  softspi_write_uint8((uint8_t)(x & 0xff));}#if (SOFTSPI_DONT_USE_MISO == 0)static inline void softspi_read_bit(uint8_t* x, uint8_t i){  /* read at falling edge */  softspi_clk_high();#if 0/* no need, atmega328p clock below 50mhz *//* softspi_wait_clk(); */#endif  softspi_clk_low();  if (SOFTSPI_MISO_PIN & SOFTSPI_MISO_MASK) *x |= 1 << i;}static uint8_t softspi_read_uint8(void){  /* receive msb first, sample at clock falling edge */  /* must be initialized to 0 */  uint8_t x = 0;  softspi_read_bit(&x, 7);  softspi_read_bit(&x, 6);  softspi_read_bit(&x, 5);  softspi_read_bit(&x, 4);  softspi_read_bit(&x, 3);  softspi_read_bit(&x, 2);  softspi_read_bit(&x, 1);  softspi_read_bit(&x, 0);  return x;}static inline uint16_t softspi_read_uint16(void){  /* msB ordering */  const uint8_t x = softspi_read_uint8();  return ((uint16_t)x << 8) | (uint16_t)softspi_read_uint8();}#endif /* SOFTSPI_DONT_USE_MISO == 0 */

MSP430 SPI-Master IO without interrupt

Guenther Klenner March 23, 2013 Coded inC++ for theTI MSP430
/** * @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}

Simple serial and timer ISR state machine

March 23, 2013 Coded inC for theAtmel AT89
/*    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");        }

Matlab code to plot values from port in real time

March 12, 2013 Coded inMatlab
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 buffer

March 23, 20132 comments Coded inC
// 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;   }

A simple software timer system

March 31, 20132 comments Coded inC
/** * @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 */

Debug print trace macro

March 22, 2013 Coded inC
#if defined NDEBUG    #define TRACE( format, ... )#else    #define TRACE( format, ... )   printf( "%s::%s(%d) " format, __FILE__, __FUNCTION__,  __LINE__, __VA_ARGS__ )#endif// Example usagevoid example(){    unsigned var = 0xdeadbeef ;    TRACE( "var=0x%x", var ) ;}// Resultant output example://    example.c::example(5) var=0xdeadbeef//

Previous13456

ADXL345 Driver

May 29, 20131 comment Coded inC for theMicrochip PIC16
#define ADXL_SDA  PIN_C4#define ADXL_SCL  PIN_C3#define ADXL_CS   PIN_C0#use i2c(master, sda=ADXL_SDA, scl=ADXL_SCL)void init_adxl345() {   output_float(ADXL_SCL);   output_float(ADXL_SDA);   output_high(ADXL_CS);}BOOLEAN adxl345_ready() {   int1 ack;   i2c_start();            // If the write command is acknowledged,   ack = i2c_write(0x3a);  // then the device is ready.   i2c_stop();   return !ack;}void write_adxl345(BYTE address, BYTE data) {   while(!adxl345_ready());   i2c_start();   i2c_write(0x3a);   i2c_write(address);   i2c_write(data);   i2c_stop();}BYTE read_adxl345(BYTE address) {   BYTE data;   while(!adxl345_ready());   i2c_start();   i2c_write(0x3a);   i2c_write(address);   i2c_start();   i2c_write(0x3b);   data=i2c_read(0);   i2c_stop();   return(data);}int16 read_adxl345_axis(BYTE address) {   BYTE msb,lsb;   while(!adxl345_ready());   i2c_start();   i2c_write(0x3a);   i2c_write(address);   i2c_start();   i2c_write(0x3b);   lsb=i2c_read(1);   msb=i2c_read(0);   i2c_stop();   return((msb<<8)|lsb);}

LCD, 4 bit data mode

Fabien Le Mentec May 21, 2013 Coded inC for theATMEGA328P
/* note: lcd model MC21605A6W *//* note: DB0:3 and RW must be grounded *//* note: see https://github.com/texane/lcmeter for usage */#include <stdint.h>#include <avr/io.h>#define LCD_POS_DB 0x02#define LCD_PORT_DB PORTD#define LCD_DIR_DB DDRD#define LCD_MASK_DB (0x0f << LCD_POS_DB)#define LCD_POS_EN 0x06#define LCD_PORT_EN PORTD#define LCD_DIR_EN DDRD#define LCD_MASK_EN (0x01 << LCD_POS_EN)#define LCD_POS_RS 0x07#define LCD_PORT_RS PORTD#define LCD_DIR_RS DDRD#define LCD_MASK_RS (0x01 << LCD_POS_RS)static inline void wait_50_ns(void){  __asm__ __volatile__ ("nop\n\t");}static inline void wait_500_ns(void){  /* 8 cycles at 16mhz */  __asm__ __volatile__ ("nop\n\t");  __asm__ __volatile__ ("nop\n\t");  __asm__ __volatile__ ("nop\n\t");  __asm__ __volatile__ ("nop\n\t");  __asm__ __volatile__ ("nop\n\t");  __asm__ __volatile__ ("nop\n\t");  __asm__ __volatile__ ("nop\n\t");  __asm__ __volatile__ ("nop\n\t");}static inline void wait_50_us(void){  /* 800 cycles at 16mhz */  uint8_t x;  for (x = 0; x < 100; ++x) wait_500_ns();}static inline void wait_2_ms(void){  wait_50_us();  wait_50_us();  wait_50_us();  wait_50_us();}static inline void wait_50_ms(void){  /* FIXME: was _delay_ms(50), but not working */  uint8_t x;  for (x = 0; x < 25; ++x) wait_2_ms();}static inline void lcd_pulse_en(void){  /* assume EN low */  LCD_PORT_EN |= LCD_MASK_EN;  wait_50_us();  LCD_PORT_EN &= ~LCD_MASK_EN;  wait_2_ms();}static void lcd_write_db4(uint8_t x){  /* configured in 4 bits mode */  LCD_PORT_DB &= ~LCD_MASK_DB;  LCD_PORT_DB |= (x >> 4) << LCD_POS_DB;  lcd_pulse_en();  LCD_PORT_DB &= ~LCD_MASK_DB;  LCD_PORT_DB |= (x & 0xf) << LCD_POS_DB;  lcd_pulse_en();}static void lcd_write_db8(uint8_t x){  /* configured in 8 bits mode */  /* only hi nibble transmitted, (0:3) grounded */  LCD_PORT_DB &= ~LCD_MASK_DB;  LCD_PORT_DB |= (x >> 4) << LCD_POS_DB;  lcd_pulse_en();}/* exported interface */void lcd_setup(void){  LCD_DIR_DB |= LCD_MASK_DB;  LCD_DIR_RS |= LCD_MASK_RS;  LCD_DIR_EN |= LCD_MASK_EN;  LCD_PORT_DB &= ~LCD_MASK_DB;  LCD_PORT_RS &= ~LCD_MASK_RS;  LCD_PORT_EN &= ~LCD_MASK_EN;  /* small delay for the lcd to boot */  wait_50_ms();  /* datasheet init sequence */#define LCD_MODE_BLINK (1 << 0)#define LCD_MODE_CURSOR (1 << 1)#define LCD_MODE_DISPLAY (1 << 2)  lcd_write_db8(0x30);  wait_2_ms();  wait_2_ms();  wait_500_ns();  lcd_write_db8(0x30);  wait_2_ms();  lcd_write_db4(0x32);  wait_2_ms();  lcd_write_db4(0x28);  wait_2_ms();  lcd_write_db4((1 << 3) | LCD_MODE_DISPLAY);  wait_2_ms();  lcd_write_db4(0x01);  wait_2_ms();  lcd_write_db4(0x0f);  wait_2_ms();}void lcd_clear(void){  /* clear lcd */  lcd_write_db4(0x01);  wait_2_ms();}void lcd_home(void){  /* set cursor to home */  lcd_write_db4(0x02);  wait_2_ms();}void lcd_set_ddram(uint8_t addr){  lcd_write_db4((1 << 7) | addr);  wait_2_ms();}void lcd_goto_xy(uint8_t x, uint8_t y){  /* assume 0 <= x < 8 */  /* assume 0 <= y < 2 */  /* from datasheet: */  /* first line is 0x00 to 0x27 */  /* second line is 0x40 to 0x67 */  static const uint8_t row[] = { 0x00, 0x40 };  lcd_set_ddram(row[y] | x);}void lcd_write(const uint8_t* s, unsigned int n){  wait_50_ns();  LCD_PORT_RS |= LCD_MASK_RS;  for (; n; --n, ++s)  {    lcd_write_db4(*s);    wait_2_ms();  }  LCD_PORT_RS &= ~LCD_MASK_RS;}

Plotting 16-bit binary data

Stephen Friederichs May 17, 2013 Coded inMatlab
%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")

10-bit A/D Data Sampling and Transmission

Stephen Friederichs May 17, 2013 Coded inC for theATMega328P
/**@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}}

Software SPI

May 6, 20131 comment Coded inASM for theMicrochip PIC16
#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

Interfacing SM630

May 6, 2013 Coded inC for theMicrochip PIC16
#define cmd_add_fingerprint0x40#define cmd_search_fingerprint 0x44#define cmd_packet0x10#define data_packet0x20#define res_packet0x30#define res_rcv_correct 0x01#define res_rcv_error0x02#define res_opr_success0x31#define res_finger_detected0x32#define res_timeout0x33#define res_process_fail 0x34#define res_para_error0x35#define res_fingerprint_found 0x39#define res_fingerprint_unfound 0x3A#use rs232(baud=57600,xmit=PIN_C6,rcv=PIN_C7,bits=8,parity=n,stop=1,stream=Finger,timeout=1000)//,force_sw)int8 cmd_buffer[10],response_buffer[15];int8 find_checksum(int8 total_byte){int8 byte_count;int16 check_sum=0;for(byte_count=0;byte_count<total_byte;byte_count++){check_sum+=cmd_buffer[byte_count];}return(make8(check_sum,0));}void cmd_to_sm630(int8 total_byte){int8 byte_count;for(byte_count=0;byte_count<total_byte;byte_count++){fputc(cmd_buffer[byte_count],Finger);delay_us(10);}}void response_from_sm630(int8 total_byte){int8 byte_count;while(fgetc(Finger)!=0x4D);response_buffer[0]=0x4D;for(byte_count=1;byte_count<total_byte;byte_count++){response_buffer[byte_count]=fgetc(Finger);}}int8 add_finger(int16 finger_id){cmd_buffer[0]=0x4D; //Packet Headcmd_buffer[1]=0x58; //Packet Headcmd_buffer[2]=cmd_packet; //Command Packetcmd_buffer[3]=0x03; //3 byte lengthcmd_buffer[4]=cmd_add_fingerprint; //Add finger Print cmdcmd_buffer[5]=make8(finger_id,1);//Higher byte of finger print idcmd_buffer[6]=make8(finger_id,0);//Lower byte of finger print idcmd_buffer[7]=find_checksum(7);//Check sum of 7 bytescmd_to_sm630(8);response_from_sm630(6); //Read 6 bytesif(response_buffer[4] == res_rcv_correct){response_from_sm630(7); //Read 6 bytesif(response_buffer[5] == res_opr_success){//Display Press finger again//lcd_goto(2,1);//lcd_send_byte("  Press again   ");response_from_sm630(7); //Read 6 bytes}}return (response_buffer[5]);}int8 search_finger(int16& result_id,int16 num_fingerprint){output_low(PIN_A5);cmd_buffer[0]=0x4D; //Packet Headcmd_buffer[1]=0x58; //Packet Headcmd_buffer[2]=cmd_packet; //Command Packetcmd_buffer[3]=0x05; //5 byte lengthcmd_buffer[4]=cmd_search_fingerprint; //Search finger Print cmdcmd_buffer[5]=0x00; //Higher byte of Starting idcmd_buffer[6]=0x00; //Lower byte of Starting idcmd_buffer[7]=make8(num_fingerprint,1);//Higher byte of number of  fingerprints searchedcmd_buffer[8]=make8(num_fingerprint,0);//Lower byte of number of  fingerprints searchedcmd_buffer[9]=find_checksum(9);//Check sum of 9 bytescmd_to_sm630(10);response_from_sm630(6); //Read 6 bytesif(response_buffer[4] == res_rcv_correct){response_from_sm630(7); //Read 7 bytesif(response_buffer[5] == res_opr_success){delay_ms(10);response_from_sm630(6); //Read 6 bytes//disp_response(6);if(response_buffer[5] == res_fingerprint_found){response_buffer[0]=fgetc(Finger);response_buffer[1]=fgetc(Finger);result_id=make16(response_buffer[0],response_buffer[1]);}}}elseresponse_buffer[5]=response_buffer[4];return (response_buffer[5]);}

Interfacing SIM300

May 6, 2013 Coded inC for theMicrochip PIC16
#use rs232(baud=19200,xmit=pin_C6,rcv=pin_C7,parity=n,bits=8,stop=1,stream=GSM,timeout=100) int8 sms_buffer[40],ph_number[15];   void sync() {fprintf(GSM,"AT\n\r");delay_ms(100);fprintf(GSM,"AT\n\r");delay_ms(100);fprintf(GSM,"AT\n\r");delay_ms(100);fprintf(GSM,"AT\n\r");delay_ms(100);}void dial_modem(){int8 i=0;fputc('A',GSM);fputc('T',GSM);fputc('D',GSM);fputc(' ',GSM);while(ph_number[i] !='\0' && i<16){fputc(ph_number[i],GSM);i++;}fputc(';',GSM);fputc(0x0D,GSM);fputc(0x0A,GSM);} void hang_call(){fputc('A',GSM);fputc('T',GSM);fputc('H',GSM);fputc(0x0D,GSM);fputc(0x0A,GSM);}void set_text_mode(){sync();fprintf(GSM,"AT+CMGF=1\n\r");}int1 get_sms(int8 intex_no){int8 count=0;set_text_mode();delay_ms(100);fprintf(GSM,"AT+CMGR=%u\n\r",intex_no);while(fgetc(GSM)!=0x0A);if(fgetc(GSM)=='+'){while(fgetc(GSM)!='"');while(fgetc(GSM)!='"');while(fgetc(GSM)!='"');do{ph_number[count]=fgetc(GSM);count++;}while(ph_number[count-1] !='"' && count<15);ph_number[count-1]='\0';while(fgetc(GSM)!=0x0A);count=0;do{sms_buffer[count]=fgetc(GSM);count++;}while(sms_buffer[count-1] !=0x0D && count<24);sms_buffer[count-1]='\0';delay_ms(500);sync();fprintf(GSM,"AT+CMGD=%u\n\r",intex_no);//delete sms}else{count=24;}if(count>=24)return 0;else{return 1;}}void send_sms(){int8 array_index;set_text_mode();delay_ms(100);fprintf(GSM,"AT+CMGS=");fputc('"',GSM);array_index=0;while(ph_number[array_index] !='\0'){fputc(ph_number[array_index],GSM);array_index++;}fputc('"',GSM);fputc(0x0D,GSM);fputc(0x0A,GSM);while(fgetc(GSM) !=' ');array_index=0;while(sms_buffer[array_index] !='\0'){fputc(sms_buffer[array_index],GSM);array_index++;}fputc(0x1A,GSM);// Ctrl-Zdelay_ms(100);}int8 read_strength(){int8 rssi[3],rssi_byte;//output_low(PIN_A5);fprintf(GSM,"AT+CSQ\n\r");while(fgetc(GSM) !=' ');//output_high(PIN_A5);rssi[0]=fgetc(GSM) & 0x0F;rssi[1]=fgetc(GSM) & 0x0F;rssi_byte=rssi[0]*10;rssi_byte=rssi_byte+rssi[1];return rssi_byte;}

soft Real Time Clock implementation

April 25, 2013 Coded inC
typedef struct t_smalltm{  u16 year;  u8 mon;  u8 day;  u8 hour;  u8 min;  u8 sec;} t_smalltm;t_smalltm rtc;//**************************************************************// call this function every 1 sec. from timer interrupt.// for fast code execution rtc will be placed in internal RAM.//**************************************************************void realTimeClock(void) {u8 rest;  if (++rtc.sec==60)        // sec   {    rtc.sec=0;    if (++rtc.min==60)      // min     {      rtc.min=0;      if (++rtc.hour==24)   // hour       {        rtc.hour=0;        rtc.day++;          // day        rest=rtc.year%4;        if ((((rest==0 && rtc.year%100!=0) || rtc.year%400==0)      && rtc.mon==2 && rtc.day==30)           || (rest && rtc.mon==2 && rtc.day==29)           || ((rtc.mon==4 || rtc.mon==6 || rtc.mon==9 || rtc.mon==11)       && rtc.day==31)           || (rtc.day==32))             {              rtc.day=1;              if (++rtc.mon==13)   // mon                rtc.mon=1, rtc.year++; // HAPPY NEW YEAR !  :)             }        }      }    } }//**************************************************************// read RTC functionvoid getRTC(t_smalltm* stm) {  disableInterrupts();     // evite erronated read                           // because realTimeClock is called from interrupt  memcpy(stm,&rtc,sizeof(t_smalltm));  enableInterrupts(); }//**************************************************************// set RTC functionvoid setRTC(u16 year, u8 mon, u8 day, u8 hour, u8 min, u8 sec) {  disableInterrupts();  rtc.year=year;  rtc.mon=mon;  rtc.day=day;  rtc.hour=hour;  rtc.min=min;  rtc.sec=sec;  enableInterrupts(); }

Stack Implementation with data hiding

Stephen Friederichs April 20, 20131 comment Coded inC
/**@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

Arithmetic Operations

April 15, 2013 Coded inASM for theMicrochip PIC16
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

Previous13456
The 2026 Embedded Online Conference

Sign in

Forgot username or password?  | Create account

Search code

Blogs - Hall of Fame

So You Want To Be An Embedded Systems Developer

So You Want To Be AnEmbedded Systems Developer
Steve Branam

Introduction to Microcontrollers

Introduction toMicrocontrollers
Mike Silva

Important Programming Concepts (Even on Embedded Systems)

ImportantProgramming Concepts (Even on Embedded Systems)
Jason Sachs

How FPGAs Work and Why You'll Buy One

HowFPGAs Work and Why You'll Buy One
Yossi Krenin

MSP430 Launchpad Tutorial

MSP430 Launchpad Tutorial
Enrico Garante

Arduino Robotics

Arduino Robotics
Lonnie Honeycutt

Free PDF Downloads

Introduction to Arduino
First Steps with Embedded Systems
Getting Started with C Programming for the ATMEL AVR Microcontrollers

Quick Links

About EmbeddedRelated.com

The Related Sites


[8]ページ先頭

©2009-2026 Movatter.jp