Output Devices

Output Devices

By Saheen Palayi | 22 April 2021 | FAB Academy 2021

week 12 assignment is to add an output device to a microcontroller board I've designed, and program it to do something

Like I planned before I'll be continuing my Tachometer project which started during my input week,This week of output devices I'm adding an OLED Display device to the PCB that I already made.


 output-week

This is the schematic of the board that I already Design


 output-week

And this is the board layout

Check my Input Devices week to know how I designed the board and how did I added the input sensor and all

OLED Display

An OLED Displays are a Type of Display technology which use Organic Light Emitting Diode for each Individual pixel


 output-week

The above Diagram is shows a Physical OLED Structure.This is a modern achievement in Display technologies that finlay we can create almost true black or dark colours while displaying pictures. Because,The main advantage of OLED Displays are we do n't need a huge backlight to power up the entire display .each individual pixel light up itself .

There are many different type of OLED displays module Available in the market


 output-week

These are the commonly use for prototyping purpose.These type of Module have I2C Protocol to communicate with it.Fablab Kerala has one of these in it's Inventory stock.It's a 0.96" I2C yelLow Blue color OLED Display

I2C Protocol

The Inter Integrated Circuits AKA the IIC or the I2C is a two wire serial Interface communication Protocol just like USB in our Computers.It can communicate between almost upto 128(112) devices when using 7 bits addressing and almost upto 1024(1008)devices when using the 8 bits addressing.

 output-week
From analog.com

From the figure You can see mainly 2 wires used.one is SDA or Serial Data and other one is SCL Serial Clock

The OLED That I have is using the I2C protocol to receive data for displaying on it.I will do more documentation about I2C in upcoming Networking and communication week. for more checkout the documentation from Howtomechatronics.com

Testing

the Fabrication and design of the my PCB is already done during the Input Devices week,so I can connect the OLED module then start programing.The OLED that I'm Using was based on SSD1306 chip which support both SPI and ISP

Then I edited the OLED Hello world program from Professor Neil ,found on fab output devices class page for the Attiny412 chip with the help of it's data sheet


 output-week

I loaded the code into the arduino IDE and selected the chip Attiny412,port,programmer etc...


 output-week

I inserted the OLED Display in place on the PCB and connected to the UPDI board That I made then connected the FTDI cable and finally to my PC.I didn't soldered those pins of OLED,It still get contact because I used copper revet for the Through holes


 output-week

I got an unexpected error!.It was an Upload error.I did programed the board before during the input week.I tried to debug the board and the software,USB plugs..etc.. at last I found out the problem.


 output-week

Look at this picture the OLED Pins order is different the left one is Neil's Board and the right one is from our LAB.I was following Neil's board while designing the PCB.Now I have to either redesign the PCb or have to buy a new OLED Module with correct pin order.

After removing the OLED I tried to program the IC again because I can wire the OLED to my board by soldering.But the board not responding! That was strange! and unbelievable .The OLED PIn order mistakes some how course damaged the Attiny412 Chip.


With Arduino

I has to replace the chip in order to continue but because of the Covid 19 protocols I can't access the lab these days.So I'm at home,but have some components with me not the Attiny412 .So I did tested the OLED with an Arduino UNO board


 output-week

I connected the OLED Display module to the Arduino UNO development board like in the picture.with few jumper wires the hardware very simple!


 output-week

I couldn't edit the Neil's c file for the Atmega328p chip on the Arduino UNO,so I followed the suggested Adafruit library for the SSD1306 OLED Modules.found trouble while programing


 output-week

with little bit of research and some effort I found another library for the OLED called u8g2 from Github/olikraus .still got trouble while adding the zipp libary to the arduino,but I mangged to clear the trouble here is the simplified and easy to install version of the u8g2 by me


 output-week

after adding the zip library to the arduino ide I loaded the hello world program for the OLED by following File >>Examples >>U8x8lib >>HelloWorld


 output-week

As per the instructions I uncomment the line for selecting the OLED display type and compiled successfully

Then I plugged the arduino uno board and selected the board, as well as the port then uploaded the sketch


 output-week

It's working!.This is not my first time with the OLED module I worked with 0.91" IIC 128x32 type module before

Re-Designing

After the covid lock-down, I return to the LAB and Continue the assignment by redesigning the Board by correcting the mistakes that I found


 output-week

The RXD TXD connections in the previouse board was not really oky it was twisted so I switch them in between to make it right


 output-week

Here is the design of board looks like . you can see I also added a slide switch and battery terminals to turn on and off the power of the entire board If I make it battery powered device.


 output-week

Also completed the 3D model of the PCB to create the enclosure in fusion's product designing techniques


 output-week

Here is the final schematic diagram of the tachometer also organized for better understanding the Circuit.


 output-week

Then I Milled out the board and soldered everything in place with new components and also soldered the OLED display in the board.


 output-week

Here is the new programing setup that I use and that's right I did make my own USb to Serial COnverter using FT232R FTDI chip.


 output-week

Then I tried to program the board to make the OLED running using the attiny412 turns out the U8x8lib is not compatible with Attiny412 and I've also tried the Adafruit SSD1306 library example but I thing the size is too large for the flash memmory of the Attiny412 chip.


 output-week

By doing some digging in the fab documentations of previous students I found out This output week documentation by a guy named Vincent Zhou has same problems I did and he solved the problem by modifying Neil's OLED code for Attiny45 and he got succeed!

CODE :-

        #include < avr/io.h>
        #include < util/delay.h>
        #include < avr/pgmspace.h>
        #include < stdlib.h>
        
        #define I2C_slave_address 0x78
        #define I2C_delay() _delay_us(5)
        
        #define TWI0_BAUD(F_SCL)      ((((float)F_CPU / (float)F_SCL)) - 10 )
        void TWI_init()
        {
          TWI0.MBAUD = (uint8_t)TWI0_BAUD(100000);  // Set MBAUD register for 100kHz
          TWI0.MCTRLA = 1 << TWI_ENABLE_bp          // Enable TWI Master: enabled
          | 0 << TWI_QCEN_bp                        // Quick Command Enable: disabled
          | 0 << TWI_RIEN_bp                        // Read Interrupt Enable: disabled
          | 1 << TWI_SMEN_bp                        // Smart Mode Enable: enabled
          | TWI_TIMEOUT_DISABLED_gc                 // Bus Timeout Disabled
          | 0 << TWI_WIEN_bp;                       // Write Interrupt Enable: disabled
        
          TWI0.MCTRLB |= TWI_FLUSH_bm;              // Purge MADDR and MDATA 
          TWI0.MSTATUS |= TWI_BUSSTATE_IDLE_gc;     // Force TWI state machine into IDLE state
          TWI0.MSTATUS |= (TWI_RIF_bm | TWI_WIF_bm);
        }
        
        uint8_t TWI_start(uint8_t deviceAddr)
        {
          if ((TWI0.MSTATUS & TWI_BUSSTATE_gm) != TWI_BUSSTATE_BUSY_gc)   //Verify Bus is not busy
          {
            TWI0.MCTRLB &= ~(1 << TWI_ACKACT_bp);
            TWI0.MADDR = deviceAddr ;
            if (deviceAddr&0x01)  {while(!(TWI0.MSTATUS & TWI_RIF_bm));}  // If addressRead
            else                  {while(!(TWI0.MSTATUS & TWI_WIF_bm));}  // If addressWrite
            return 0;
          }
          else return 1;                                                  // Bus is busy
        }
        
        uint8_t TWI_read(uint8_t ACK)                                     // ACK=1 send ACK ; ACK=0 send NACK
        {
        
          if ((TWI0.MSTATUS & TWI_BUSSTATE_gm) == TWI_BUSSTATE_OWNER_gc)  // Verify Master owns the bus
          {
            while(!(TWI0.MSTATUS & TWI_RIF_bm));                          // Wait until RIF set
            uint8_t data=TWI0.MDATA;
            if(ACK==1)  {TWI0.MCTRLB &= ~(1< action send ack
            else        {TWI0.MCTRLB |= (1< put 1 ACKACT => nack prepared for actionstop
        
            return data ;
          }
          else
          return 1; //Master does not own the bus
        
        }
        uint8_t TWI_write(uint8_t write_data)
        {
          if ((TWI0.MSTATUS&TWI_BUSSTATE_gm) == TWI_BUSSTATE_OWNER_gc)              // Verify Master owns the bus
          {
            TWI0.MDATA = write_data;
            while (!((TWI0.MSTATUS & TWI_WIF_bm) | (TWI0.MSTATUS & TWI_RXACK_bm))); // Wait until WIF set and RXACK cleared
            return 0;
          }
          else
          return 1;                                                                 // Master does not own the bus
        }
        
        void TWI_stop(void)
        {
          TWI0.MCTRLB |= TWI_ACKACT_NACK_gc;
          TWI0.MCTRLB |= TWI_MCMD_STOP_gc;
        }
        
        // This function is central to I2C communications. Normal pin setting is replaced with TWI functions.
        char TWI_master_write(unsigned char* data,unsigned char nbytes,unsigned char slave_address) 
        {
          unsigned char index, ret, slave_address_write;
        
          // Send start and send slave address
          slave_address_write = slave_address << 1;
          if (TWI_start(slave_address) != 0)
            // No ACK,return 1
            return 1;
        
          // Loop over bytes
          for (index = 0; index < nbytes; ++index) {
            ret = TWI_write((data[index]));
            if (ret != 0) 
               // No ACK, return 1
               break;
            // Yes ACK, continue
          }
        
          //Send stop
          TWI_stop();
          return ret;
        }
        
        static const uint8_t MonospaceBold7x8[] PROGMEM = {0,0,0,0,0,0,0,0,0,0,223,223,0,0,0,0,7,0,7,0,0,32,228,62,231,124,39,4,0,76,154,255,154,112,0,39,37,23,232,168,228,0,0,112,247,159,241,192,240,0,0,0,7,0,0,0,0,0,24,126,195,0,0,0,0,195,126,24,0,0,0,18,12,63,12,18,0,0,16,16,124,16,16,0,0,128,112,48,0,0,0,0,0,48,48,48,0,0,0,0,192,192,0,0,0,0,0,192,56,6,1,0,0,126,255,129,
                                                            137,255,126,0,129,129,255,255,128,128,0,129,193,161,153,143,134,0,129,137,137,137,247,118,0,48,44,38,255,255,32,0,143,143,137,137,249,113,0,124,255,139,137,249,112,0,1,129,241,125,31,3,0,118,247,137,137,247,118,0,14,159,145,209,255,62,0,0,204,204,0,0,0,0,0,204,204,0,0,0,0,48,48,120,72,72,204,0,40,40,40,40,40,40,0,204,
                                                            72,72,120,48,48,0,2,217,215,7,0,0,124,130,57,69,69,254,0,0,192,252,47,47,252,192,0,255,255,137,137,247,118,0,60,126,195,129,129,66,0,255,255,129,129,255,60,0,255,255,137,137,137,129,0,255,255,9,9,9,1,0,60,126,195,145,241,242,0,255,255,8,8,255,255,0,129,129,255,255,129,129,0,64,128,129,129,255,127,0,255,255,24,62,227,193,
                                                            0,255,255,128,128,128,128,0,255,254,28,28,254,255,0,255,255,14,112,255,255,0,126,255,129,129,255,126,0,255,255,17,17,31,14,0,126,255,129,129,255,126,0,255,255,17,17,111,206,128,78,143,153,153,241,114,0,1,1,255,255,1,1,0,127,255,128,128,255,127,0,3,63,240,240,63,3,15,255,240,12,240,255,15,0,129,231,60,60,231,129,0,1,15,252,
                                                            252,15,1,0,193,225,185,141,135,131,0,0,255,255,129,0,0,0,1,6,56,192,0,0,0,0,129,255,255,0,0,4,6,3,3,6,4,0,128,128,128,128,128,128,128,0,1,3,2,0,0,0,0,96,244,148,148,252,248,0,255,255,136,136,248,112,0,120,252,204,132,132,132,0,112,248,136,136,255,255,0,120,252,148,148,156,152,0,8,254,255,9,9,0,0,28,190,162,162,254,126,0,255,
                                                            255,8,8,248,240,0,136,136,251,251,128,128,0,136,136,251,123,0,0,0,255,255,16,124,196,128,1,1,127,255,128,128,0,0,252,252,4,252,4,252,0,252,252,4,4,252,248,0,120,252,132,132,252,120,0,254,254,34,34,62,28,0,28,62,34,34,254,254,0,0,252,252,4,4,4,0,88,156,180,180,228,104,4,4,255,255,132,132,0,0,124,252,128,128,252,252,0,12,124,224,
                                                            224,124,12,12,252,224,16,224,252,12,0,132,204,120,120,204,132,0,130,142,248,56,14,2,0,196,228,164,148,156,140,0,16,16,239,239,129,129,0,0,0,255,0,0,0,0,129,129,239,239,16,16,0,16,16,16,32,32,32};
        
        static const uint8_t MonospaceBold10x16lo[] PROGMEM = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,254,254,0,0,0,0,0,0,30,30,0,0,30,30,0,0,0,48,176,248,62,50,240,254,62,48,0,112,248,216,254,152,152,0,0,0,28,34,162,162,156,64,64,32,32,0,0,0,220,126,230,198,134,12,128,128,0,0,0,0,30,30,0,0,0,0,0,0,0,224,252,30,2,0,0,0,0,0,2,30,252,224,0,0,0,0,0,72,120,48,254,48,120,72,0,0,0,128,128,128,240,240,128,128,
                                                                128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,240,60,14,2,0,0,240,252,14,198,198,14,252,248,0,0,0,12,6,254,254,0,0,0,0,0,12,6,6,6,134,198,124,56,0,0,12,6,198,198,198,198,252,56,0,0,128,192,112,24,14,254,254,0,0,0,254,126,102,102,102,230,198,128,0,0,240,252,206,102,102,230,204,128,0,0,6,6,6,6,230,254,
                                                                62,14,0,0,56,252,198,198,198,198,252,56,0,0,120,252,206,134,134,206,252,248,0,0,0,0,0,224,224,0,0,0,0,0,0,0,0,224,224,0,0,0,0,0,128,128,192,64,96,96,32,48,0,0,96,96,96,96,96,96,96,96,0,0,48,32,96,96,64,192,128,128,0,0,12,6,134,198,102,126,28,0,0,224,240,56,156,204,204,220,248,240,0,0,0,192,252,62,62,252,192,0,0,0,254,254,198,198,198,
                                                                198,252,60,0,0,240,252,12,6,6,6,6,12,0,0,254,254,6,6,6,12,252,240,0,0,254,254,198,198,198,198,198,6,0,0,254,254,198,198,198,198,198,6,0,0,240,252,12,6,134,134,134,140,0,0,254,254,192,192,192,192,254,254,0,0,0,6,6,254,254,6,6,0,0,0,0,0,0,6,6,6,254,254,0,0,254,254,224,240,252,14,6,2,0,0,254,254,0,0,0,0,0,0,0,0,254,254,62,240,240,62,254,
                                                                254,0,0,254,254,30,240,192,0,254,254,0,0,240,252,14,6,6,14,252,240,0,0,254,254,198,198,198,198,124,124,0,0,240,252,14,6,6,14,252,240,0,0,254,254,198,198,198,198,252,60,0,0,56,124,230,198,198,198,140,0,0,0,6,6,6,254,254,6,6,6,0,0,254,254,0,0,0,0,254,254,0,0,6,254,252,0,0,252,254,6,0,30,254,224,0,240,240,0,224,254,30,0,2,14,62,248,248,62,
                                                                14,2,0,2,14,62,120,224,224,120,62,14,2,0,6,6,134,198,246,126,30,14,0,0,0,0,254,254,2,2,0,0,0,0,2,14,56,224,128,0,0,0,0,0,0,2,2,254,254,0,0,0,0,16,24,28,14,6,14,28,24,16,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,6,4,0,0,0,0,0,0,96,48,176,176,176,240,224,0,0,254,254,96,48,48,112,224,192,0,0,192,224,112,48,48,48,48,96,0,0,192,224,112,48,48,96,254,254,0,
                                                                0,192,224,176,176,176,176,224,192,0,0,48,48,252,254,54,54,54,0,0,0,192,224,112,48,48,96,240,240,0,0,254,254,96,48,48,48,240,224,0,0,0,48,48,247,247,0,0,0,0,0,0,48,48,247,247,0,0,0,0,0,254,254,128,224,112,48,16,0,0,0,6,6,254,254,0,0,0,0,0,0,240,240,48,240,224,48,240,224,0,0,240,240,96,48,48,48,240,224,0,0,192,224,112,48,48,112,224,192,0,0,
                                                                240,240,96,48,48,112,224,192,0,0,192,224,112,48,48,96,240,240,0,0,0,240,240,96,48,48,48,48,0,0,224,240,176,176,176,176,48,96,0,0,48,48,252,252,48,48,48,0,0,0,240,240,0,0,0,0,240,240,0,0,48,240,224,0,0,224,240,48,0,112,240,0,0,192,192,0,0,240,112,0,16,48,240,192,192,240,48,16,0,0,16,240,240,128,0,240,240,48,0,0,48,48,48,48,176,240,112,48,
                                                                0,0,0,0,0,252,254,2,2,0,0,0,0,0,0,254,254,0,0,0,0,0,0,2,2,254,252,0,0,0,0,0,128,192,192,192,128,128,128,192,0,0,0,0,0};
        
        static const uint8_t MonospaceBold10x16hi[] PROGMEM = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,25,25,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,27,31,3,3,31,15,3,3,0,0,12,24,24,127,25,31,15,0,0,1,1,0,0,14,17,17,17,14,0,0,7,15,28,24,25,31,30,31,19,0,0,0,0,0,0,0,0,0,0,0,0,0,7,63,120,64,0,0,0,0,0,64,120,63,7,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,1,15,15,1,1,1,0,0,0,0,64,124,60,0,0,0,0,0,0,3,3,3,3,3,0,0,0,0,0,0,0,28,28,0,0,
                                                                0,0,0,32,56,30,7,1,0,0,0,0,0,3,15,28,24,24,28,15,7,0,0,24,24,24,31,31,24,24,24,0,0,24,28,30,27,25,24,24,24,0,0,12,24,24,24,24,25,15,15,0,0,3,3,3,3,3,31,31,3,0,0,12,24,24,24,24,28,15,7,0,0,7,15,28,24,24,28,15,7,0,0,0,16,28,15,3,0,0,0,0,0,15,15,24,24,24,24,15,15,0,0,0,12,25,25,25,28,15,3,0,0,0,0,0,28,28,0,0,0,0,0,0,0,64,124,60,0,0,0,0,0,1,
                                                                1,3,2,6,6,4,12,0,0,6,6,6,6,6,6,6,6,0,0,12,4,6,6,2,3,1,1,0,0,0,0,27,27,0,0,0,0,0,7,31,56,115,103,102,102,119,39,0,0,24,31,15,3,3,15,31,24,0,0,31,31,24,24,24,24,31,15,0,0,3,15,12,24,24,24,24,12,0,0,31,31,24,24,24,12,15,3,0,0,31,31,24,24,24,24,24,24,0,0,31,31,0,0,0,0,0,0,0,0,3,15,12,24,25,25,31,15,0,0,31,31,0,0,0,0,31,31,0,0,0,24,24,31,31,
                                                                24,24,0,0,0,12,24,24,24,24,24,15,15,0,0,31,31,0,0,3,15,30,24,0,0,31,31,24,24,24,24,24,24,0,0,31,31,0,1,1,0,31,31,0,0,31,31,0,0,3,30,31,31,0,0,3,15,28,24,24,28,15,3,0,0,31,31,0,0,0,0,0,0,0,0,3,15,28,24,24,60,111,7,0,0,31,31,0,0,1,3,31,30,16,0,12,24,24,24,24,25,15,15,0,0,0,0,0,31,31,0,0,0,0,0,7,15,28,24,24,28,15,7,0,0,0,0,31,31,31,31,0,0,
                                                                0,0,31,31,30,1,1,30,31,31,0,0,16,28,31,3,3,31,28,16,0,0,0,0,0,31,31,0,0,0,0,0,28,30,31,27,24,24,24,24,0,0,0,0,127,127,64,64,0,0,0,0,0,0,0,0,3,14,56,32,0,0,0,64,64,127,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,31,27,25,25,13,31,31,0,0,31,31,12,24,24,28,15,7,0,0,7,15,28,24,24,24,24,12,0,0,7,15,28,24,24,
                                                                12,31,31,0,0,7,15,29,25,25,25,25,13,0,0,0,0,31,31,0,0,0,0,0,0,7,111,220,216,216,204,255,127,0,0,31,31,0,0,0,0,31,31,0,0,24,24,24,31,31,24,24,24,0,0,192,192,192,255,127,0,0,0,0,0,31,31,1,3,7,30,24,16,0,0,0,0,15,31,24,24,24,0,0,0,31,31,0,31,31,0,31,31,0,0,31,31,0,0,0,0,31,31,0,0,7,15,28,24,24,28,15,7,0,0,255,255,12,24,24,28,15,7,0,0,7,15,
                                                                28,24,24,12,255,255,0,0,0,31,31,0,0,0,0,0,0,0,12,25,25,25,25,27,31,14,0,0,0,0,15,31,24,24,24,0,0,0,15,31,24,24,24,12,31,31,0,0,0,1,15,30,30,15,1,0,0,0,7,31,30,3,3,30,31,7,0,0,16,24,30,7,7,30,24,16,0,0,0,192,195,255,63,15,1,0,0,0,24,28,30,27,25,24,24,24,0,0,0,1,1,126,254,128,128,0,0,0,0,0,0,255,255,0,0,0,0,0,0,128,128,254,126,1,1,0,0,0,1,
                                                                0,0,0,1,1,1,0,0,0,0,0,0};
        
        void OLEDcommand(uint8_t c) {
          static uint8_t data[2];
          data[0] = 0;
          data[1] = c;
          TWI_master_write(data,2,I2C_slave_address);
        }
        
        void OLEDcommands(uint8_t c1,uint8_t c2) {
          static uint8_t data[3];
          data[0] = 0;
          data[1] = c1;
          data[2] = c2;
          TWI_master_write(data,3,I2C_slave_address);
        }
        
        void OLEDdata(uint8_t d) {
          static uint8_t data[2];
          data[0] = 0x40;
          data[1] = d;
          TWI_master_write(data,2,I2C_slave_address);
        }
        
        void OLED7x8string(uint8_t row,uint8_t col,char str[]) {
          static uint8_t index,offset,pointer;
          static char chr;
          OLEDcommands(0x00+(col & 0x0F),0x10+((col >> 4) & 0x0F));
          OLEDcommand(0xB0+row);
          index = 0;
          while (1) {
            chr = str[index];
            if (chr == '\0') break;
            pointer = chr-' ';
            for (offset = 0; offset < 7; ++offset) {
               OLEDdata(pgm_read_byte(&(MonospaceBold7x8[7*pointer+offset])));
            }
            ++index;
          }
        }
        
        void OLED10x16string(uint8_t row,uint8_t col,char str[]) {
          static uint8_t index,offset,pointer;
          static char chr;
          OLEDcommands(0x00+(col & 0x0F),0x10+((col >> 4) & 0x0F));
          OLEDcommand(0xB0+row);
          index = 0;
          while (1) {
            chr = str[index];
            if (chr == '\0') break;
            pointer = chr-' ';
            for (offset = 0; offset < 10; ++offset) {
               OLEDdata(pgm_read_byte(&(MonospaceBold10x16lo[10*pointer+offset])));
            }
            ++index;
          }
          OLEDcommands(0x00+(col & 0x0F),0x10+((col >> 4) & 0x0F));
          OLEDcommand(0xB0+row+1);
          index = 0;
          while (1) {
            chr = str[index];
            if (chr == '\0') break;
            pointer = chr-' ';
            for (offset = 0; offset < 10; ++offset) {
               OLEDdata(pgm_read_byte(&(MonospaceBold10x16hi[10*pointer+offset])));
            }
            ++index;
            }
          }
        void OLED128x64init() {
          uint8_t i,j;
          //Init TWI
          TWI_init();
        
          //Init SSD1306
          OLEDcommand(0xae);       // Display off
          OLEDcommands(0xa8,0x3f); // Set multiplex ratio, ratio 63
          OLEDcommands(0xd3,0x00); // Set display offset, no offset
          OLEDcommand(0x40);       // Set display start line
          OLEDcommand(0xa1);       // Set segment remap col 127 to seg 0
          OLEDcommand(0xc8);       // Set COM output reverse
          OLEDcommands(0xda,0x12); // COM pin config, alt bottom to top
          OLEDcommands(0x81,0xff); // Set contrast, max contrast
          OLEDcommand(0xa4);       // Resume to RAM display
          OLEDcommand(0xa6);       // Normal non-inverted display
          OLEDcommands(0xd5,0x80); // Set clock divider, default
          OLEDcommands(0x8d,0x14); // Set charge pump, enable
          OLEDcommands(0x20,0x02); // Set memory mode, page addressing
          OLEDcommand(0xaf);       // Display on
          //
          // clear screen
          //
          for (j = 0; j < 8; ++j) {
            OLEDcommands(0x00,0x10);
            OLEDcommand(0xB0+j);
            for (i = 0; i < 128; ++i) OLEDdata(0);
            }
        }
        
        uint16_t count = 0;
        char str[3];
        void setup() {
          // Initialize OLED
          OLED128x64init();
        
          // Static text
          OLED7x8string(0,0,"Hello World!");
          OLED7x8string(1,28,"in a 7x8 font");
          OLED10x16string(2,0,"Hello World!");
          OLED10x16string(4,0,"in 10x16 font");
          OLED10x16string(6,0,"Count:");
        }
        
        void loop() {
          itoa(count,str,10);
          OLED10x16string(6,60,str);
          ++count;
          if (count == 1000) {
             OLED10x16string(6,80," ");
             count = 0;
          }
        }

    
Enter fullscreen mode Exit fullscreen mode

 output-week

Here is the results after I tried out Vincent's code it was awesome he also converted the code to arduino environment means it still a C code but works in Arduino IDE.


 output-week

There is another problem caught in my attention which is the flash memory of the Attiny412 is 94% full because of the fonts in the program so I need to optimize and reduce in order to complete the tachometer program.


 output-week

Again I used ll my effort and time through internet documentations and find out a github repo of a guy named Stefan wagiminator. He did an amazing job to write demo codes and projects for Attiny AVR series .So one of his project to interface the OLED display module in smallest microcontrollers like Attiny10,Attiny13 and Attiny202. check his ATtiny13-TinyOLEDdemo github repo here.

Group Assignment

week 12 Group assignment is to measure the power consumption of an output device

We all did not got chance to finish the project in the week so we done after our project presentation. For this week we wanted to know how much a servo takes the power while it's working. and planned to try out the stepper motor.The simple basic power calculation equation is given below



Here we already aware of the Voltage that we are given to the component or circuit . There are many ways to measure current and calculate the Power consumption of an electronic device. We already met some of the electronic measurement equipments during the Electronics design week .That's made the jo easy.


 output-week

We are decided measure the power consumption of a servo motor and a Nema17 stepper motor .And also we are gonna use the 2 Axis CNC Shield with arduino UNO setup for making the Servo and stepper working .because both need control signals in order to perform.


 output-week

Before we connect any output device to the hardware we measured the power of the arduino UNO and shield setup.

Power Consumption of a Servo Motor

We will be using a standard TowerPro SG90 Mini Servo with 180 degree rotation which works in the range of 3.0 ~ 7.2 VDC. And will be uploading the servo sweep example from arduino IDE to the Arduino Uno board.


 output-week

The code will works as sweeping motion that the angle of the servo will change from 0 to 180 degree and vice versa with a uniform time interval

SERVO SWEEP CODE :-

                    /* Sweep
                    by BARRAGAN 
                    This example code is in the public domain.
                   
                    modified 8 Nov 2013
                    by Scott Fitzgerald
                    https://www.arduino.cc/en/Tutorial/LibraryExamples/Sweep
                   */
                   
                   #include < Servo.h>
                   
                   Servo myservo;  // create servo object to control a servo
                   // twelve servo objects can be created on most boards
                   
                   int pos = 0;    // variable to store the servo position
                   
                   void setup() {
                     myservo.attach(9);  // attaches the servo on pin 9 to the servo object
                   }
                   
                   void loop() {
                     for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees
                       // in steps of 1 degree
                       myservo.write(pos);              // tell servo to go to position in variable 'pos'
                       delay(15);                       // waits 15 ms for the servo to reach the position
                     }
                     for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
                       myservo.write(pos);              // tell servo to go to position in variable 'pos'
                       delay(15);                       // waits 15 ms for the servo to reach the position
                     }
                   }
    
Enter fullscreen mode Exit fullscreen mode

 output-week

Here is our test setup After uploading the servo sweep program we attached the servo and hooked the shield to the power supply



You can see the test video above that the servo sweeps fom 0 to 180 degree and vice versa and we also observed the current consumption from the Power supply live reading



Then we also tried giving a load push by our hand fingers pushing against the sweeping direction That takes more current for running the servo in position

Power Consumption of a Stepper Motor

Now let's try a stepper motor in action , we are using NEMA 17 Stepper motor from our Inventory @ 12 volts in combination with the DRV 8825 Stepper drivers


 output-week

The code actually borrowed from HowToMechatronics.com stepper motor tutorials and made some changes of owr own for the hardware setup

STPPER SWEEP CODE :-

                    /*     Simple Stepper Motor Control Exaple Code
                    *      
                    *  by Dejan Nedelkovski, www.HowToMechatronics.com
                    *  Modified by Saheen Palayi, https://saheenpalayi.github.io/
                    */

                    // define time_delay (this decide the speed of the motor)
                    #define time_delay 50

                    // defines pins numbers
                    #define stepPin   2 
                    #define dirPin    3 
                    #define enablePin 8


                    void setup() {
                    // Sets the two pins as Outputs
                    pinMode(enablePin,OUTPUT);
                    pinMode(stepPin,OUTPUT); 
                    pinMode(dirPin,OUTPUT);

                    delay(100);

                    // Set Enable pin high to turn on the motor
                    digitalWrite(enablePin,HIGH);
                    }
                    void loop() {
                    digitalWrite(dirPin,HIGH); // Enables the motor to move in a particular direction
                    // Makes 6400 pulses for making one full cycle rotation
                    for(int x = 0; x < 6400; x++) {
                    digitalWrite(stepPin,HIGH); 
                    delayMicroseconds(time_delay); 
                    digitalWrite(stepPin,LOW); 
                    delayMicroseconds(time_delay); 
                    }
                    delay(1000); // One second delay

                    digitalWrite(dirPin,LOW); //Changes the rotations direction
                    // Makes 6400 pulses for making one full cycle rotation
                    for(int x = 0; x < 6400; x++) {
                    digitalWrite(stepPin,HIGH);
                    delayMicroseconds(time_delay);
                    digitalWrite(stepPin,LOW);
                    delayMicroseconds(time_delay);
                    }
                    delay(1000);
                    }
    
Enter fullscreen mode Exit fullscreen mode


 output-week

Here is our Stepper sweep test setup just like the servo. But we are using the DRV8825 module as the stepper driver for the NEMA17 stepper motor.


In the test 1 the motor moves back in forth 1 revolution we taped the motor shaft for capturing the motor movement in camera. At the is condition no load on the motor presents and the current was very less.

We decide to give some load on the motor.so, for that we attached a GT2 pulley for trying to hold the motor while running.



Here the above video shows the test 2 of the stepper motor that we are trying to hold the motor while rotating which act as a load on the motor and the current dose increased littil bit.

And still it's not reach the specified power consuption by the manufacturer . we thought the load wasn't enough and we need to increase.


 output-week

so we built a test bench set up using a wrench and holded the motor on the table's end using a clamp.



In the video of test 3 we can see the motor skipping the steps to lift the wrench which is attached to the stepper motor's shaft.Which means it doesn't have the poer to list the wrench.


 output-week

Then we realize this happening becouse the stepper driver not allowing to rise the current for the stepper motor over a certine level so we adjusted the Vref for the DRV8825 by turning the pot on the stepper driver.



Then we repated the test again this time the minmum power increased to 0.55A first we did the no load test also turned on the microsteppring for the motor driver.


Then we repated the wrench load test again as test 5 this time the current rised .

From all of these 5 tests with the stepper motor we undersatand the we can mess with the power consuption by adjusting the stepper driver's Vref voltage.

References


Downloads

Back to Top Back to top