ssaguiar
Joined: 02 Nov 2003 Posts: 11 Location: Brazil
|
2 serials problem. |
Posted: Mon Mar 01, 2010 9:31 pm |
|
|
Dear friends:
I am trying to implement a data logger (gps and adc), and, to achieve this, I need to:
-In the gps side, I use the hardware usart with interrupts;
-In the other side, i need to send/receive data thru software serial routines;
The problem is that, after some time working (some minutes), the system stops to work with the hardware usart stuff.
The code is below.
Can somebody indicate if this approach is the best for this kind of project and if somebody can give me some clue about this problem because I really am losing my last hairs.
Explanation of usart interrupts use:
When my state machine's enters the STATE_FUEL_READ state it means that it's time for the system to read the gps data and the adc stuff, so it enables the usart interrupt.
When the usart interrupt ends the gps data capture, the new state is STATE_GPS_REC. Here, we know that the gps data is ready to be processed and we can also capture and process the adc sensors, so we disable the usart interrupt and call the process routine which will capture and display data in the glcd.
I just don't know why the usart interrupt locks up after some time.
The code is:
Code: |
/************************************************************************
**** Controle Combustivel ****
**** ****
**** Rs-232 parameters : 9600,8,n,1 ****
**** ****
*************************************************************************
**** ****
*************************************************************************
*************************************************************************
**** _ _ _ _ _ _ _ _ ****
**** | | | _| _| |_| |_ |_ | |_| |_| ****
**** |_| | |_ _| | _| |_| | |_| _| ****
**** ****
************************************************************************/
#include <18F4620.h>
#device ADC=10
#device PASS_STRINGS = IN_RAM
//#DEVICE HIGH_INTS=TRUE
#zero_ram
#case
/************************************************************************/
#FUSES NOWDT // NO Watch Dog Timer
#FUSES WDT128 // Watch Dog Timer uses 1:128 Postscale
#FUSES HS // High speed Osc (> 4mhz)
//#FUSES H4 // Multiply by 4?
#FUSES NOPROTECT // Code not protected from reading
#FUSES NOIESO // Internal External Switch Over mode disabled
#FUSES NOBROWNOUT // No brownout reset
#FUSES BORV21 // Brownout reset at 2.1V
#FUSES PUT // Power Up Timer
#FUSES NOCPD // No EE protection
#FUSES STVREN // Stack full/underflow will cause reset
#FUSES NODEBUG // No Debug mode for ICD
#FUSES NOLVP // No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOWRT // Program memory not write protected
#FUSES NOWRTD // Data EEPROM not write protected
#FUSES NOEBTR // Memory not protected from table reads
#FUSES NOCPB // No Boot Block code protection
#FUSES NOEBTRB // Boot block not protected from table reads
#FUSES NOWRTC // Configuration not registers write protected
#FUSES NOWRTB // Boot block not write protected
#FUSES NOFCMEN // Fail-safe clock monitor disabled
#FUSES NOXINST // Extended set extension and Indexed Addressing mode disabled (Legacy mode)
#FUSES NOPBADEN // PORTB pins are not configured as analog input channels on RESET
#FUSES LPT1OSC // Timer1 configured for low-power operation
#FUSES MCLR // Master Clear pin enabled
#use delay(clock=20000000)
//#use delay(clock=48M, oscillator=20M)
//#use i2c ( master, scl=EEPROM_SCL, sda=EEPROM_SDA )
#use rs232(baud=4800, parity=N, bits=8, stop=1, xmit=PIN_C6, rcv=PIN_C7, STREAM=GPS, ERRORS)
#use rs232(baud=19200, parity=N, bits=8, stop=1, xmit=PIN_B6, rcv=PIN_B7, STREAM=RADIO)
/*****************************************************************************/
// ROM definitions
#ROM int8 0xf00000 = // Start of EEPROM address.
{
0,1, // Time between captures, in minutes byte 0 * 256 + byte 1 (max 65535).
'L','Y','Q','4','1','3','7',0 // Vehicle's ID (7 chars).
}
#define LOCALID_ADD 2 // Start at ROM Address 2
#define ROM_Localid_Size 8 // 7 for id + trailling 0.
/*****************************************************************************/
// Includes
#include <stdlib.h>
#include <241025.c>
#include "pcf8583.c"
#include "vt100.h"
/*****************************************************************************/
// System defines
#define _HAS_GLCD_ // Use Graph LCD?
//#undef _HAS_GLCD_ // No.
#define PCF8583_SDA PIN_C4
#define PCF8583_SCL PIN_C3
#define EEPROM_SDA PIN_C4
#define EEPROM_SCL PIN_C3
#define BUZZER PIN_C2
#define BUTTON_1 PIN_E0
#define RX_IN PIN_C7
#define LED_OK PIN_E1
#define LED_SYS PIN_E2
#define ON 1
#define OFF 0
#define HIGH 1
#define LOW 0
#define TRUE 1
#define FALSE 0
#define EOF 0x00
#define COMMA ','
#define SPACE ' '
#define PERIOD '.'
#define DOLLAR '$'
#define CR 13
#define GPRMC_CODE 75
#define RX_BUFFER_SIZE 80
#define VDD 14.00
#define EEPROM_BYTE_SIZE 131072 // 1 Mbits eeprom = 128 KBytes = 131072 Bytes
#define SAMPLE_COUNT_BANK 1
#define SAMPLE_COUNT_HI 2
#define SAMPLE_COUNT_LO 3
#define COMMAND_SIZE 30
#define NUM_COMMANDS 5
#define TIMER_COUNT_HI 0xf00000
#define TIMER_COUNT_LOW 0xf00001
#ifdef _HAS_GLCD_
#include <HDM64GS12.c>
#include <GRAPHICS.c>
#endif
#include "auxiliar.c"
/*****************************************************************************/
// Define Variables
int Timer_1ms, Timer_100ms, Timer_1s, count1, plottemp;
long Timer_1m, plotfuel, plotSolar, Timer_100ms2;
static char cstate, cChar;
date_time_t dt;
char DateTime[36];
static long iSampleCount;
long iVal, maxtemp, mintemp;
long SampleCap;
float iSolar;
float iTemp;
char g_CWD[200] = ""; //current working directory
char Solar[12];
char Temp[12];
char MaxTemps[12];
char MinTemps[12];
char ReadSample[20];
char LocalID [8] = {0, 0, 0, 0, 0, 0, 0, 0};
char buffer[255];
char *cmd, *option1, *option2;
int i, speed, old_speed, readsindex, fuel, gauge, fuel_old, errflag;
char speed_val[9];
char latitude_val[13];
char longitude_val[14];
char speedt[4];
static char cC[ 10 ]; // local buffer
static char tmp[10]; // temp conversion buffer
static char cTimeOut;
static char cRxBuffer [ RX_BUFFER_SIZE ]; // Fifo
static char cRxByteCnt; // Number of bytes in the recv fifo
static char *cRxBufferWritePtr; // Pointers for the Rx buffer
static char *cRxBufferReadPtr;
static char cRxIsrState, cRxMsgTypeReceived, cRxMsgTypeDesired;
static char cReceiveFlag;
static char cSkip;
static char updatetime;
long result;
int day, month_index,min,sec;
signed int hour;
enum
{
STATE_IDDLE,
STATE_SECOND,
STATE_SHOW_TIME,
STATE_FUEL_READ,
STATE_FUEL_READY,
STATE_SERIAL_READY,
STATE_GPS_REC
};
char commands[NUM_COMMANDS][COMMAND_SIZE]=
{
"RTC", // Option1=date/time.Sets date and time.
"TIME", // Ask for remote sensor's time
"DUMP", // Dump Data
"SETID", // Set vehicle's ID
"help" // help!
};
/*****************************************************************************/
// Functions Prototypes
void ShowHelp (void);
char * GetCMD (char *in);
char * GetOption (char *in);
void ShowHelp (void);
int FindCommand (char *cmd);
int SetTime (char *opt_buffer);
void DisplayPrompt(void);
void showtime (void);
void readadc (void);
void readadc2 (void);
void glcd_imagen (void);
void ShowLocalTime(char *id);
void DumpData (void);
void SysStart (void);
#separate void read_eeprom_string(char * array, int8 address, int8 max_size);
#separate void write_eeprom_string(char * array, int8 address, int8 max_size);
#separate void play(void);
#separate void GpsProcess(void);
#separate void SkipField (char cCnt);
#separate char GetField (void);
#separate void InitRxBuffer (char cCode);
#separate char GetRxChar (void);
#separate void AtolProcess (void);
#ifdef _HAS_GLCD_
#separate void GlcdInit(void);
#endif
#include "image.h"
/****************************************************************************
* DESCRIPTION: USART interrupt for data from GPS.
* RETURN: none
* ALGORITHM: none
* NOTES: none
*****************************************************************************/
#int_rda
// Apenas para lembrar:
// NUNCA NUNCA NUNCA!!! Chamar funções externas à interrupção...
// Isto bagunça o sistema de interrupts.
void SerialInterrupt ( void )
{
/*
Reads incoming data from the USART and puts in in a rolling buffer
( but in this application, it should never roll.)
If the buffer is full, this routine just discards the received byte.
Not checking the LRC byte at the end of the NMEA-0183 sentence.
*/
if ( rs232_errors & 0x04 ) // get framing error bit from Rx status reg
{
//cRxErrorFlag = ON;
}
output_high(LED_SYS);
cChar = getc(); // get char from UART, clear any errors
if ( cRxByteCnt == RX_BUFFER_SIZE ) // is recv fifo full ???
{
goto done;
}
switch ( cRxIsrState )
{
case 0:
{
if ( cChar == DOLLAR ) // if start of NMEA0183 message
{
cRxByteCnt = 0; // reset byte count
cReceiveFlag = OFF; // default to off
cRxMsgTypeReceived = NULL; // set hashed value to null
cRxIsrState++; // next state
}
break;
}
case 1: // five type characters to obtain
case 2:
case 3:
case 4:
case 5:
{
cRxMsgTypeReceived ^= cChar; // hash in msg type
if ( cRxIsrState++ == 5 ) // if time to check message type
{
if ( cRxMsgTypeReceived == cRxMsgTypeDesired )// if good
{
cReceiveFlag = YES; // enable receiving
cRxBufferWritePtr = cRxBuffer;// reset to beginning of buffer
}
else // don't want this message
{
cRxIsrState = 0; // reset to look for next msg
}
}
break;
}
case 6:
{
/* Case 6 skips the comma character following msg type */
cRxIsrState++;
break;
}
default: // remainder of characters
{
if ( cReceiveFlag == YES ) // if this message is wanted
{
*cRxBufferWritePtr = cChar; // put char in fifo
cRxBufferWritePtr++; // increment pointer
if ( cRxBufferWritePtr == ( cRxBuffer + RX_BUFFER_SIZE ) ) // pointer past end ?
{
cRxBufferWritePtr = cRxBuffer;// set pointer to start of fifo
}
cRxByteCnt++; // Increment byte count
if ( cChar == CR )
{
cReceiveFlag = NO; // no more receive
cstate = STATE_GPS_REC; // GPS data ready to process...
output_low(LED_SYS);
}
}
}
}
done:;
output_low(LED_SYS);
}
/****************************************************************************
* DESCRIPTION: Timer 1 Interrupt ISR
* Overflow: 1/((20000000/4)/8)) = 1/(5000000/8) = 1/625000 = 0,0000016s=1.6us.
* If timer1 is preloaded with 65535 = Overflow = 1.6us * 65536 = 0,1048576 s.
* For an overflow of 100ms:
* 0,100 = 0,0000016 * X
* X = 0,100/0,0000016 => X = 62500
* For an overflow of 100ms, preload Timer1 with: 65536-62500, wich is: 3036.
*
* RETURN: none
* ALGORITHM: none
* NOTES: interrupt every 100ms
*****************************************************************************/
#INT_TIMER1
void TIMER1_isr(void)
{
output_toggle(LED_OK);
set_timer1(8700 - get_timer1());//(3036 - get_timer1()); // Restart 100 ms timming
if(Timer_100ms++ == 10) // 1 second?
{
Timer_100ms2++;
Timer_100ms = 0;
Timer_1s++;
cstate = STATE_SHOW_TIME;
if (Timer_1s == 10) // 1 minute?
{
Timer_1s = 0;
Timer_1m++;
if (Timer_1m == SampleCap) // Time to capture adc data?
{
Timer_1m = 0;
cstate = STATE_FUEL_READ; // Capture adc
}
}
}
}
/****************************************************************************
* DESCRIPTION: Main program
* RETURN: none
* ALGORITHM: none
* NOTES: none
*****************************************************************************/
void main()
{
SysStart();
while (TRUE)
{
if (cstate == STATE_FUEL_READ)
{
enable_interrupts ( INT_RDA ); // Enable serial interrupt - start to capture GPS data...
cstate = STATE_IDDLE;
}
if (cstate == STATE_SERIAL_READY) // Nothing yet...
{
cstate = STATE_IDDLE;
}
if (cstate == STATE_SHOW_TIME)
{
showtime();
cstate = STATE_IDDLE;
}
if (cstate == STATE_GPS_REC)
{
disable_interrupts ( INT_RDA ); // Disable serial interrupt so we can process gps data and adc
GpsProcess();
InitRxBuffer( GPRMC_CODE );
cstate = STATE_IDDLE;
}
if (kbhit(RADIO)) // Receive data from soft serial port.
{
buffer[i] = fgetc(RADIO);
// Check for a backspace
if(buffer[i] != 8)
{
fprintf(RADIO, "%c", buffer[i]);
i++;
}
else if(i > 0)
{
// Delete the last character
i--;
fputc(8, RADIO);
fputc(' ', RADIO);
fputc(8, RADIO);
}
buffer[i] = '\0';
}
if (buffer[i - 1] == '\r')
{
// Parse the command and options
cmd = GetCMD(buffer);
option1 = GetOption(cmd + strlen(cmd) + 1);
option2 = GetOption(option1 + strlen(option1) + 1);
if (cmd)
{
i = 0;
switch(FindCommand(cmd))
{
case 0: // RTC
SetTime(option1);
DisplayPrompt();
break;
case 1: // TIME
if (strstr(option1, LocalID) )
{
ShowLocalTime(option1);
}
break;
case 2: // DUMP
if (strstr(option1, LocalID) )
{
DumpData();
}
break;
case 3: // SETID
if (strstr(option1, LocalID) )
{
if (strlen(option2)==7)
{
write_eeprom_string (option2, LOCALID_ADD, ROM_Localid_Size);
read_eeprom_string (LocalID, LOCALID_ADD, ROM_Localid_Size);
}
}
break;
case 4: // Help
ShowHelp();
DisplayPrompt();
break;
default:
fprintf(RADIO, "\r\nUnkown Command '%s'", cmd);
DisplayPrompt();
break;
}
}
}
}
}
/****************************************************************************
* DESCRIPTION: ShowHelp function
* RETURN: none
* ALGORITHM: none
* NOTES: Send a help text thru rs-232
*****************************************************************************/
void ShowHelp()
{
__VT100_GOTOXY(0, 4)
fprintf(RADIO, _NORMAL_ _FG_BLACK_);
fprintf(RADIO, _BRIGHT_ _FG_YELLOW_ "\r\nLog System help");
fprintf(RADIO, _NORMAL_ _BRIGHT_ "\r\n\n RTC ddmmYYhhmmss\t\t--- Sets Date / Time for remote sensors (all)");
fprintf(RADIO, "\r\n TIME VehicleId\t\t\t--- Ask for vehicle's date/time");
fprintf(RADIO, "\r\n DUMP XXX0000\t\t\t--- Dump Vehicle's data");
fprintf(RADIO, "\r\n SETID AAA0000 BBB9999\t\t--- Set vehicle's ID");
fprintf(RADIO, "\r\n\ help\tThis help.");
fprintf(RADIO, _NORMAL_ "\r\n\n Enclose parameter with quotes if it has spaces.");
DisplayPrompt();
}
/****************************************************************************
* DESCRIPTION: Parse the command in the receive buffer.
* RETURN: none
* ALGORITHM: none
* NOTES: none
*****************************************************************************/
char * GetCMD(char *in)
{
char tokens[]=" \r\n";
return(strtok(in,tokens));
}
/****************************************************************************
* DESCRIPTION: Parse the option(s) in the command
* RETURN: none
* ALGORITHM: none
* NOTES: none
*****************************************************************************/
char * GetOption(char *in)
{
char tokensSpace[]=" \r\n";
char tokensQuote[]="\"\r\n";
// Trim leading spaces
while (*in==' ')
in++;
// If first char is a quote, then end token on a quote. ELSE end token on a space
if (*in == '\"')
return(strtok(in,tokensQuote));
else
return(strtok(in,tokensSpace));
}
/****************************************************************************
* DESCRIPTION: Search if the command exist in the command table
* RETURN: none
* ALGORITHM: none
* NOTES: Find if the command received from rs-232 exists.
*****************************************************************************/
int FindCommand(char *cmd)
{
char buf[COMMAND_SIZE];
int i;
for (i=0; i<NUM_COMMANDS; i++)
{
strcpy(buf, &commands[i][0]);
if (stricmp(buf, cmd)==0)
return(i);
}
return(0xFF);
}
/****************************************************************************
* DESCRIPTION: Set date/time in the RTC, from the rs-232 receive buffer.
* RETURN: none
* ALGORITHM: none
* NOTES: The buffer has the form: ddmmyyhhmmss
*****************************************************************************/
int SetTime(char *opt_buffer)
{
char day[3];
char month[3];
char year[3];
char hour[3];
char min[3];
char sec[3];
strncpy (day, opt_buffer, 2);
strcpy (day + 2, "\0");
strncpy (month, opt_buffer+2, 2);
strcpy (month + 2, "\0");
strncpy (year, opt_buffer+4, 2);
strcpy (year + 2, "\0");
strncpy (hour, opt_buffer+6, 2);
strcpy (hour + 2, "\0");
strncpy (min, opt_buffer+8, 2);
strcpy (min + 2, "\0");
strncpy (sec, opt_buffer+10, 2);
strcpy (sec + 2, "\0");
dt.month = atoi(month);
dt.day = atoi(day);
dt.year = atoi(year);
dt.hours = atoi(hour);
dt.minutes = atoi(min);
dt.seconds = atoi(sec);
//dt.weekday = 0; // 0 = Sunday, 1 = Monday, etc.
PCF8583_set_datetime(&dt);
return(0);
}
/****************************************************************************
* DESCRIPTION: Display a prompt thru rs-232
* RETURN: none
* ALGORITHM: none
* NOTES: none
*****************************************************************************/
void DisplayPrompt(void)
{
__VT100_GOTOXY(0, 16)
fprintf(RADIO, "\r\n\n%s> ", g_CWD);
}
/****************************************************************************
* DESCRIPTION: Show the date/time in the selected output.
* RETURN: none
* ALGORITHM: none
* NOTES: Read date/time from RTC chip (pcf8583)
*****************************************************************************/
void showtime(void)
{
PCF8583_read_datetime(&dt);
#ifdef _HAS_GLCD_
glcd_text35(60,59,DateTime,OFF);
#endif
sprintf(DateTime,"%02u/%02u/%02u %02u:%02u:%02u", dt.day, dt.month, dt.year, dt.hours, dt.minutes, dt.seconds);
#ifdef _HAS_GLCD_
glcd_text35(60,59,DateTime,ON);
#endif
}
/****************************************************************************
* DESCRIPTION: Read the adc channels and plot the results and the date/time
* RETURN: none
* ALGORITHM: none
* NOTES: none
*****************************************************************************/
void readadc(void)
{
//output_high(LED_SYS);
set_adc_channel ( 0 );
delay_ms(10);
iVal = read_adc();
delay_ms(10);
iSolar = ( float ) iVal / 1023 * 5;
set_adc_channel ( 1 );
delay_ms(10);
iVal = read_adc();
delay_ms(10);
iTemp = ( float ) iVal / 1023 * 5;
iTemp = iTemp * 100;
#ifdef _HAS_GLCD_
glcd_text35(26,59,Solar,OFF);
sprintf ( Solar, "%02.2fV", iSolar );
glcd_text35(26,59,Solar,ON);
glcd_text35(00,59,Temp,OFF);
sprintf ( Temp, "%02.1foC", iTemp );
glcd_text35(00,59,Temp,ON);
plotfuel = 55 - (int)iTemp;
glcd_line(plottemp,55,plottemp,10,OFF);
glcd_pixel(plottemp,plotfuel,ON);
glcd_line(plottemp+1,55,plottemp+1,10,ON);
if (plottemp++ == 60)
{
glcd_line(plottemp,55,plottemp,10,OFF);
plottemp=12;//126) plottemp=12;
}
if (maxtemp < iVal)
{
maxtemp = iVal;
//glcd_rect(66,55,70,10,YES,OFF);
//glcd_rect(66,55,70,plotfuel,YES,ON);
glcd_text35(85,00,MaxTemps,OFF);//74,50,MaxTemps,OFF);
sprintf ( MaxTemps, "%02.1f", iTemp );
glcd_text35(85,00,MaxTemps,ON);//74,50,MaxTemps,ON);
}
if (mintemp > iVal)
{
mintemp = iVal;
//glcd_rect(96,55,100,10,YES,OFF);
//glcd_rect(96,55,100,plotfuel,YES,ON);
glcd_text35(110,00,MinTemps,OFF);//104,50,MinTemps,OFF);
sprintf ( MinTemps, "%02.1f", iTemp );
glcd_text35(110,00,MinTemps,ON);//104,50,MinTemps,ON);
}
glcd_text35(66,17,latitude_val,ON);
glcd_text35(66,32,longitude_val,ON);
//glcd_text57(x,y,textptr,size,color)
glcd_text57(80,40,speedt,2,ON);
//glcd_text35(66,47,speedt, ON);
//__VT100_GOTOXY(0, 20)
//fprintf(RADIO, _NORMAL_ "Solar: %4.4f Temp.: %4.4f - %s \n\rLatitude: %s Longitude: %s Speed: %u", iSolar, iTemp, DateTime, latitude_val, longitude_val, speed);
__VT100_GOTOXY(0, 24)
fprintf (RADIO, _FG_RED_ "%s",LocalID);
DisplayPrompt();
//output_low(LED_SYS);
#endif
}
/****************************************************************************
* DESCRIPTION: Initialize the Graphic Lcd
* RETURN: none
* ALGORITHM: none
* NOTES: Clears the GLCD screen
*****************************************************************************/
#ifdef _HAS_GLCD_
#separate void GlcdInit(void)
{
glcd_init(ON);
glcd_fillScreen(OFF);
delay_ms(200);
}
#endif
/****************************************************************************
* DESCRIPTION: Plot image on GLCD (128X64)
* RETURN: none
* ALGORITHM: none
* NOTES: none
*****************************************************************************/
void glcd_imagen()
{
char i,j;
signed char k;
for( i = 0 ; i < 64 ; i ++ )
{
for( j = 0 ; j < 16 ; j ++)
{
for(k=7;k>-1;k--)
{
if( bit_test(imagen[i][j] ,7-k ))
glcd_pixel( j*8+k,i, ON );
}
}
}
}
/****************************************************************************
* DESCRIPTION: Inform local time to net manager
* RETURN: none
* ALGORITHM: none
* NOTES: none
*****************************************************************************/
void ShowLocalTime (char *id)
{
PCF8583_read_datetime(&dt);
sprintf(DateTime,"%02u/%02u/%02u %02u:%02u:%02u", dt.day, dt.month, dt.year, dt.hours, dt.minutes, dt.seconds);
fprintf(RADIO, "Date/Time of %s: %s", id, DateTime);
}
/****************************************************************************
* DESCRIPTION: Dump captured data to net manager
* RETURN: none
* ALGORITHM: none
* NOTES: none
*****************************************************************************/
void DumpData(void)
{
// Dump captured data to net manager
}
/****************************************************************************
* DESCRIPTION: Read a string from EEPROM.
* RETURN: none
* ALGORITHM: none
* NOTES: none
*****************************************************************************/
#separate void read_eeprom_string(char * array, int8 address, int8 max_size)
{
int8 i=0;
*array=0;
while (i<max_size)
{
*array = read_eeprom(address+i);
if (*array == 0) {i=max_size;}
else {
array++;
*array=0;
}
i++;
}
}
/****************************************************************************
* DESCRIPTION: Write a string to EEPROM
* RETURN: none
* ALGORITHM: none
* NOTES: none
*****************************************************************************/
#separate void write_eeprom_string(char * array, int8 address, int8 max_size)
{
int8 i=0;
while (i<max_size) {
write_eeprom(address+i,*array);
if (*array == 0) {i=max_size;}
array++;
i++;
}
}
/****************************************************************************
* DESCRIPTION: Init all system's units and variables.
* RETURN: none
* ALGORITHM: none
* NOTES: none
*****************************************************************************/
void SysStart (void)
{
delay_ms ( 200 ); // Wait enough time after Vdd rise
Timer_1ms = 0; // Reset Timer counters
Timer_100ms = 0; // " " "
Timer_1s = 0; // " " "
Timer_1m = 0; // " " "
cstate = STATE_IDDLE;
i = 0;
plottemp = 12;
maxtemp = 0;
mintemp = 1023;
cSkip = 0;
// Read Vehicle's ID from internal eeprom.
read_eeprom_string (LocalID, LOCALID_ADD, ROM_Localid_Size);
// Read Sample period, in minutes (from 1 to 65535 minutes), from internal eeprom.
SampleCap = ( 256 * read_eeprom ( TIMER_COUNT_HI ) ) + read_eeprom ( TIMER_COUNT_LOW );
output_float ( RX_IN ); // Ensure Rx input is HiZ
output_float ( BUTTON_1 ); // Ensure switch input is HiZ
cstate = STATE_IDDLE;
output_low (BUZZER);
PCF8583_init();
#ifdef _HAS_GLCD_
GlcdInit();
delay_ms(200);
#endif
glcd_imagen();
delay_ms(4000);
glcd_fillScreen(OFF);
InitRxBuffer( GPRMC_CODE );
setup_ccp1 ( CCP_OFF );
setup_ccp2 ( CCP_OFF );
setup_comparator(NC_NC_NC_NC);
setup_psp (PSP_DISABLED);
setup_timer_1 ( T1_INTERNAL | T1_DIV_BY_8 );
setup_adc_ports (AN0_TO_AN1);
setup_adc (ADC_CLOCK_DIV_16 | ADC_TAD_MUL_0);//Vide: http://www.ccsinfo.com/forum/viewtopic.php?t=41205&highlight=adc
set_timer1 (8700 - get_timer1());
enable_interrupts ( INT_TIMER1 ); // Enable Timer1 interrupt
enable_interrupts ( GLOBAL ); // Enable all interrupts
__VT100_GOTOXY(0, 0)
fprintf(RADIO, _NORMAL_ _FG_BLACK_ _CLRSCR_);
fprintf(RADIO, _BRIGHT_ _FG_YELLOW_ "Sistema de Monitoramento de Combustivel");
#ifdef _HAS_GLCD_
glcd_line(0,57,127,57,ON);
glcd_line(0,7,127,7,ON);
glcd_text35(0,0,"TINYLOGGER 1.0",ON);// (c)2010 ssaguiar",ON);
glcd_text35(0,11,"40_",ON);
glcd_text35(0,21,"30_",ON);
glcd_text35(0,31,"20_",ON);
glcd_text35(0,41,"10_",ON);
glcd_text35(0,51,"00_",ON);
glcd_line(62,10,62,55,ON);
glcd_text35(66,10,"Latitude:",ON);
glcd_text35(66,25,"Longitude:",ON);
#endif
DisplayPrompt();
play();
}
/****************************************************************************
* DESCRIPTION: Play a beep.
* RETURN: none
* ALGORITHM: none
* NOTES: none
*****************************************************************************/
#separate void play()
{
output_high (BUZZER); // Buzzer on
output_high (LED_OK); // Led_OK on
delay_ms (50); // Wait a bit...
output_low (BUZZER); // Buzzer off
output_low (LED_OK); // Led_Ok off
}
/****************************************************************************
* DESCRIPTION: Display GPS data received .
* RETURN: none
* ALGORITHM: none
* NOTES: none
*****************************************************************************/
void GpsProcess (void)
{
/*
SEE: http://www.ccsinfo.com/forum/viewtopic.php?t=34404&highlight=gps
To transform 2 ASCII bytes to 1 bcd byte:
UTC_Mins = 0x10 * (GPS_String[8]-0x30) + (GPS_String[9]-0x30);
*/
#ifdef _HAS_GLCD_
glcd_text35(66,17,latitude_val,OFF);
glcd_text35(66,32,longitude_val,OFF);
glcd_text57(80,40,speedt,2,OFF);
#endif
GetField(); //Time hh:mm:ss
GetField(); // Status -> A = OK, V = warning
if ( cC [ 0 ] == 'A' )
{
GetField(); // LATITUDE
latitude_val[0]=cC[0];
latitude_val[1]=cC[1];
latitude_val[2]=':';
latitude_val[3]=cC[2];
latitude_val[4]=cC[3];
latitude_val[5]=cC[4];
latitude_val[6]=cC[5];
latitude_val[7]=cC[6];
latitude_val[8]=cC[7];
latitude_val[9]=cC[8];
latitude_val[10]=' ';
GetField(); // NS
latitude_val[11]=cC[0];
latitude_val[12]=0;
GetField(); // LONGITUDE
longitude_val[0]=cC[0];
longitude_val[1]=cC[1];
longitude_val[2]=cC[2];
longitude_val[3]=':';
longitude_val[4]=cC[3];
longitude_val[5]=cC[4];
longitude_val[6]=cC[5];
longitude_val[7]=cC[6];
longitude_val[8]=cC[7];
longitude_val[9]=cC[8];
longitude_val[10]=cC[9];
longitude_val[11]=' ';
GetField(); // EW
longitude_val[12]=cC[0];
longitude_val[13]=0;
}
else
{
play();
//__VT100_GOTOXY(70, 24)
//fprintf(RADIO, _FG_RED_ "WARNING!");
latitude_val = "ERROR ";
longitude_val = "ERROR ";
errflag = TRUE;
}
GetField(); // Get Speed
AtolProcess();
result = atol (tmp);
result *= 1.852; // in Km/h
speed = (int)result;
if (errflag == TRUE)
{
speed = 0;
errflag = FALSE;
}
sprintf (speedt, "%03u", speed);
readadc();
}
/****************************************************************************
* DESCRIPTION: get field's data
* RETURN: none
* ALGORITHM: none
* NOTES: none
*****************************************************************************/
#separate char GetField ( void )
{
char cX, cIndex;
cX = NULL;
cIndex = 0;
while ( !cSkip )
{
cX = GetRxChar();
if ( ( cX == COMMA ) || ( cX == CR ) )
{
break;
}
cC [ cIndex++ ] = cX;
}
cC [ cIndex ] = EOF;
return ( cIndex ); // return number of characters in field
}
/****************************************************************************
* DESCRIPTION: skip field's data
* RETURN: none
* ALGORITHM: none
* NOTES: none
*****************************************************************************/
#separate void SkipField ( char cCnt )
{
char cX;
for ( cX = 0; cX < cCnt; cX++ )
{
while ( GetRxChar() != COMMA );
}
}
/****************************************************************************
* DESCRIPTION: get next byte in fifo buffer
* RETURN: none
* ALGORITHM: none
* NOTES: none
*****************************************************************************/
#separate char GetRxChar ( void )
{
// Get the next available byte in the recv fifo.
// Call this function ONLY if the recv fifo contains data.
char cValue;
cValue = 0;
if ( cRxByteCnt > 0 ) // For safety, check if there is any data
{
cValue = *cRxBufferReadPtr++; // Read byte from fifo
if ( cRxBufferReadPtr == ( cRxBuffer + RX_BUFFER_SIZE ) ) // Did tail ptr wrap ?
{
cRxBufferReadPtr = cRxBuffer; // If so, reset it to start of buffer
}
cRxByteCnt--; // Decrement byte count
}
return ( cValue );
}
/****************************************************************************
* DESCRIPTION: Init rx buffer and variables
* RETURN: none
* ALGORITHM: none
* NOTES: none
*****************************************************************************/
#separate void InitRxBuffer ( char cCode )
{
cRxBufferWritePtr = cRxBuffer; // point to beginning of buffer
cRxBufferReadPtr = cRxBuffer;
cRxByteCnt = 0;
cRxIsrState = 0;
cRxMsgTypeDesired = cCode;
}
/****************************************************************************
* DESCRIPTION: AtolProcess - modified ATOL
* RETURN: none
* ALGORITHM: none
* NOTES: none
*****************************************************************************/
#separate void AtolProcess ()
{
int count;
count = 0;
while (cC[count] != '.') // Find the decimal dot...
{
tmp[count] = cC[count];
count++;
}
tmp[count] = 0;// for atol/atoi work
}
/**********************************/
|
And the vt100.h file's content is:
Code: |
/*****************************************************************************/
// VT100 defines
/******************************************************************************
VT100 definitions
******************************************************************************/
#define _ESC_ "\033" // octal 033 = hexadecimal 01B = <_ESC_>
/******************************************************************************
VT100 Set Display Attributes definitions
******************************************************************************/
// Font mode
#define VT100_NORMAL 0
#define VT100_BRIGHT 1
#define VT100_DIM 2
#define VT100_UNDERLINE 3
#define VT100_BLINK 4
#define VT100_REVERSE 5
#define VT100_HIDDEN 6
// Foreground colours
#define VT100_FG_BLACK 30
#define VT100_FG_RED 31
#define VT100_FG_GREEN 32
#define VT100_FG_YELLOW 33
#define VT100_FG_BLUE 34
#define VT100_FG_MAGENTA 35
#define VT100_FG_CYAN 36
#define VT100_FG_WHITE 37
// Background colours
#define VT100_BG_BLACK 40
#define VT100_BG_RED 41
#define VT100_BG_GREEN 42
#define VT100_BG_YELLOW 43
#define VT100_BG_BLUE 44
#define VT100_BG_MAGENTA 45
#define VT100_BG_CYAN 46
#define VT100_BG_WHITE 47
//Set disp attr macro
#define __VT100_DISP_ATTR(_ATTR_) { printf(_ESC_"[%dm",_ATTR_); }
#define __VT100_ATTR(_ATTR_) { printf(_ESC_"[%dm",_ATTR_); }
#define __VT100_GOTOXY(X, Y) { printf(_ESC_"[%d;%df", Y, X); }
/******************************************************************************
VT100 Device Status definitions
******************************************************************************/
#define _GOTOXY_ _ESC_"[%u;%uf"
#define _TERM_RESET_ _ESC_ "c"
#define _CURSOR_HOME_ _ESC_ "[H"
#define _CURSOR_UP_ _ESC_ "[A"
#define _CURSOR_DOWN_ _ESC_ "[B"
#define _CURSOR_FORWARD_ _ESC_ "[C"
#define _CURSOR_BACKWARD_ _ESC_ "[D"
#define _CURSOR_PUSH_ _ESC_ "[s"
#define _CURSOR_POP_ _ESC_ "[u"
#define _ATTR_PUSH_ _ESC_ "7"
#define _ATTR_POP_ _ESC_ "8"
#define _CLREOL_ _ESC_ "[K"
#define _CLRSOL_ _ESC_ "[1K"
#define _CLRLN_ _ESC_ "[2K"
#define _CLRDOWN_ _ESC_ "[J"
#define _CLRUP_ _ESC_ "[1J"
#define _CLRSCR_ _ESC_ "[2J"
#define _NORMAL_ _ESC_ "[0m"
#define _BRIGHT_ _ESC_ "[1m"
#define _DIM_ _ESC_ "[2m"
#define _UNDERLINE_ _ESC_ "[4m"
#define _BLINK_ _ESC_ "[5m"
#define _REVERSE_ _ESC_ "[7m"
#define _HIDDEN_ _ESC_ "[8m"
#define _FG_BLACK_ _ESC_ "[30m"
#define _FG_RED_ _ESC_ "[31m"
#define _FG_GREEN_ _ESC_ "[32m"
#define _FG_YELLOW_ _ESC_ "[33m"
#define _FG_BLUE_ _ESC_ "[34m"
#define _FG_MAGENTA_ _ESC_ "[35m"
#define _FG_CYAN_ _ESC_ "[36m"
#define _FG_WHITE_ _ESC_ "[37m"
// Background colours
#define _BG_BLACK_ _ESC_ "[40m"
#define _BG_RED_ _ESC_ "[41m"
#define _BG_GREEN_ _ESC_ "[42m"
#define _BG_YELLOW_ _ESC_ "[43m"
#define _BG_BLUE_ _ESC_ "[44m"
#define _BG_MAGENTA_ _ESC_ "[45m"
#define _BG_CYAN_ _ESC_ "[46m"
#define _BG_WHITE_ _ESC_ "[47m"
|
The pc8583.c (found in this forum) is:
Code: |
// PCF8583.C
#ifndef PCF8583_SDA
#define PCF8583_SDA PIN_C4
#define PCF8583_SCL PIN_C3
#endif
#use i2c(MASTER, sda=PCF8583_SDA, scl=PCF8583_SCL)
#ifndef PCF8583_WRITE_ADDRESS
#define PCF8583_WRITE_ADDRESS 0xA0
#define PCF8583_READ_ADDRESS 0xA1
#endif
// Register addresses
#define PCF8583_CTRL_STATUS_REG 0x00
#define PCF8583_100S_REG 0x01
#define PCF8583_SECONDS_REG 0x02
#define PCF8583_MINUTES_REG 0x03
#define PCF8583_HOURS_REG 0x04
#define PCF8583_DATE_REG 0x05
#define PCF8583_MONTHS_REG 0x06
#define PCF8583_TIMER_REG 0x07
#define PCF8583_ALARM_CONTROL_REG 0x08
#define PCF8583_ALARM_100S_REG 0x09
#define PCF8583_ALARM_SECS_REG 0x0A
#define PCF8583_ALARM_MINS_REG 0x0B
#define PCF8583_ALARM_HOURS_REG 0x0C
#define PCF8583_ALARM_DATE_REG 0x0D
#define PCF8583_ALARM_MONTHS_REG 0x0E
#define PCF8583_ALARM_TIMER_REG 0x0F
// Use the first NVRAM address for the year byte.
#define PCF8583_YEAR_REG 0x10
// Commands for the Control/Status register.
#define PCF8583_START_COUNTING 0x00
#define PCF8583_STOP_COUNTING 0x80
char const weekday_names[7][10] =
{
{"Dom"},
{"Seg"},
{"Ter"},
{"Qua"},
{"Qui"},
{"[spam]"},
{"Sab"}
};
// This structure defines the user's date and time data.
// The values are stored as unsigned integers. The user
// should declare a structure of this type in the application
// program. Then the address of the structure should be
// passed to the PCF8583 read/write functions in this
// driver, whenever you want to talk to the chip.
typedef struct
{
int8 seconds; // 0 to 59
int8 minutes; // 0 to 59
int8 hours; // 0 to 23 (24-hour time)
int8 day; // 1 to 31
int8 month; // 1 to 12
int8 year; // 00 to 99
int8 weekday; // 0 = Sunday, 1 = Monday, etc.
}date_time_t;
//----------------------------------------------
void PCF8583_write_byte(int8 address, int8 data)
{
disable_interrupts(GLOBAL);
i2c_start();
i2c_write(PCF8583_WRITE_ADDRESS);
i2c_write(address);
i2c_write(data);
i2c_stop();
enable_interrupts(GLOBAL);
}
//----------------------------------------------
int8 PCF8583_read_byte(int8 address)
{
int8 retval;
disable_interrupts(GLOBAL);
i2c_start();
i2c_write(PCF8583_WRITE_ADDRESS);
i2c_write(address);
i2c_start();
i2c_write(PCF8583_READ_ADDRESS);
retval = i2c_read(0);
i2c_stop();
enable_interrupts(GLOBAL);
return(retval);
}
void PCF8583_init(void)
{
PCF8583_write_byte(PCF8583_CTRL_STATUS_REG,
PCF8583_START_COUNTING);
}
//----------------------------------------------
// This function converts an 8 bit binary value
// to an 8 bit BCD value.
// The input range must be from 0 to 99.
int8 bin2bcd(int8 value)
{
char retval;
retval = 0;
while(1)
{
// Get the tens digit by doing multiple subtraction
// of 10 from the binary value.
if(value >= 10)
{
value -= 10;
retval += 0x10;
}
else // Get the ones digit by adding the remainder.
{
retval += value;
break;
}
}
return(retval);
}
//----------------------------------------------
// This function converts an 8 bit BCD value to
// an 8 bit binary value.
// The input range must be from 00 to 99.
char bcd2bin(char bcd_value)
{
char temp;
temp = bcd_value;
// Shifting the upper digit right by 1 is
// the same as multiplying it by 8.
temp >>= 1;
// Isolate the bits for the upper digit.
temp &= 0x78;
// Now return: (Tens * 8) + (Tens * 2) + Ones
return(temp + (temp >> 2) + (bcd_value & 0x0f));
}
//----------------------------------------------
void PCF8583_set_datetime(date_time_t *dt)
{
int8 bcd_sec;
int8 bcd_min;
int8 bcd_hrs;
int8 bcd_day;
int8 bcd_mon;
// Convert the input date/time into BCD values
// that are formatted for the PCF8583 registers.
bcd_sec = bin2bcd(dt->seconds);
bcd_min = bin2bcd(dt->minutes);
bcd_hrs = bin2bcd(dt->hours);
bcd_day = bin2bcd(dt->day) | (dt->year << 6);
bcd_mon = bin2bcd(dt->month) | (dt->weekday << 5);
// Stop the RTC from counting, before we write to
// the date and time registers.
PCF8583_write_byte(PCF8583_CTRL_STATUS_REG,
PCF8583_STOP_COUNTING);
// Write to the date and time registers. Disable interrupts
// so they can't disrupt the i2c operations.
disable_interrupts(GLOBAL);
i2c_start();
i2c_write(PCF8583_WRITE_ADDRESS);
i2c_write(PCF8583_100S_REG); // Start at 100's reg.
i2c_write(0x00); // Set 100's reg = 0
i2c_write(bcd_sec);
i2c_write(bcd_min);
i2c_write(bcd_hrs);
i2c_write(bcd_day);
i2c_write(bcd_mon);
i2c_stop();
enable_interrupts(GLOBAL);
// Write the year byte to the first NVRAM location.
// Leave it in binary format.
PCF8583_write_byte(PCF8583_YEAR_REG, dt->year);
// Now allow the PCF8583 to start counting again.
PCF8583_write_byte(PCF8583_CTRL_STATUS_REG,
PCF8583_START_COUNTING);
}
//----------------------------------------------
// Read the Date and Time from the hardware registers
// in the PCF8583. We don't have to disable counting
// during read operations, because according to the data
// sheet, if any of the lower registers (1 to 7) is read,
// all of them are loaded into "capture" registers.
// All further reading within that cycle is done from
// those registers.
void PCF8583_read_datetime(date_time_t *dt)
{
int8 year_bits;
int8 year;
int8 bcd_sec;
int8 bcd_min;
int8 bcd_hrs;
int8 bcd_day;
int8 bcd_mon;
// Disable interrupts so the i2c process is not disrupted.
disable_interrupts(GLOBAL);
// Read the date/time registers inside the PCF8583.
i2c_start();
i2c_write(PCF8583_WRITE_ADDRESS);
i2c_write(PCF8583_SECONDS_REG); // Start at seconds reg.
i2c_start();
i2c_write(PCF8583_READ_ADDRESS);
bcd_sec = i2c_read();
bcd_min = i2c_read();
bcd_hrs = i2c_read();
bcd_day = i2c_read();
bcd_mon = i2c_read(0);
i2c_stop();
enable_interrupts(GLOBAL);
// Convert the date/time values from BCD to
// unsigned 8-bit integers. Unpack the bits
// in the PCF8583 registers where required.
dt->seconds = bcd2bin(bcd_sec);
dt->minutes = bcd2bin(bcd_min);
dt->hours = bcd2bin(bcd_hrs & 0x3F);
dt->day = bcd2bin(bcd_day & 0x3F);
dt->month = bcd2bin(bcd_mon & 0x1F);
dt->weekday = bcd_mon >> 5;
year_bits = bcd_day >> 6;
// Read the year byte from NVRAM.
// This is an added feature of this driver.
year = PCF8583_read_byte(PCF8583_YEAR_REG);
// Check if the two "year bits" were incremented by
// the PCF8583. If so, increment the 8-bit year
// byte (read from NVRAM) by the same amount.
while(year_bits != (year & 3))
year++;
dt->year = year;
// Now update the year byte in the NVRAM
// inside the PCF8583.
PCF8583_write_byte(PCF8583_YEAR_REG, year);
}
|
|
|