/**************************************************************************************************************** ELE31EMP Laboratory 4 Introduction to ZiLOG Z8Encore Development Environment This program blinks LED block 3 on the development board. The program is based on the original 'ledblink' program written by ZiLOG, but has been simplified. Writen by Tim Smith, 22/4/2004 Modified JCD March 2005 Modified DJS March 2006 Modified GT Thu 22 March 2007 ****************************************************************************************************************/ #include #include // GT prefers bytes to chars typedef unsigned char byte; // values for bit masks for bits 0 to 7 enum { b0 = 0x01, b1 = 0x02, b2 = 0x04, b3 = 0x08, b4 = 0x10, b5 = 0x20, b6 = 0x40, b7 = 0x80 }; // LED block labels typedef enum { D1, D2, D3, D4 } block; // Each LED block has 7 rows and 5 columns. // The rows are selected by Port G bits 6 to 0. // The columns are selected by Port E bits 4 to 0. enum { row_mask = 0x7F, col_mask = 0x1F }; // Values for turning on all rows and/or columns of a LED block enum { all_rows = row_mask, all_cols = col_mask }; // GLOBALS = BAD, BUT THIS IS FOR BORLAND C TEST PURPOSES ONLY. // byte PEADDR, PECTL, PEDD, PEIN, PEOUT; // byte PGADDR, PGCTL, PGDD, PGIN, PGOUT; // Function Prototypes, in alphabetic order. void delay (int); void init_io_ports (void); void latch_block (block b); void led_pattern (byte rows, byte cols); void turn_off_all_leds (void); void turn_off_block (block b); void turn_on_block (block b); /****************************************************************************************************************/ /* Main program begins here */ /* This program blinks ALL LED Blocks on the evaluation board */ /****************************************************************************************************************/ void main (void) { init_io_ports(); // Initializes LED ports (Port G, Port H) while(1) // Infinite while loop { turn_off_all_leds(); // Turns off ALL LED's delay (200); // 200 ms delay // Turn On LED block D1 turn_on_block (D1); delay (200); }// while }// main /****************************************************************************************************************/ // Turn on all LEDs in LED block b, which may be D1, D2, D3 or D4. void turn_on_block (block b) { led_pattern (all_rows, all_cols); latch_block (b); } // Turn off whole LED block b. void turn_off_block (block b) { // no rows, no columns. led_pattern (0, 0); latch_block (b); } // Pattern of LEDs we want on. // We can set a pattern occupying specified rows and columns. // Rows (top to bottom) are Port G bits 6 to 0. // Columns (left to right) are Port E bits 4 to 0. // This function sets up the pattern data at the inputs of the D latches // that drive the LED blocks but does not load it, // so the LEDs won't light up until we call latch_block(). void led_pattern (byte rows, byte cols) { // Keep non-row bits of Port G the same; // change only the row bits. // Rows connect to LED anodes, so they're active high. PGOUT = (PGIN & ~row_mask) | (rows & row_mask); // Likewise for Port E which controls the columns, // except that Columns connect to LED cathodes, // so they're active low; cols are inverted here // to hide that irregularity. PEOUT = (PEIN & ~col_mask) | (~cols & col_mask); } // If a pattern is ready at the inputs of the D latches driving the LED blocks, // we then want to load it into the latches with a rising edge at the latches' // clock inputs; latch_block() does that. Once the data is stored and appears // at the outputs of the latches, then the LED pattern will be visible. void latch_block (block b) { // A LED block is selected by placing a rising edge on appropriate port bit: // for D1, it's Port E bit 7; in brief: // D1: E7 // D2: G7 // D3: E5 // D4: E6 enum { D1_mask = b7, D2_mask = b7, D3_mask = b5, D4_mask = b6 }; switch (b) { // A rising edge is a 0 followed by a 1 clocks the data // into the latches which control one block of LEDs. case D1: PEOUT = PEIN & ~D1_mask; // 0 in D1 trigger bit PEOUT = PEIN | D1_mask; // 1 in D1 trigger bit break; case D2: PGOUT = PGIN & ~D2_mask; PGOUT = PGIN | D2_mask; break; case D3: PEOUT = PEIN & ~D3_mask; PEOUT = PEIN | D3_mask; break; case D4: PEOUT = PEIN & ~D4_mask; PEOUT = PEIN | D4_mask; break; } } /****************************************************************************************************************/ // Initializes LED ports. // Requires no input, returns nothing. // Ports E and G are used as outputs. /****************************************************************************************************************/ void init_io_ports (void) { // Initialise Port G the "long" way as an example // Note only data direction needs to be set to zero, // as other registers were initialised to zero by reset. PGADDR = 0x02; // Select Alternate Function Register PGCTL = 0x00; // Select GPIO function PGADDR = 0x01; // select the Data Direction register PGCTL = 0x00; // set all bits of port to output PGADDR = 0x03; // Select Output Control Register PGCTL = 0x00; // Set output control to enable drain of output port PGOUT = 0x00; // init to all zeros - no need, but completes init PGADDR = 0x00; // Set ADDR register back to 0x00 to prevent further changes // Could initialise Port E the "long" way, too: // PEADDR = 0x02; // Select Alternate Function Register // PECTL = 0x00; // Select GPIO function // PEADDR = 0x01; // select the Data Direction register // PECTL = 0x00; // set all bits of port to output // PEADDR = 0x03; // Select Output Control Register // PECTL = 0x00; // Set output control to enable drain of output port // PEOUT = 0x00; // init to all zeros - no need, but completes init // PEADDR = 0x00; // Set ADDR register back to 0x00 to prevent further changes // Port E the easy (short) way using the set data direction macro defined in eZ8.h // we don't do the Alt function or Open Drain setting as they are correct from the reset PEDD = 0; // macro sets Port G address to 1 then sets Port G control to 0 PEOUT = 0x00; // init to all zeros - no need, but completes init PEADDR = 0x00; // Set ADDR register back to 0x00 to prevent further changes } // End of init io ports function /****************************************************************************************************************/ /****************************************************************************************************************/ // function to turn off LEDs // requires no input, returns nothing /****************************************************************************************************************/ void turn_off_all_leds (void) { block b; // Pattern is NO LEDS on, i.e. ALL LEDs OFF. led_pattern (0, 0); // Store pattern into every LED block for (b = D1; b <= D4; ++b) latch_block (b); } // End of turn off leds function /****************************************************************************************************************/ /****************************************************************************************************************/ // A simple (blocking) delay routine using a nested 'for' loop. // For a precise delay use an internal Z8 TIMER. // requires int input (approx No of milliseconds), returns nothing. /****************************************************************************************************************/ void delay (int time_ms) { // adjust inner_loop parameter based on your timing tests enum { inner_loop = 1080 }; int i; for (i=0; i < time_ms; i++) { int j; for(j=0; j<1080; j++) // this will waste ~1ms of the CPU's time { // do nothing. } } } // end of delay() /****************************************************************************************************************/