// // adproj.c Analog to Digital test program for the // 68HC12. // // This file is written using Imagecraft's icc12 // compiler. // // Written as part of an Encoder article for the // seattle robotics society. See www.seattlerobotics.org // for details. // #include #include #define TRUE -1 #define FALSE 0 int g_CurrentChannel; int g_CurrentValue; void InitializeSystem() { // The 68HC12 COP (Watchdog timer) needs to be disabled COPCTL = 0; // Turn of the COP // Turn on the serial port setbaud(13); // Set to 19200 baud // Power up the A/D converter ATDCTL2 |= 0x80; // Turn on the TCNT timer TSCR |= 0x80; // Initialize global variables g_CurrentChannel = 0; g_CurrentValue = -1; } // Single channel scan returns the average A/D result for channel iChannel int SingleChannelScan(int iChannel) { int iSum = 0; int i; unsigned char *pADR = (unsigned char *)&(ADR0H); if((iChannel < 0) || (iChannel > 7)) { // Something bad has happened return -1; } // // Perform a single channel A/D read cycle. By setting the // S8CM bit, the single channel is sampled 8 times consecutively // The low 3 bits determine which channel is going to be sampled // and is derived from the argument passed to this function. // // The 8 results are stored in registers ADR0 thru ADR7 // // This provides a quick way of grabbing an average value // // Writing to ATDCTL5 will initiate the conversion ATDCTL5 = 0x40 + iChannel; // Now we wait for the SCF (Sequence Complete Flag) of ATSTAT to be // set. When it is set, then the result registers are valid while( !(ATDSTAT & 0x8000)); // The results are now in ADR0 thru ADR7. ADR0 thru ADR7 are // aligned on word boundaries (70,72,74,76...), so we do some // extra math on the index for (i = 0 ; i < 8 ; i++) { iSum += pADR[i<<1]; } iSum = iSum >> 3; // Divide sum by 8 to determine average return iSum; } void RunSingleChannelTest(int iChannel) { char ch; int iNewValue; iNewValue = SingleChannelScan(iChannel); // Report the changed value printf("(%x) Single Channel 0x%x: 0x%x\n",TCNT,iChannel,iNewValue); } void RunMultiChannelTest() { int i; unsigned char *pResult = (unsigned char *) &(ADR0H); printf("(%x) Multi Channel Scan \n",TCNT); // Put the A/D converter into SC8M | MULT and let it rip ATDCTL5 = 0x50; // Now we wait for the SCF (Sequence Complete Flag) of ATSTAT to be // set. When it is set, then the result registers are valid while( !(ATDSTAT & 0x8000)); // // Print out the results // for(i=0;i<8;i++) { printf("Channel %u = 0x%x\n",i,pResult[i<<1]); } return ; } // // The idea being this program is simple. On the RS-232 line, just press // the numeric key of the channel you wish to sample. To get all of the // channels using Multi-channel mode, press 'm' // void main() { int ch; InitializeSystem(); printf("adproj started\n"); for(;;) { ch = getchar(); printf("ch = %x '%c'\n",ch,ch); switch(ch) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': { RunSingleChannelTest(ch - '0'); break; } case 'm': { RunMultiChannelTest(); break; } default: printf("Press number (0-7) for single channel\n"); printf("Press 'm' for multi-channel\n"); } } } /* As is, all interrupts except reset jumps to 0xffff, which is most * likely not going to useful. To replace an entry, declare your function, * and then change the corresponding entry in the table. For example, * if you have a SCI handler (which must be defined with * #pragma interrupt_handler ...) then in this file: * add * extern void SCIHandler(); * before th table. * In the SCI entry, change: * DUMMY_ENTRY, * to * SCIHandler, */ extern void _start(); /* entry point in crt??.s */ #define DUMMY_ENTRY (void (*)())0xFFFF #pragma abs_address:0xffd0 /* change the above address if your vector starts elsewhere */ void (*interrupt_vectors[])() = { /* to cast a constant, say 0xb600, use (void (*)())0xb600 */ DUMMY_ENTRY, /* BDLC */ DUMMY_ENTRY, /* ATD */ DUMMY_ENTRY, /* RESERVED */ DUMMY_ENTRY, /* SCI */ DUMMY_ENTRY, /* SPI */ DUMMY_ENTRY, /* PAIE */ DUMMY_ENTRY, /* PAO */ DUMMY_ENTRY, /* TOF */ DUMMY_ENTRY, /* TOC5 */ /* HC12 TC7 */ DUMMY_ENTRY, /* TOC4 */ /* TC6 */ DUMMY_ENTRY, /* TOC3 */ /* TC5 */ DUMMY_ENTRY, /* TOC2 */ /* TC4 */ DUMMY_ENTRY, /* TOC1 */ /* TC3 */ DUMMY_ENTRY, /* TIC3 */ /* TC2 */ DUMMY_ENTRY, /* TIC2 */ /* TC1 */ DUMMY_ENTRY, /* TIC1 */ /* TC0 */ DUMMY_ENTRY, /* RTI */ DUMMY_ENTRY, /* IRQ */ DUMMY_ENTRY, /* XIRQ */ DUMMY_ENTRY, /* SWI */ DUMMY_ENTRY, /* ILLOP */ DUMMY_ENTRY, /* COP */ DUMMY_ENTRY, /* CLM */ _start /* RESET */ }; #pragma end_abs_address // End of file