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/
Diff: main.cpp
- Revision:
- 9:e98e94ba17f9
- Parent:
- 8:7b033903c8fb
- Child:
- 11:20e7a45f1448
--- a/main.cpp Sat Nov 22 23:09:17 2014 +0000 +++ b/main.cpp Thu Jan 01 05:08:31 2015 +0000 @@ -5,7 +5,7 @@ * http://www.page.sannet.ne.jp/kenjia/index.html * http://mbed.org/users/kenjiArai/ * Created: October 18th, 2014 - * Revised: Nobember 23rd, 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 @@ -15,10 +15,19 @@ */ #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; @@ -37,48 +46,404 @@ #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); -DigitalIn sw_01(PC_0); -DigitalIn sw_10(PC_1); +DigitalOut led_gate(LED1); Serial pc(USBTX, USBRX); +Serial gps(NC, PA_10); // GPS RX I2C i2cBus(PB_9,PB_8); // SDA, SCL -// PC_6,PC_7 & PB6 use for Timer3 & 4 -// PA_0,PA_1 & PB_10 use for Timer2 -FRQ_CUNTR fc(PC_6, 1.0); // Input port & gate time[sec] +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 --------------------------------------------------------------------------- - -// 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 //------------------------------------------------------------------------------------------------- -int main() +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) { - uint32_t counter_1pps = 0; - uint32_t new_frequency = 0; + 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); - // PA8 & PC9 uses for MCO_1 & MCO_2 -> Clock output for checking - fc.port_mco1_mco2_set(2); // Clk/2 ->1/1(100MHz) cannot measure!! - wait(1.0); - fc.read_frequency_TIM2(1.0); - fc.read_frequency_TIM3P4(1.0); + 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) { - while (fc.status_1pps() == 0) { - ; + 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 "); } - counter_1pps = fc.read_avarage_1pps(); - while (fc.status_freq_update() == 0) { - ; + 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); } - new_frequency = fc.read_freq_data(); - PRINTF("1PPS/ave = %9d , FREQUENCY = %9d\r\n", counter_1pps, new_frequency); + /* 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; +}