Este artigo tem por objetivo mostrar a implementação de um driver para comunicação entre um Shield LCD e Teclado da DFRobots (veja imagem de destaque do artigo) e uma placa Connected Launchpad.
Esse shield da DFRobots é interessante pois possui um display LCD compatível com Hitach 44780 conectado através de uma interface de 4 bits, o qual já foi extensamente explorado pelos ótimos artigos do Daniel Madeira e do Henrique Puhlmann. Um outro elemento existente nesta placa é um teclado de 5 teclas construído através de uma rede resistiva.
Fonte: https://www.dfrobot.com/
Muitas vezes temos alguns shields Arduino em casa e não os usamos pois achamos que não vale a pena ou que é complicado usá-los em nossos projetos. Este artigo também vem para desmitificar isso: podemos usar esses shields em qualquer tipo de projeto, para prototipagem rápida e testes de viabilidade de produtos/projetos.
Objetivos
Neste artigo temos dois objetivos:
- Implementar um driver para teclado resistivo e;
- Implementar um driver para o display LCD 44780.
Conexões do Shield LCD e Teclado da DFRobots
O primeiro aspecto que tive que enfrentar foi saber qual a tensão que eu alimentaria o módulo LCD/Teclado de tal forma que conseguisse alimentar o display e operar o teclado. Conforme está descrito no datasheet do módulo LCD, a sua tensão de trabalho está entre 4,5V e 5,5V. Alimentando o módulo com 5V não nos traz problema pois, conforme podemos ver no datasheet do controlador LCD, se este estiver operando com uma tensão de 5V, a tensão mínima para que o controlador entenda um nível alto é de 2,2V e como não é necessário ler a CGRAM ou a DDRAM do controlador, o TM4C1294 conseguirá controlá-lo.
As conexões utilizadas no decorrer do artigo são as apresentadas abaixo:
Outro problema que enfrentamos foi a tensão de trabalho da entrada AD do TM4C1294 conectado ao teclado resistivo. Analisando o circuito do teclado concluí-se que a máxima tensão gerada por ele é de 5V, que excede as especificações do canal analógico do TM4C1294. Para permitir o uso deste shield em nossa Connected Launchpad houve a necessidade de alterar o circuito do teclado, inserindo um resistor RX, de 1K5 Ω, entre o resistor R6 e o terra, como mostrado na figura a seguir:
Driver para Teclado Resistivo
Inicialmente tive que definir os valores que seriam mensurados pelo conversor Digital/Analógico do TM4C1294 para realizar a correta interpretação de cada tecla pressionada. Através de algumas contas e ajustes realizando medidas, obtivemos os valores abaixo:
#define KB_AN_RIGHTKEY_UPPER_LIMIT (100) #define KB_AN_RIGHTKEY_LOWER_LIMIT (0) #define KB_AN_UPKEY_UPPER_LIMIT (620+100) #define KB_AN_UPKEY_LOWER_LIMIT (620-100) #define KB_AN_DOWNKEY_UPPER_LIMIT (1570+100) #define KB_AN_DOWNKEY_LOWER_LIMIT (1570-100) #define KB_AN_LEFTKEY_UPPER_LIMIT (2500+100) #define KB_AN_LEFTKEY_LOWER_LIMIT (2500-100) #define KB_AN_SELKEY_UPPER_LIMIT (3380+100) #define KB_AN_SELKEY_LOWER_LIMIT (3380-100) #define KB_AN_NONE_UPPER_LIMIT (4095) #define KB_AN_NONE_LOWER_LIMIT (4095-100)
O processo de leitura do teclado foi implementado utilizando soft timers, onde implementamos uma pequena máquina de estados que gerencia a operação do conversor A/D de tal forma que ele não realiza a conversão em um único passo.
uint32_t ReadKbAnTask( void* pParam )
{
static BYTE bKbAnState = 0;
static uint32_t dwADCValue = 0;
switch( bKbAnState )
{
case 0:
{ ADCIntClear(KB_AN_ADC_BASE, KB_AN_ADC_SEQUENCE);
ADCProcessorTrigger(KB_AN_ADC_BASE, KB_AN_ADC_SEQUENCE);
bKbAnState = 1;
}
break;
case 1:
{ bKbAnState = 1;
if ( ADCIntStatus(KB_AN_ADC_BASE, KB_AN_ADC_SEQUENCE, false) )
{
bKbAnState = 2;
}
}
break;
case 2:
{ ADCSequenceDataGet(KB_AN_ADC_BASE, KB_AN_ADC_SEQUENCE, &dwADCValue);
bKbAnState = 3;
}
break;
case 3:
{ dwAnalogKbValue = dwADCValue;
bKbAnState = 0;
}
break;
default:
bKbAnState = 0;
break;
}
return 0;
}
E a leitura da tecla é realizada através da função KbAnReadKey abaixo:
uint8_t KbAnReadKey( KB_AN key )
{
uint8_t bRetKb=0;
switch( key )
{
case KB_AN_RIGHT :
case KB_AN_UP :
case KB_AN_DOWN :
case KB_AN_LEFT :
case KB_AN_SELECT:
{
if ( (dwAnalogKbValue > kbAnLimits[key].wLowerLimit) &&
(dwAnalogKbValue <= kbAnLimits[key].wUpperLimit))
{
bRetKb = 1;
}
}
break;
default:
{
bRetKb = 0;
}
break;
}
return bRetKb;
}
Driver para display LCD 44780
Implementamos um driver com interface 4-bits para o controlador de display LCD 44780. Procurei manter a mesma interface da biblioteca LiquidCrystal Library, permitindo que seja bem simples de um usuário de Arduino portar o seu código para utilizar este driver.
Aplicação de exemplo
Com os drivers para o teclado e para o LCD desenvolvemos uma pequena aplicação que controla um LED da Connected Launchpad baseado na tecla que foi pressionada e, concomitantemente, realiza a atualização de um contador no display LCD. A seguir estou colocando o código fonte da função main(), que realiza a inicialização do teclado e do display e algumas outras tarefas.
int main()
{
uint32_t dwTimerHandle;
SetSystemClock(); /* configure the system clock */
TTimerCfgTimeOut( 500 ); /* initialize the ttimer engine */
BrdLedsInit(); /* initialize the board leds engine */
BrdKeyInit(); /* initialize the board keys engine */
KbAnInit(); /* initialize the DFRobot analog keyboard engine */
Lcd44780Init( 2, 16 );
Lcd44780BackLightOn();
Lcd44780SetCursor( 0, 0 );
Lcd44780Write( "***EMBARCADOS***" );
BrdLedsSetState( USR_LED0, 0 );
BrdLedsSetState( USR_LED1, 0 );
BrdLedsSetState( USR_LED2, 0 );
BrdLedsSetState( USR_LED3, 0 );
TTimerRegisterCallBack( 10*TTIMER_1MS_INTERVAL, TimerPeriodic, TaskReadKbAn, NULL, &dwTimerHandle );
TTimerStart( dwTimerHandle );
TTimerRegisterCallBack( TTIMER_1SEC_INTERVAL/3, TimerPeriodic, UsrPrintText, NULL, &dwTimerHandle );
TTimerStart( dwTimerHandle );
for( ;; );
}
E a seguir apresentamos as funções para exemplificar o uso das funções do teclado e do LCD:
uint32_t UsrPrintText( void* lpParam )
{
typedef enum
{
TSPLASHSCREEN,
TCLEAN,
TUPDATEBUFFER,
TPOSCURSOR,
TWRITELCD,
} TUSRPRINT;
static TUSRPRINT stPrintText = TSPLASHSCREEN;
static uint16_t wCounter = 0;
static char cDispOut[7] = {0};
switch( stPrintText )
{
case TSPLASHSCREEN:
{
stPrintText = TCLEAN;
break;
}
case TCLEAN:
{
Lcd44780Clear();
stPrintText = TUPDATEBUFFER;
break;
}
case TUPDATEBUFFER:
{
memset( cDispOut, 0, sizeof( cDispOut ));
sprintf( cDispOut, "%06d", wCounter );
stPrintText = TPOSCURSOR;
break;
}
case TPOSCURSOR:
{
uint8_t s = (Lcd44780GetCol() - sizeof(cDispOut)) >> 1;
Lcd44780SetCursor( Lcd44780GetCurLin() , s );
stPrintText = TWRITELCD;
break;
}
case TWRITELCD:
{
Lcd44780Write( cDispOut );
wCounter++;
stPrintText = TUPDATEBUFFER;
break;
}
}
return 0;
}
/******************************************************************************/
uint32_t TaskReadKbAn( void* lpParam )
{
static uint32_t dwUsrLed3TimeHandle;
static uint8_t bTaskReadKbAnInit = 0;
KB_AN xPressKey = KB_AN_NONE;
const uint32_t bLedTimeTbl[] =
{
[KB_AN_RIGHT ] = 1*TTIMER_1SEC_INTERVAL,
[KB_AN_UP ] = 2*TTIMER_1SEC_INTERVAL,
[KB_AN_DOWN ] = 3*TTIMER_1SEC_INTERVAL,
[KB_AN_LEFT ] = 4*TTIMER_1SEC_INTERVAL,
[KB_AN_SELECT] = 5*TTIMER_1SEC_INTERVAL,
};
static KB_AN xKb = KB_AN_RIGHT;
if ( !bTaskReadKbAnInit )
{
if (!TTimerRegisterCallBack( 0, TimerOneShot, UsrLed2Off, NULL, &dwUsrLed3TimeHandle))
{
bTaskReadKbAnInit = 1;
}
}
else
{
if ( KbAnReadKey( xKb) )
{
xPressKey = xKb;
}
if ( xPressKey != KB_AN_NONE )
{
BrdLedsSetState( USR_LED2, 1 );
TTimerSetTime( dwUsrLed3TimeHandle, bLedTimeTbl[xKb] );
TTimerStart( dwUsrLed3TimeHandle );
}
xKb++;
if ( xKb == KB_AN_NONE )
{
xKb = KB_AN_RIGHT;
}
}
return 0;
}
A figura abaixo ilustra a aplicação de exemplo funcionando no ambiente final.
Os códigos fontes dos drivers e do exemplo podem ser encontradas projeto criado no github.
Conclusão
Como apresentado no início deste artigo, apresentamos drivers para o teclado resistivo e display LCD compatíveis com o controlador 44780. Também foi demonstrado o uso desses drivers em uma aplicação de exemplo utilizando a placa de avaliação Connected Launchpad da Texas Instruments.
Convido os leitores para que teçam os seus comentários, apontem erros e dêem sugestões de drivers que possamos implementar para outras shields e outras placas de desenvolvimento. Com isso poderemos montar um conjunto de bibliotecas para uso em vários projetos.





Claro que tem coisas que não estão 100%. Por exemplo, como o tempo para escrita no display é um pouco demorado, o mais certo é retirar a escrita no display do contexto da ISR (onde as rotinas do soft-timer executam) e jogar para o user space.
Legal o artigo bem didático e o código limpo e claro! Parabéns e obrigado por compartilhar!
de nada. Se tiver sugestão de dispositivos, é só mandar que damos um jeito.
Excelente Rafael. Parabéns!
Se tiver algum shield ou módulo com interface I2C e SPI seria bacana um driver.
Abraços
Opa!
Estou começando um driver para um BMP180
https://www.adafruit.com/products/1603
E também está na fila um driver para um display desses https://playground.arduino.cc/Main/MAX72XXHardware
Muito bacana. Vai ser top!