// Microsystems on Silicon(Pty) Ltd. // M2012A DOCI to RS232 SERIAL INTERFACE // Version 1 made for m2012a1_smd1.pcb // 24 Feb 2003 #define alog(x) (1<<(x)) //#define DEBUG 1 #include <pic.h> #define TX_LED_OUT 0b00000001 // Transmit LED output #define RX_LED_OUT 0b00000010 // Receive LED output #define ERROR_LED_OUT 0b00000100 // Error LED output #define RUN_LED_OUT 0b00100000 // RUN LED output #define CS_OUT 0b00000010 // Chip select/Load to DAC #define SCK_OUT 0b00001000 // Clock output for DAC #define MOSI_OUT 0b00100000 // Data output to DAC #define RX_OUT 0b01000000 // RS232 PIC Transmit PC RX #define TX_IN 0b10000000 // RS232 PIC Receive PC TX #define DOCI_BID 0b00010000 // Bidirectional data/clock for 1st DPIR #define INTR_OUT 0b00000001 // Toggle output on interrupt #define NOP() asm("nop") #define PORTBIT(p,b) ((unsigned)&(p)*8+(b)) // Port A assignments static bit TX_LED @ PORTBIT(PORTA,0); static bit RX_LED @ PORTBIT(PORTA,1); static bit RUN_LED @ PORTBIT(PORTA,2); static bit ERROR_LED @ PORTBIT(PORTA,5); static bit PC0 @ PORTBIT(PORTC,0); // Input static bit CS @ PORTBIT(PORTC,1); static bit PC2 @ PORTBIT(PORTC,2); static bit SCK @ PORTBIT(PORTC,3); static bit PC4 @ PORTBIT(PORTC,4); static bit MOSI @ PORTBIT(PORTC,5); static bit RX @ PORTBIT(PORTC,6); static bit TX @ PORTBIT(PORTC,7); static bit DOCI @ PORTBIT(PORTB,4); static bit INTR @ PORTBIT(PORTB,0); //---------------------------------------------------------------------- #define SENSORS 1 // RS232 sensor strings to send //could be up to 8 #define HEADER_BYTES 3 // Header + Device Info + amount of bytes #define DEV_INFO 1 // Device type only 7 bits #define IGNORE_INTRRUPTS_FROM_DPIR 0 // Interrupts to ignore from sensors //------------------------------------------------------------------------- #define HEADER 0xA5 // Header byte for serial packet #define MAX_SLOTS (SENSORS*2)+HEADER_BYTES #define SERIAL_SPEED 9 //18.432MHz 115.2kbps High speed #define LED_ON 0 #define LED_OFF 1 unsigned char que[MAX_SLOTS+1]; // array that makes up the que in memory pir_temp[j] unsigned int t, pir_data; // variable with PIR movement data unsigned char new_portb; // sample port B unsigned char old_portb; // sample port B unsigned char elements; // amount of elements in buffer maximum is MAX_SLOTS+1 unsigned char read_skip; // If serial data is too much some interrupts will be ignored unsigned char i; // Temp variable unsigned char n; // Temp Variable unsigned int mask; // Mask for shift out unsigned char rank; // rank in the array that is set via serial port unsigned int cnt; // Counter for Run LED //------------------------------------------------------------------------- // Do initialization of the micro controller //------------------------------------------------------------------------- void do_startup(void) { //processor setup // (1 is input, 0 is output) TRISA=0x00; // (ONLY 6 PINS) TRISB=0x00; // upper bits of portB is outputs for change on interrupt TRISC=0x00; //Port B TRISB|=DOCI_BID; // Only one input TRISB&=~INTR_OUT; // Shows interrupts by the M2012A //Port A TRISA&=~TX_LED_OUT; // TRISA&=~RX_LED_OUT; // TRISA&=~ERROR_LED_OUT; // TRISA&=~RUN_LED_OUT; // //Port C TRISC&=~SCK_OUT; // used with DAC TRISC&=~MOSI_OUT; TRISC&=~CS_OUT; TRISC&=~RX_OUT; // Names as PC sees it TRISC|=TX_IN; // Names as PC sees it ADCON1=0x07; // RE and RA pins to digital IOs RBPU=1; // Disable RB pull ups INTEDG=0; // 1==Rising edge of RB0 T0CS=0; // Timer0 clock source = internal T0SE=0; // Timer0 source edge = falling // not used PSA=0; // Prescalers assigned to WDT PS2=0; // Timer is set to 1:128 PS1=0; PS0=0; CLRWDT(); GIE=0; // Disable all interrupts PEIE=0; // Peripheral int enable T0IE=0; // Timer interrupt enable INTE=0; // RB0 interrupt RBIE=1; // Port B change interrupt T0IF=0; // Clear timer0 interrupt flag INTF=0; // Clear Port B interrupt flag RBIF=0; // Clear Port B change interrupt flag ADIE=0; // A/D int RCIE=0; // USART receive int TXIE=0; // USART transmit int SSPIE=0; // Serial port int CCP1IE=0; // Comp disable bit TMR2IE=0; // Timer 2 match int TMR1IE=0; // Timer 1 overflow match int ADIF=0; RCIF=0; TXIF=1; SSPIF=0; CCP1IF=0; TMR2IF=0; TMR1IF=0; BRGH=1; SPBRG=SERIAL_SPEED; SYNC = 0; // Set to async port SPEN = 1; // Enable serial port TXEN=1; // Enable transmit CREN=0; // 1 = Continuous RX enable TXIE=0; // Disable Transmit Interrupt RCIE=0; //1 = Enable Receive Interrupt PEIE=1; // Enable peripheral interrupts EEIE=0; // EEPROM int BCLIE=0; // int CCP2IE=0; //int EEIF=0; BCLIF=0; CCP2IF=0; GIE=1; // Enable all interrupts // Program variables TX_LED=LED_OFF; RX_LED=LED_OFF; ERROR_LED=LED_OFF; RUN_LED=LED_OFF; read_skip=IGNORE_INTRRUPTS_FROM_DPIR; CS=1; } //========================================================================= static void interrupt __INT(void) { new_portb=PORTB; RBIF=0; } //========================================================================= // This leaves the MOS bus in a state where the sensor can generate an interrupt //========================================================================= void clear_DOCI_interrupt(void) { //Release the DOCI Line leave in zero state DOCI=0; // Clear DOCI Pin TRISB&=~DOCI_BID; // DOCI Output pin NOP(); TRISB|=DOCI_BID; // DOCI Input pins high impedance } //========================================================================= // Put micro controller in a sleep state //========================================================================= void goto_sleep(void) { old_portb=PORTB; // Save state of port B SLEEP(); } //========================================================================= // Send a 16 bit word to a 16 bit DAC LT1655 // Procedure was used for debugging //========================================================================= void load_dac(int dat) { CS=0; NOP(); mask=0x8000; for(n=0;n<16;n++) { if(dat&mask) MOSI=1; else MOSI=0; dat<<=1; // Clock bit in DAC SCK=1; NOP(); NOP(); SCK=0; } NOP(); CS=1; } //========================================================================= // Read filter from M2012A // DOCI is a IO pin // DOCI_BID is a bit pattern that set or clear the direction // of the IO pad on the processor //========================================================================= unsigned int dpir_filt_rd(void) { unsigned char n; // Wait for at least 1 device clock on the sensor before loading NOP(); NOP(); NOP(); NOP(); NOP(); // NOP(); NOP(); NOP(); NOP(); NOP(); // The micro controller takes much longer than a clock cycle on the M2012A // to wake up from sleep mode. So the delay here is not a problem pir_data=0; // this is the word that will contain the data from the M2012A for(n=0;n<15;n++) // There are 15 bits of data from the sensors { DOCI=0; // Clear DOCI pin TRISB&=~DOCI_BID; // DOCI pin output NOP(); // Wait a bit DOCI=1 ; // Set DOCI pin TRISB|=DOCI_BID; // DOCI Pin input pir_data<<=1; // make room for first bit NOP(); NOP(); // Wait before sampling the DOCI pin if(DOCI) // Test DOCI pin pir_data++; // Set LSB } return pir_data; // pir_data holds sensor info } //========================================================================= void pack_data(void) { unsigned int x; unsigned char sensors; // PCB uses only 1 sensor, the header and PC SW will accept more inputs from sensors // This was kept in to stay compatible with the windows scope program sensors=SENSORS; elements=0; rank=(sensors*2)+HEADER_BYTES; // positions in the array //rank=MAX_SLOTS; que[rank--]=HEADER; // Identification byte elements++; que[rank--]=(DEV_INFO<<1); // Device info for windows SW elements++; que[rank--]=rank+2; // Total packet length elements++; // This part makes provision for multiple sensors for(n=0;n<sensors;n++) { t=pir_data; x=t&0xff00; x>>=8; que[rank--]=(unsigned char)x; elements++; que[rank--]=(unsigned char)t&0x00ff; elements++; } } //========================================================================= void main(void) { do_startup(); clear_DOCI_interrupt(); while(1) { CLRWDT(); INTR^=1; if(cnt++>50) { RUN_LED^=1; // Show some activity cnt=0; } if(!read_skip--) { read_skip=IGNORE_INTRRUPTS_FROM_DPIR; //Could skip some interrupts if needed dpir_filt_rd(); // Read the Digital PIR clear_DOCI_interrupt(); // Leave port B in high Z state ready for interrupts pack_data(); // Put PIR data in a array // load_dac(pir_data); // Send data to the DAC (Only for debugging) while(elements>0) // Amount of elements comes from pack_data() { if(TRMT) // Transmit buffer Empty { TX_LED=LED_ON; TXREG=que[elements--]; // send next element } if(elements==0) //Finished with the transmission TX_LED=LED_OFF; } } while(!TRMT) //wait here until serial data is sent NOP(); clear_DOCI_interrupt(); // Leave port B in high Z state ready for interrupts goto_sleep(); } }