Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: ADT7410 CheckRTC DRV8830 Frq_cuntr_full PID TextLCD mbed-rtos mbed iSerial
Fork of Frequency_Counter by
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;
}
