Showing posts with label Programming. Show all posts
Showing posts with label Programming. Show all posts

Thursday, January 19, 2012

Nokia 5110 LCD

I bought a SparkFun Nokia 5110 LCD through InMotion. Both sites have the datasheet and example documentation for how to use it.
Adafruit also sells this and documents its use with another excellent Ladyada tutorial.

Here it is with connectors already soldered:


The soldering is pretty bad. Maybe I should buy a new tip for my soldering iron...

This screen supports direct connection to an Arduino (5V), but in doing so we push it to the datasheet defined limits, so to it is best to reduce all signals to a confortable 3.3V.

My Arduino Duomilanove only outputs 5V signals, so in order to translate those signals to 3.3V, the simplest way is to use a Voltage Divider.
I used this site to calculate the best resistor values to use for this case (10kOhm and ~5kOhm).
Adafruit offers a free level shifter with the LCD that can be used as a more efficient Voltage Divider.

Also to light up the 4 leds used as backlight I used a 22Ohm resistor, so that I could connect to a 5V signal on the Arduino in order to control them with PWM.


And here it is using the Arduino example code 2:

Tuesday, June 7, 2011

7 Segment Display

So now it's time to control a 7 Segment Display.

I got mine from Sparkfun.
There you can find the datasheet as well as some examples of how to use.



It has 16 pins and for you to be able to use all digits, it multiplexes the anodes. There's a cathode for each pin and 8 anodes for the digit segments and the following dot.
Because of these common anodes, we can only light up one digit at a time for them to show different results.

To control it I used an Arduino connected to a Shift Register. As its specs are 2.1V on 20mA, for the 5V output from the Arduino we need 150 Ohm resistors.
I only have 3 at the moment, and there are 7 output pins on the display to connect to.

So I used some serial (100 Ohm + 47 Ohm) and parallel (220 Ohm + 470 Ohm).
If you need to refresh your theory on calculating resistors or reading the values, hail to Wikipedia.

This is the simplified circuit, without resistors, so that it is easier to view what the connections are.

The next photos are for the complete setup, but can be somewhat confusing. Sorry about that...





The basic usage of this setup is to control what pins from the shift register sink current from the displays anodes and which digit is lit on a given moment with the Arduino.

And now for some code:
//
// thylux
// 7-Segment 4-digit display control using a 74HC595N shift register
//
// This driver only supports writing the digits for the moment
// As the Shift Register controls the anodes (sink current), we need to set the outputs as LOW to turn a light ON

// Display definitions
//
//  __A__
// |     |          Vcc < 2.1V, 20mA --> R = 150 Ohm
// F     B          
// |__G__|
// |     |
// E     C          DIG1 = 1, DIG2 = 2, DIG3 = 6, DIG4 = 8, COLON_P = 4, APOSTROPHE_P = 10
// |__D__|        A = 14, B = 16, C = 13, D = 3, E = 5, F = 11, G = 15, DP = 7, COLON_N = 12, APOSTROPHE_N = 9
//

// Shift Register definitions
//
//   VCC Q0  DAT ENB LAT CLK RES OVR
// ---+---+---+---+---+---+---+---+---        Vcc < 5V, 70mA --> R = 72 Ohm
// |                                  |        Qn < 20mA
// D             74HC595N              |
// |                                  |
// ---+---+---+---+---+---+---+---+---
//   Q1  Q2  Q3  Q4  Q5  Q6  Q7  GND
//

// Display connection to Shift Register (direct breadboard connections)
// Q1 -> B, Q2 -> G, Q3 -> A, Q4 -> C, Q5 -> D, Q6 -> F, Q7 -> E

// Character mapping
//                 HBGACDFE
byte chars[11] = {B10100000, // 0
          B10110111, // 1 
          B10001010, // 2
          B10000011, // 3
          B10010101, // 4
          B11000001, // 5
          B11000000, // 6
          B10100111, // 7
          B10000000, // 8
          B10000101, // 9
                  B11111111};// blank

// Arduino pin definition
int _LATCH = 12;
int _CLOCK = 11;
int _DATA = 10;
int _DIG1 = 7;
int _DIG2 = 6;
int _DIG3 = 5;
int _DIG4 = 4;

#define _BUFF_SIZE   4
#define _SHOWTIME    50

// initializes the buffer with empty characters
byte buffer[_BUFF_SIZE] = { chars[10], chars[10], chars[10], chars[10] };
int digits[_BUFF_SIZE] = { _DIG1, _DIG2, _DIG3, _DIG4 };

void setup()
{
  pinMode(_LATCH, OUTPUT);
  pinMode(_CLOCK, OUTPUT);
  pinMode(_DATA, OUTPUT);

  // TODO: Can a 555 reduce these 4 pins to 1?
  pinMode(_DIG1, OUTPUT);
  pinMode(_DIG2, OUTPUT);
  pinMode(_DIG3, OUTPUT);
  pinMode(_DIG4, OUTPUT);
    
  Serial.begin(9600);
}

void loop()
{
  for(int i = 0; i < 100; i++)
  {
    fillBuffer(i);
    for(int j = 0; j < _SHOWTIME; j++)
      writeScreen();
  }
  
  // Clean the latch for the next execution
  // TODO : needed???
  digitalWrite(_LATCH, LOW); // Begin Write
  shiftOut(_DATA, _CLOCK, LSBFIRST, chars[10]);
  digitalWrite(_LATCH, HIGH);  // End Write
}

void fillBuffer(int num)
{
  bool cleanChar = false;
  
  if(num==0)
  {
    buffer[_BUFF_SIZE - 1] = chars[0];
    return;
  }
    
  for(int i = _BUFF_SIZE - 1; i >= 0; i--)
  {
    if(num==0 && cleanChar) // We need to make sure that all the unused buffer positions are cleaned
      buffer[i] = chars[10];
    else
    {
      buffer[i] = chars[num > 9 ? num%10 : num];
      num/=10;
      cleanChar = true;
    }
  }
}

void writeScreen()
{
  for(int i = 0; i < _BUFF_SIZE; i++)
  {
    for(int i = 0; i < _BUFF_SIZE; i++)
      // TODO: find if it is possible to turn HIGH and LOW an entire PORT
      digitalWrite(digits[i], LOW);
      
    /*
    shiftOut(dataPin, clockPin, bitOrder, value)

    dataPin:     the pin on which to output each bit (int)
    clockPin:     the pin to toggle once the dataPin has been set to the correct value (int)
    bitOrder:     which order to shift out the bits; either MSBFIRST or LSBFIRST. (Most Significant Bit First, or, Least Significant Bit First)
    value:         the data to shift out. (byte) 
    */
    
    digitalWrite(_LATCH, LOW); // Begin Write
    shiftOut(_DATA, _CLOCK, LSBFIRST, buffer[i]);
    digitalWrite(_LATCH, HIGH);  // End Write
    
    digitalWrite(digits[i], HIGH);
    
    delay(3);
  }
}

I believe that this code could be more efficient (a quick side note - Performant isn't a word), so I'll look up ways to make it better. As a proof of concept, works just fine!

Tuesday, May 31, 2011

Python for fun

Interested in learning Python?
I found this site with several well documented small projects that will make an interesting way to learn this language.

Saturday, December 4, 2010

Big LED Matrix

In my last post I built a 5x7 LED matrix. After reading this hackaday article, I decided to expand my LED matrix to the most.


In order to reuse the board I had to grow on the columns, which are 7 leds each.
So I soldered 7 more columns to a total of 12. With the existing 7 rows, I will need now 19 pins of the Arduino, the same as in the Jack-o-lantern (14+5), but my matrix totals 84 leds, against 70 of the mentioned article.


As I'm lighting by column, I can send a current of 20mA for the 7 leds to total the same safe 140mA to the Arduino.

In the previous post I also mentioned the issue when each pin of the Arduino can only support a 40mA current. To solve it we need to connect transistors to the matrix cathodes, for diverting that current to a real GND pin. That way, the Arduino pins that were connected to the cathodes will now connect to the base pin of each transistor, and the other pins will receive the total column current and send it to GND.
Notice that the GND pins can only support up to 200mA.


There are two types of transistors we can use in this case.
Here's the basic lecture I read on their differences.
In this case the difference will be how to program the Arduino. Using NPN transistors means we need to set the pin to HIGH to light a led column, an using PNP transistors the pin has to be LOW.

I wanted to use PNP transistors because that way I could save my NPN for other projects. But after some tests on finding the best resistor to attach to the base, I didn't achieve any satisfactory result, in comparison to the currents I could obtain using NPN transistors.

According to the math, I should be using 100 Ohm resistors for each line, and 2.2k Ohm resistors for the base of each transistor, but after some tests with a multimeter, those numbers were quite different from the reality.
I ended up using 47 Ohm for the lines and 1k Ohm for the transistors.
[WILL TRY TO UNDERSTAND THIS BETTER]

I used a flat ribbon for the wires to the Arduino. The male connector soldered on the board may look as a tidy way to use, but it's a nighmare to solder the wires, so I wouldn't recommend to use it for this kind of amateur project...

To finish the hardware I applied hot glue on the connections for isolation and fixation.


Now it's time for the software...

//
// Controlo de uma matriz de LEDs 12x7
// thylux
//
int L01 = 4;
int L02 = 6;
int L03 = 5;
int L04 = 8;
int L05 = 10;
int L06 = 12;
int L07 = 11;
int C01 = A5;
int C02 = A4;
int C03 = A3;
int C04 = A2;
int C05 = A1;
int C06 = A0;
int C07 = 0;
int C08 = 1;
int C09 = 2;
int C10 = 3;
int C11 = 7;
int C12 = 9;

void setup()
{
  // Positivos
  pinMode(L01, OUTPUT);
  pinMode(L02, OUTPUT);
  pinMode(L03, OUTPUT);
  pinMode(L04, OUTPUT);
  pinMode(L05, OUTPUT);
  pinMode(L06, OUTPUT);
  pinMode(L07, OUTPUT);
  // Negativos
  pinMode(C01, OUTPUT);
  pinMode(C02, OUTPUT);
  pinMode(C03, OUTPUT);
  pinMode(C04, OUTPUT);
  pinMode(C05, OUTPUT);
  pinMode(C06, OUTPUT);
  pinMode(C07, OUTPUT);
  pinMode(C08, OUTPUT);
  pinMode(C09, OUTPUT);
  pinMode(C10, OUTPUT);
  pinMode(C11, OUTPUT);
  pinMode(C12, OUTPUT);

  //Serial.begin(9600);
}

int freq = 1000 / 600; // Hz
void loop()
{
  //char debug[10];
  
  // Demo
  for(int i = 1; i <= 12; i++)
  {
      for(int j=0; j<7; j++)
      {
        light(i, (byte) 2^j);
        delay(100);
      }
        
      //pot = map(analogRead(A0), 0, 1023, 0, 500);
      //delay(pot);
    
      //sprintf(debug, "i:%d j:%d", i, j);
      //debug[9]='\0';
      //Serial.println(debug);
  }
  
  int i=0;
  while(i<10000)
  {
      writeSymbol('a');
      i++;
  }
  
  i = 0;
  while(i<10000)
  {
      writeSymbol('b');
      i++;
  }
}

void writeMessage(char* msg)
{
  for(int i = 0; i < sizeof(msg); i++)
    writeSymbol(msg[i]);
}

void writeSymbol(char chr)
{
  switch(chr)
  {
      case 'a':
      case 'A':
        light(1, B1111100);
        light(2, B0010010);
        light(3, B0010001);
        light(4, B0010010);
        light(5, B1111100);
        break;
      case 'b':
      case 'B':
        light(1, B1111111);
        light(2, B1001001);
        light(3, B1001001);
        light(4, B1001001);
        light(5, B0111110);
        break;
  }
}

// Ilumina os LED indicados na coluna
void light(int column, byte data)
{
  reset();
  
  switch(column)
  {
      case 1: digitalWrite(C01, HIGH); break;
      case 2: digitalWrite(C02, HIGH); break;
      case 3: digitalWrite(C03, HIGH); break;
      case 4: digitalWrite(C04, HIGH); break;
      case 5: digitalWrite(C05, HIGH); break;
      case 6: digitalWrite(C06, HIGH); break;
      case 7: digitalWrite(C07, HIGH); break;
      case 8: digitalWrite(C08, HIGH); break;
      case 9: digitalWrite(C09, HIGH); break;
      case 10: digitalWrite(C10, HIGH); break;
      case 11: digitalWrite(C11, HIGH); break;
      case 12: digitalWrite(C12, HIGH); break;
  }
  
  digitalWrite(L01, data & B0000001 ? HIGH : LOW);
  digitalWrite(L02, data & B0000010 ? HIGH : LOW);
  digitalWrite(L03, data & B0000100 ? HIGH : LOW);
  digitalWrite(L04, data & B0001000 ? HIGH : LOW);
  digitalWrite(L05, data & B0010000 ? HIGH : LOW);
  digitalWrite(L06, data & B0100000 ? HIGH : LOW);
  digitalWrite(L07, data & B1000000 ? HIGH : LOW);
  
  delay(freq);
}

void reset()
{
  digitalWrite(L01, LOW);
  digitalWrite(L02, LOW);
  digitalWrite(L03, LOW);
  digitalWrite(L04, LOW);
  digitalWrite(L05, LOW);
  digitalWrite(L06, LOW);
  digitalWrite(L07, LOW);
  
  digitalWrite(C01, LOW);
  digitalWrite(C02, LOW);
  digitalWrite(C03, LOW);
  digitalWrite(C04, LOW);
  digitalWrite(C05, LOW);
  digitalWrite(C06, LOW);
  digitalWrite(C07, LOW);
  digitalWrite(C08, LOW);
  digitalWrite(C09, LOW);
  digitalWrite(C10, LOW);
  digitalWrite(C11, LOW);
  digitalWrite(C12, LOW);
}

Note:
During my initial tests I couldn't understand why the columns connected to pin 0 (RX) and pin 1 (TX) were always HIGH.
I found later that it was caused by turning on Serial communication with Serial.begin().
The Serial was used to send debug information to the computer, so if you try to debug my program don't be alarmed by some row/column of leds not behaving as intended.

Saturday, October 30, 2010

A game for my old Nokia 5100

My old cellphone was a Nokia 5100, S40 Series. It had an 128x128px screen and ran on Nokia's MIDP 2.0 framework to J2ME.


(Yes, the 6 years of life were hard on it...)

But, well there was a time when I created a small game so I could learn J2ME.
I was just on my freshman year at ISEP, so my programming skills where still on it's early stages.
And the creativity wasn't much also...

But, the main idea was to learn J2ME and to create something other than academic projects that could be used in my life.

In order to show some images of that game, I downloaded an emulator from Nokia, but the standards have changed a lot since then (8 years of technology), so I couldn't get full compatibility.
The standard screen has a higher resolution and the OS is very different.

This was the entry screen. The image was from Nokia's SDK resources.


This was the main menu. On my cell I would only see text.


The About screen.


The Difficulty selection screen.


The mid-game Options screen.




The Cheat screen. We could activate the ability to cross the screen borders or the added difficulty of reversing the controls.


The game screen. On my cell it would be full screen.
The weird square on the top left is an 128x128px image resource as the background of the game screen. As you can see I couldn't configure the emulator to use the same resolution as my cellphone.
Besides the background image, all the screen is designed on-the-run. The players are geometrical shapes and the grid is built according to the screen resolution.

Friday, July 9, 2010

Digital Catalog

Um dos meus hobbies foi a construção de um sistema de catalogação em .NET, que fui construindo com amigos em 'tempos áureos da inocência'.

Este (http://digitalcatalog.uni.cc) teve uma versão beta participada por todos, mas ao longo do tempo outras prioridades se foram acumulando, até que só eu programava de vez em quando.

Ainda lancei uma beta2, mas o projecto sofreu por ter surgido um pouco tarde, pois o objectivo principal (catalogação de cds e dvds) acabou por deixar de fazer sentido, com o embaratecimento de discos rígidos nos quais podemos armazenar sem perder tempo a gravar.

É possível catalogar de tudo com o DC (volumes virtuais), mas acabou por ser tornar um projecto mais académico, onde se foi aplicando ideias de patterns e arquitecturas de código, como modo de aprendizagem.

Pretendo apresentar aqui ideias que tivemos para o projecto para procurar uma discussão sobre arquitectura de sistemas, implementações de algoritmos .NET, ...