ECE 4760: Final Project

Remote Controlled POV Display

Yuan Cui (

Jin Sha (

Introduction    top

POV Displaying an Analog Clock

For our ECE 4760 final project, we designed and implemented a remote controlled persistence-of-vision (POV) display that is able to display multiple patterns based on remote input. The primary components of the display are a rotor and a motor. The rotor is mainly consisted of a row of LEDs and a microcontroller. The microcontroller controls LEDs. The basic theory behind POV is that if LEDs flash at the exact same location on each revolution and the motor is rotating fast enough, human eye is not able to detect the LEDs’ downtime between flashes, and has the perception that they are constantly on. The goal of this project is to implement a portable POV display for home entertainment or decoration. Therefore, weight, size and balance play crucial roles in our design.

High Level Design    top


Top View of Our Display

The stand of the system is a gift box inside which the DC motor is located. The motor has its shaft sticking out of the box to the middle of box surface. Two layers of coils sit around this shaft. The inner coil closely wraps around a plastic cylindrical structure that can accommodate the motor shaft. This structure is also glued to the bottom of the rotor. When motor spins, it drives the cylindrical structure to spin along, hence the rotor. The rotor has two different circuit boards that are put together with two wood beams glued to them for support. One circuit board is the microcontroller PCB, and the other is a electrical board where LEDs and other circuits are soldered. The roto and the motor can be separated.


There are mainly two parts of the hardware design, motor circuit and rotor circuit. Motor circuit is powered by 5V generator while the rotor circuit is powered by a small transformer which has an outer coil and an inner coil. The rotor sits on the motor’s shaft and the shaft is surrounded by inner coil and outer coil. With the help of transformer, a battery is no longer needed to power rotor circuit, thus cutting down the weight of rotor. Motor circuit sets up the Infrared LED for the Infrared (IR) receiver to detect cycle time, time required for one rotation. It also converts the DC from a DC generator to AC. The AC flows in the outer coil and induces an AC in the inner coil. The rotor takes the AC and does a conversion to DC to power the microcontroller and the LEDs. The rotor also has two IR receivers, one of which is used for detecting a complete cycle and the other one is responsible for receiving remote control.


The software allows us to generate different display patterns: a static heart image, an analog clock, a modifiable digital clock and a rotatable phrase “ECE4760 JS-YC”. All the images are attached in the appendices.

Our POV has a 2-degree resolution. This is achieved by splitting cycle time into 180 time intervals. Every 1/180 of this time, LEDs are switched. There are two files for our software design. One is main.c and the other is IR_Receive.h. IR_Receive.h detects key press from the remote control. Main.c displays according to corresponding key press. There are four timers and two external interrupts used for this project. Two of the timers, timer1 and timer3 are responsible for the 2-degree resolution. Timer0 generates a 1us timebase. Timer2 is used for IR communication between remote controller and IR receiver on the rotor. External interrupt 0 is used to indicate end of cycle and external interrupt 1 is used to receive signals from remote controller.

Hardware Design    top

Our hardware design is primarily consisted of two components and worked on together by both members.

Motor Circuit

Motor Circuit Image

Voltage of Primary Coil after DC to AC Conversion

The schematic for motor circuit is attached in appendices. The motor circuit has four parts: 5V DC power supply, motor, infrared transmitter and LC circuit. The motor is connected to the power supply through a diode, preventing the reverse current generated from the motor when shut down from damaging other electrical components in the circuit. The infrared LED combined with the receiver on the rotor side is used to detect the cycle time of rotor. It has a 470 ohm resistor connected to it for protection. The generator is connected to a 470uf capacitor for stabilization. The most important part in the motor circuitry is the LC circuit that converts DC to AC. A LC circuit can store energy oscillating at its resonant frequency 195kHz. The power transistors used in the circuit are there to amplify signals and compensate power loss in the circuit. The outer coil is the inductor in the circuit and it outputs a 5 volt AC voltage. While running, the motor circuit draws 0.35A current while the rotor circuit draws 0.1A current. Hence, the power efficiency of such transformer is calculated to be (5V * 0.1A) / (5V * 0.35A) = 28.6%. As the LEDs on the rotor require little current to function, such an efficiency is sufficient to power all our LEDs and other electrical components. The outer and inner coil are careful chosen insulating copper wires and each wounded to about 60 rounds. The diameters for both coils are about 2 cm. The process of engineering those coils is more of a trial and error process. We made multiple attempts here until our windings can provide enough power.

Rotor Circuit

Back of Rotor

Front of Rotor

The rotor circuit has many parts connected together, the microcontroller, LED array, AC to DC convertor, and Infrared receiver.

Voltage of Secondary Coil After AC to DC Conversion

The schematic for AC to DC conversion circuit is attached in appendices. The four diodes that are connected to the inner coil form a full wave rectifier that is able to convert AC input into voltage with only one polarity. This single polarity voltage gets stored in a 220uf capacitor, and a zener diode works as a voltage regulator to stabilize the output voltage of the capacitor to 5 voltages. The 5 volt DC voltage is fed into the Vcc port of microcontroller to provide power.

IR Receiver for Dectecting Cycle Time

The IR receiver corresponding to the IR transmitter in motor circuit is connected to Vcc through a 10k resistance. 10k resistor lowers the current in that branch. The positive lead of the receiver is connected to Vcc via a resistance and the external interrupt port PORTD2 while the negative lead is connected to ground. Under normal operation, the receiver is open. PORTD2 is always high. When it receives from the transmitter, it closes and pulls PORTD2 low. The external interrupt 0 is trigger on falling edge. It is used to calculate cycle time.

Another IR receiver is used to receive inputs from the remote control. Its schematic is shown in appendices. It has three connections, Vcc, Gnd and Xin. The Xin is connected to the other external interrupt port PORTD3 on the microcontroller board. The theory behind remote control is that each key on the remote controller sends a sequence of 0s and 1s.The 0 and 1 differ from their pulse width. 0s last 0.57ms while 1s last 1.68ms. Each key is composed of 32 pulses. The microcontroller uses external interrupt to reconstruct the 32 bit key press. This second external interrupt triggers on falling edge of those pulses.

LED Array

There is a row of LEDs on one side of the rotor. Each LED’s positive lead is connected to a pin on microcontroller and negative lead is connected to ground via a 330 ohm resistor. The 330 ohm resistor is there for protecting the LED. There are 21 LEDs in total, out of which 20 are blue colored and one is red colored. The red colored LED is the outmost LED and is responsible for producing the outer frame of the display. It is constantly on once the power-on button is pressed. The red LED is a normal LED used in previous labs. It has long leads and stands higher than the rest. The difference in height creates a 3D effect. The LEDs are mapped to all pins for PORTA and PORTB, and some pins of PORTC. Each port on this microcontroller has 8 pins.

The principal component used in our project is the Atmel ATmega1284P microcontroller. This microcontroller has countless features and functions. The pertinent features that we exploit are listed as below:

  • PORTA, PORTB, PORTC accounting for controlling 21 LEDs
  • Two external interrupts for IR communication
  • 4 internal timers, timer0-timer3
  • 2 timer compare match ISR

Remote Controller

Remote Controller

Another piece of hardware is the remote controller.The remote controll used is a standard 38k IR remote controller. This is used because its behavior is well understood and decoding code examples are widely avaible online.

Software Design    top

Software Interaction

Our software consists of code written by Jin Sha and Yuan Cui. There are two files main.c and IR_Receive.h. IR_Receive.h handles decoding the remote controller key press and main.c handles generating display based on the requested mode.

The software is heavily consisted of math equations, interrupt service routines (ISR) and function calls. To enable all the functionalities we have for our projects, four timers and two external interrupts are used. The explanation of the software is divided into a few parts in a function based approach. First, we will explain the general thoery of creating a 2-degree resolution display. Second, we will explain how different patterns are generated by using math equations and LED manipulations. In the end, we will explain how the decoding works.


All the display algorithms are done in the main.c file. We have three interrupt service routines in this file.

Timer1 (TCCR1B= 3)

Timer1 is used purely as timer without a corresponding ISR that continuously runs until reset on a full cycle of rotor rotation. Timer1 is used because it is a 16-bit timer and does not overflow in one rotation. Simple math is calculated to ensure that criteria. Assuming our motor rotates 10 cycles a second which is less than the real rpm, the timer should be able to count up to 16000000/(64*10) = 25000 with a prescaler of 64. This value is beyond an 8-bit timer counting range but works for a 16-bit timer.

Timer3 (TCCR3B = 3; TIMSK3 = 2)

Timer3 is designed to have the same speed as timer1 and uses a compare match ISR to create the 2-degree resolution. Hence, timer3’s compare register OCR3A is set to 1/180 of TCNT1 when external interrupt 0 signals a full rotation.

Timer0 (TIMSK0 = 2; TCCR0B = 3; OCR0A = 249)

Timer0 creates a 1us time base based on the above setting. It is used to calculate the current second, minute and hour essential for the analog and digital clocks

ISR (INT0_vect)

The primary functions of this interrupt service routine are to get the cycle time from timer1 in the variable TCNT1, and assign TCNT1/180 to OCR3A. It also resets TCNT1, TCNT3, and a global variable DISP_LINE which will be explained in the flowing paragraph.


Timer3 ISR generates the display. It increments DISP_LINE and resets it when it is already 180. A switch statement takes DISP_LINE and contains possible cases from case 0, case 1, … , to case 179. Inside each case, the LED array is manipulated. This creates a 2-degree display resolution.


This ISR maintains and increments several variables. The variable time1 is used to count to a second. When time1 reaches 1000, it is reset and the variable second is incremented. When second increments to 60, minute variable is incremented. When minute increments to 60, the hour variable is incremented. It also increments time2 and time3 to create time base for other applications in our software, which will be explained.

Our POV display is able to create multiple patterns: a static heart image, an analog clock, a shifting phrase-“ECE4760 JS-YC” and a digital clock. We laid out all the pixels in our display by using MATLAB and this layout allows us to know where and when to manipulate the LEDs.

Matrix Used to Construct Pattern

The middle is empty because there are no LEDs in that region. The radius of the graph has 20 pixels indicating 20 LEDs. The graph’s circumference has 180 pixels. We can label the columns from 0 to 179 for each DISP_LINE value. The 20 LEDs from inside to outside are PORTB pin 0-7, PORTA pin 0-7 and PORTC pin 4-7.

The heart image and the frame of analog clock are easily created with the help of pixel layout. We just need to turn on the right LEDs at the right column number inside the switch statement that takes in DISP_LINE. Our analog clock has a second hand and a minute hand. The way to show the second hand is to turn on all LEDs connected to PORTA and PORTB, which form a straight line, when DISP_LINE is equal to 3 times of the second variable. This is because DISP_LINE counts up to 180 whereas second counts up to 60. Same idea applies to the minute hand.

Since we will be reusing letters and numbers for other patterns we display. We created data structures that help us store the port manipulations.

struct Letter_row

This struct has three variables A,B,C. They indicate the values for PORTA, PORTB, and PORTC. With the help of pixel layout, we roughly know how many columns each letter or number span. We could then for each letter or number, define its variable to be an array of Letter_row and fill in A,B,C values for each column required to form that letter or number.

For instance, letter S has its own variable “Letter_S”: struct Letter_row Letter_S[10]={ {.A =0xE2,.B=0x00,.C=0x00},{.A=0x11,.B=0x00,.C=0x80},{.A=0x08,.B=0x80,.C=0x40},{.A=0x08,.B=0x80,.C=0x40},{.A=0x08,.B=0x80,.C=0x40},{.A=0x04,.B=0x80,.C=0x80},{.A=0x83,.B=0x00,.C=0x00}};. Letter S spans 10 columns in our case. If we want to display it in ISR (TIMER3_COMPA_vect), we would assign 10 consecutive case statements for each element in the array. For example, case 98: PORTA =Letter_S[0].A;PORTB =Letter_S[0].B; PORTC =Letter_S[0].C; break; case 99 … , until case 107. This data structure provides us the convenience of creating digital clock and words on the display.

Moving Display

Our software also allows words to move around. We have created the phrase “ECE4760 JS-YC” that is able to move or stay static based on user command. The way to make a static image move around on the POV is to augment the parameter the switch statement takes. We augment the parameter DISP_LINE with a variable n and take the mod of their sum. n is a variable that decrements by 5 every 0.1ms. This way, we created a shifting pattern that moves every 0.1ms. The switch becomes switch ((DISP_LINE+n)%180){ code }. Orignally, we would like to make the case parameter a variable. However, the case statement is precompiled and its parameter must be a constant. We used another approach that is to make the switch parameter a variable. Overall, we created the effect that for the same case, the time that triggers this case is different between each rotation. The mod ensures the sum of the two staying within 180.

Digital Clock

We are also able to display a digital clock. We have six placeholder arrays for numbers from 0 to 9. These placeholder arrays are Number_0 to Number_5. The arrays are shown on the display as follows:

tens place of hour unit’s place of hour tens place of minute unit’s place of minute tens place of second unit’s place of second
Number_0 Number_1 Number_2 Number_3 Number_4 Number_5


In the while(1) loop at the end of void main(), The Number arrays are assigned according to the second, minute, and hour variables mentioned earlier. Certainly, there are restrictions on the range of values each placeholder can take. For example, Number_2 can only be 0 to 5 while Number_3 can be any number from 0 to 9. To get the tens place of the any variable among second, minute and hour, we divide the variable by 10. To get the value for its unit’s place, we mod the variable by 10. The piece of code below demonstrates the said ideas.

switch (hour/10){ case 0: pass_value(Num_0,Number_0,8); break; case 1: pass_value(Num_1,Number_0,8); break; }

switch (hour %10){ case 0: pass_value(Num_0,Number_1,8); break; case 1: pass_value(Num_1,Number_1,8); break; case 2: pass_value(Num_2,Number_1,8); break;

Also, we pre-filled the values for Num_0 to Num_9, which hold the Letter_row arrays for 0 to 9. The function pass value copys Num_0 to Num_9 to the placeholders based on current time. Therefore, the placeholders have the latest time stored. When we need to display the digital clock, the ISR (TIMER3_COMPA_vect) extract the current time from the placeholders. We could also do the value copying inside the ISR, but this separation, writing code to the main function, allows more structured code and reduces the ISR’s code length, which is helpful for improving the system’s performance.


This file decodes the key press from remote control and adjusts a few state variables that are called in the main.c.

Timer2(TIMSK2 = 2; TCCR2B = 3; OCR2A = 79)

Timer2 is used to create a 160us time base. It uses a prescaler of 32 and triggers compare match ISR when TCNT2 counts up to 79.


In this ISR, a time counter T0_CNT is incremented. When it reaches 250, 160us * 250 = 40ms, a time out flag is set and the counter is reset.


The external interrupt 1 stops timer2 from running until it finishes executing. When the time out flag is set, the external interrupt stays idle. When the time out flag is false, it pushes T0_CNT onto an IR_Time array which holds 32 elements. This array stores the time required to trigger this ISR for each pulse sent from the remote control. It then calls a function decode that figures out whether 1 or 0 is sent by looking at its pulse with from IR_Time. The decode function reconstructs the sent sequence and stores it in a struct variable IR_Data. If IR_Data maps to any key, it stores the key value into a variable called key_code that is used from the main.c file to indicate different display modes.

A mapping from the remote key to its hexadecimal representation is shown in the appendices. We have enabled numbers from 0 to 9 except for numbers 2, 5, 6 and 7. Number 0 means the heart mode, number 1 means the analog clock, number 3 means the moveable phrase, number 4 means the digital clock, number 8 makes the phrase movable and finally number 9 makes the phrase stop moving. Moreover, the power on button from the remote control is also used to start up the display. Without pressing the power button first, the display will not show anything. This is done by set a global variable display_on, when decoder obtains the hexadecimal representation for the power button, which is 0x45. Then, all the switch and case statements inside ISR (TIMER3_COMPA_vect) are enclosed in a condition check for display_on. If it is set, all those code is able to run. Otherwise, nothing happens. The following piece of code demonstrates this idea.

if(display_on) { switch (key_code){ case 0x18: break; case 0x5A:break;….thousands of cases}

Similarly, the other state variables are set in the decode function in IR_Receive.h and are called in the main.c file.

void changetime(unsigned char Data, int num)

Our display offers a mode that allows users to change any digit on the digital clock to the number they press on remote control. This is enabled by the changetime function. To change the digital clock, the user has to grab a lock on the display that disallows users from entering other modes momentarily. The lock is grabbed is the user pressed test button on the remote control. In the test mode, a cursor will show underneath the digit the user currently able to change. Pressing the left or right button on the remote control can shift the cursor. The position of the cursor is also stored in a variable. The outer switch statement of changetime takes in the position of the cursor, and inner switches take in the number user presses. The changetime functions changes the hour, minute and second variables depending on the cursor position. For example, in the following piece of code, when the cursor position is 0, it means the user is modifying the tens place of the hour, and thus the hour needs to be changed to 10 plus the mod of 10 of the current hour, hour = hour%10 + 10.The mod is used to preserve the unit’s place of the current hour.

void changetime(unsigned char Data, int num) { switch(num) {case 0: {switch (Data) { case 0x16: hour = hour%10; break; case 0x0c: hour = hour%10+10; break; … }}}

Results    top

The results we have achieved so far greatly exceed our original expectations. Firstly, we designed the rotor to have a battery to power the controller board. We did some research, and realized a simple transformer with a LC resonant circuit can give us wireless power. This greatly cuts down the weight of rotor, makes it rotate more stable and faster. Secondly, we are amazed at what math algorithms allow us to create on this display. Basically, anything with a 2-degree resolution is creatable. We originally designed the display to only have static images and an analog clock. However, we are able to add the changeable digital clock and moveable patterns to the display. The images we generate are fairly stable and clearly recognizable. They are especially vivid under dim light.

Since we did not make an attempt to manipulate the motor speed, we require the motor to spin at a fairly constant rate. The balance of the system plays an import role in that criterion. We put metal screws on the side with LED array to increase that side’s weight to better balance between two sides. We load our gift box which contains supports the motor with sand to stabilize the stand. The final result meets our expectations. The stand is very stable if sits on a flat surface. The rotor makes a little honing noise, as it can make contact with the loosely attached purple tape around the outer coil. However, the noise is far from being agitating. These effects all contribute to the stable images created even without a mechanism to stabilize the motor speed.


Hardware testing is immediately done after each part of circuit is soldered. We first used oscilloscope to probe the voltage waveform of the primary coil to make sure the DC voltage is converted to AC voltage and the frequency could meet our requirements. Then after the bridge circuit is finished, we tested if the DC voltage can be generated. It is important to maintain 5V to make sure the microcontroller could work normally. The finally step of hardware testing is to use a simple program to light up all the LEDS to verify if the wireless power supply is enough.

Software testing is pretty difficult in our project since the microcontroller is keeping rotating, which means we cannot use UART to test. Thus we used several small tricks, we implemented a testing mode and use the LEDs to indicate the variable that we want to test. Since we have 20 LEDs and 2^20=1048576, by using binary number, it can indicate all stuffs that we want to test. Timing is the most important feature in our project. Since OCR3A is always updating and it will heavily affect the display, we did many tests on it to guarantee the calculation of OCR3A can be always correct. Then we test each display pattern including letter A-Z, number 0-9 and symbol ‘:’ after they are done. Finally after combining all parts, we did an overall to test everything can work normally.


The safety is an area of improvements, as the rotor rotates in the open space. Although the stand is very stable on a flat surface, rotor might cut people who come to close. The author has been cut on the figure once during debugging. Therefore, the users should stay with a safe distance from the display when it is on. Also, the outer frame does not indicate the end of rotor, as the rotor stretches out further. Mistaken user might approach the outer frame and get injured. The way to make the system safe is to enclose it inside a glass cover.

User Friendliness:

Our original plan is to make the display as a commercial ready product as possible. We made the system lightweight and compact. However, due to time and technology constraints, we are not able to create our own PCB board, which would make the design more compact and lightweight. We used the materials and components at hand to create our system. The difficulty to solder surface mount electrical components is tremendous; hence the soldering does not look very well. In spite of that, when the display is on, none of the soldering and wiring can be seen and the display is pleasant to look at. We utilized the remote controller in a user-friendly manner, by setting keys on the remote controller to intuitive functionalities, such as the power button, the shift buttons, and the test mode button.

Conclusions    top

The outcome of our projects has greatly exceeded our expectations, and we used a lot of knowledge we learned in this class and also learned a lot from building this project. In the end, we are able to realize multiple patterns for our POV display. These patterns include a static heart image, an analog clock with second and minute hands, a rotatable phrase and a changeable digital clock. The user can use the remote controller to communicate with the device. A user manual has been attached in the appendices.

Future considerations

Besides what we have accomplished so far, there is still a lot that can be done for the system. First, the analog clock starts at a predefined time in the software. Ideally, we would like to reflect the current time on the analog clock. We could have a time chip that communicates with the microcontroller to indicate current time. Second, making a PID control for the motor to stabilize the speed could further enhance the display. This would cause a crisper and more stable image. Third, a glass cover for safety purposes explained earlier could enclose our system. Fourth, we could make a PCB board out of our design to make the system more compact and lightweight. Finally, there are some keys on the remote control that are not mapped. We could use those keys to realize other patterns.

Relevant Standards

Our project follows all legal and standards and relevant standards of industry. Any 5-volt DC source can power our project, and the data communication is done by infrared transceivers in an allowable frequency range.


The technologies that we use can be potentially found in other products that are already to market. The algorithms for generating displays are completely original and did not require outside help. The way to write the decoder is learned through an example online. The 38k infrared remote controller has existed for a long time and there are many examples of the decoding online. The decoding mechanism is heavily customized to fit in our project for mode switching and changing numbers.

Ethical Considerations

When designing and implementing our project, we had the IEEE code of Ethics in mind. We believe we sufficiently and properly abided by all the rules laid out by IEEE standards. We considered the safety of our project. We made the stand stable on the table and ensured that rotor is safe from flying out of the shaft. We did our best of not copying existing projects and products. Instead, we improved on previous similar POV projects in a number of areas.

Appendices    top

A. Program Listing

B. Display Demonstrations

POV Displaying an Analog Clock

POV Displays Rotatable Phrase

POV Displays Modifiable Digital Clock

C. Schematics

Motor Circuit Schematic

AC to DC Converter Circuit Schematic

IR Receiver for Remote Controller

Remote Controller Key Mapping

D. User Manual

Button Functionality
Power Button Turn on and off display
0 Static Heart Image
1 Analog Clock
2 Phrase
8 Rotate the Phrase
9 Stop Rotation
3 Digital Clock
Test Enable Modification
Left Shift Shift Cursor to Left
Right Shift Shift Cursor to Right
Others Does nothing outside of test mode

C. Parts List and Costs

Part Vendor Cost/Unit Quantity Total Cost
Atmega 1284P Lab $5.00 1 $5.00
Zener Diode Lab Free 1 $0.00
IR LEDs DigiKey $0.97 2 $1.94
Wires, Resistors, Capacitors Lab Stock 0 Many $0.00
Gift Box Dollar Store $0.99 1 $0.99
DC Motor Digikey $3.19 1 $3.19
38K Remote Controller Ebay $2.39 1 $2.39
38K IR Receiver Ebay $11.39 1 $11.39
Insolating Copper Coil Ebay $10.85 1 $10.85
Power Transistor Lab Stock 0 1 $0.00
Other Transistors Lab Stock 0 4 $0.00
Diodes Lab Stock 0 5 $0.00        
TOTAL: $35.75

References    top


Inspiration for Code

Background Sites

Acknowledgements    top

We would like to sincerely thank professor Bruce Land for his continued help and insightful advices throughout projects. His detailed lectures and practical lab sections offer us strong foundation to tackle our project. We also would like to thank the TAs that are in the lab in the extended lab periods that provide us with lab access to refine our work.