// Chapter 2 9S12C32 C programs // Jonathan W. Valvano, 2/07/07 // This software accompanies the book, // Embedded Microcomputer Systems: Real Time Interfacing, Second Edition // published by Thomson Engineering, 2006 #define size 10 short data[size]; void initialize(void){ short j for(j=0;j<10;j++) data[j]=0; }; // Program 2.8 An inappropriate use of #define. #define size 10 short data[size]; void initialize(void){ short j for(j=0;jOut; Timer_Wait10ms(Pt->Time); Input = PORTA&0x03; Pt = Pt->Next[Input]; } } //Program 2.11. Two 6812 C implementations of a Moore FSM. // outputs defined as numbers const struct State{ unsigned char Out[4]; // outputs const struct State *Next[4]; // Next }; typedef const struct State StateType; #define Standing &fsm[0] #define Sitting &fsm[1] #define Sleeping &fsm[2] #define None 0x00 #define SitDown 0x08 // pulse on PB3 #define StandUp 0x04 // pulse on PB2 #define LieDown 0x02 // pulse on PB1 #define SitUp 0x01 // pulse on PB0 StateType FSM[3]={ {{None,SitDown,None,None}, //Standing {Standing,Sitting,Standing,Standing}}, {{None,LieDown,None,StandUp}, //Sitting {Sitting,Sleeping,Sitting,Standing }}, {{None,None,SitUp,SitUp}, //Sleeping {Sleeping,Sleeping,Sitting,Sitting}} }; void main(void){ StatePtr *Pt; // Current State unsigned char Input; DDRB = 0xFF; // Output to robot DDRA &= ~0x03; // Input from sensor Pt = Standing; // Initial State while(1){ Input = PORTA&0x03; // Input=0-3 PORTB = Pt->Out[Input]; // Pulse PORTB = 0; Pt = Pt->Next[Input]; // next state } } // outputs defined as functions const struct State{ void (*CmdPt)[4](void); // outputs const struct State *Next[4]; // Next }; typedef const struct State StateType; #define Standing &fsm[0] #define Sitting &fsm[1] #define Sleeping &fsm[2] void None(void){}; void SitDown(void){ PORTB=0x08; PORTB=0;} // pulse on PB3 void StandUp(void){ PORTB=0x04; PORTB=0;} // pulse on PB2 void LieDown(void){ PORTB=0x02; PORTB=0;} // pulse on PB1 void SitUp(void) { PORTB=0x01; PORTB=0;} // pulse on PB0 StateType FSM[3]={ {{&None,&SitDown,&None,&None}, //Standing {Standing,Sitting,Standing,Standing}}, {{&None,&LieDown,&None,&StandUp},//Sitting {Sitting,Sleeping,Sitting,Standing }}, {{&None,&None,&SitUp,&SitUp}, //Sleeping {Sleeping,Sleeping,Sitting,Sitting}} }; void main(void){ StatePtr *Pt; // Current State unsigned char Input; DDRB = 0xFF; // Output to robot DDRA &= ~0x03; // Input from sensor Pt = Standing; // Initial State while(1){ Input = PORTA&0x03; // Input=0-3 (*Pt->CmdPt[Input])(); // function Pt = Pt->Next[Input]; // next state } } //Program 2.13. Two C implementation of a Mealy Finite State Machine. unsigned int Median (unsigned int ul, unsigned int u2, unsigned int u3) { unsigned int result; printf("The inputs are %d, %d, %d.\n",u1,u2,u3); if(u1>u2) if(u2>u3) result=u2; // u1>u2,u2>u3 u1>u2>u3 else if(u1>u3) result=u3; // u1>u2,u3>u2,u1>u3 u1>u3>u2 else result=u1; // u1>u2,u3>u2,u3>u1 u3>u1>u2 else if(u3>u2) result=u2; // u2>u1,u3>u2 u3>u2>u1 else if(u1>u3) result=u1; // u2>u1,u2>u3,u1>u3 u2>u1>u3 else result=u3; // u2>u1,u2>u3,u3>u1 u2>u3>u1 printf("The median is %d.\n",result); return(result): } // Program 2.16 A median function that is not very portable. void SCI_Init(unsigned short baudRate); // Enable serial port char SCI_InChar(void); // Input an ASCII character void SCI_InString(char *buffer, unsigned short maxSize); // Input a String unsigned short SCI_InUDec(void); // Input a 16-bit number void SCI_OutChar(char letter); // Output an ASCII character void SCI_OutUDec(unsigned short number); // Output a 16-bit number void SCI_OutString(char *buffer); // Output String //-------------------------SCI_Init------------------------ // Initialize Serial port SCI // Input: baudRate is the baud rate in bits/sec // Output: none void SCI_Init(unsigned short baudRate); //-------------------------SCI_InChar------------------------ // Wait for new serial port input // Input: none // Output: ASCII code for key typed char SCI_InChar(void); //-------------------------SCI_InString------------------------ // Wait for a sequence of serial port input // Input: maxSize is the maximum number of characters to look for // Output: Null-terminated string in buffer void SCI_InString(char *buffer, unsigned short maxSize); //----------------------SCI_InUDec------------------------------- // InUDec accepts ASCII input in unsigned decimal format // and converts to a 16-bit unsigned number (0 to 65535) // Input: none // Output: 16-bit unsigned number unsigned short SCI_InUDec(void); //-------------------------SCI_OutChar------------------------ // Output 8-bit to serial port // Input: letter is an 8-bit ASCII character to be transferred // Output: none void SCI_OutChar(char letter); //-------------------------SCI_OutString------------------------ // Output String (NULL termination) // Input: pointer to a NULL-terminated string to be transferred // Output: none void SCI_OutString(char *buffer); //-----------------------SCI_OutUDec----------------------- // Output a 16-bit number in unsigned decimal format // Input: 16-bit number to be transferred // Output: none // Variable format 1-5 digits with no space before or after void SCI_OutUDec(unsigned short number); #include "HC12.H" #include "LCD12.H" #include "Timer.H" void main(void){ char letter; int n=0; LCD_Init(); Timer_Init(); LCD_String("LCD"); Timer_MsWait(1000); LCD_clear(); letter='a'-1; while(1){ if (letter=='z') letter='a'; else letter++; LCD_putchar(letter); Timer_MsWait(250); if(++n==16){ n=0; LCD_clear(); } } } // Program 2.19 Main program with three modules. void Timer_Init(void); void Timer_Wait10ms(unsigned short delay); // Program 2.20 Timer.H header file has public functions. unsigned short CyclesPerMs; // private global void Clock_Init(void){ // public function TSCR1 |=0x80; // TEN(enable) CyclesPerMs = 4000; // 4000 counts per ms } void wait(unsigned short cycles){ // private function unsigned short startTime = TCNT; while((TCNT-startTime) <= cycles){} // wait 10ms } void Clock_MsWait(unsigned short time){ // public function for(;time>0;time--){ wait(CyclesPerMs); // 1.00ms wait } } //Program 2.21. Clock.C implementation file defines all functions /* 6812 Port M bits 1,0 are input, Port T bits 1,0 are output */ #define OutPort (*(unsigned char volatile *)(0x0240)) #define OutDDR (*(unsigned char volatile *)(0x0242)) #define InPort (*(unsigned char volatile *)(0x0250)) #define InDDR (*(unsigned char volatile *)(0x0252)) void main(void){ STyp *Pt; // state pointer unsigned char Input; Timer_Init(); // enable TCNT OutDDR = 0xFF; InDDR &= ~0x03; Pt = goN; while(1){ OutPort = Pt->Out; Timer_Wait10ms(Pt->Time); Input = InPort&0x03; Pt = Pt->Next[Input]; } } //Program 2.22. Enhanced C implementation of the Traffic Light FSM. // a DDRAddress of 1 means fixed output port with no DDR // a DDRAddress of 0 means fixed input port with no DDR template class port{ protected : unsigned char *PortAddress; // pointer to data unsigned char *DDRAddress; // pointer to data direction register public : port(unsigned short ThePortAddress, unsigned short TheDDRAddress){ PortAddress = (unsigned char *)ThePortAddress; // pointer to I/O port DDRAddress = (unsigned char *)TheDDRAddress; // pointer to DDR } virtual short Initialize(unsigned char data){ if((int)DDRAddress==1){ // fixed output port return(data==0xFF); // OK if initializing all bits to output } if(DDRAddress==0){ // fixed input port return(data==0); // OK if initializing all bits to input } (*DDRAddress) = data; // configure direction register return 1; // successful } virtual void put(unsigned char data){ if((int)DDRAddress==0) return; // fixed input if((*DDRAddress)==0) return; // all input (*PortAddress) = data; // output data to port } virtual unsigned char get(void){ return (*PortAddress); // input data from port } /* 6812 Port M bits 1,0 are input, Port T bits 1,0 are output */ port OutPort(0x0240,0x0242); port InPort(0x0250,0x0252); void main(void){ StateType *Pt; unsigned char Input; Pt=SA; // Initial State OutPort.Initialize(0xFF); // Make Output port outputs InPort.Initialize(0x00); // Make Input port inputs Timer_Init(); // Enable TCNT while(1){ OutPort.put(Pt->Out); Timer_Wait10ms(Pt->Time); // Time to wait in this state Input=InPort.get()&0x03; // Input=0,1,2,or 3 Pt=Pt->Next[Input]; } //Program 2.23. C++ implementation of the Traffic Light FSM. T operator = (T data){ put(data); // output to port return data; // returns data itself } operator T () (T data){ return get(); // returns port data } virtual T operator |= (T data){ put(data |= get()); // read modify write port access return data; // returns new data } virtual T operator &= (T data){ put(data &= get()); // read modify write port access return data; // returns new data } virtual T operator ^= (T data){ put(data ^= get()); // read modify write port access return data; // returns new data } // Program 2.24 Additional member functions for the I/O port class. // global variables in RAM #define size 20 unsigned char buffer[size][2]; unsigned int cnt=0; // dump happy and sad void Save(void){ if(cnt100){ if(cnt0) { profile(1); t = 32; // initial guess 2.0 do{ profile(2); oldt = t; // calculation from the last iteration t = ((t*t+16*s)/t)/2;} // t is closer to the answer while(t!=oldt);} // converges in 4 or 5 iterations profile(3); return t; } // Program 2.34 A time/ position profile dumping into a data array. unsigned int sqrt(unsigned int s){ unsigned int t,oldt; PTT=0; t = 0; // based on the secant method if(s>0) { PTT=1; t = 32; // initial guess 2.0 do{ PTT=2; oldt = t; // calculation from the last iteration t = ((t*t+16*s)/t)/2;} // t is closer to the answer while(t!=oldt);} // converges in 4 or 5 iterations PTT=3; return t; } // Program 2.35 A time/position profile using two output bits. // programs from first edition // Program 2.2. An inappropriate use of #define. #define size 10 short data[size]; void initialize(void){ short j for(j=0;j<10;j++) data[j]=0; }; // Program 2.3. An appropriate use of #define. #define size 10 short data[size]; void initialize(void){ short j for(j=0;j0); /* wait */ }; void main(void){ StatePtr *Pt; /* Current State */ unsigned char Input; Pt=SA; /* Initial State */ DDRC=0x08; /* PortC bit3 is output */ while(1){ Wait(Pt->Time); /* Time to wait in this state */ Input=PORTC<<7; /* Input=0 or 1 */ PORTC=Pt->Out[Input]; /* Perform output for this state */ Pt=Pt->Next[Input]; /* Move to the next state */ }}; // Program 2.6. 6812 C implementation of a Moore Finite State Machine. /* PortC bits 1,0 are input, Port B bits 1,0 are output */ const struct State { unsigned char Out; /* Output to Port B */ unsigned int Time; /* Time in 100 µsec to wait in this state */ const struct State *Next[4]; /* Next state if input=0,1,2,3 */ }; typedef const struct State StateType; #define SA &fsm[0] #define SB &fsm[1] #define SC &fsm[2] StateType fsm[3]={ {0x01, 4000,{SB,SA,SB,SC}}, /* SA out=1, wait= 500usec, next states */ {0x02, 8000,{SC,SA,SB,SC}}, /* SB out=2, wait=1000usec, next states */ {0x03,16000,{SA,SA,SB,SA}} /* SC out=3, wait=2000usec, next states */ }; void Wait(unsigned int delay){ int Endt; Endt=TCNT+delay; /* Time (125ns cycles) to wait */ while((Endt-(int)TCNT)>0); /* wait */ }; void main(void){ StatePtr *Pt; /* Current State */ unsigned char Input; Pt=SA; /* Initial State */ DDRB=0xFF; /* Make Port B outputs */ DDRC=0x00; /* Make Port C inputs */ TSCR=0x80; /* Enable TCNT, default rate 8 MHz */ while(1){ PORTB=Pt->Out; /* Perform output for this state */ Wait(Pt->Time); /* Time to wait in this state */ Input=PORTC&0x03; /* Input=0,1,2,or 3 */ Pt=Pt->Next[Input]; /* Move to next state */ } }; // Program 2.7: A median function that is not very portable. unsigned int Median(unsigned int u1,unsigned int u2,unsigned int u3){ unsigned int result; printf("The inputs are %d, %d, %d.\n",u1,u2,u3); if(u1>u2) if(u2>u3) result=u2; // u1>u2,u2>u3 u1>u2>u3 else if(u1>u3) result=u3; // u1>u2,u3>u2,u1>u3 u1>u3>u2 else result=u1; // u1>u2,u3>u2,u3>u1 u3>u1>u2 else if(u3>u2) result=u2; // u2>u1,u3>u2 u3>u2>u1 else if(u1>u3) result=u3; // u2>u1,u2>u3,u1>u3 u2>u1>u3 else result=u1; // u2>u1,u2>u3,u3>u1 u2>u3>u1 printf("The median is %d.\n",result); return(result):} // Program 2.14: C implementation of SCI basic input/output. // 68HC812A4 SCI routines void init(void) { SC0BD=417; // 1200 baud SC0CR1=0x00; // 8data, 1stop SC0CR2=0x0C;} // enable gadfly #define RDRF 0x20 #define TDRE 0x80 #define TC 0x40 unsigned char insci(void){ while ((SC0SR1 & RDRF) == 0); return(SC0DRL); } /* letter is character to print, */ void OutChar(unsigned char letter){ /* Wait for TDRE then output */ while ((SC0SR1 & TDRE) == 0); SC0DRL=letter; } //Program 2.18. Main program with three modules. #include "HC12.H" #include "LCD12.H" #include "COP12.H" #include "Timer.H" void main(void){ char letter; int n=0; COPinit(); // Enable TOF interrupt to make COP happy LCDinit(); TimerInit() LCDString("Adapt812 LCD"); TimerMsWait(1000); LCDclear(); letter='a'-1; while(1){ if (letter=='z') letter='a'; else letter++; LCDputchar(letter); TimerMsWait(250); if(++n==16){ n=0; LCDclear(); }}} #include "LCD12.C" #include "COP12.C" #include "Timer.C" #include "VECTORS.C" // Program 2.19: Timer.H header file has public functions void TimerInit(void); void TimerMsWait(unsigned int time); // Program 2.20: Timer.C implementation file defines all functions unsigned int TimerClock; // private global void TimerInit(void){ // public function TSCR |=0x80; // TEN(enable) TMSK2=0xA2; // TOI arm, TPU(pullup) timer/4 (500ns) TimerClock=2000; // 2000 counts per ms } void TimerWait(unsigned int time){ // private function TC5=TCNT+TimerClock; // 1.00ms wait TFLG1 = 0x20; // clear C5F while((TFLG1&0x20)==0){};} void TimerMsWait(unsigned int time){ // public function for(;time>0;time--) TimerWait(TimerClock); // 1.00ms wait } // Program 2.21. Enhanced C implementation of a Mealy Finite State Machine. /* 6812 PortC bits 1,0 are input, Port B bits 1,0 are output */ #define OutPort (*(unsigned char volatile *)(0x0001)) #define OutDDR (*(unsigned char volatile *)(0x0003)) #define InPort (*(unsigned char volatile *)(0x0004)) #define InDDR (*(unsigned char volatile *)(0x0006)) /* rate is the number of cycles/100usec */ #define rate 800 const struct State{ unsigned char Out; /* Output values */ unsigned int Time; /* Time in 100 µsec to wait in this state */ const struct State *Next[4]; /* Next state if input=0,1,2,3 */ }; typedef const struct State StateType; #define SA &fsm[0] #define SB &fsm[1] #define SC &fsm[2] StateType fsm[3]={ {0x01,5*rate,{SB,SA,SB,SC}}, /* SA out=1, wait= 500usec, next states */ {0x02,10*rate,{SC,SA,SB,SC}}, /* SB out=2, wait=1000usec, next states */ {0x03,20*rate,{SA,SA,SB,SA}} /* SC out=3, wait=2000usec, next states */ }; void Wait(unsigned int delay){ int Endt; Endt=TCNT+delay; /* Time (125ns cycles) to wait */ while((Endt-(int)TCNT)>0); /* wait */ }; void main(void){ StateType *Pt; unsigned char Input; Pt=SA; /* Initial State */ OutDDR=0xFF; /* Make Output port outputs */ InDDR=0x00; /* Make Input port inputs */ TSCR=0x80; /* Enable TCNT, default rate 8 MHz */ while(1){ OutPort=Pt->Out; Wait(Pt->Time); /* Time to wait in this state */ Input=InPort&0x03; /* Input=0,1,2,or 3 */ Pt=Pt->Next[Input]; } }; // Program 2.22. C++ implementation of a Mealy Finite State Machine. // a DDRAddress of 1 means fixed output port with no DDR // a DDRAddress of 0 means fixed input port with no DDR template class port{ protected : unsigned char *PortAddress; // pointer to data unsigned char *DDRAddress; // pointer to data direction register public : port(unsigned short ThePortAddress, unsigned short TheDDRAddress){ PortAddress = (unsigned char *)ThePortAddress; // initialize pointer to I/O port DDRAddress = (unsigned char *)TheDDRAddress;} // initialize pointer to DDR virtual short Initialize(unsigned char data){ if((int)DDRAddress==1) // fixed output port return(data==0xFF); // OK if initializing all bits to output if(DDRAddress==0) // fixed input port return(data==0); // OK if initializing all bits to input (*DDRAddress) = data; // configure direction register return 1;} // successful virtual void put(unsigned char data){ if((int)DDRAddress==0) return; // fixed input if((*DDRAddress)==0) return; // all input (*PortAddress) = data;} // output data to port virtual unsigned char get(void){ return (*PortAddress);} // input data from port } // 6812 PortC bits 1,0 are input, Port B bits 1,0 are output port OutPort(0x0001,0x0003); port InPort(0x0004,0x0006); void main(void){ StateType *Pt; unsigned char Input; Pt=SA; // Initial State OutPort.Initialize(0xFF); // Make Output port outputs InPort.Initialize(0x00); // Make Input port inputs TSCR=0x80; // Enable TCNT, default rate 8 MHz while(1){ OutPort.put(Pt->Out); Wait(Pt->Time); // Time to wait in this state Input=InPort.get()&0x03; // Input=0,1,2,or 3 Pt=Pt->Next[Input]; } // Program 2.23. Additional member functions for the I/O port class. T operator = (T data){ put(data); // output to port return data;} // returns data itself operator T () (T data){ return get();} // returns port data virtual T operator |= (T data){ put(data |= get()); // read modify write port access return data;} // returns new data virtual T operator &= (T data){ put(data &= get()); // read modify write port access return data;} // returns new data virtual T operator ^= (T data){ put(data ^= get()); // read modify write port access return data;} // returns new data // Program 2.24: Recursion is when a function calls itself. //-----------------------Start of OutUDec------------------------------------- // Output a 16 bit number in unsigned decimal format // Variable format 1 to 5 digits with no space before or after // This function uses recursion to convert a decimal number of // unspecified length as an ASCII string void OutUDec(unsigned int number){ if (number>=10){ OutUDec(number/10); OutUDec(number%10); } else OutChar(number+'0'); } // Program 2.27: Empirical measurement of dynamic efficiency in C. unsigned short before,elasped; void main(void){ ss=100; before=TCNT; tt=sqrt(ss); elasped=TCNT-before; } // Program 2.29. Another empirical measurement of dynamic efficiency in C. void main(void){ DDRB=0xFF; // PB7 is connected to a scope ss=100; while(1){ PORTB |= 0x80; // set PB7 high tt=sqrt(ss); PORTB &= ~0x80; // clear PB7 low } } // Program 2.30: A time/position profile dumping into a data array. unsigned short time[100]; unsigned short place[100]; unsigned short n; void profile(unsigned short p){ time[n]=TCNT; // record current time place[n]=p; n++; } unsigned short sqrt(unsigned short s){ unsigned short t,oldt; profile(0); t=0; // based on the secant method if(s>0) { profile(1); t=32; // initial guess 2.0 do{ profile(2); oldt=t; // calculation from the last iteration t=((t*t+16*s)/t)/2;} // t is closer to the answer while(t!=oldt);} // converges in 4 or 5 iterations profile(3); return t;} // Program 2.31: A time/position profile using two output bits. unsigned int sqrt(unsigned int s){ unsigned int t,oldt; PORTB=0; t=0; // based on the secant method if(s>0) { PORTB=1; t=32; // initial guess 2.0 do{ PORTB=2; oldt=t; // calculation from the last iteration t=((t*t+16*s)/t)/2;} // t is closer to the answer while(t!=oldt);} // converges in 4 or 5 iterations PORTB=3; return t;}