Charles Young's development fork. Going forward I only want to push mature code to main repository.
Fork of GEO_COUNTER_L432KC by
main.cpp
- Committer:
- Charles David Young
- Date:
- 2018-09-03
- Revision:
- 16:b2e77eb76ab4
- Parent:
- 15:808e98afe32b
- Child:
- 17:6eed17197004
File content as of revision 16:b2e77eb76ab4:
// 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 QEPB (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; bool QEPBpressed = false; // only react to button when pressed enum WheelState { WHEEL_INACTIVE = 0, WHEEL_MODE_SELECT = 1, WHEEL_SUBMODE_SELECT = 2 }; enum WheelStateEvent { WHEEL_Pressed = 0, WHEEL_Timeout = 1 }; WheelState currentWheelState; 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 UpdateInput(void); // periodically called by the ticker void UpdateOutput(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(0x543210); 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(&UpdateInput, 100000); Sec_Beat.attach_us(&UpdateOutput, 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 %d", WheelCurrent, QEPB.read()); } void UpdateOutput() { 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--; } } void UpdateInput() { 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 ( (WHEEL_MODE_SELECT == currentWheelState) || (WHEEL_SUBMODE_SELECT == currentWheelState)) { WheelCurrent = int(Wheel.getPulses()); if (WheelCurrent > WheelPrevious) LED_status_index = ++LED_status_index % sizeof(LED_statuses); else if (WheelCurrent < WheelPrevious) LED_status_index = --LED_status_index % sizeof(LED_statuses); WheelPrevious = WheelCurrent; } // detect when wheel button is pressed but wait until it is released // before doing anything bool QEPBbutton = QEPB.read(); if ( (QEPBbutton) && (!QEPBpressed)) { QEPBpressed = true; } else if ( (!QEPBbutton) && (QEPBpressed)) { QEPBpressed = false; WheelStateMachine(WHEEL_Pressed); } logToPC(); return; } void WheelStateMachine(WheelStateEvent event) { switch currentWheelState { WHEEL_INACTIVE: if (WHEEL_Pressed == event) currentWheelState = WHEEL_MODE_SELECT; break; WHEEL_MODE_SELECT: if (WHEEL_Pressed == event) currentWheelState = WHEEL_SUBMODE_SELECT; else if (WHEEL_Timeout == event) currentWheelState = WHEEL_INACTIVE; break; WHEEL_SUBMODE_SELECT: if (WHEEL_Pressed == event) currentWheelState = WHEEL_MODE_SELECT; else if (WHEEL_Timeout == event) currentWheelState = WHEEL_INACTIVE; break; default: } } //--------------------------------------------------------------------------- // 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 -------------- //==============================================================================