Laboratório de Sistemas Microprocessados
Módulo 3 – v8.3
Módulo 3 – Comunicação Serial e Conv. A/D
ORIENTAÇÕES:
O módulo 3 trata de comunicação serial e conversão de sinais analógicos em digitais. Este
módulo vale 25 pontos. Toda semana será selecionado um exercício para receber visto. Serão
4 vistos ao total. Cada visto vale 3 pontos. No final do módulo, um problema será proposto para
sumarizar o conteúdo do módulo. O problema vale 13 pontos.
OBJETIVOS DESTE MÓDULO:
• Compreender protocolos de comunicação serial síncrona e assíncrona.
• Diferenciar bit-banging do uso do periférico dedicado.
• Entender o processo de amostragem e conversão de um sinal analógico em digital.
• Configurar as interfaces seriais e o conversor A/D.
Comunicação Serial
Comunicação serial é o processo de envio de dados de maneira sequencial, um bit após o
outro. Esse tipo de comunicação permite economizar (preciosos) pinos de entrada e saída ao
realizar transferências de grandes quantidades de dados de maneira serial. Ao invés de 16
pinos para enviar uma palavra de 16-bits é necessário apenas 1.
Em sistemas embarcados, dispositivos com funcionalidade específica geralmente implementam
algum tipo de comunicação serial para enviar ou receber dados e instruções. Acelerômetros,
cartões de memória, GPS, sensores de temperatura, umidade e pressão, todos possuem
internamente um microcontrolador que trata o dado bruto e o envia por uma linha serial. Diante
disso, é de suma importância compreender as diferentes formas de comunicação para
interfacear o microcontrolador com outros dispositivos.
Podemos enquadrar a comunicação serial em duas classes:
• Síncrona, na qual é disponibilizado um relógio que indica o instante de validade do bit.
Exemplos: SPI, I2C
• Assíncrona, quando não há a disponibilidade deste relógio. Exemplos: UART, USB.
Comunicação Serial Síncrona: I2C
O protocolo I2C (Inter-Integrated Circuit Communication) permite que vários dispositivos se
conectem a um mesmo barramento e se comuniquem entre si. Esse barramento, também
conhecido como TWI (Two Wire Interface) utiliza apenas dois fios para realizar a comunicação
bidirecional entre diversos dispositivos. Na terminologia utilizada, o dispositivo que está
gerando uma mensagem é chamado de transmissor, enquanto o dispositivo que está
recebendo a mensagem é chamado de receptor. O dispositivo que controla o barramento é
chamado de mestre (master), e os dispositivos que respondem ao mestre são chamados de
escravos (slave). Os dispositivos mestre e escravo assumem o papel de transmissor ou
receptor em diferentes etapas da comunicação. O fio do barramento que carrega dados é
chamado de SDA (Serial DAta). O outro fio estabelece o ritmo de comunicação e é chamado de
SCL (Serial CLock). Apenas o mestre controla o clock, mesmo quando estiver recebendo uma
mensagem.
1
Laboratório de Sistemas Microprocessados
Módulo 3 – v8.3
Figura 1 – Barramento I2C
Sinais de controle: Start e Stop
Quando o barramento está ocioso as linhas SDA e SCL ficam em nível lógico HIGH. Isso é
garantido através de resistores de pull-up como os da Figura 1. Para iniciar uma transmissão, o
mestre força a descida de SDA (mudança de HIGH para LOW) enquanto o clock está em nível
alto. Este sinal é a condição de partida (START), e prepara os dispositivos para a
comunicação. Para finalizar a transmissão, o mestre libera SDA (mudança de LOW para HIGH)
quando o clock está em nível alto. Este sinal é a condição de parada (STOP) liberando assim o
barramento para outras comunicações. Se for necessário reestabelecer a comunicação, deve-
se gerar novamente a condição de partida. A Figura 2 apresenta as condições de START e
STOP.
Figura 2 – Comandos de Start e Stop
Transferência de 1 bit
Na transferência de um bit, como mostrado na Figura 3, o dado em SDA deve permanecer
estável entre a subida e a descida do clock (SCL). Mudanças em SDA enquanto SCL está em
nível alto são entendidas como sinais de controle (como visto nas condições de START e
STOP). Durante a transmissão, o valor de SDA é constante enquanto SCL estiver em nível
HIGH e assume o valor do bit a ser transmitido.
Figura 3 – Transferência de 1 bit
2
Laboratório de Sistemas Microprocessados
Módulo 3 – v8.3
Transferência de uma palavra (8-bits) + ACK/NACK
A comunicação no barramento é feita em bytes (8 bits). A cada byte transmitido, um sinal de
acknowledge (ACK) deve ser gerado. Portanto, para cada byte transmitido, 9 batidas de clock
precisam ser geradas. O número de bytes enviados entre um sinal de START e STOP é
ilimitado. A figura 4 mostra a comunicação entre dois dispositivos. O transmissor envia os 8
primeiros bits e libera a linha no nono bit. O receptor então puxa a linha para LOW indicando
que entendeu a mensagem, com um ACK. Se a linha ficar em HIGH na nona batida do relógio
significa um “not-acknowledge” (NACK) e pode ter diversos significados: pode ser que o
escravo não entendeu a palavra enviada; ou que não há nenhum dispositivo na linha
escutando; ou que o escravo decidiu enviar um NACK de propósito para indicar que não quer
ou não pode mais receber bytes.
Na Figura 4, as ações do mestre-transmissor e escravo-receptor são apresentadas separadas,
porém ambos compartilham a mesma linha SDA. Isso deixa claro que é o escravo (e não o
mestre) que envia o ACK no momento certo. Note que o clock é controlado pelo mestre,
inclusive na batida do ACK. Outra curiosidade interessante, é que no momento do ACK, o
escravo deixa de ser receptor para transmitir o bit de ACK/NACK e o mestre deixa de ser
transmissor para receber o bit de ACK/NACK. Isso reforça a afirmação anterior que diz que o
mestre e escravo assumem papeis de transmissor e receptor em diferentes estágios da
comunicação.
Figura 4 - Transferência de 1 byte
Endereçamento
O primeiro byte enviado logo após a condição de START é especial e é interpretado como
endereço do escravo. São enviados 7 bits de endereço e um bit de leitura/escrita que indica se
o mestre vai ler ou escrever no escravo, como mostrado na Figura 5. O endereço é enviado na
parte mais significativa do primeiro byte e o bit de R/W é enviado por último, ou seja, ele é o
LSB.
Figura 5 - Endereçamento de um escravo.
Após o envio dessa palavra inicial, as próximas são sempre bytes (8 bits) seguidos do ciclo de
ACK/NACK. Por fim, termina-se a comunicação com uma condição de STOP (P).
3
Laboratório de Sistemas Microprocessados
Módulo 3 – v8.3
No MSP430 usamos a interface dedicada USCI, sigla para Universal Serial Communication
Interface. Ela é capaz de se comunicar em UART, SPI e I2C. Nesta primeira parte vamos
estudar apenas o protocolo I2C. A interface pode ser configurada pelos registros UCBxCTL1 e
UCBxCTL0 mostrados na Figura 6:
UCBxCTL0
UCBxCTL1
Figura 6 - Registros de configuração
Perceba que alguns bits (hachurados) só podem ser escritos enquanto a interface estiver
resetada, ou seja, UCSWRST = 1. Para o modo I2C, devemos fazer UCMODE = 3. O bit
UCMST indica se a interface vai se comportar como mestre ou escravo, ou seja, se vai
controlar o clock ou só escutar o clock.
A configuração deve ser feita na seguinte ordem: (1) Resete a interface fazendo o bit
UCSWRST = 1. (2) Configure os registros de controle CTL0 e CTL1 evitando zerar o bit de
reset. (3) Configure os pinos para usar a funcionalidade dedicada (PxSEL). (4) Desative o reset
fazendo UCSWRST = 0. (5) Opcionalmente, habilite as interrupções que forem necessárias.
Configuração como mestre: Quando a interface for configurada como mestre, devemos
escolher o clock nos bits UCSSEL. A frequência do clock pode ser dividida pelo valor escrito
em UCBxBRW. O bit UCTR configura a interface como transmissora (1) ou receptora (0). Os
bits UCTXSTT e UCTXSTP são usados para enviar a sinalização de start e stop,
respectivamente. O endereço do escravo que o mestre quer se comunicar deve ser escrito em
UCBxI2CSA (Slave Address). O valor deve estar disponível antes da sinalização de start.
Durante a comunicação, os bytes podem ser enviados escrevendo em UCBxTXBUF e
recebidos em UCBxRXBUF. As flags de interrupção podem ser encontradas no registro
UCBxIFG. A flag UCTXIFG sinaliza quando o buffer de transmissão estiver vazio e pode ser
escrito. Já a flag UCRXIFG sinaliza quando o buffer de recepção estiver cheio e deve ser lido.
Recomenda-se uma implementação por polling no mestre.
Configuração como escravo: Não há a necessidade de configurar o clock quando a interface for
configurada como escravo. O endereço do escravo deve ser configurado no registro
UCBxI2COA (I2C Own Address). Recomenda-se uma implementação a base de interrupções
para o escravo. Os eventos de TX, RX, NACK, STT e STP podem ser decodificados a partir do
vetor de interrupções (IV) associado à interface.
O MSP430F5529 possui duas instâncias da USCI chamadas de B0 e B1. A interface B0 está
mapeada nos pinos P3.0 (SDA) e P3.1 (SCL). Já a interface B1 está nos pinos P4.1 (SDA) e
P4.2 (SCL). Você deve habilitar os resistores de pull-up internos (e configurar DIR=0) para
garantir o bom funcionamento da interface ou usar resistores externos. Recomendamos não
ultrapassar 100kHz para o clock. Os resistores internos do MSP430 são elevados e limitam a
velocidade de operação da linha.
4
Laboratório de Sistemas Microprocessados
Módulo 3 – v8.3
Exercício 1: Teste da interface I2C.
Neste módulo, iremos usar o LCD de 2x16 caracteres, como mostrado na Figura 7. Neste
primeiro exercício iremos apenas ligar e desligar a retroiluminação do display num ritmo de
1Hz. Configure a interface USCI-B0 como mestre como descrito na página 4. Configure os
pinos P3.0 e P3.1 para usar a função dedicada dessa interface (PxSEL = 1). Não se esqueça
de habilitar os resistores de pull-up ou coloque resistores externos.
Figura 7 – MSP430 conectado ao LCD.
Em seguida, escreva a função uint8_t i2cSend(uint8_t addr, uint8_t data) para fazer
o mestre enviar um byte para o escravo. O primeiro byte é o endereço do escravo e o segundo
é o byte que deve ser enviado. A função deve retornar 0 se houve ACK e 1 se houve NACK.
Implemente essa função seguindo as etapas abaixo:
1. Escreva o endereço do escravo em I2CSA
2. Faça TR = 1 e STT = 1 para requisitar um start como transmissor
3. Escreva o byte data em TXBUF quando o buffer de transmissão ficar vazio (TXIFG = 1)
para destravar o ciclo de ACK
4. Espere o ciclo de acknowledge observando quando STT volta para zero.
5. Se o escravo respondeu (NACKIFG = 0),
a. Espere o byte data ser transmitido (TXIFG=1)
6. Por fim, envie um stop fazendo STP = 1
7. Aguarde STP voltar para zero para garantir que o stop foi enviado
8. Retorne a variável que sinaliza se houve um ACK ou NACK (NACKIFG)
Atenção: existem duas versões do chip PCF8574 com endereços distintos. Faça uma tentativa
para ver qual o endereço de seu chip.
• PCF8574AT → 0x3F e
• PCF8574T → 0x27
Faça a retroiluminação do LCD piscar em aproximadamente 1 Hz. Mande o byte 0x00
para desligar a retroiluminação do LCD e 0x08 para acendê-la.
Sugestão extra: Generalizar a função i2cSend(..) para enviar nBytes.
5
Laboratório de Sistemas Microprocessados
Módulo 3 – v8.3
Exercício 2: Scanner de endereços I2C
Aproveite a configuração do exercício anterior para implementar um scanner de endereços do
barramento I2C i2cScan(uint8_t * addrs). O mestre deve varrer todos os endereços
disponíveis no barramento e escrever num vetor todos os endereços dos dispositivos que
responderam com ACK. DICA: Se você requisitar start e stop ao mesmo tempo, o byte de
dados não é enviado. É recomendado o uso da técnica de amostragem (polling) das flags da
interface USCI ao invés de interrupções.
Liquid Crystal Display (LCD)
É comum utilizar displays de LCD, como o da Figura 8, em aplicações com microcontroladores.
A maioria dos displays do mercado utiliza o controlador HD 44780.
Figura 8 - LCD de 2 linhas e 16 colunas de caracteres.
Esse display tem 16 pinos de interface – 2 pinos de alimentação (Vss, Vdd), 1 para o ajuste de
contraste (Vo), 2 para o backlight (A, K), 8 pinos de dados D[7:0] (1 byte) e 3 pinos de controle
(𝑅𝑆, 𝑅/𝑊 ̅ e 𝐸𝑁). O controlador do LCD aguarda um pulso em 𝐸𝑁 (Enable) para realizar a
leitura/escrita dos dados nos pinos D[7:0].
A Figura 9 apresenta a temporização para acessar o LCD. É importante seguir esse diagrama
de tempo já que o MSP430 é capaz de escrever nas portas do LCD mais rápido do que o
próprio LCD consegue ler. Faz-se necessário o uso de pequenos atrasos para garantir a
temporização especificada.
Figura 9 – Temporização de escrita/leitura no LCD
A duração do pulso de enable não deve ser menor que 𝑇𝐸𝑁 = 300𝑛𝑠 e deve ser espaçado de
𝑇𝐶 ≥ 500ns. Em modo de leitura, o dado fica disponível em D[7:0] 𝑇𝑑 = 90ns após o pulso do
sinal enable. Em modo de escrita, o dado deve estar presente em D[7:0] antes da subida do
pulso de enable.
6
Laboratório de Sistemas Microprocessados
Módulo 3 – v8.3
Tirando os pinos de alimentação, o protocolo completo exige o uso de 11 pinos, entretanto, a
quantidade de pinos de um microcontrolador é um recurso limitado e geralmente escasso.
Alguns microcontroladores do mercado possuem apenas 6 pinos utilizáveis. Com tão poucos
pinos, é impossível implementar o protocolo LCD em modo paralelo. Uma alternativa muito
comum é usar a configuração do LCD para barramento de dados de 4 bits. Neste caso, a
transação de cada byte é feita com 2 acessos de 4 bits, o primeiro para os MSBs e o segundo
para os LSBs. A Figura 10 mostra o caso de uma escrita no LCD.
Figura 10 – Escrita de 1 byte no LCD em modo 4 bits.
No modo de operação em 4 bits, são necessários apenas 7 pinos, que podem ser reduzidos
para 6 se as operações forem apenas de escrita. Se a quantidade de pinos ainda for um fator
limitante do projeto, pode-se usar um conversor de serial para paralelo através de um
registrador de deslocamento com portas bidirecionais.
Figura 11 – Esquemático do conversor serial paralelo e conexão com o LCD
7
Laboratório de Sistemas Microprocessados
Módulo 3 – v8.3
O circuito integrado PCF8574 faz exatamente isso. Ele possui uma interface serial síncrona I2C
que escreve num registrador de deslocamento transformando dados enviados de maneira
serial num barramento paralelo de 8 bits. Desses 8 bits, 3 são usados para controle (𝑅𝑆, 𝑅/𝑊̅ e
𝐸𝑁), 4 bits para o barramento de dados reduzido (modo de 4 bits) e 1 bit para ligar e desligar a
retroiluminação (backlight) do LCD, como mostrado na Figura 11, no pino 16 do LCD.
Inicialização do LCD
A escrita de um caractere é feita com 𝑅𝑆 = 1. Uma escrita com 𝑅𝑆 = 0 permite enviar
instruções. A leitura com 𝑅𝑆 = 0 permite ler a posição atual do cursor e o bit indicativo de
ocupado (BUSY FLAG) que é colocado na posição mais significativa (BIT7). Apenas as
instruções essenciais do LCD estão listadas na tabela 1. A lista completa consta no datasheet
do controlador Hitachi.
Tabela 1 – Comandos do LCD (RS=0, R/W=0).
Comando Valor da instrução (binário) Explicação
Apaga todos os caracteres e retorna o
Limpar display 0 0 0 0 0 0 0 1 cursor para o início (leva 1,53ms para
executar)
Retorna o cursor Retorna o cursor para o início (leva 1,53ms
0 0 0 0 0 0 1 -
para o início para executar)
D=0 Desliga o display, D=1 liga o display,
Configura o
0 0 0 0 1 D C B C=0 Desliga o cursor, C=1 liga o cursor,
display
B=0 Cursor estático, B=1 Cursor piscando
M=0 Modo 4 btis, M=1 Modo 8 bits
Configura a
0 0 1 M L F - - L=0 Display de 1 linha, L=1 Usa 2 linhas
interface
F=0 Fonte 5x8, F=1 Fonte 5x11
Configura que a próxima escrita de dados
Seta o endereço
0 1 𝐴5 𝐴4 𝐴3 𝐴2 𝐴1 𝐴0 com RS = 1 será na CGRAM a partir do
da CGRAM
endereço de 6 bits A[5:0].
Configura que a próxima escrita de dados
Seta o endereço
1 𝐴6 𝐴5 𝐴4 𝐴3 𝐴2 𝐴1 𝐴0 com RS = 1 será na DDRAM a partir do
da DDRAM
endereço de 7 bits A[6:0].
Para inicializar o LCD, precisamos colocá-lo em modo 4-bits. Entretanto, como o estado do
LCD é desconhecido no início do programa, precisamos fazer com que o LCD retorne ao modo
8 bits para garantirmos que ele comece de um estado conhecido. Para fazer isso, precisamos
enviar a instrução [Link] (veja a Tabela 1). No início do programa do MSP430, o
controlador do LCD pode estar num dos estados abaixo:
1. O LCD está em modo 8 bits
2. O LCD está em modo 4 bits esperando o MSNibble
3. O LCD está em modo 4 bits esperando os LSNibble
O primeiro caso é o melhor, pois já estamos no estado que queremos, bastar enviar a instrução
para configurar o modo 4-bits. Se estivermos no segundo caso, não precisamos voltar para o
modo 8-bits, basta continuar configurar o display e o cursor. No terceiro caso, não sabemos
8
Laboratório de Sistemas Microprocessados
Módulo 3 – v8.3
qual foi o MSNibble enviado, então enviamos um nibble qualquer (dummy) para completar a
última palavra e em seguida enviamos mais dois nibbles para enviar uma instrução de
configuração.
Como não sabemos em qual estado o LCD está, precisamos de alguma estratégia para
garantir que o LCD entre num estado conhecido. Vamos enviar o nibble 0x3 três vezes para
garantir que o estado inicial seja o modo 8 bits. O leitor é convidado a testar mentalmente essa
solução nos 3 casos. Note que ela funciona para todos os casos.
Com o LCD em modo 8-bits, prosseguimos enviando a instrução para configurar a interface em
modo 4-bits e as instruções de configuração do display e cursor. Por fim, limpamos o display e
estamos prontos para escrever caracteres. Note que a instrução que limpa o display leva
1,53ms para executar. É recomendado o esperar esse tempo ao final da inicialização
antes de escrever caracteres no display.
Exercício 3: Escreva uma função lcdWriteNibble(uint8_t nibble, uint8_t isChar)
para escrever um nibble no LCD em modo 4 bits seguindo o diagrama ilustrado na Figura 10.
Faça uso da função i2cSend(...) 3 vezes da seguinte forma:
1. Prepare RS (isChar) e D[7:4] com EN=0 e R/W = 0 (write)
2. Em seguida mantenha R/W, RS e D[7:4] constantes e faça EN=1.
3. Por fim, faça EN voltar a 0 mantendo os outros campos constantes.
A variável isChar deve representar o valor de RS, ou seja, se for 1 o nibble representa parte
de um caractere, se for 0 o nibble é parte de uma instrução.
Exercício 4: Escreva a função lcdWriteByte(uint8_t byte, uint8_t isChar), chamando
lcdWriteNibble duas vezes. O primeiro nibble enviado corresponde aos 4 bits mais
significativos do byte conforme descrito na Figura 10.
Exercício 5: Escreva a função lcdInit() que inicializa o LCD seguindo o que foi descrito na
seção “Inicialização do LCD”. Note que você irá utilizar a função lcdWriteNibble três vezes
para garantir que o LCD parte de um estado conhecido, ou seja, do modo 8 bits. Em seguida,
coloca-se o LCD em modo 4 bits chamando a função lcdWriteNibble uma quarta vez. A partir
daí devemos usar apenas a função lcdWriteByte para escrever as próximas instruções.
Lembre-se que toda instrução é escrita com RS = 0, ou seja, isChar = 0.
Exercício 6: Escreva a função lcdWrite(char *str) que escreve uma string no LCD e
gerencia a quebra de linha. Lembre-se que uma string é representada por uma sequência de
caracteres que termina no byte 0x00.
Exercício 7: Repita a lógica dos exercícios 3 e 4 para fazer a leitura de um nibble e depois de
um byte numa função lcdReadByte(...). O momento ideal de leitura é no meio do pulso do EN.
Exercício 8: Use a rotina do exercício 7 para escrever a função uint8_t lcdBusy() e verificar
se o LCD está ocupado. A função não recebe nenhum parâmetro de entrada e deve retornar o
valor do bit busy.
9
Laboratório de Sistemas Microprocessados
Módulo 3 – v8.3
Conversor A/D e DMA
Conversores A/D são dispositivos de interface entre o mundo analógico e o mundo digital. Eles
permitem que um microcontrolador colete dados de transdutores que convertem grandezas
físicas (como som, luz, temperatura, pH) no formato de tensão.
Neste roteiro, iremos estudar o princípio da conversão A/D. Para isso, utilizaremos divisores
resistivos (na forma de potenciômetros) na entrada do conversor. Dessa forma, iremos realizar
leituras de tensões proporcionais à posição do potenciômetro.
Um dispositivo simples que aplica esse princípio é o manche de um joystick. Esse dispositivo é
tipicamente composto por dois potenciômetros, um para o eixo x e outro para o eixo y, como
mostrado na Figura 12. Os dois terminais de leitura da posição do eixo x e y são na verdade
valores de tensão entre uma referência positiva (ex: 3,3V) e uma referência negativa (ex: 0V).
Importante: ao conectar o joystick à LaunchPad, o pino rotulado de +5V deve ser ligado ao pino
3,3V. NÃO O LIGUE AOS 5V. Um sinal acima de 3,3V pode queimar o pino do MSP430.
Figura 12 – Joystick com dois potenciômetros e
visualização interna de um pot.
O MSP430 possui um conversor A/D integrado de até 12 bits que funciona por aproximações
sucessivas. Num primeiro momento, o sinal de entrada é amostrado e a tensão da entrada
carrega um capacitor que guarda essa tensão. Numa segunda etapa, o conversor testa bit a bit,
começando do MSB até o LSB para descobrir qual é o valor binário que melhor representa
aquele nível de tensão. A Figura 13 mostra as etapas de conversão de um caso simplificado de
apenas 3 bits.
10
Laboratório de Sistemas Microprocessados
Módulo 3 – v8.3
Figura 13 – Etapas de conversão de um conversor por aproximações sucessivas
No exemplo da Figura 13, a tensão de entrada 𝑉𝑖𝑛 está acima da metade da referência. Assim,
na primeira etapa de conversão, o conversor A/D atribui o valor “1” ao MSB. Em seguida, o
conversor divide a escala da etapa anterior (região hachurada) em duas e verifica se a entrada
se encontra na parte superior ou inferior. No exemplo a tensão se encontra na parte inferior da
segunda etapa e então o segundo bit é “0”. Por fim, repete-se esse procedimento até que todos
os bits sejam definidos. No exemplo, a palavra binária que representa a tensão 𝑉𝑖𝑛 é 101.
O MSP430 disponibiliza um conversor A/D de 12 bits, compartilhado entre 16 entradas, como
mostrado na Figura 14. Somente uma entrada analógica por ser convertida a cada vez.
Figura 14 – Conversor AD do MSP430.
11
Laboratório de Sistemas Microprocessados
Módulo 3 – v8.3
Para que a conversão seja feita em etapas sucessivas, é necessário que a entrada 𝑉𝑖𝑛 esteja
estável durante todo o processo de conversão. Isso é garantido através de um capacitor na
entrada do conversor. Devido à natureza desse elemento, o capacitor leva um certo tempo para
acumular carga, então é necessária uma etapa de amostragem do sinal antes de iniciar a
conversão. Esse processo é conhecido como sample and hold. A Figura 15 modela a entrada
do conversor A/D. O resistor Ri representa a resistência de entrada do multiplexador e o
capacitor Ci representa o bloco “Sample and Hold”.
Figura 15 – Amostragem da entrada
A resistência de saída do dispositivo externo (RS) conectado à porta do conversor AD influencia
o tempo de amostragem, ou seja, o tempo que leva para o capacitor da entrada (Ci) carregar.
Inicie o seu projeto calculando o tempo de carga do capacitor de entrada do conversor A/D
seguindo a seguinte expressão:
𝑡𝑐𝑎𝑝 = (𝑅𝑆 + 𝑅𝐼 ) ∙ 𝐶𝑖 ∙ 𝑙𝑛(2𝑁+1 ) + 800𝑛𝑠
Considere a resistência interna de 1,8kΩ (resistência do mux de entrada do conversor) e o
capacitor interno de 25pF. A resistência Rs deve ser o valor do potenciômetro no pior caso de
medida, ou seja, em 50%. Para pequenas variações (quando alteramos a posição do
potenciômetro) o MSP “enxerga” dois caminhos para a referência e no pior caso a resistência
vista pelo MSP é dada por:
𝑅𝑝𝑜𝑡 𝑅𝑝𝑜𝑡 𝑅𝑝𝑜𝑡
𝑅𝑆 = ‖ =
2 2 4
Exercício 9:
O ADC12 possui um timer interno que pode ser usado para garantir o tempo de carregamento
do capacitor 𝑡𝑐𝑎𝑝 . Se o potenciômetro tem 10kΩ de resistência total, qual é o valor de 𝑡𝑐𝑎𝑝 ?
Consequentemente, se SHP=1, qual deve ser o valor de SHT se escolhermos o clock SMCLK
@1MHz?
Exercício 10:
Escreva a função uint16_t adcRead(uint8_t pin) que faz uma leitura pontual de qualquer
pino da porta P6. Considere no pior caso, sensores com 50kΩ de resistência. Use 12 bits de
resolução. Use o modo single-channel, single-conversion.
12
Laboratório de Sistemas Microprocessados
Módulo 3 – v8.3
Exercício 11:
Configure o módulo do conversor A/D em modo repeated single channel, para amostrar a
tensão de entrada que representa apenas um eixo da posição do joystick. Use apenas 8 bits de
resolução. Configure um timer para realizar essa amostragem a cada 100ms. Você pode plotar
o resultado da leitura no próprio CCS colocando o vetor na aba de variáveis ou de expressões
(Watch). Em seguida, clique no vetor com o botão direito e selecione a opção “Graph Selected
Value”, como mostrado na Figura 16.
Figura 16 – Plotar um gráfico a partir de um vetor no CCS
Exercício 12:
Repita o exercício anterior sem usar o timer interno do ADC (SHP = 0). Use o canal 1 do timer
A0 e o escolha como fonte do gatilho, ou seja, faça SHS = 1. Não há mais necessidade de
configurar o SHT. No timer, configure o canal 1 para gerar um sinal PWM e ajuste o valor de
CCR1 para se adequar ao tempo de carregamento do capacitor projetado no exercício anterior.
Se desejar precisão, use a frequência do SMCLK dividida por 2.
Exercício 13:
Incremente o exercício anterior para fazer a leitura dos dois eixos do joystick. Use o modo
sequencial repetitivo e configure o controlador do buffer de memória para ler os dois canais. No
último canal, ative o bit de final de sequência (EOS). Evite usar o bit MSC no modo sequencial
repetitivo.
Exercício 14:
Neste programa, iremos ler simultaneamente (ou quase) o valor da posição de dois eixos do
potenciômetro. Use a informação da posição dos dois eixos para controlar a luminosidade dos
dois LEDs da LaunchPad. Se a posição do joystick estiver no centro, os dois LEDs devem estar
em 50% da luminosidade.
Use o eixo X para controlar a luminosidade do LED vermelho e o eixo Y para controlar a
luminosidade do LED verde. Trabalhe com um sinal PWM a 100Hz com 256 passos (de 0 a
255). Ajuste a resolução do conversor A/D para 8-bits de forma a ficar na mesma resolução da
PWM. Amostre a posição do potenciômetro a cada 20ms (50Hz). A figura 17 apresenta um
diagrama do sistema proposto.
13
Laboratório de Sistemas Microprocessados
Módulo 3 – v8.3
Figura 17 – Controle do brilho dos leds usando um joystick
Neste exercício, utilizaremos a saída dos canais 1 e 2 do timer B para controlar a luminosidade
de ambos os LEDs. Para isso, use a porta P4 que permite remapear a funcionalidade dedicada
de seus pinos como no exemplo abaixo.
// Configure o mapeamento dos pinos da porta P4
PMAPKEYID = 0x02D52; // Escreve a senha para liberar a config do PMAP
P4MAP3 = PM_TB0CCR1A; // Conecta P4.3 na saída do canal 1 do timer B
P4MAP7 = PM_TB0CCR2A; // Conecta P4.7 na saída do canal 2 do timer B
Copiar regiões de memória, seja entre periféricos ou entre posições de memória, é uma tarefa
trivial e bastante comum em programas de sistemas embarcados. O DMA (Direct Memory
Access) é um periférico dedicado para realizar transferência de dados e permite que cópias
sejam realizadas sem intervenção do processador. Neste exercício, utilize o DMA para mover o
resultado da conversão para os canais de saída do timer B e consequentemente ajustar a
largura do pulso de saída automaticamente (isso irá modificar a luminosidade do LED).
Se não souber usar o DMA ainda, use a interrupção do ADC para mover os resultados de
conversão para o CCR1 e CCR2 do timerB.
14
Laboratório de Sistemas Microprocessados
Módulo 3 – v8.3
Comunicação Serial Assíncrona
A comunicação serial assíncrona é provavelmente a forma serial mais simples de todas. Sua
popularidade vem justamente da sua simplicidade e facilidade de implementar usando lógica
digital ou microcontroladores.
Para cada linha serial, a comunicação está ociosa quando em nível alto. Para iniciar uma
transmissão, é necessário puxar a linha para nível baixo e transmitir bit a bit de maneira
sequencial, começando pelo menos significativo. A taxa de transferência é um acordo prévio,
ou seja, ambas as partes devem estar configuradas para se comunicar na mesma velocidade.
Figura 18 – Comunicação serial assíncrona
Um dispositivo UART (Universal Asynchronous Receiver/Transmitter) não permite comunicação
bidirecional através de um único fio. São necessários pelo menos dois fios para uma
comunicação full-duplex. Uma particularidade desta forma de comunicação é a ausência de
sincronia entre o transmissor e receptor. Isso pode levar a erros de comunicação caso haja
diferença significativa entre os clocks internos de cada dispositivo e limita a taxa de
comunicação possível entre dispositivos. O máximo recomendado é de aproximadamente
100kbps, entretanto, o valor mais comum é de 9600bps.
O MSP430 possui um módulo de comunicação serial dedicado. Isso torna o processo de
comunicação tão simples quanto escrever num registro e esperar que o byte seja enviado pela
linha serial. Isso nem sempre acontece com microcontroladores mais simples. Nesses casos o
protocolo deve ser implementado manualmente através de leituras e escritas dos pinos. Este
tipo de implementação é chamado de bit-banging e exige cuidado extra com a temporização
para não perder sincronia.
Exercício 15:
A interface serial USCI-A0 está roteada nos pinos P3.3 (TX) e P3.4 (RX). Configure esses
pinos para sua funcionalidade dedicada. Conecte os dois como na Figura 19 para testar a
interface de comunicação serial. Note que a USCI transmite e recebe o dado transmitido. Para
este exercício, e para os próximos, iremos trabalhar à uma taxa (baudrate) de 1200 bps. Teste
a interface enviando um byte qualquer e verifique que ele é recebido de volta. Verifique, através
de breakpoints nas interrupções, ou por amostragem da flag de recepção (RXIFG), se o valor
foi recebido corretamente no buffer de recepção.
P3.3
uC
P3.4
Figura 19 – USCI transmitindo pelo pino P3.3 e
recebendo o dado transmitido pelo pino P3.4.
15
Laboratório de Sistemas Microprocessados
Módulo 3 – v8.3
Exercício 16:
Ainda com a mesma configuração do exercício anterior, envie e receba o seu nome pela
interface serial, caractere por caractere. Use dois vetores:
• char nome_tx[] = “Joaquim José” → com o nome a ser transmitido e
• char nome_rx[] = “xxxxxxxxxxxx” → espaço para receber o nome
Lembre-se de que as strings terminam com zero (‘\0’). Use este fato para finalizar tanto a
transmissão quanto a recepção.
Exercício 17:
Utilize a interface serial para controlar os LEDs de outro microcontrolador. Ao pressionar o
botão S1 o LED vermelho do outro uC deve alternar, já o botão S2 controla o LED verde. A
ligação entre dois microcontroladores deve ser feita conforme a Figura 20.
P3.3 P3.3
MSP430 MSP430
P3.4 P3.4
Figura 20 – Conexão para comunicação entre dois MSPs.
O receptor responde aos seguintes códigos:
• 0x01 – Liga o LED vermelho • 0x10 – Liga o LED verde
• 0x0A – Apaga o LED vermelho • 0xA0 – Apaga o LED verde
O transmissor deve enviar apenas um código a cada pressionar de botão:
• S1 – Envia 0x01 e 0x0A alternadamente
• S2 – Envia 0x10 e 0xA0 alternadamente
Exemplo: Ao pressionar uma vez o botão S1 o transmissor deve enviar a palavra 0x01. Ao
pressionar uma segunda vez, o transmissor envia 0x0A.
Exercício 18:
Iremos repetir o exercício anterior usando a técnica de bit-banging. Este exercício é importante
pois nem todos os microcontroladores disponíveis no mercado possuem interfaces de
comunicação serial dedicada. Você pode usar os mesmos pinos do exercício anterior, porém
em modo GPIO. Mantenha a mesma taxa de transferência que os exercícios anteriores. A
recepção dos dados deve ser feita no centro da janela (temporal) de cada bit, conforme a
Figura 18, pois assim se evita erros de recepção caso os dispositivos estejam ligeiramente fora
de sincronia.
Exercício 19:
A LaunchPad oferece uma conexão UART com o PC que pode ser muito útil para auxiliar na
depuração do código. A Figura 21 apresenta um esquema desta conexão serial. Veja que a
placa programadora “eZ-FET” funciona como um conversor USB/Serial pelos pinos P4.4 e P4.5
que estão conectados na instância USCI_A1. Esta é uma conexão interna à LaunchPad. Você
não precisa ligar cabo algum, apenas use a USCI_A1. No PC, deve ser usado um emulador de
terminal serial. Sugerimos o uso do terminal do próprio CCS.
16
Laboratório de Sistemas Microprocessados
Módulo 3 – v8.3
Figura 21 – Conexão serial entre o PC e o MSP.
Quando você conecta o MSP no computador, o Sistema Operacional detecta dois dispositivos
UART. Um para depuração e outro para uso geral chamado “MSP Application UART1”. No
Windows, você pode descobrir o número da porta (COMx) no gerenciador de dispositivos como
ilustrado na Figura 22. No Linux, o dispositivo é criado no arquivo /dev/ttyACMx. No Mac é o
dispositivo /dev/[Link] (escolher o dispositivo de maior número).
Figura 22 – Seleção da porta (COM) a ser usada no PC.
Para criar um terminal no Code Composer, clique em View → Console → Serial Console.
Encontre a janela do terminal “Serial Console” e abra uma nova conexão. Configure os
detalhes da conexão da mesma forma que você fez no MSP430. Veja a Figura 23.
Neste exercício vamos criar uma função void uartPrint(char * str) que envia uma string
pela interface serial USCI_A1 e exibe a string no computador pelo terminal serial do CCS.
Vamos gerenciar a recepção por interrupções. Grave o que for recebido num buffer circular de
32 caracteres na ISR da USCI_A1.
17
Laboratório de Sistemas Microprocessados
Módulo 3 – v8.3
Figura 23: Criação de uma conexão serial com o MSP no CCS
Passo 1 – Abrir a vista do terminal serial
Passo 2 – Abrir uma nova conexão
Passo 3 – Configurar a conexão
18
Laboratório de Sistemas Microprocessados
Módulo 3 – v8.3
Problema 3 – Conversor A/D, LCD e UART
OBJETIVO:
Fazer um osciloscópio digital usando as entradas do A/D do MSP430.
PEDIDO:
Osciloscópios são aparelhos muito úteis para visualizar formas de onda, otimizar, depurar ou
simplesmente estudar circuitos. Neste exercício iremos projetar um osciloscópio digital de até 8
entradas usando o MSP430. O usuário poderá selecionar quantos canais quer usar através de
uma interface UART pelo PC. Os requisitos de projeto são:
1) A resolução deve ser fixa em 12 bits.
2) O valor das leituras será mostrado em hexadecimal usando 3 algarismos.
3) O MSP pode receber a qualquer momento, um dígito N de 1 a 8 que servirá para
(re)configurar o número de canais.
4) A UART deve operar em 19200 bps.
5) O formato de impressão deve ser c: xxx, onde “c” é o número do canal e “xxx” é o
valor lido em hexadecimal. Exemplo com 3 canais:
0: 800
1: FFF
2: 4A3
6) No LCD será mostrado apenas o canal A0. O terminal UART mostrará os N canais
7) A taxa de amostragem depende do número de canais. Ela deve ser configurada para
200/N amostras por segundo.
8) Considere uma resistência externa de 10kΩ.
DICAS:
a) As sequências de caracteres abaixo podem ser usadas para limpar a tela ou fazer o
cursor retornar para o início da linha.
#define TERM_CLR "\033[2J"
#define TERM_HOME "\033[0;0H"
b) Para escrever uma nova linha a partir do início deve-se enviar os caracteres “\n” (nova
linha) e “\r” (retorna o cursor para o início da linha).
c) Você pode usar a função sprintf(str_out, “%03x”, value) da biblioteca “string.h”
para gerar uma string (str_out) correspondente a um número (value) em hexadecimal
com 3 dígitos fixos com preenchimento de zeros à esquerda.
d) Implemente a transmissão UART por pooling (na main)
e) Implemente a recepção UART por interrupção
f) Use um timer para gerenciar o gatilho de amostragem do ADC
g) Se for usar o joystick para testar, não conecte a alimentação em 5V. Lembre-se que o
MSP430 opera em 3V3.
19