Frequency counter using GPS 1PPS signal and temperature controlled 50MHz Base clock. Ported from F411 Frequency Counter.
Dependencies: QEI DRV8830 PID ADT7410 TextLCD Frq_cuntr_Nucleo-F746ZG RingBuffer
Fork of Frequency_Counter_w_GPS_1PPS by
Please refer following.
/users/kenjiArai/notebook/frequency-counters/
main.cpp
- Committer:
- kenjiArai
- Date:
- 2015-01-01
- Revision:
- 9:e98e94ba17f9
- Parent:
- 8:7b033903c8fb
- Child:
- 11:20e7a45f1448
File content as of revision 9:e98e94ba17f9:
/* * mbed Application program / Frequency Counter with GPS 1PPS Compensation * * Copyright (c) 2014 Kenji Arai / JH1PJL * http://www.page.sannet.ne.jp/kenjia/index.html * http://mbed.org/users/kenjiArai/ * Created: October 18th, 2014 * Revised: January 1st, 2015 * * 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. */ #define USE_COM // use Communication with PC(UART) #define SET_RTC //#define USE_DEBUG // Include --------------------------------------------------------------------------------------- #include "mbed.h" #include "rtos.h" #include "TextLCD.h" #include "DRV8830.h" #include "ADT7410.h" #include "PID.h" #include "frq_cuntr_full.h" #include "CheckRTC.h" #include "gps.h" using namespace Frequency_counter; // Definition ------------------------------------------------------------------------------------ #ifdef USE_COM #define BAUD(x) pc.baud(x) #define GETC(x) pc.getc(x) #define PUTC(x) pc.putc(x) #define PRINTF(...) pc.printf(__VA_ARGS__) #define READABLE(x) pc.readable(x) #else #define BAUD(x) {;} #define GETC(x) {;} #define PUTC(x) {;} #define PRINTF(...) {;} #define READABLE(x) {;} #endif #ifdef USE_DEBUG #define DEBUGBAUD(x) pc.baud(x) #define DEBUG(...) pc.printf(__VA_ARGS__) #else #define DEBUGBAUD(x) {;} #define DEBUG(...) {;} #endif #define CLOCK_BASE (24.999982f) #define GSP_BUF_B (128 * 3) #define GPS_BUF_S (128 * 2) // Object ---------------------------------------------------------------------------------------- DigitalOut led_gate(LED1); Serial pc(USBTX, USBRX); Serial gps(NC, PA_10); // GPS RX I2C i2cBus(PB_9,PB_8); // SDA, SCL DRV8830 heater(i2cBus, (uint8_t)DRV8830ADDR_00); ADT7410 t(i2cBus, ADT7410ADDR_NN); TextLCD lcd(PB_0, PA_4, PC_0, PC_1, PC_2, PC_3, TextLCD::LCD20x4); // rs, e, d4-d7 PID pid(14.0f, 50.0f, 1.5f, 1.0f); // PC_6,PC_7 & PB_6 use for Timer3 & 4(16+16bit) // PA_0,PA_1 & PB_10 use for Timer2(32bit) // PA_8 & PC_7 use for MCO (Test purpose) FRQ_CUNTR fc(PC_6, 1.0, CLOCK_BASE); // Input port, gate time[sec] and External clock freq. // RAM ------------------------------------------------------------------------------------------- // Freq. uint32_t counter_1pps; double new_frequency; double base_clock_1pps; // Temp Control float volt = 0.0; float tmp = 0; float pid_val = 0; uint32_t n = 0; // GPS uint32_t gps_status; uint8_t gps_rmc_ready; char GPS_Buffer[GSP_BUF_B]; //GPS data buffer char MsgBuf_RMC[GPS_BUF_S]; char MsgBuf_GGA[GPS_BUF_S]; // Time time_t seconds; time_t seconds_jst; struct tm t_gps; // rtos Queue<uint32_t, 2> queue0; // ROM / Constant data --------------------------------------------------------------------------- // 12345678901234567890 static char *const msg_clear = " "; static char *const msg_msg0 = "Frequency Counter "; static char *const msg_msg1 = " mbed Nucleo F411RE"; static char *const msg_msg2 = " by JH1PJL K.Arai"; static char *const msg_msg3 = " "__DATE__" "; // Function prototypes --------------------------------------------------------------------------- void gps_rcv(void); uint32_t check_gps_ready(void); uint8_t check_gps_rmc_ready(void); void get_time_and_date(struct tm *pt); void getline_gps(void); //------------------------------------------------------------------------------------------------- // Control Program //------------------------------------------------------------------------------------------------- void measure_freq(void const *args) { while(true) { if (fc.status_freq_update() != 0) { new_frequency = fc.read_freq_data(); queue0.put((uint32_t*)1); } if (fc.status_1pps() != 0) { counter_1pps = fc.read_avarage_1pps(); } Thread::wait(100); } } void temp_control(void const *args) { t.set_config(OPERATION_MODE_CONT + RESOLUTION_16BIT); pid.setInputLimits(0.0, 4.5); pid.setOutputLimits(0.0, 5.0); pid.setSetPoint(2.5); while(true) { tmp = t.read_temp(); pid.setProcessValue(tmp / 10); pid_val = pid.compute(); volt = pid_val - 2.5f; if (volt < -0.8f) { volt = -0.8f; } else if (volt > 0.8f) { volt = 0.8f; } heater.set_voltage(volt); if (heater.status()) { heater.reset(); } /* Wait until it is time to check again. */ Thread::wait(1000); } } // Get GAA data void gps_data_rcv(void const *args) { int8_t i; time_t old_ave_sec[2]; uint32_t diff; gps.baud(9600); seconds = time(NULL); DEBUG("\r\nCurrent Time: %s\r\n", ctime(&seconds)); old_ave_sec[0] = 0; old_ave_sec[1] = 0; while(true) { getline_gps(); // Get GPS data from UART if (strncmp(GPS_Buffer, "$GPRMC",6) == 0) { for (i=0; GPS_Buffer[i] != 0; i++) {// Copy msg to RMC buffer MsgBuf_RMC[i] = GPS_Buffer[i]; } MsgBuf_RMC[i+1] = 0; DEBUG("GET RMC\r\n"); if (gps_status > 3) { get_time_and_date(&t_gps); seconds = mktime(&t_gps); if (old_ave_sec[0] == 0){ old_ave_sec[0] = seconds; } else if (old_ave_sec[1] == 0){ old_ave_sec[1] = seconds; } else { if (old_ave_sec[0] >= old_ave_sec[1]){ diff = old_ave_sec[0] - old_ave_sec[1]; } else { diff = old_ave_sec[1] - old_ave_sec[0]; } if (diff > 100 ){ old_ave_sec[0] = seconds; old_ave_sec[1] = 0; } else { if (old_ave_sec[0] > old_ave_sec[1]){ diff = seconds - old_ave_sec[0]; if (diff < 100){ old_ave_sec[1] = seconds; } } else { diff = seconds - old_ave_sec[1]; if (diff < 100){ old_ave_sec[0] = seconds; } } set_time(seconds); DEBUG("SET RTC\r\n"); } } } } else if (strncmp(GPS_Buffer, "$GPGGA",6) == 0) { for (i=0; GPS_Buffer[i] != 0; i++) {// Copy msg to GGA buffer MsgBuf_GGA[i] = GPS_Buffer[i]; } MsgBuf_GGA[i+1] = 0; DEBUG("GET GGA\r\n"); gps_status = check_gps_ready(); } } } void display_data(void const *args) { char buf[40]; BAUD(9600); DEBUGBAUD(9600); PRINTF("\r\nFrequency Counter by JH1PJL created on "__DATE__"\r\n"); // Initial screen lcd.locate(0, 0); lcd.printf(msg_msg0); lcd.printf(msg_msg1); lcd.printf(msg_msg2); lcd.printf(msg_msg3); Thread::wait(3000); lcd.locate(0, 0); lcd.printf(msg_clear); lcd.printf(msg_clear); lcd.printf(msg_clear); lcd.printf(msg_clear); while(true) { osEvent evt = queue0.get(); PRINTF("FRQ= %11.1f Hz, ", new_frequency); PRINTF("1PPS= %9d , %9d (new), ",counter_1pps, fc.read_newest_1pps()); PRINTF("%+6.3f dC, ", tmp); PRINTF("PID= %+6.3f , ", volt); // PRINTF("t= %5d S, ", n++); seconds = time(NULL); seconds_jst = seconds + 32400; // +9 hours ->JST // December 31,'14, 13:12:11 // strftime(buf, 40, "%B %d,'%y, %H:%M:%S", localtime(&seconds)); // 31 Dec 2014 13:12:11 // strftime(buf,40, "%x %X ", localtime(&seconds)); // 1:12:11 PM (2014/12/31) strftime(buf,40, "%I:%M:%S %p (%Y/%m/%d)", localtime(&seconds_jst)); PRINTF("%s, ", buf); if (fc.status_gps()) { PRINTF("RDY"); } else { PRINTF("NO "); } PRINTF("\r\n"); lcd.locate(0, 0); lcd.printf("Freq= %11.2f Hz", new_frequency); lcd.locate(0, 1); lcd.printf("1PPS=%9d Hz", counter_1pps); lcd.locate(0, 2); strftime(buf,40, " %I:%M:%S %p (%m/%d)", localtime(&seconds_jst)); lcd.printf("%s, ", buf); lcd.locate(0, 3); lcd.printf("t= %+4.1f%cC", tmp, 0xdf); if (fc.status_gps()) { lcd.printf(" GPS RDY"); } else { lcd.printf(" NO GPS "); } base_clock_1pps = (double)counter_1pps / 1000000; double diff = base_clock_1pps - CLOCK_BASE; if (diff < 0) { diff *= -1; } if (diff < 0.00001) { // less than 10Hz fc.set_external_clock(base_clock_1pps); } /* Wait until it is time to check again. */ Thread::wait(100); } } // Thread definition osThreadDef(measure_freq, osPriorityNormal,1024); osThreadDef(temp_control, osPriorityNormal,1024); osThreadDef(display_data, osPriorityNormal,3072); osThreadDef(gps_data_rcv, osPriorityNormal,3072); int main() { // PA8 & PC9 uses for MCO_1 & MCO_2 -> Clock output for checking fc.port_mco1_mco2_set(4); // Clk/4 ->1/1(100MHz) cannot measure!! osThreadCreate(osThread(measure_freq), NULL); Thread::wait(5); //wait osThreadCreate(osThread(temp_control), NULL); Thread::wait(8); //wait osThreadCreate(osThread(display_data), NULL); Thread::wait(10); //wait if (CheckRTC() == OK) { // If RTC is NG, no need to start GPS RX function DEBUG("\r\nGPS task starts\r\n"); osThreadCreate(osThread(gps_data_rcv), NULL); } while(true) { /* Wait until it is time to check again. */ Thread::wait(5000); } } /////////////////////////////////////////////////////////////////////////////// // GPS data Analysis // // PA6C GPS Module // http://www.gtop-tech.com/en/product/MT3339_GPS_Module_03.html // Update time: 1 second (1PPS: ±10ns RMS) // MediaTek MT3339 Chipset, L1 Frequency, C/A code, 66 Channels // NMEA 0183 // // current setting: GGA, VTG, GGA, RMC // /////////////////////////////////////////////////////////////////////////////// // Get line of data from GPS void getline_gps(void) { while (gps.getc() != '$') { //DEBUG("GETC but not $\r\n"); Thread::yield(); } GPS_Buffer[0] = '$'; for (int8_t i = 1; i < GSP_BUF_B; i++) { GPS_Buffer[i] = gps.getc(); if (GPS_Buffer[i] == '\r' || GPS_Buffer[i] == '\n') { GPS_Buffer[i] = '\r'; GPS_Buffer[i+1] = '\n'; GPS_Buffer[i+2] = 0; GPS_Buffer[i+3] = 0; //DEBUG("Get one GPS data\r\n"); return; } } } // ASCII to hex uint8_t hex(char c) { if(c<= '/') return( ERR ); if(((c -= '0')<= 9 || 10 <= ( c -= 'A' - '0' - 10)) && c <= 15) { return((uint8_t)c); } return(ERR); } // Search next ',' (comma) char *next_comma( char *p ) { while (1) { if ( *p== ',' ) { return ++p; } else if ( *p == 0 ) { return (char*)-1; } else { p++; } } } // 2 digits ASCII char to one byte hex unsigned char change_acii_hex( char*p ) { unsigned char c; c = hex(*p++); /* No concern ERR condition! */ c = (c * 10) + hex(*p++); return c; } // Skip number of comma char *num_of_comma( char *p, int8_t n ) { for (; n> 0; n--) { if ( (p = next_comma(p)) == (char*) -1 ) { return (char*)-1; } } return p; } // Get GPS status and number of satelites uint32_t check_gps_ready(void) { char *p; uint32_t x; uint8_t d; // pick-up time p = MsgBuf_GGA; p = num_of_comma(p,6); // skip ',' // reach to "Position Fix Indicator" if (*p == '0') { x = 0; } else if (*p == '1') { x = 0x10; } else if (*p == '2') { x = 0x20; } else { x= 0; } ++p; if (*p == ',') { ++p; d = hex(*p++); if (d != ERR) { x += (uint32_t)d; if (*p != ',') { x = 0; } } else { x = 0; } } else { x = 0; } return x; } // Get time(UTC) from GPS data void get_time_and_date(struct tm *pt) { char *p; p = MsgBuf_RMC; p = num_of_comma(p,1); /* skip one ',' */ pt->tm_hour = change_acii_hex(p); p += 2; pt->tm_min = change_acii_hex(p); p += 2; pt->tm_sec = change_acii_hex(p); p = MsgBuf_RMC; p = num_of_comma(p,9); /* skip one ',' */ pt->tm_mday = change_acii_hex(p); p += 2; pt->tm_mon = change_acii_hex(p) - 1; p += 2; pt->tm_year = change_acii_hex(p) + 100; }