some features added

This commit is contained in:
eddyem 2019-08-19 16:26:36 +03:00
parent 7e9f81ca54
commit 29d62c26c7
14 changed files with 307 additions and 47 deletions

View File

@ -0,0 +1,144 @@
****** Распиновка ******
=== Интерфейсы I/O ===
- PA11/12 - USB
- PA9(Tx), PA10(Rx) - USART1 - прокси RMC-сообщений GPS.
- PA2(Tx), PA3(Rx) - USART2 - подключение GPS-приемника.
- PB10(Tx), PB11(Rx) - USART3 - подключение лидара.
=== Остальные порты ===
- PA1 - PPS сигнал от GPS; сюда можно подключать любой дополнительный высокоомный вход напрямую.
- PA4 - TRIG2 - подключен к каналу 12В.
- PA13 - TRIG0 - кнопка или створ, замыкающий контакты.
- PA14 - TRIG1 - так же, как и вход TRIG0.
- PA15 - подтяжка USB.
- PB0 - TRIG4 - триггер по АЦП.
- PB8, PB9 - индикаторные светодиоды.
- PC13 - пищалка.
=== Светодиоды ===
- LED0 (зеленый) - при отсутствии сигнала PPS просто горит, если PPS появляется - мигает (затухает на 0.25с на каждый сигнал).
- LED1 (красный) - индикатор GPS: не горит, если приемник не обнаружен, горит, если неуверенный прием времени (буква "V" во второй позиции RMC-сообщения), мигает при уверенном приеме (буква "A" во второй позиции).
Судя по эксперименту, даже через час после пропадания сигнала точность определения события - не хуже 1мс. Сам GPS-приемник выдает
PPS даже при отсутствии спутников - лишь бы он успел "подхватить" точное время и начать генерировать pps. Начинать работу можно сразу,
как только замигает зеленый светодиод после мигающего красного.
****** Триггеры ******
На прототипе распаяно два входа на триггеры: TRIG0 и TRIG2. К TRIG2 нужно подключать 12-вольтный сигнал, ток не меньше 10мА.
Если створ имеет открытый коллектор, то выход створа подключается к минусу TRIG2, а к плюсу подключается 12В с источника питания.
TRIG0 предназначен для подключения кнопки или концевика, просто замыкающего контакты. Никакого внешнего напряжения там быть не должно!
TRIG4 - аналоговый вход. Если будут ложные срабатывания на девбордах, порт PB0 нужно напрямую или через резистор до 10кОм посадить на землю.
Иногда бывают ложные срабатывания триггеров TRIG0..TRIG2, связанные с мощными источниками искр (зажигание, искрящиеся обмотки и т.п.).
В случае таких ложных срабатываний рекомендуется заземлить катод источника питания хронометра.
При подключении внешней кнопки желательно, чтобы она имела нормально замкнутые контакты - это предотвратит ложные срабатывания из-за электромагнитных помех.
****** Подключение ******
Хронометр эмулирует "китайский" преобразователь PL2303. В линуксе нужно, чтобы был скомпилирован соответствующий модуль ядра.
В андроиде работает "из коробки". В мастдайке новые драйвера PL2303 имеют защиту от подделок (те просто не работают с этими дровами),
поэтому для нормальной работы необходимо найти и установить старые драйвера.
К выходам PA9/PA10 можно подключить преобразователь USART<>USB или накинуть их напрямую на ноги Rx/Tx "малинки" (не забыв соединить
земли хронометра и малинки): PA9(Tx) соединить с Rx, PA10(Rx) - с Tx. Этот USART проксирует RMC-сообщения GPS-приемника (уже после
обработки микроконтроллером, поэтому если МК выключен, а приемник включен, сигнала все равно не будет).
Для подключения PPS сигнала к "малинке" нужно напрямую соединить соответствующую ногу GPIO "малинки" с портом PA1 девборды.
На прототипе нужно подпаяться к дорожке, выходящей с ноги PPS (отмечено маркером).
Подтяжка USB есть лишь на прототипе, на девбордах ее нет. Поэтому в случае перезагрузки микроконтроллера девборды для возобновления
соединения необходимо переткнуть шнурок USB. В этом плане прототип надежней: сбросить МК можно независимо от питания GPS.
На прототипе и девбордах отсутствует подсоединение пищалки. На девбордах при желании можно накинуть на PC13 что-нибудь для индикации
срабатывания створа (активный выход - "1" в течение 0.3с).
На девбордах не распаяны светодиодные индикаторы. Особого смысла в них нет, но если понадобится подключить, нагрузка должна висеть на
PB8/PB9. Активный выход - низкий. Нога МК настроена в режиме open-drain, но внешняя подтяжка не должна быть выше +3.5В. И потребление
не больше 5мА на ногу.
****** Конфигурация ******
Хронометр конфигурируется через USB. Ввод команд не сопровождается эхом (чтобы удобней было работать из внешних программ), поэтому
для удобства можно тексты команд копировать из окна текстового редактора.
Чтобы увидеть подсказку, достаточно отправить любую строку, начинающуюся с вопросительного знака. Появится справка:
adcmax - max ADC value treshold for trigger
adcmin - min -//- (triggered when ADval>min & <max
adcval - get ADC value
buzzerS - turn buzzer ON/OFF
distmin - min distance threshold (cm)
distmax - max distance threshold (cm)
gpsrestart - send Full Cold Restart to GPS
gpsstring - current GPS data string
ledsS - turn leds on/off (1/0)
mcutemp - MCU temperature
pullupNS - triggers pullups state (N - trigger No, S - 0/1 for off/on)
showconf - show current configuration
time - print time
store - store new configuration in flash
triglevelNS - working trigger N level S
trigpauseNP - pause (P, ms) after trigger N shots
trigtimeN - show last trigger N time
vdd - Vdd value
Из нужного здесь:
- gpsrestart - перезапуск GPS (если вдруг начнет глючить - у меня такого не случалось), делает "холодный" рестарт. Команда
проверялась лишь на прототипе.
- gpsstring - вывод очередного сообщения от GPS. Если все нормально, то появится строка RMC вроде
$GPRMC,124001.000,A,4340.9369,N,04127.5034,E,0.00,33.26,150819,,,A*5C
- pullupNS - включить или выключить внутренние верхние подтяжки для триггеров 0..3 (особо не нужно, т.к. подтяжки слабые, и если
будет нужна подтяжка, лучше сделать сильную внешнюю).
- showconf - отображение текущей конфигурации, например:
CONFIG:
DISTMIN=50
DISTMAX=1000
ADCMIN=1024
ADCMAX=3072
PULLUPS=255
TRIGLVL=0
TRIGPAUSE={400, 400, 400, 300, 300}
ENDCONFIG
пункты конфигурации: DISTMIN/DISTMAX относятся к лидару, ADCMIN/ADCMAX ко входу АЦП, PULLUPS - состояние подтяжек
(каждый бит, начиная с младшего - состояние соответствующей подтяжки; 0 - не активна, 1 - активна).
TRIGLVL - конфигурация уровней срабатывания, каждый бит, начиная с младшего (всего три младших бита, как и в PULLUPS),
равен нулю, если для соответствующего триггера срабатывание при перепаде 1->0, равен единице, если при
перепаде 0->1.
TRIGPAUSE - пауза между срабатываниями триггера: если после срабатывания произойдет следующее событие за интервал, меньший
данного, это событие учитываться не будет.
- time - отображает текущее время так, как оно бы отобразилось при срабатывании триггера, например,
55725.961 (15:28:45)
ВРЕМЯ ИЗМЕРЯЕТСЯ В UTC!!! Первое число - количество секунд и миллисекунд с начала суток по UTC, в скобках
указывается человекочитаемое время.
- store - сохранить новую конфигурацию во флеш-памяти МК.
- triglevelNS - рабочий уровень триггера. Здесь N - номер триггера (0..2), S - уровень (0/1). Скажем, чтобы триггер 0 срабатывал
при перепаде 1->0, нужно написать команду
triglevel00
а чтобы триггер 2 срабатывал при перепаде 0->1,
triglevel21
- trigpauseNP - задать паузу для триггера N, пауза в миллисекундах. Если написать 0, паузы не будет и каждое срабатывание
будет вызывать соответствующее сообщение. Эта пауза нужнад для защиты от "звона" и нескольких срабатываний на "дырках"
в объекте. Меньше 50мс лучше не делать.
- trigtimeN - отображение последнего времени срабатывания триггера N, например, на запрос trigtime0, может быть выведено:
TRIG0=45212.930 (12:33:32)
Если срабатываний с момента включения не было, выведутся нули:
TRIG4=0.000 (00:00:00)
После изменения конфигурации и ее сохранения необходимо нажатием на reset или отключением/включением питания перезагрузить МК,
т.к. некоторые параметры активируются лишь при старте.
****** Девборды и плата-прототип ******
На платках из девборд два канала опторазвязок подключены к триггерам TRIG0 и TRIG1.
Синий провод - земля, красные - +12В для каждого канала. Т.е. схема рассчитана на срабатывание по появлению плюса на одном из каналов.
В случае необходимости срабатывания по подтяжке к земле, нужно разорвать землю на входах опторазвязок и, наоборот, объединить плюсы.
На плюсы подать +12В, минусы подключить к сигнальным выходам створов.
На прототипе распаяны развязки только на два канала: TRIG0 - для подключения чего-то, замыкающего контакты, и TRIG2 - для подключения
чего-то, выдающего 12В. Я оставил такую конфигурацию: к TRIG0 можно подключить нормально замкнутую кнопку (triglevel01), а TRIG2
сработает при поступлении туда 12В (triglevel21).

View File

@ -71,18 +71,23 @@ uint32_t getVdd(){
return vdd;
}
void chkADCtrigger(){
/**
* @brief chkADCtrigger - check ADC trigger state
* @return value of `triggered`
*/
uint8_t chkADCtrigger(){
static uint8_t triggered = 0;
savetrigtime();
uint16_t val = getADCval(0);
int16_t val = getADCval(0);
if(triggered){ // check untriggered action
if(val < the_conf.ADC_min || val > the_conf.ADC_max){
if(val < (int16_t)the_conf.ADC_min - ADC_THRESHOLD || val > (int16_t)the_conf.ADC_max + ADC_THRESHOLD){
triggered = 0;
}
}else{ // check if thigger shot
if(val > the_conf.ADC_min && val < the_conf.ADC_max){
if(val > (int16_t)the_conf.ADC_min + ADC_THRESHOLD && val < (int16_t)the_conf.ADC_max - ADC_THRESHOLD){
triggered = 1;
fillshotms(4);
}
}
return triggered;
}

View File

@ -24,10 +24,12 @@
// interval of trigger's shot (>min && <max), maybe negative
#define ADC_MIN_VAL (1024)
#define ADC_MAX_VAL (3072)
// 2*ADC_THRESHOLD = hysteresis width
#define ADC_THRESHOLD (50)
extern uint16_t ADC_array[];
int32_t getMCUtemp();
uint32_t getVdd();
uint16_t getADCval(int nch);
void chkADCtrigger();
uint8_t chkADCtrigger();
#endif // ADC_H

Binary file not shown.

View File

@ -24,6 +24,8 @@
#include "adc.h"
#include "hardware.h"
#include "flash.h"
#include "lidar.h"
#include "str.h"
#include "time.h"
#include "usart.h"
@ -41,10 +43,10 @@ static uint8_t trigstate[DIGTRIG_AMOUNT];
trigtime shottime[TRIGGERS_AMOUNT];
// Tms value when they shot
static uint32_t shotms[TRIGGERS_AMOUNT];
// trigger length (-1 if > MAX_TRIG_LEN)
int16_t triglen[TRIGGERS_AMOUNT];
// if trigger[N] shots, the bit N will be 1
uint8_t trigger_shot = 0;
// time when Buzzer was turned ON
uint32_t BuzzerTime = 0;
static inline void gpio_setup(){
BUZZER_OFF(); // turn off buzzer @start
@ -78,7 +80,9 @@ static inline void gpio_setup(){
uint16_t pin = trigpin[i];
// fill trigstate array
uint8_t trgs = (the_conf.trigstate & (1<<i)) ? 1 : 0;
#ifdef EBUG
trigstate[i] = trgs;
#endif
// turn on pullups
if(the_conf.trig_pullups & (1<<i)) trigport[i]->ODR |= pin;
EXTI->IMR |= pin;
@ -147,17 +151,52 @@ void savetrigtime(){
memcpy(&trgtm.Time, &current_time, sizeof(curtime));
}
/**
* @brief fillshotms - save trigger shot time
* @param i - trigger number
*/
void fillshotms(int i){
if(i < 0 || i > TRIGGERS_AMOUNT) return;
if(i < 0 || i >= TRIGGERS_AMOUNT) return;
if(Tms - shotms[i] > (uint32_t)the_conf.trigpause[i]){
shotms[i] = Tms;
memcpy(&shottime[i], &trgtm, sizeof(trigtime));
shotms[i] = Tms;
trigger_shot |= 1<<i;
BuzzerTime = Tms;
BUZZER_ON();
}
}
/**
* @brief fillunshotms - calculate trigger length time
*/
void fillunshotms(){
if(!trigger_shot) return;
uint8_t X = 1;
for(int i = 0; i < TRIGGERS_AMOUNT; ++i, X<<=1){
// check whether trigger is OFF but shot recently
if(trigger_shot & X){
uint32_t len = Tms - shotms[i];
uint8_t rdy = 0;
if(len > MAX_TRIG_LEN){
triglen[i] = -1;
rdy = 1;
}else triglen[i] = (uint16_t) len;
if(i == LIDAR_TRIGGER){
if(!parse_lidar_data(NULL)) rdy = 1;
}else if(i == ADC_TRIGGER){
if(!chkADCtrigger()) rdy = 1;
}else{
uint8_t pinval = (trigport[i]->IDR & trigpin[i]) ? 1 : 0;
if(pinval != trigstate[i]) rdy = 1; // trigger is OFF
}
if(rdy){
shotms[i] = Tms;
show_trigger_shot(X);
trigger_shot &= ~X;
}
}
}
}
void exti4_isr(){ // PA4 - trigger[2]
savetrigtime();
fillshotms(2);
@ -176,6 +215,7 @@ void exti15_10_isr(){ // PA13 - trigger[0], PA14 - trigger[1]
}
}
#ifdef EBUG
/**
* @brief gettrig - get trigger state
* @return 1 if trigger active or 0
@ -186,3 +226,18 @@ uint8_t gettrig(uint8_t N){
if(curval == trigstate[N]) return 1;
else return 0;
}
#endif
void chk_buzzer(){
if(!trigger_shot && BUZZER_GET()){ // should we turn off buzzer?
uint8_t notrg = 1;
for(int i = 0; i < DIGTRIG_AMOUNT; ++i){
uint8_t curval = (trigport[i]->IDR & trigpin[i]) ? 1 : 0;
if(curval == trigstate[i]){
notrg = 0;
break;
}
}
if(notrg) BUZZER_OFF(); // turn off buzzer when there's no trigger events
}
}

View File

@ -39,6 +39,7 @@ extern uint8_t buzzer_on;
#define BUZZER_pin (1<<13)
#define BUZZER_ON() do{if(buzzer_on)pin_set(BUZZER_port, BUZZER_pin);}while(0)
#define BUZZER_OFF() pin_clear(BUZZER_port, BUZZER_pin)
#define BUZZER_GET() (pin_read(BUZZER_port, BUZZER_pin))
// PPS pin - PA1
#define PPS_port GPIOA
@ -49,11 +50,18 @@ extern uint8_t buzzer_on;
#define TRIGGERS_AMOUNT (5)
// number of LIDAR trigger
#define LIDAR_TRIGGER (3)
// number of ADC trigger
#define ADC_TRIGGER (4)
// amount of digital triggers (on interrupts)
#define DIGTRIG_AMOUNT (3)
// max length of trigger event (ms)
#define MAX_TRIG_LEN (1000)
#ifdef EBUG
uint8_t gettrig(uint8_t N);
#endif
void fillshotms(int i);
void fillunshotms();
void savetrigtime();
#define GET_PPS() ((GPIOA->IDR & (1<<1)) ? 1 : 0)
@ -83,11 +91,12 @@ typedef struct{
extern uint8_t LEDSon;
// time of triggers shot
extern trigtime shottime[TRIGGERS_AMOUNT];
// length (in ms) of trigger event (-1 if > MAX_TRIG_LEN
extern int16_t triglen[TRIGGERS_AMOUNT];
// if trigger[N] shots, the bit N will be 1
extern uint8_t trigger_shot;
// time when Buzzer was turned ON
extern uint32_t BuzzerTime;
void chk_buzzer();
void hw_setup();
#endif // __HARDWARE_H__

View File

@ -24,14 +24,20 @@ uint16_t last_lidar_dist = 0;
uint16_t last_lidar_stren = 0;
uint16_t lidar_triggered_dist = 0;
void parse_lidar_data(char *txt){
/**
* @brief parse_lidar_data - parsing of string from lidar
* @param txt - the string or NULL (if you want just check trigger state)
* @return trigger state
*/
uint8_t parse_lidar_data(char *txt){
static uint8_t triggered = 0;
if(!txt) return triggered;
last_lidar_dist = txt[2] | (txt[3] << 8);
last_lidar_stren = txt[4] | (txt[5] << 8);
if(last_lidar_stren < LIDAR_LOWER_STREN) return; // weak signal
if(last_lidar_stren < LIDAR_LOWER_STREN) return 0; // weak signal
if(!lidar_triggered_dist){ // first run
lidar_triggered_dist = last_lidar_dist;
return;
return 0;
}
IWDG->KR = IWDG_REFRESH;
if(triggered){ // check if body gone
@ -60,4 +66,5 @@ void parse_lidar_data(char *txt){
#endif
}
}
return triggered;
}

View File

@ -34,6 +34,6 @@ extern uint16_t last_lidar_dist;
extern uint16_t lidar_triggered_dist;
extern uint16_t last_lidar_stren;
void parse_lidar_data(char *txt);
uint8_t parse_lidar_data(char *txt);
#endif // LIDAR_H__

View File

@ -158,23 +158,26 @@ char *parse_cmd(char *buf){
}
#endif
#define USBBUF 63
// usb getline
static char *get_USB(){
static char tmpbuf[512], *curptr = tmpbuf;
static int rest = 511;
static char tmpbuf[USBBUF+1], *curptr = tmpbuf;
static int rest = USBBUF;
int x = USB_receive(curptr, rest);
curptr[x] = 0;
if(!x) return NULL;
curptr[x] = 0;
USB_send(curptr); // echo
//if(x == 1 && *curptr < 32){USB_send("\n"); USB_send(u2str(*curptr)); USB_send("\n");}
if(curptr[x-1] == '\n'){
curptr = tmpbuf;
rest = 511;
rest = USBBUF;
return tmpbuf;
}
curptr += x; rest -= x;
if(rest <= 0){ // buffer overflow
SEND("USB buffer overflow!\n");
//SEND("USB buffer overflow!\n");
curptr = tmpbuf;
rest = 511;
rest = USBBUF;
}
return NULL;
}
@ -215,7 +218,6 @@ void break_handler(){ // client disconnected
#ifdef EBUG
extern int32_t ticksdiff, timecntr, timerval, Tms1;
extern uint32_t last_corr_time;
#endif
int main(void){
@ -245,10 +247,8 @@ int main(void){
while (1){
IWDG->KR = IWDG_REFRESH; // refresh watchdog
if(Timer > 499) LED_on(); // turn ON LED0 over 0.25s after PPS pulse
if(BuzzerTime && Tms - BuzzerTime > 249){
BUZZER_OFF();
BuzzerTime = 0;
}
// check if triggers that was recently shot are off now
fillunshotms();
if(lastT > Tms || Tms - lastT > 499){
if(need2startseq) GPS_send_start_seq();
IWDG->KR = IWDG_REFRESH;
@ -301,8 +301,7 @@ int main(void){
}
#endif
}
IWDG->KR = IWDG_REFRESH;
if(trigger_shot) show_trigger_shot(trigger_shot);
//if(trigger_shot) show_trigger_shot(trigger_shot);
IWDG->KR = IWDG_REFRESH;
usb_proc();
IWDG->KR = IWDG_REFRESH;
@ -312,7 +311,7 @@ int main(void){
DBG("Received data over USB:");
DBG(txt);
if(parse_USBCMD(txt))
USB_send(txt); // echo back non-commands data
USB_send("Bad command!");
IWDG->KR = IWDG_REFRESH;
}
#if defined EBUG || defined USART1PROXY
@ -352,7 +351,7 @@ int main(void){
parse_lidar_data(txt);
}
}
chkADCtrigger();
chk_buzzer(); // should we turn off buzzer?
}
return 0;
}

View File

@ -111,6 +111,7 @@ int parse_USBCMD(char *cmd){
CMD_DISTMIN " - min distance threshold (cm)\n"
CMD_DISTMAX " - max distance threshold (cm)\n"
CMD_GPSRESTART " - send Full Cold Restart to GPS\n"
CMD_GPSSTAT " - get GPS status\n"
CMD_GPSSTR " - current GPS data string\n"
CMD_LEDS "S - turn leds on/off (1/0)\n"
CMD_GETMCUTEMP " - MCU temperature\n"
@ -125,6 +126,7 @@ int parse_USBCMD(char *cmd){
);
}else if(CMP(cmd, CMD_PRINTTIME) == 0){
USB_send(get_time(&current_time, get_millis()));
USB_send("\n");
}else if(CMP(cmd, CMD_DISTMIN) == 0){ // set low limit
DBG("CMD_DISTMIN");
GETNUM(CMD_DISTMIN);
@ -258,14 +260,34 @@ int parse_USBCMD(char *cmd){
if(Nt > 1) goto bad_number;
USB_send("BUZZER=");
if(Nt){
BuzzerTime = 0;
buzzer_on = 1;
USB_send("ON\n");
}else{
BuzzerTime = 0;
buzzer_on = 0;
USB_send("OFF\n");
}
}else if(CMP(cmd, CMD_GPSSTAT) == 0){
USB_send("GPS status: ");
const char *str = "unknown";
switch(GPS_status){
case GPS_NOTFOUND:
str = "not found";
break;
case GPS_WAIT:
str = "waiting";
break;
case GPS_NOT_VALID:
str = "no satellites";
break;
case GPS_VALID:
str = "valid time";
break;
}
USB_send(str);
if(Tms - last_corr_time < 1500)
USB_send(", PPS working\n");
else
USB_send(", no PPS\n");
}else return 1;
IWDG->KR = IWDG_REFRESH;
if(succeed) USB_send("Success!\n");
@ -285,7 +307,7 @@ void show_trigger_shot(uint8_t tshot){
IWDG->KR = IWDG_REFRESH;
if(tshot & X) tshot &= ~X;
else continue;
if(trigger_shot & X) trigger_shot &= ~X;
if(!triglen[i]) continue; // noice
if(i == LIDAR_TRIGGER){
USB_send("LIDAR, dist=");
sendu(lidar_triggered_dist);
@ -296,6 +318,9 @@ void show_trigger_shot(uint8_t tshot){
}
USB_send("=");
USB_send(get_time(&shottime[i].Time, shottime[i].millis));
USB_send(", len=");
if(triglen[i] < 0) USB_send(">1s");
else sendu((uint32_t) triglen[i]);
USB_send("\n");
}
}

View File

@ -42,6 +42,7 @@
#define CMD_LEDS "leds"
#define CMD_GPSRESTART "gpsrestart"
#define CMD_BUZZER "buzzer"
#define CMD_GPSSTAT "gpsstat"
extern uint8_t showGPSstr;

View File

@ -79,6 +79,26 @@ static char *puttwo(uint8_t N, char *buf){
return buf;
}
/**
* @brief ms2str - fill buffer str with milliseconds ms
* @param str (io) - pointer to buffer
* @param T - milliseconds
*/
static void ms2str(char **str, uint32_t T){
char *bptr = *str;
*bptr++ = '.';
if(T > 99){
*bptr++ = T/100 + '0';
T %= 100;
}else *bptr++ = '0';
if(T > 9){
*bptr++ = T/10 + '0';
T %= 10;
}else *bptr++ = '0';
*bptr++ = T + '0';
*str = bptr;
}
/**
* print time: Tm - time structure, T - milliseconds
*/
@ -95,26 +115,18 @@ char *get_time(curtime *Tm, uint32_t T){
S /= 10;
}
// now bstart is buffer starting index; bptr points to decimal point
*bptr++ = '.';
if(T > 99){
*bptr++ = T/100 + '0';
T %= 100;
}else *bptr++ = '0';
if(T > 9){
*bptr++ = T/10 + '0';
T %= 10;
}else *bptr++ = '0';
*bptr++ = T + '0';
ms2str(&bptr, T);
// put current time in HH:MM:SS format into buf
*bptr++ = ' '; *bptr++ = '(';
bptr = puttwo(Tm->H, bptr); *bptr++ = ':';
bptr = puttwo(Tm->M, bptr); *bptr++ = ':';
bptr = puttwo(Tm->S, bptr); *bptr++ = ')';
bptr = puttwo(Tm->S, bptr);
ms2str(&bptr, T);
*bptr++ = ')';
if(GPS_status == GPS_NOTFOUND){
strcpy(bptr, " GPS not found");
bptr += 14;
}
*bptr++ = '\n';
*bptr = 0;
return bstart;
}

View File

@ -46,6 +46,7 @@ typedef struct{
extern volatile uint32_t Tms;
extern volatile uint32_t Timer;
extern curtime current_time;
extern uint32_t last_corr_time;
extern curtime trigger_time[];
extern uint32_t trigger_ms[];

View File

@ -45,7 +45,7 @@
#define usartrx(n) (linerdy[n])
#define usartovr(n) (bufovr[n])
extern volatile int linerdy[4], bufovr[4], txrdy[4];
extern volatile int linerdy[], bufovr[], txrdy[];
void transmit_tbuf(int n);
void usarts_setup();