Charles Young's development fork. Going forward I only want to push mature code to main repository.

Dependencies:   mbed

Fork of GEO_COUNTER_L432KC by Geo Electronics "Geo Counter"

main.cpp

Committer:
Charles David Young
Date:
2018-09-02
Revision:
12:258fc423e0fd
Parent:
11:6e15cc2b2328
Child:
13:0e7b06af9a2a

File content as of revision 12:258fc423e0fd:

//  GEO COUNTER V1 firmware
//  This FW provides a basic operation of GEO-COUNTER
//
//  Latest review: August 27, 2018 - Walter Trovo
//
//  Feb 14, 2018: initial release aimed to test the counters, the serial port
//                the PWM output and the MAX7219 operation.
//  Feb 15, 2018: Removed MAX7219 libray (replaced with custom routine). 
//                Added 74HC595 routine. Added beep. Added Gate_write
//


// this block includes key libraries
#include "mbed.h"       // global Mbed library (always needed)
#include <string>       // strings management
#include "QEI.h"        // Quadrature Encoder functions

// definitions of fixed parameters

#define DEC_MODE    0x09FF  // BCD decoding on all digits
#define BRIGHTNESS  0x0A0F  // max brightness
#define SCAN_LIM    0x0B07  // use all 8 digits  
#define TURN_ON     0x0C01  // no shutdown (operating)
#define SHUTDOWN    0x0C00  // shutdown
#define TEST        0x0F00  // no test

#define DT      1      // delay time in us for SPI emulation

#define TGATE   10       // gate time (currently fixed for testing purpose)
#define MAX_VAL 999999  // Max value managed by the 6-digits display


#define CPM     0x01
#define CPS     0x02
#define PLS     0x04
#define VOLTS   0x08
#define CNT1    0x10
#define CNT2    0x20
#define HV      0x40
#define MENU    0x80
uint8_t LED_statuses [CPM, CPS, PLS, VOLTS, CNT1, CNT2, HV, MENU];
uint8_t LED_status = CPM;
uint8_t LED_status_index = 0;

// definitions of the input/outputs (pins)
DigitalOut  AUX   (D2);    // AUX control for GPS module
InterruptIn TRIG1 (D3);    // Counter 1 trigger
InterruptIn TRIG2 (D6);    // Counter 2 trigger
DigitalIn   QEIPB (D9);    // Quadrature encoder pushbutton
PwmOut      PWM   (D10);   // PWM output
DigitalOut  BUZZ  (D13);   // Buzzer

AnalogIn    AIN0  (A0);    // ADC input 0 (High Voltage)
AnalogIn    AIN1  (A1);    // ADC input 1 (aux)
DigitalOut  CS2   (A2);    // 74HC595 RCLK (pin 12)
DigitalOut  CS1   (A3);    // MAX7219 CS (pin 12)
DigitalOut  SCK   (A4);    // 74HC595 SRCLK (pin 11) & MAX7219 SCK (pin 13)
AnalogIn    KEYB  (A5);    // Keyboard input (SW2 & SW3) 
DigitalOut  MOSI  (A6);    // 74HC595 SER (pin 14) & MAX7219 DIN (pin 1)
DigitalIn   UN    (A7);    // Unused (in V1 PCB A5 and A7 must be connected)

// LED on processor board
DigitalOut led1(LED1);

// definitions of peripherals and devices

// QEI class supports the mode wheel.  In its most basic function it will tell
// us which direction the wheel is moving (right or left) so that we can
// use it to select the current mode.
QEI     Wheel(D12, D11, NC, 16);    // Quadrature encoder
int WheelCurrent = 0;
int WheelPrevious = 0;

I2C     i2c(D4, D5);                // I2C port
Ticker  Sec_Beat;                // 1 second ticker
Serial  PC(USBTX, USBRX);        // Virtual COM via USB (PC connection)
Serial  GPS(D1, D0);             // Serial port for GPS module

// Global variables
uint8_t     Disp_Digit[8]; // used to manage 8-digits through MAX7219
uint16_t    Stream;        // used to stream out serial data to MAX7219
time_t      seconds;       // Real-Time Clock (RTC) timestamp
unsigned int value = 0;    // displayed value on the 6-digits of the display
uint8_t     gate = TGATE;          // displayed value on the 2-digits display
uint32_t    Count1, Count2;    // pulse counters (32-bit)
char        Text[40]="";   // used to send messages over the serial port
uint8_t     Disp_mode = 0x01, Disp_unit = 0xA0;   // status of 1st row and 2nd rows of LEDs
bool        Stopped = 0;        // status of counting activity
bool        StartStopPressed = 0;// status of counting activity
double      ADC_val;    // used to read ADC value

// ----- Prototypes of routines (defined below the main) -------------------
void Update(void);  // periodically called by the ticker
void Count1_up(void);  // called every time an edge is detected on TRIG1 pin
void Count2_up(void); // called every time an edge is detected on TRIG2 pin
void Beep(void);    // used to generate a short beep (buzzer)
void LEDs_write(unsigned short);    // write to 74HC595 (8x LEDs)
void Display_init(void);    // initialize MAX7219
void Display_6D_write(uint8_t);    // write to MAX7219 (Main 6-digits display)
void Display_2D_write(unsigned short);    // write to MAX7219 (Gate 2-digits display)

//==============================================================================
//==============================================================================

int main() 
{
    
    PC.baud(115200);        // set baud-rate of virtual COM port (PC connection)
    PC.printf("\nGEO COUNTER V1 2108");
    PC.printf(__DATE__);
    PC.printf("  ");
    PC.printf(__TIME__);
    
    GPS.baud(9600); // set the baud-rate of the serial port dedicated to the GPS
    
    CS1 = 1;    // presets CS of MAX7219
    CS2 = 1;    // preset CS of 74HC595

    Display_6D_write(543210);
    Display_2D_write(TGATE);
    Display_init(); // initialize MAX7219

    // RTC is supposed to be loose time at power down (no backup battery)
    // An initialization is performed anyway 
    set_time(0); // Set time
 
    Wheel.reset();        // clear the variable associated to the encoder    
    
    PWM.period_ms(3);    // set the PWM period
    PWM.write(0.8);      // set the PWM duty-cycle
    
    LEDs_write(0x00);   // initialize LEDs (CPM and CNT1 on)
    Beep(); // initial beep    
    
    // set the 1 sec ticker to periodically call the Update() routine
    // NOTE: this is also the 1-sec time base for counters. A better approach
    // would replace the ticker with an interrupt from the RTC (to be implemented)
    Sec_Beat.attach_us(&Update, 1000000);  
    //RTC::attach(&Update, RTC::Second);
    //RTC::detach(RTC::Second);  
  
    // main loop does nothing as all activities are interrupt driven    
    while(1) 
    {
        // dance (or drink a beer)                
    }
}


//-------- END OF MAIN --------------
//==============================================================================

// Definition of routines

//---------------------------------------------------------------------------
// Update values to be displayed  
void logToPC()
{               
   PC.printf("\nADC: %.02f", ADC_val); 
   PC.printf(Stopped ? " stopped" : " started");
   // Timestamp to PC (debug)
   seconds = time(NULL);   // get current time 
   strftime(Text, 50, "%H:%M:%S", localtime(&seconds));
   PC.printf(" RTC: %s, CNT1: %7d CNT2: %7d",Text, Count1, Count2);
   PC.printf(" wheel %d", WheelCurrent);
}

void Update()   
{               
    LEDs_write(LED_statuses[LED_status_index]);
        
    ADC_val = KEYB.read();  // read voltage from keyboard
    if (   (ADC_val<0.1)    // START/STOP pushbutton pressed
        && (!StartStopPressed))
    {
        StartStopPressed = true;
        Stopped=!Stopped;           // toggle status
    }
    else
        StartStopPressed = false;
    
    if((ADC_val>0.6)&&(ADC_val<0.7))    // CLEAR pushbutton pressed
    { 
        Count1 = 0; // clear counters     
        Count2 = 0;              
   }

    if(Stopped)
    {    
        // disable interrupts on TRIG1 and TRIG2
        
        TRIG1.rise(NULL);      
        TRIG2.rise(NULL); 
        
        // show zero gate time   
        gate = 0;                   
        Display_2D_write(gate);
        
        // show selected content on main display
        value = (int)(Count1/TGATE);
        Display_6D_write(value);    // refresh the main display              
    }
    
    else
    {
        // Enable interrupts on rising edge of digital inputs TRIG1 & TRIG2
        TRIG1.rise(&Count1_up);     
        TRIG2.rise(&Count2_up);         
        
        if(gate==0) // show the counter value at the end of the gate time
        {
            value = (int)(Count1/TGATE);
                
            Display_6D_write(value);    // refresh the main display 
        
            Count1 = 0;     // clear both counters
            Count2 = 0;
            gate = TGATE;// and reload the gate time

        }

        Display_2D_write(gate);     // show gate time countdown 
        gate--;
    }
        
    WheelCurrent = int(Wheel.getPulses());
    if (WheelCurrent > WheelPrevious)
       LED_status_index++ | sizeof(LED_statuses);
    else
       if (WheelCurrent < WheelPrevious)
          LED_status_index-- | sizeof(LED_statuses);
    WheelPrevious = WheelCurrent;
    
    logToPC();
    return;
}

//---------------------------------------------------------------------------
// Increment CNT1 every time a rising edge is detected on TRIG1 (interrupt)

void Count1_up(void)
{                       
    Count1++;                        
    return; 
}


//---------------------------------------------------------------------------
// Increment CNT1 every time a rising edge is detected on TRIG2 (interrupt)

void Count2_up(void)
{                      
    Count2++;                        
    return; 
}


//---------------------------------------------------------------------------
//Generates a short beep via BUZZ

void Beep(void)       
{                       
    BUZZ = 1;         // turn-on the buzzer
    wait(0.3);        // wait
    BUZZ = 0;         // turn-off the buzzer   
    return; 
}


//---------------------------------------------------------------------------
//Write to 74HC595 (LEDs) - Take care to avoid conflict with MAX7219

void LEDs_write(unsigned short data_val)       
{                       
    // Update 74HC595 shift registers 
    unsigned short mask;
    
    SCK = 0;
    wait_us(DT);
    CS2 = 0;    
    
    for(mask = 0x80; mask!= 0; mask>>= 1)
    {
      wait_us(DT);
      SCK = 0;
      if(mask & data_val)
        MOSI = 0;
      else
        MOSI = 1;
      wait_us(DT);
      SCK = 1;
    }
    
    SCK = 0;
    wait_us(DT);
    CS2 = 1;

    return; 
}


//---------------------------------------------------------------------------
// Initialize the MAX7219

void Display_init(void)
{
    uint8_t i;
    uint16_t mask;
    uint16_t data_to_send[6] = {SHUTDOWN, TURN_ON, DEC_MODE, BRIGHTNESS, SCAN_LIM, TEST};
             //{SHUTDOWN, TURN_ON, DEC_MODE, BRIGHTNESS, SCAN_LIM, TEST};
    for(i = 0; i <6; i++)
    {
        CS1 = 0;
      
        for(mask = 0x8000; mask!= 0; mask>>= 1)
        {
            wait_us(DT);
            SCK = 0;
            if(mask & data_to_send[i])
                MOSI = 1;
            else
                MOSI = 0;
            wait_us(DT);    
            SCK = 1;
        }
        
        wait_us(DT);
        SCK = 0;
        wait_us(DT);
        CS1 = 1;
    }
    
  return;
}


//---------------------------------------------------------------------------
// Refresh the 6 digits of the main display

void Display_6D_write(uint8_t value)
{
 
    uint8_t digit;
    uint16_t mask, data_to_send;
    char TextString[6];
    
    // int to string, then string to digits
    
    sprintf(TextString, "%6d", value);   // int to string
    
    for(uint8_t i=0; i<6; i++)
    {   
        if(TextString[i] == ' ')  // blank empty digits
            Disp_Digit[i] = 0xFF;
        else
            Disp_Digit[i] = TextString[i]-'0';      
    }

    // write to chip

    SCK = 0;
    wait_us(DT);    
    
    for(digit = 1; digit <7; digit++)
    {
        // each stream consists of digit address and data to show
        data_to_send = 7 - digit;
        data_to_send<<=8;
        data_to_send = data_to_send | Disp_Digit[digit-1];
        
        CS1 = 0;
        
        for(mask = 0x8000; mask!= 0; mask>>= 1)
        {
            wait_us(DT);
            SCK = 0;
            if(mask & data_to_send)
                MOSI = 1;
            else
                MOSI = 0;
                
            wait_us(DT);
            SCK = 1;
        }
        
        wait_us(DT);    
        SCK = 0;
        wait_us(DT);
        CS1 = 1;
    }
    
  return;
}


//---------------------------------------------------------------------------
// Refresh the 2 digits of the gate display

void Display_2D_write(unsigned short value)
{
 
    uint8_t digit;
    uint16_t mask, data_to_send;
    char TextString[2];

    // int to string, then string to digits
    
    sprintf(TextString, "%2d", value);   // int to string

    if(TextString[0] == ' ')  // blank empty digits
        Disp_Digit[7] = 0xFF;    
    else
        Disp_Digit[7] = TextString[0] - '0';
    
    Disp_Digit[6] = TextString[1] - '0';

    // write to chip
    
    SCK = 0;
    wait_us(DT);    
    
    for(digit = 7; digit <9; digit++)
    {
        // each stream consists of digit address and data to show
        data_to_send = digit;
        data_to_send<<=8;
        data_to_send = data_to_send | Disp_Digit[digit-1];
        
        CS1 = 0;
        
        for(mask = 0x8000; mask!= 0; mask>>= 1)
        {
            wait_us(DT);
            SCK = 0;
            
            if(mask & data_to_send)
                MOSI = 1;
            else
                MOSI = 0;
                
            wait_us(DT);
            SCK = 1;
        }
        
        wait_us(DT);    
        SCK = 0;
        wait_us(DT);
        CS1 = 1;
    }
    
  return;
}

//-------- END OF FILE --------------
//==============================================================================