Posts Tagged ‘Display LCD’

Twitter Hardware

Posted in Adobe AIR, Arduino, Electronics, Projects on abril 18th, 2009 by Bruno Soares – 4 Comments

Twitter Hardware é um projeto que utiliza a placa Arduino e um Display LCD para exibir as mensagens do Twitter. Para que a Arduino tenha as mensagens escrevi um software em Adobe AIR / Flex, que se conecta ao Serial Proxy enviando o conteúdo para a Arduino.

Arduino:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
/**
 * Twitter Hardware
 *
 * @author   Bruno Soares
 * @link     http://www.bsoares.com.br
 * @language Arduino / C++
 */


// Includes
#include <LiquidCrystal.h>

// Defines
#define DEBUG_PIN                 13

#define COMMAND_RIGHT             0
#define COMMAND_LEFT              1
#define QUANTITY_COMMANDS         2

#define ANALOG_PIN_COMMAND_RIGHT  0
#define ANALOG_PIN_COMMAND_LEFT   1
#define ANALOG_PIN_SPEED          2

#define MESSAGE_START             94  //  94 = ^
#define MESSAGE_END               126 // 126 = ~

#define SERIAL_BOUND              9600

#define LCD_LINES                 2
#define LCD_COLUMNS               16

#define ANIMATE_CMD_WIDTH         4

// Global variables
unsigned long time;

// LiquidCrystal display with:
// rs on pin 12
// rw on pin 11
// enable on pin 2
// dbs 3, 4, 5, 6, 7, 8, 9, 10
LiquidCrystal lcd(12, 11, 2, 3, 4, 5, 6, 7, 8, 9, 10);

// Analog configuration
unsigned int analogCmd[QUANTITY_COMMANDS];
unsigned int analogSpeed = 0;

// Control commands
boolean changingSpeed = true;
boolean readingSerial = false;
boolean pressedCmd[QUANTITY_COMMANDS];
unsigned int lastSpeed = 0;

// Massages
char currentMessage[400] = "No messages.";
unsigned int currentMessageLenght;

// ------------------------------------------------------------------------ \\
// Program
void setup() {
  Serial.begin(SERIAL_BOUND);
  pinMode(DEBUG_PIN, OUTPUT);
 
  smartDelay(10);
  lastSpeed = analogSpeed;
 
  presentation();
  changingSpeed = false;
}

void loop() {
 
  // Show current message
  clearLcd();
  writeLongTextInLcd(currentMessage);
  smartDelay(applySpeed(7000));
 
}

void presentation() {
  lcd.clear();
  writeLongTextInLcd("Twitter Hardwareby Bruno Soares");
  smartDelay(3000);
}

void refreshAnalogVars() {
  analogCmd[COMMAND_RIGHT] = analogRead(ANALOG_PIN_COMMAND_RIGHT);
  analogCmd[COMMAND_LEFT]  = analogRead(ANALOG_PIN_COMMAND_LEFT);
  analogSpeed              = analogRead(ANALOG_PIN_SPEED);
}

// ------------------------------------------------------------------------ \\
// [INI] Commands
void detectCommand() {
  unsigned int i = 0;
  while (i < QUANTITY_COMMANDS) {
    if (analogCmd[i] > 500 && !pressedCmd[i]) {
      executeCommand(i);
    }
    i++;
  }
}

void executeCommand(int command) {
  pressedCmd[command] = true;
  digitalWrite(DEBUG_PIN, 1);
 
  if (command == 0) {
    animateNext();
  } else {
    animatePrevious();
  }
 
  currentMessage[0] = 'L';
  currentMessage[1] = 'o';
  currentMessage[2] = 'a';
  currentMessage[3] = 'd';
  currentMessage[4] = 'i';
  currentMessage[5] = 'n';
  currentMessage[6] = 'g';
  currentMessage[7] = '\0';
  currentMessageLenght = 7;
 
  Serial.print(command);
 
  while (analogCmd[command] > 500) {
    smartDelay(4);
  }
 
  pressedCmd[command] = false;
  digitalWrite(DEBUG_PIN, 0);
}

void animateNext()  {
  for (unsigned int i = 0; i < LCD_COLUMNS + ANIMATE_CMD_WIDTH; i++) {
    if (i < LCD_COLUMNS) {
      lcd.setCursor(i, 0);
      lcd.print(">");
      lcd.setCursor(i, 1);
      lcd.print(">");
    }
    delay(5);
    if (i - ANIMATE_CMD_WIDTH >= 0) {
      lcd.setCursor(i - ANIMATE_CMD_WIDTH, 0);
      lcd.print(" ");
      lcd.setCursor(i - ANIMATE_CMD_WIDTH, 1);
      lcd.print(" ");
    }
    delay(30);
  }
}

void animatePrevious() {
  for (int i = LCD_COLUMNS; i >= -ANIMATE_CMD_WIDTH; i--) {
    if (i >= 0 && i < LCD_COLUMNS) {
      lcd.setCursor(i, 0);
      lcd.print("<");
      lcd.setCursor(i, 1);
      lcd.print("<");
    }
    delay(5);
    if (i + ANIMATE_CMD_WIDTH < LCD_COLUMNS && i + ANIMATE_CMD_WIDTH >= 0) {
      lcd.setCursor(i + ANIMATE_CMD_WIDTH, 0);
      lcd.print(" ");
      lcd.setCursor(i + ANIMATE_CMD_WIDTH, 1);
      lcd.print(" ");
    }
    delay(30);
  }
}
// [END] Commands

// ------------------------------------------------------------------------ \\
// [INI] Messages
void detectSerialMessage() {
  if (Serial.available() > 0 && !readingSerial) {
    if (Serial.read() == MESSAGE_START) {
      serialReadMessage();
    }
  }
}

void serialReadMessage() {
  digitalWrite(DEBUG_PIN, 1);
  readingSerial = true;
  currentMessageLenght = 0;
 
  iniReading:
  if (Serial.available() > 0) {
    unsigned int _char = Serial.read();
    if (_char == MESSAGE_END) {
      goto endReading;
    } else {
      currentMessage[currentMessageLenght++] = _char;
      delay(2);
      goto iniReading;
    }
  }
  goto iniReading;
 
  endReading:
  currentMessage[currentMessageLenght] = '\0';
  digitalWrite(DEBUG_PIN, 0);
  readingSerial = false;
}
// [END] Messages

// ------------------------------------------------------------------------ \\
// [INI] LCD manipulation
void writeLongTextInLcd(char text[]) {
  writeInit:
  clearLcd();
  unsigned int cml = currentMessageLenght;
  int loops = -1;
  unsigned int chars = 1;
  while (text[loops++ + 1] != 0) {
    if (chars == 17) {
      lcd.setCursor(0, 1);
      smartDelay(applySpeed(600));
      if (cml != currentMessageLenght) goto writeInit;
    } else if (chars == 33) {
      smartDelay(applySpeed(3000));
      clearLcd();
      if (cml != currentMessageLenght) goto writeInit;
      chars = 1;
    }
    lcd.print(text[loops]);
    smartDelay(applySpeed(60));
    if (cml != currentMessageLenght) goto writeInit;
    chars++;
  }
  Serial.print(2);
}

void writeInLcd(char text[], int quantity) {
  for (unsigned int i = 0; i < quantity; i++) {
    if (text[i] == 0) {
      do {
        lcd.print(" ");
      } while (i++ < quantity);
      break;
    } else {
      lcd.print(text[i]);
    }
  }
  delay(2);
  //smartDelay(5);
}

void clearLcd() {
  lcd.setCursor(0, 0);
  smartDelay(5);
  lcd.print("                ");
  smartDelay(applySpeed(400));
  lcd.setCursor(0, 1);
  smartDelay(5);
  lcd.print("                ");
  lcd.setCursor(0, 0);
  smartDelay(applySpeed(0));
}
// [END] LCD manipulation

// ------------------------------------------------------------------------ \\
// [INI] Speed
void detectChangeSpeed() {
  if (changingSpeed) return;
  if (!(lastSpeed < analogSpeed + 6 && lastSpeed > analogSpeed - 6)) {
    showGraderSpeed();
  }
}

void showGraderSpeed() {
  changingSpeed = true;
  digitalWrite(DEBUG_PIN, 1);
  lcd.clear();
  writeInLcd("Speed:", LCD_COLUMNS);
 
  // Create display velocity
  showSpeed:
  for (unsigned int i = 0; i < 10; i++) {
    int charsSpeed = map(analogSpeed, 0, 1023, 0, LCD_COLUMNS);
    int percentSpeed = map(analogSpeed, 0, 1023, 0, 100);
    char* percentString;
    itoa(100 - percentSpeed, percentString, 10);
    percentString = strcat(percentString, "%");
    lcd.setCursor(7, 0);
    writeInLcd(percentString, 4);
    charsSpeed = LCD_COLUMNS - charsSpeed;
    lcd.setCursor(0, 1);
    for (unsigned int x = 1; x < LCD_COLUMNS + 1; x++) {
      if (x <= charsSpeed) {
        lcd.print(">");
      } else {
        lcd.print(" ");
      }
    }
    lastSpeed = analogSpeed;
    smartDelay(40);
  }
 
  // Verify
  for (unsigned int i = 0; i < 10; i++) {
    if (!(lastSpeed < analogSpeed + 6 && lastSpeed > analogSpeed - 6)) {
      goto showSpeed;
    }
    smartDelay(40);
  }
 
  // Finalize
  lcd.clear();
  changingSpeed = false;
  digitalWrite(DEBUG_PIN, 0);
}

long applySpeed (unsigned int value) {
  return map(analogSpeed, 0, 1023, 0, value);
}

// [END] Speed

// ------------------------------------------------------------------------ \\
// [INI] Milliseconds controller
void smartDelay(int milliseconds) {
  if (milliseconds < 2) {
    noDelayFunctions();
    delay(milliseconds);
    return;
  }
  do {
    delay(1);
    milliseconds -= noDelayFunctions();
    milliseconds -= 1;
  } while (milliseconds > 0);
}

int noDelayFunctions() {
  time = millis();
 
  // [INI] No delay functions here
  refreshAnalogVars();
  detectChangeSpeed();
  detectCommand();
  detectSerialMessage();
  // [END] No delay functions here
 
  return millis() - time;
}
// [END] Milliseconds controller

ActionScript (usando Serialproxy):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
package br.com.bsoares.air.airtwitterhardware
{
    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.events.IOErrorEvent;
    import flash.events.ProgressEvent;
    import flash.net.Socket;
   
    /**
     * Message Control
     * Control messages between the Arduino and in AIR
     * Application using Serial Proxy.
     *
     * @author Bruno Soares
     * @link   http://www.bsoares.com.br
     */

    public class MessageControl extends EventDispatcher
    {
        // Properties
        private var _host:String;
        private var _port:uint;
        private var _socket:Socket;
        private var _messages:Array;
        private var _currentMessage:uint;
        private static var _instance:MessageControl;
        private static var _allowInstantiation:Boolean = false;
       
        // Constructor
        public function MessageControl()
        {
            if (!_allowInstantiation)
                throw new Error("Use instance property (this is a Singleton Class).");
            init();
        }
       
        // Logic
        private function init():void
        {
            _host = "127.0.0.1";
            // COM2
            _port = 5332;
            _messages = [ ];
            _currentMessage = 0;
            socketConnect();
        }
       
        private function socketConnect():void
        {
            _socket = new Socket();
            _socket.addEventListener(ProgressEvent.SOCKET_DATA, onSocketData);
            _socket.addEventListener(Event.CLOSE, onSocketClose);
            _socket.addEventListener(IOErrorEvent.IO_ERROR, onSocketIoError);
            _socket.connect(_host, _port);
        }
       
        private function processData(data:String):void
        {
            trace("Arduino command:", data);
            switch (true)
            {
                // Send next message
                case data == "2" || data == "0":
                {
                    sendNextMessage();
                    break;
                }
                // Send previous message
                case data == "1":
                {
                    sendPreviousMessage();
                    break;
                }
            }
        }
       
        private function sendMessage(message:String):void
        {
            if (message == null || message == "")
                return;
           
            trace("Message:", message);
           
            // MESSAGE_START
            _socket.writeUTFBytes("^");
            _socket.flush();
           
            // MESSAGE
            for (var i:uint = 0; i < message.length; i++)
            {
                _socket.writeUTFBytes(message.charAt(i));
            }
            _socket.flush();
           
            // MESSAGE_END
            _socket.writeUTFBytes("~");
            _socket.flush();
           
            dispatchEvent(new Event(Event.CHANGE));
        }
       
        private function sendNextMessage():void
        {
            _currentMessage = _currentMessage == _messages.length - 1 ? 0 : _currentMessage + 1;
            sendMessage(_messages[_currentMessage]);
        }
       
        private function sendPreviousMessage():void
        {
            _currentMessage = _currentMessage == 0 ? _messages.length - 1 : _currentMessage - 1;
            sendMessage(_messages[_currentMessage]);
        }
       
        // Events
        private function onSocketData(event:ProgressEvent):void
        {
            while (_socket.bytesAvailable > 0)
                processData(_socket.readUTFBytes(1));
        }
       
        private function onSocketClose(event:Event):void
        {
            socketConnect();
        }
       
        private function onSocketIoError(event:IOErrorEvent):void
        {
            trace(event.text);
        }
       
        // Getters and Setters
        public static function get instance():MessageControl
        {
            if (_instance == null) {
                _allowInstantiation = true;
                _instance = new MessageControl();
                _allowInstantiation = false;
            }
            return _instance;
        }
       
        public function set messages(value:Array):void
        {
            _currentMessage = 0;
            _messages = value;
            if (_messages.length > 0)
                sendMessage(_messages[0]);
        }
       
        public function get messages():Array
        {
            return _messages;
        }
       
        public function get currentMessage():uint
        {
            return _currentMessage;
        }
    }
}

Esquemático:
twitterhardware-schematic

Baixe o código fonte aqui.

Conteúdo relacionado:
Mais fotos: http://www.flickr.com/photos/bsoares/sets/72157616923436133/
Fritzing: http://fritzing.org/
Arduino: http://arduino.cc/
Adobe AIR: http://www.adobe.com/products/air/
Adobe Flex: http://www.adobe.com/products/flex/
LiquidCrystal Library: http://arduino.cc/en/Reference/LiquidCrystal?from=Tutorial.LCDLibrary
Twitter: http://twitter.com/