The most challenging aspect of this project is processing the accelerometer data to accurately synchronize the scanning of the display’s virtual columns. This ensures that the correct LEDs turn on and off at the precise moments during hand movements. It also makes it even more difficult by using Padauk's Mini-C, which is a stripped down primitive C-like language.
Since the language lacks support for floating point numbers and signed integers, working with real-world units like meters per second would be quite cumbersome. However, for this project, I believe I can bypass this limitation by using the raw accelerometer values directly. Instead of converting them into precise physical measurements, I’ll simply rely on the raw data to determine the direction of movement and relative magnitude. This should be sufficient for synchronizing the scanning of the display's virtual columns, as the project doesn’t require exact speed values—just enough information to detect motion and adjust the LED timing accordingly.
For the purposes of this project, I will just be using the x axis of the accelerometer data.
First, I grabbed the raw data from the accelerometer with the following code:
//Get x_l I2C_Address = 0x32; I2C_Read_Byte(); x_l = A; //Get x_h I2C_Address = 0x33; I2C_Read_Byte(); x_h = A; //Combined x x = x_l | (x_h << 8);
This reads the HIGH byte and the LOW byte from the ADXL345, then combines them into a 16-bit WORD.
Since the data is represented with 2's complement numbers, I extracted the sign and magnitude separately using the following code:
// Get x_acceleration_sign and apply two's complement if necessary if (x & 0x8000) { // If MSB is 1, it's negative x = (~x + 1) & 0xFFFF; // Apply two's complement x_acceleration_sign = 1; // Set sign as negative } else { x_acceleration_sign = 0; // Set sign as positive }
In my initial approach, I tried using only the x_sign of the accelerometer data to determine the direction of hand waving. The idea was that a positive x_sign would indicate movement in one direction, while a negative value would signal the opposite. However, this method didn’t work as expected.
The issue arose during deceleration—when the user was still waving in the positive direction but began to slow down, the x_sign would flip to negative. This caused the display to misinterpret the motion, as it couldn't distinguish between slowing down and an actual change in direction. As a result, the display would sometimes show inverted characters. It took me some time to realize that deceleration was the problem.
After lots of trial and error into what works and what doesn't, I ended up with a relatively simple solution. I first check if there is any movement. This is done using the built-in ADXL interrupts.
integrating the acceleration number into a velocity, even though my approach isn't very accurate:
//Get int_source I2C_Address = 0x30; I2C_Read_Byte(); int_source = A;
//If there is movement if (int_source.4 == 1) {
// Handle negative acceleration (decrease velocity) if (x_acceleration_sign == 1) { if (x_velocity >= x) { x_velocity -= x; // Subtract from velocity } else { x_velocity = x - x_velocity; // Handle negative velocity (use two's complement) x_velocity_sign = 1; // Set sign as negative } } // Handle positive acceleration (increase velocity) else { if (x_velocity_sign == 1) { // If the velocity is currently negative if (x_velocity >= x) { x_velocity -= x; // Reduce the negative velocity magnitude } else { x_velocity = x - x_velocity; // Positive velocity takes over x_velocity_sign = 0; // Reset sign to positive } } else { x_velocity += x; // Positive acceleration, increase velocity } } }
//No Movement else{ x_velocity = 0; }
I then use the sign of the velocity to determine the direction. The following code to increments and decrements the virtual columns of the front and back LEDs and then use that to toggle on and off of the LEDs.
//Right
if(x_velocity_sign == 1){
IncrementCol_F();
DecrementCol_B();
}
//Left
else {
DecrementCol_F();
IncrementCol_B();
}
//Display Column
DisplayColumn();
//Column Delay
.delay 100;
//Briefly Turn off ALL leds
PA.7 = 0;
PA.6 = 0;
PA.5 = 0;
PB.7 = 0;
PB.4 = 0;
PA.0 = 0;
PA.4 = 0;
PA.3 = 0;
PB.3 = 0;
PB.1 = 0;
This yielded a satisfactory solution. As you can see in the pictures and video, the POV display finally works!!
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.