Skip to main content

SDI12 (Aurduino-->AVRGCC)

#include <inttypes.h>
#include <stdbool.h>
#include <avr/io.h>
#include "SDI12.h"                      // 0.1 header file for this library
#define _BUFFER_SIZE 64                 // 0.2 max RX buffer size       
#define DISABLED 0                      // 0.3 value for DISABLED state
#define ENABLED 1                       // 0.4 value for ENABLED state
#define HOLDING 2                       // 0.5 value for DISABLED state
#define TRANSMITTING 3                  // 0.6 value for TRANSMITTING state
#define LISTENING 4                     // 0.7 value for LISTENING state
#define SPACING 830                     // 0.8 bit timing in microseconds

#define PHIGH  PORTB7;
#define PLOW  PORTB7;
#define INMODE  PORTB7;
#define OUTMODE  PORTB7;

//SDI12 *SDI12__activeObject = NULL;        // 0.9 pointer to active SDI12 object
uint8_t _dataPin;                       // 0.10 reference to the data pin
bool _bufferOverflow;                   // 0.11 buffer overflow status



// See section 0 above.         // 1.1 - max buffer size
char _rxBuffer[_BUFFER_SIZE];   // 1.2 - buff for incoming
uint8_t _rxBufferHead = 0;      // 1.3 - index of buff head
uint8_t _rxBufferTail = 0;      // 1.4 - index of buff tail

// 2.1 - sets the state of the SDI-12 object. 
void SDI12_setState(uint8_t state){
  if(state == HOLDING){
    pinMode(_dataPin,OUTPUT);
    digitalWrite(_dataPin,LOW);
    *digitalPinToPCMSK(_dataPin) &= ~(1<<digitalPinToPCMSKbit(_dataPin));
    return; 
  }
  if(state == TRANSMITTING){
    pinMode(_dataPin,OUTPUT);
    noInterrupts();             // supplied by Arduino.h, same as cli()
    return; 
  }
  if(state == LISTENING) {
    digitalWrite(_dataPin,LOW);
    pinMode(_dataPin,INPUT); 
    interrupts();               // supplied by Arduino.h, same as sei()
    *digitalPinToPCICR(_dataPin) |= (1<<digitalPinToPCICRbit(_dataPin));
    *digitalPinToPCMSK(_dataPin) |= (1<<digitalPinToPCMSKbit(_dataPin));
  } else {                      // implies state==DISABLED 
    digitalWrite(_dataPin,LOW); 
    pinMode(_dataPin,INPUT);
    *digitalPinToPCMSK(_dataPin) &= ~(1<<digitalPinToPCMSKbit(_dataPin));
    if(!*digitalPinToPCMSK(_dataPin)){
        *digitalPinToPCICR(_dataPin) &= ~(1<<digitalPinToPCICRbit(_dataPin));
    }
  }
}

// 2.2 - forces a HOLDING state. 
void SDI12_forceHold(){
    setState(HOLDING); 
}
//  3.1 Constructor
SDI12_SDI12(uint8_t dataPin){ _bufferOverflow = false; _dataPin = dataPin; }   

//  3.2 Destrutor
SDI12_dest(){ setState(DISABLED); }

//  3.3 Begin
void SDI12_begin() { setState(HOLDING); setActive(); }   

//  3.4 End
void SDI12_end() { setState(DISABLED); }

// 4.1 - this function wakes up the entire sensor bus
void SDI12_wakeSensors(){
  SDI12_setState(TRANSMITTING); 
  SDI12_digitalWrite(_dataPin, HIGH); 
  delayMicroseconds(12100); 
  digitalWrite(_dataPin, LOW); 
  delayMicroseconds(8400);
}
// 4.2 - this function writes a character out on the data line
void SDI12_writeChar(uint8_t out)
{

  out |= (parity_even_bit(out)<<7);         // 4.2.1 - parity bit

  digitalWrite(_dataPin, HIGH);             // 4.2.2 - start bit
  delayMicroseconds(SPACING);

  for (byte mask = 0x01; mask; mask<<=1){   // 4.2.3 - send payload
    if(out & mask){
      digitalWrite(_dataPin, LOW);
    }
    else{
      digitalWrite(_dataPin, HIGH);
    } 
    delayMicroseconds(SPACING);
  }
  
  digitalWrite(_dataPin, LOW);              // 4.2.4 - stop bit
  delayMicroseconds(SPACING); 
}

//  4.3 - this function sends out the characters of the String cmd, one by one
void SDI12_sendCommand(String cmd){
  wakeSensors();                            // wake up sensors
  for (int i = 0; i < cmd.length(); i++){
    writeChar(cmd[i]);                      // write each characters
  } 
  setState(LISTENING);                      // listen for reply
}


/* ============= 5. Reading from the SDI-12 object.  ===================*/

// 5.1 - reveals the number of characters available in the buffer
int SDI12_available()
{
  if(_bufferOverflow) return -1; 
  return (_rxBufferTail + _BUFFER_SIZE - _rxBufferHead) % _BUFFER_SIZE;
}

// 5.2 - reveals the next character in the buffer without consuming
int SDI12_peek()
{
  if (_rxBufferHead == _rxBufferTail) return -1;     // Empty buffer? If yes, -1
  return _rxBuffer[_rxBufferHead];              // Otherwise, read from "head"
}

// 5.3 - a public function that clears the buffer contents and
// resets the status of the buffer overflow. 
void SDI12_flush()
{
  _rxBufferHead = _rxBufferTail = 0;
  _bufferOverflow = false; 
}

// 5.4 - reads in the next character from the buffer (and moves the index ahead)
int SDI12_read()
{
  _bufferOverflow = false;          //reading makes room in the buffer
  if (_rxBufferHead == _rxBufferTail) return -1;     // Empty buffer? If yes, -1
  uint8_t nextChar = _rxBuffer[_rxBufferHead];  // Otherwise, grab char at head
  _rxBufferHead = (_rxBufferHead + 1) % _BUFFER_SIZE;   // increment head
  return nextChar;                                      // return the char
}




// 6.1 - a method for setting the current object as the active object
bool SDI12_setActive()
{
  if (_activeObject != this)
  {
    setState(HOLDING); 
    _activeObject = this;
    return true;
  }
  return false;
}

// 6.2 - a method for checking if this object is the active object
bool SDI12_isActive() { return this == _activeObject; }

// 6.1 - Passes off responsibility for the interrupt to the active object. 
inline void SDI12_handleInterrupt(){
  if (_activeObject) _activeObject->receiveChar();
}

// 6.2 - Quickly reads a new character into the buffer. 
void SDI12_receiveChar()
{
  if (digitalRead(_dataPin))                // 6.2.1 - Start bit?
  {
    uint8_t newChar = 0;                    // 6.2.2 - Make room for char.
    
    delayMicroseconds(SPACING/2);           // 6.2.3 - Wait 1/2 SPACING

    for (uint8_t i=0x1; i<0x80; i <<= 1)    // 6.2.4 - read the 7 data bits
    {
      delayMicroseconds(SPACING);
      uint8_t noti = ~i;
      if (!digitalRead(_dataPin))
        newChar |= i;
      else 
        newChar &= noti;
    }
    
    delayMicroseconds(SPACING);             // 6.2.5 - Skip the parity bit. 
    delayMicroseconds(SPACING);             // 6.2.6 - Skip the stop bit. 

                                        // 6.2.7 - Overflow? If not, proceed.
    if ((_rxBufferTail + 1) % _BUFFER_SIZE == _rxBufferHead) 
    { _bufferOverflow = true; 
    } else {                            // 6.2.8 - Save char, advance tail. 
      _rxBuffer[_rxBufferTail] = newChar; 
      _rxBufferTail = (_rxBufferTail + 1) % _BUFFER_SIZE;
    }
  }
}

//6.3
#if defined(PCINT0_vect)
ISR(PCINT0_vect){ SDI12_handleInterrupt(); }
#endif

#if defined(PCINT1_vect)
ISR(PCINT1_vect){ SDI12_handleInterrupt(); }
#endif

#if defined(PCINT2_vect)
ISR(PCINT2_vect){ SDI12_handleInterrupt(); }
#endif

#if defined(PCINT3_vect)
ISR(PCINT3_vect){ SDI12_handleInterrupt(); }
#endif

Comments

Popular posts from this blog

Questions

1. What is a Stub function? Ans : A function without any definition which presents no error when called. 2. Why there are two ld scripts generated by STM32Cube IDE? Ans: The CubeIDE always presents two different LDscripts on for generating the executable for Debugging which goes to RAM another for normal code upload that goes to flash memory. 3. What is Supervisory Mode/ privileged mode ? Ans : When you are using a Kernel then there are two modes user mode and privileged mode. In User mode the applications cant have system calls. 4. What is "make -j6" ? Ans : Make has an argument for number of jobs, so when you add -j6 it will create 6 different compiler instances, so that the systems could use multicore to the fullest.  Linux people generally do add "-j $(nproc)" where nproc is a command line which returns number of processors attached. 5. What is weak attribute ? Ans : Weak attribute used to denote weak symbols which helps linkers to choose one function out of mul...

#@$%

  #include  "msp430x21x2.h"     #define PWM_OUTPUT              0x03 #define DUTY_CYCLE              TA0CCR2 #define MAX_LIMIT               300   /* #define no_of_samples           1 #define duty_cycle_limit        1000 #define temp_sensor             0xA000   #define panel_selection_cutoff  250 */ #define PV_VOLTAGE              INCH_0 #define PV_CURRENT              INCH_1 #define BATT_VOLTAGE            INCH_2 #define BATT_CURRENT            INCH_3   #define UPPER_CRG_LVL           0x0105 // 0x00FF // 0x00F5 //0x023A #define LOWER_CRG_LVL   ...

Preparing for embedded systems interview

  Preparing for a technical interview in embedded systems involves a wide range of topics, as the field encompasses both hardware and software components. Here are some key areas and example questions that you might encounter in such an interview: Basic Concepts and Theory: What is an embedded system? Can you explain the difference between a microprocessor and a microcontroller? Describe the various types of memory in an embedded system. Programming and Software Design: 4. How do you write an interrupt service routine in C? 5. Explain the concept of a real-time operating system (RTOS). How does it differ from a general-purpose operating system? 6. What are the different states of a thread in an RTOS? Hardware and Interfacing : 7. How does SPI communication work? What about I2C communication? 8. Explain the concept of GPIO (General-Purpose Input/Output). How would you use it in an embedded application? 9. What are interrupts, and how are they handled in embedded systems? Low-Level P...