* Turn off watchdog timer */ #pragma config WDT=OFF /* Set oscillator mode to be HS (high speed) */ #pragma config OSC=HS #include //#include #include #include /* Frequency of the oscillator */ #define FOSC 4000000 /* Baud rate for serial communication */ #define BAUD_RATE 19200 /* Timer0 interval in microseconds */ #define TIMER0 500000 #define DATA_SIZE 16 /* ANSI escape sequences */ #define ANSI_ESC "\033[" #define ANSI_CLEAR_SCREEN (ANSI_ESC"2J") #define ANSI_CLEAR_LINE (ANSI_ESC"K") #define ANSI_SAVE_CURSOR (ANSI_ESC"s") #define ANSI_RESTORE_CURSOR (ANSI_ESC"u") /* A simple cyclic buffer implementation */ /* The size of such buffer is 2^5 = 32 */ #define BUF_BITS 5 #define BUF_SIZE (1 << BUF_BITS) #define BUF_MASK (BUF_SIZE - 1) /* Initialize buffer */ #define BUF_INIT(buf) \ do { \ (buf).head = (buf).tail = 0; \ } while (0) /* Pop an element from the head of the FIFO buffer */ #define BUF_GET(buf) \ ((buf).data[(buf).head++ & BUF_MASK]) /* Append an element into the end of the FIFO buffer */ #define BUF_ADD(buf, c) \ do { \ (buf).data[(buf).tail & BUF_MASK] = (c); \ (buf).tail++; \ } while (0) /* Append an array of elements into the buffer */ #define BUF_ADDSTR(buf, str) \ do { \ char __i; \ for(__i = 0; (str)[__i]; __i++) { \ BUF_ADD(buf, (str)[__i]); \ } \ } while(0) /* Test if the buffer is empty */ #define BUF_EMPTY(buf) \ (!(((buf).tail ^ (buf).head) & BUF_MASK)) /* Test if the buffer is full */ #define BUF_FULL(buf) \ (!((((buf).tail + 1) ^ (buf).head) & BUF_MASK)) /* Return the number of elements in the buffer */ #define BUF_LEN(buf) \ (((buf).tail - (buf).head) & BUF_MASK) /* A struct for the cyclic buffer */ struct buffer { char data[BUF_SIZE]; volatile char head; volatile char tail; }; /* Sending buffer */ struct buffer txbuf; /* Receiving buffer */ struct buffer rcbuf; /* Interrupt handler function */ void intr_handler(void); /* Setting interrupt entrance on PIC18 */ #pragma code intr_section = 0x8 void intr_entry(void) { _asm goto intr_handler _endasm } #pragma code /* Interrupt handler function */ #pragma interrupt intr_handler void intr_handler(void) { /* If the microcontroller received a byte */ if (PIR1bits.RCIF) { /* Add the byte into receiving buffer */ BUF_ADD(rcbuf, RCREG); } /* If the microcontroller sent a byte */ if (PIR1bits.TXIF) { /* If there is nothing to send (the sending buffer is empty) */ if (BUF_EMPTY(txbuf)) { /* Turn off sending interrupt */ PIE1bits.TXIE = 0; } else { /* Send the first byte in the sending buffer */ TXREG = BUF_GET(txbuf); } } if (INTCONbits.TMR0IF) { //INTCONbits.TMR0IF = 0; INTCONbits.TMR0IE = 0; } } /* Initialize serial port */ void uart_init(void) { unsigned int i; /* Set baud rate */ /* BRGH mode */ TXSTAbits.BRGH = 1; /* BRG16 mode */ BAUDCONbits.BRG16 = 0; /* Value of the SPBRG registor for the given baud rate. Check datasheet to make sure that the combination of BAUD_RATE,FOSC,BRGH,BRG16 produces a valid SPBRG. */ i = 64 >> ((TXSTAbits.BRGH + BAUDCONbits.BRG16) * 2); i = FOSC / BAUD_RATE / i - 1; SPBRGH = i >> 8; SPBRG = i & 0xFF; /* Configure the pins for UART */ TRISCbits.TRISC6 = 1; TRISCbits.TRISC7 = 1; /* Enable serial port */ RCSTAbits.SPEN = 1; /* Enable asynchronous mode */ TXSTAbits.SYNC = 0; /* Enable transmission (sending) */ TXSTAbits.TXEN = 1; /* Enable receiving */ RCSTAbits.CREN = 1; /* Enable interrupt priority */ RCONbits.IPEN = 1; /* Set high priority for sending and receiving interrupt */ IPR1bits.RCIP = 1; IPR1bits.TXIP = 1; /* Enable high priority interrupt */ INTCONbits.GIEH = 1; /* Enable receiving interrupt */ PIE1bits.RCIE = 1; /* Initialize receiving buffer */ BUF_INIT(rcbuf); /* Initialize sending buffer */ BUF_INIT(txbuf); } /* Initialize Timer0 */ void timer0_init(void) { /* Clock periods needed to get the time interval */ unsigned long i = (float)FOSC * TIMER0 / 1000000; /* TMR0ON T08BIT T0CS T0SE PSA T0PS2 T0PS1 T0PS0 */ T0CON = 0b10000000; /* Set prescaler */ if (i >> 16) { for (i >>= 1; i >> 16; i >>= 1, T0CON++); } else { T0CON |= 8; } /* Set TMR0 = 65536 - i, so after i periods, an interrupt will fire up */ i = (0xFFFF ^ i) + 1; TMR0H = i >> 8; TMR0L = i & 0xFF; /* Clear TMR0IF flag */ INTCONbits.TMR0IF = 0; /* Enable Timer0 interrupt */ INTCONbits.TMR0IE = 1; } /* Initialize ventricle sense */ void sense_init(void) { /* Set ventricle sense (pin33) to be input */ TRISBbits.TRISB0 = 1; } /* Initialize A/D converter */ void adc_init(void) { /* Enable ventricle sensing (MICRO_VENT_SENSE_BLANK_CNTL) */ TRISDbits.TRISD4 = 0; PORTDbits.RD4 = 1; /* Enable atrial sensing (MICRO_ATRIAL_SENSE_BLANK_CNTL) */ TRISDbits.TRISD5 = 0; PORTDbits.RD5 = 1; /* Set SCK to be output pin */ TRISCbits.TRISC3 = 0; /* Set SDI to be input pin */ TRISCbits.TRISC4 = 1; /* Set SDO to be output pin */ TRISCbits.TRISC5 = 0; /* Set SS to be input pin */ TRISAbits.TRISA5 = 1; } /* Read a number from A/D converter */ unsigned int adc_get(void) { unsigned int c = 0; char i; for (i = 0; i < 16; i++) { /* Flip clock line (SCK) */ PORTCbits.SCK = 0; PORTCbits.SCK = 1; /* Shift buffer */ c <<= 1; /* Read a bit and place it at the end of the buffer */ c |= PORTCbits.SDI; } return c; } /* Wait for A/D converter to be ready for reading */ void adc_start(void) { /* Ask if A/D converter is ready */ PORTCbits.SDO = 0; PORTCbits.SCK = 0; PORTCbits.SCK = 1; PORTCbits.SDO = 1; /* Wait for reply */ while (!PORTCbits.SDI); } /* Turn off the conversation with A/D converter */ void adc_stop(void) { PORTCbits.SCK = 0; PORTCbits.SDO = 0; } /* Convert an integer to string, similar to printf("%0nd", i) */ char *intstr(unsigned int i, char n) { static char buf[6]; char j; /* Get the least significant digit */ buf[4] = '0' + i % 10; buf[5] = 0; /* Get the rest digits */ for (i /= 10, j = 3; i; i /= 10, j--) { buf[j] = '0' + i % 10; } /* Fill the leading zeros */ n = (n >= 4 - j) ? n : (4 - j); for (; j > 4 - n; j--) { buf[j] = '0'; } return &buf[j + 1]; } /* Timer0 event handler */ void on_timer0(void) { char buf[6]; unsigned int d; float v; /* Reset Timer0 */ timer0_init(); /* Start conversation with A/D converter */ adc_start(); /* Save the current cursor position */ BUF_ADDSTR(txbuf, ANSI_SAVE_CURSOR); /* Get ventricle voltage */ v = 5.0 * adc_get() / 65535; /* Print integer part */ BUF_ADDSTR(txbuf, intstr(v, 0)); v = modf(v, (void *)0) * 1000; /* Print decimal point */ BUF_ADD(txbuf, '.'); /* Print decimal part */ BUF_ADDSTR(txbuf, intstr(v, 3)); BUF_ADD(txbuf, ' '); /* Get atrial voltage */ v = 5.0 * adc_get() / 65535; /* Print integer part */ BUF_ADDSTR(txbuf, intstr(v, 0)); v = modf(v, (void *)0) * 1000; /* Print decimal point */ BUF_ADD(txbuf, '.'); /* Print decimal part */ BUF_ADDSTR(txbuf, intstr(v, 3)); BUF_ADD(txbuf, ' '); /* Stop conversation with A/D converter */ adc_stop(); /* Print ventricle sensing bit */ BUF_ADD(txbuf, '0' + PORTBbits.RB0); BUF_ADD(txbuf, '\n'); /* Clear rest of the line */ BUF_ADDSTR(txbuf, ANSI_CLEAR_LINE); /* Restore cursor position */ BUF_ADDSTR(txbuf, ANSI_RESTORE_CURSOR); /* Enable sending interrupt */ PIE1bits.TXIE = 1; } /* UART event handler */ void on_uart(void) { char c; char d; BUF_ADDSTR(txbuf, "\n\r"); /* Read one byte from the receiving buffer */ c = BUF_GET(rcbuf); /* Get the first hex code of the byte */ d = c >> 4; d += (d < 10) ? '0' : ('a' - 10); /* Put the code in sending buffer */ BUF_ADD(txbuf, d); /* Get the second hex code of the byte */ d = c & 0xF; d += (d < 10) ? '0' : ('a' - 10); /* Put the code in sending buffer */ BUF_ADD(txbuf, d); BUF_ADD(txbuf, ' '); /* Now the sending buffer is non-empty, we enable transmission interrupt to send the contents in sending buffer */ PIE1bits.TXIE = 1; } char sData[DATA_SIZE];//buffer to hold information char checkSum;//checksum register struct mode { /* define a stucture for checking the function code */ char mode1; char mode2; }FnCode; /* Main entrance */ void main(void) { /* Initialize */ sense_init(); uart_init(); timer0_init(); adc_init(); /* Clear screen and append a string to sending buffer */ BUF_ADDSTR(txbuf, ANSI_CLEAR_SCREEN); /* Enable sending interrupt */ PIE1bits.TXIE = 1; FnCode.mode1='a'; /* define two actually fields for the function code stucture*/ FnCode.mode2='b'; while (1) { /* If the receiving buffer is not empty and there is enough space in the sending buffer */ if (!BUF_EMPTY(rcbuf)&&BUF_GET(rcbuf) == 0x16) { //check buffer empty and rcbuf scan for 0x16 int index =-1; checkSum = 0x00; //initial checksum //writing sData from rcbuf(receiving buffer) while(index++ < 16){ sData[index] = BUF_GET(rcbuf); if(index>2 && index<14) checkSum ^= sData[index];//calculate checksum } if (checkSum != sData[15]) return 1;//compare checksumm } if (sData[1]==FnCode.mode1) /*check if the function code is vaild or not*/ BUF_ADDSTR(txbuf,"valid fncode"); else if (sData[1]==FnCode.mode2) BUF_ADDSTR(txbuf,"invalid fncode"); if (BUF_LEN(txbuf) + 16 < BUF_SIZE) { //checking if txbuf has enough space to hold data package int index = -1; checkSum = 0x00; //initial checksum //writing txbuf(transfer buffer)with information in sData while(index++<16){ if(index==15) sData[index] = checkSum;//write checksum to the last char in sData BUF_ADDSTR(txbuf,sData); if(index>2&&index<14) checkSum ^= sData[index]; //calculate checksum } PIE1bits.TXIE = 1; //pull up transfer register } /* Put the microcontroller in idle mode */ /* WARNING: If you want to debug the code with MPLAB Sim, you need to remove the following two lines, since MPLAB Sim cannot be waked up in idle mode by UART interrupt */ //OSCCONbits.IDLEN = 1; //Sleep(); } }