collapse

* Posts Recentes

Arame de Estendal por almamater
[Ontem às 16:16]


O que é isto ? por SerraCabo
[12 de Abril de 2024, 14:20]


Amplificador - Rockboard HA 1 In-Ear por almamater
[11 de Abril de 2024, 20:46]


Emulador NES em ESP32 por dropes
[10 de Abril de 2024, 15:30]


Meu novo robô por josecarlos
[29 de Março de 2024, 18:30]


Bateria - Portátil por almamater
[25 de Março de 2024, 22:14]


Escolher Osciloscópio por jm_araujo
[06 de Fevereiro de 2024, 23:07]


TP4056 - Dúvida por dropes
[31 de Janeiro de 2024, 14:13]


Leitura de dados por Porta Serie por jm_araujo
[22 de Janeiro de 2024, 14:00]


Distancia Cabo por jm_araujo
[08 de Janeiro de 2024, 16:30]

Autor Tópico: Introdução ao avr-gcc usando o AvrStudio [Mais timers/mood light]  (Lida 116386 vezes)

0 Membros e 1 Visitante estão a ver este tópico.

Offline Njay

  • Mini Robot
  • *
  • Mensagens: 3.598
    • Tróniquices
Re: Introdução ao avr-gcc usando o AvrStudio
« Responder #15 em: 29 de Setembro de 2010, 00:52 »
Tenho uma questão: estive a fazer um programa que altera um número num LCD. Consegui pô-lo a funcionar perfeitamente. No entanto queria que fosse mais portátil caso decidisse alterar os pinos usados. Para isso, queria guardar em três arrays os seguintes dados para cada ligação: o register de direcção de dados, o register da porta e o bit (neste momento apenas guardo os bits, usando apenas um register DDR e PORT para todos).
Alguém sabe qual o tipo de dados que uso para guardar os registers PORT e DDR num array? (será que um void * a apontar para a variável funcionaria?)
Nos includes, só encontro que são o resultado de _SFR_IO8(valor), mas não faço a mínima ideia do que essa macro faça :S

Como 1ª aproximação eu colocava as definições dos portos e pinos num ficheiro .h à parte, e depois mudava esse ficheiro para cada aplicação. Esse ficheiro teria qq coisa do género

#define DATA0_AVRPORT  A
#define DATA0_BIT  3
#define DATA1_AVRPORT  A
#define DATA1_BIT  4
...


Depois na biblioteca do LCD criava macros para usar os valores definidos, tipo isto:

#define DATA0_PORT_DIR(port)  DDR # port
#define DATA0_PORT_VAL(port)  PORT # port
#define DATA1_PORT_DIR(port)  DDR # port
#define DATA1_PORT_VAL(port)  PORT # port
...


E para usar no código do LCD faria isto:

// inicialização
DATA0_PORT_DIR(DATA0_AVRPORT) |= _BV(DATA0_BIT);
DATA1_PORT_DIR(DATA1_AVRPORT) |= _BV(DATA1_BIT);
...

// utilização
DATA0_PORT_VAL(DATA0_AVRPORT) |= _BV(DATA0_BIT);


Podes simplificar se assumires que por exemplo todas as linhas de dados estão no mesmo porto. E em vez de criar o .h, também podes passar directamente os valores das macros na linha de compilação, tipo

gcc ... -DDATA0_AVRPORT=A -DDATA0_BIT=3 ...

É capaz de haver formas mais elegantes de fazer isto mas era o que eu começava por fazer.

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.733
  • Helpdesk do sitio
Re: Introdução ao avr-gcc usando o AvrStudio
« Responder #16 em: 29 de Setembro de 2010, 00:56 »
Mas que grande coding ninja que o senhor Njay se está a revelar!!
Avr fanboy

Offline Cynary

  • Mini Robot
  • *
  • Mensagens: 182
Re: Introdução ao avr-gcc usando o AvrStudio
« Responder #17 em: 29 de Setembro de 2010, 09:08 »
Njay, a tua solução é válida, e é mais ou menos o que eu fiz.
No entanto, não era bem isso que que eu queria, pois queria ser capaz de percorrer os DDR e PORTs num loop, e essa aproximação não mo permite.
O que eu preciso é mesmo de saber que tipo usar para guardar os valores das PORT e DDR numa array. Para colocar num loop também tenho a opção de criar uma função que use um switch, mas não é exactamente a forma mais prática de o fazer :S

Offline Njay

  • Mini Robot
  • *
  • Mensagens: 3.598
    • Tróniquices
Re: Introdução ao avr-gcc usando o AvrStudio
« Responder #18 em: 29 de Setembro de 2010, 10:15 »
Acho que podes fazer isso guardando o endereço do registo. No entanto, queres isso assim para quê? Estás a pensar mudar o LCD de pinos dinamicamente, já com o programa a correr? Não me parece... além disso esse código vai-te ocupar espaço desnecessariamente e nunca vais realmente dar-lhe uso, porque o mapeamento de pinos nunca irá mudar durante a execução do programa.

Offline Cynary

  • Mini Robot
  • *
  • Mensagens: 182
Re: Introdução ao avr-gcc usando o AvrStudio
« Responder #19 em: 29 de Setembro de 2010, 11:32 »
Acho que podes fazer isso guardando o endereço do registo. No entanto, queres isso assim para quê? Estás a pensar mudar o LCD de pinos dinamicamente, já com o programa a correr? Não me parece... além disso esse código vai-te ocupar espaço desnecessariamente e nunca vais realmente dar-lhe uso, porque o mapeamento de pinos nunca irá mudar durante a execução do programa.

Não estou a pensar mudar dinamicamente durante a execução do programa. O que quero é codificar de forma a que, caso mude de pinos usados, ou mesmo para um display que use um número diferente de pinos, seja fácil de mudar ...
E quanto ao espaço, em princípio o compilador otimiza de forma a ter o ratio de espaço/performance melhor que estiver programado para fazer (por exemplo, em vez de usar um loop for para iterar 7 pinos, provavelmente coloca as instruções separadamente, e elimina-me as arrays).
O meu objectivo é mesmo fazer um código fácil de alterar caso seja necessário.
Mas que tipo de estrutura de dados uso para guardar o endereço do registo?

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.733
  • Helpdesk do sitio
Re: Introdução ao avr-gcc usando o AvrStudio
« Responder #20 em: 29 de Setembro de 2010, 11:41 »
Uma estrutura?
Queres fazer algo á moda da inicizalização de um lcd no arduino, é isso?
Avr fanboy

Offline Cynary

  • Mini Robot
  • *
  • Mensagens: 182
Re: Introdução ao avr-gcc usando o AvrStudio
« Responder #21 em: 29 de Setembro de 2010, 11:47 »
Uma estrutura?
Queres fazer algo á moda da inicizalização de um lcd no arduino, é isso?

Por estrutura de dados queria dizer tipo de dados (mas até pode ser uma estrutura, pois eu não faço a mínima ideia como é que os registers são representados num programa em C :/).
Queria por exemplo fazer uma coisa assim:

Código: (c) [Seleccione]
#define DPINS 7
tipo_register display_ports[DPINS] = {PORTB, PORTC, PORTD, PORTB, PORTB, PORTB, PORTB};
tipo_register display_ddrs[DPINS] = {DDRB, DDRC, DDRD, DDRB, DDRB, DDRB, DDRB};
Apenas me falta o tipo_register :S

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.733
  • Helpdesk do sitio
Re: Introdução ao avr-gcc usando o AvrStudio
« Responder #22 em: 29 de Setembro de 2010, 11:58 »
os registos são de 8bits, logo um uint8_t serve.
Avr fanboy

Offline Njay

  • Mini Robot
  • *
  • Mensagens: 3.598
    • Tróniquices
Re: Introdução ao avr-gcc usando o AvrStudio
« Responder #23 em: 29 de Setembro de 2010, 13:38 »
Continuo sem ver a vantagem do que queres fazer. Acho que vai ocupar mais espaço, e vai ficar mais complicado porque agora tens que lidar com os endereços dos registos em vez dos nomes, e esses endereços podem ser diferentes para cada chip -> lá se foi a tua portabilidade.

Qual é o problema que vês na solução com macros?
« Última modificação: 29 de Setembro de 2010, 13:39 por Njay »

Offline Cynary

  • Mini Robot
  • *
  • Mensagens: 182
Re: Introdução ao avr-gcc usando o AvrStudio
« Responder #24 em: 29 de Setembro de 2010, 14:06 »
A solução com macros funciona perfeitamente, e neste momento é a que estou a utilizar, e se não encontrar forma de fazer o que quero, fico com essa. O problema é mesmo não poder iterar pelos diferentes endereços se usar macros :S
Eu não quero ter de trabalhar com os endereços! Penso que percebeste mal essa parte. Eu quero é guardar o valor do nome (PORTB por exemplo) numa variável (ou num ponteiro que depois possa referenciar, de forma a usar o PORTB) -- se tiver de usar endereços directos dos registers, perco a portabilidade de chip para chip, e concodo que é melhor ter mais algum trabalho se precisar de modificar o código, do que perder essa portabilidade.
Um uint8_t não serve aparentemente :S dá-me este erro no compilador:

Código: [Seleccione]
error: initializer element is not constant(já tentei declarar a variável como const, e dá-me o erro de estar a escrever numa variável só de leitura)

Vou dar um exemplo do que quero fazer, a ver se fica mais claro (o que me falta é mesmo o tipo_register :S):

Código: (c) [Seleccione]
#include <avr/io.h>
#include <util/delay.h>

#define DPINS 7

unsigned char display[10][DPINS] = {{1,1,1,1,1,1,0}, {0,1,1,1,0,0,0}, {0,1,1,0,1,1,1}, {0,1,1,1,1,0,1}, {1,0,1,1,0,0,1}, {1,1,0,1,1,0,1}, {0,1,1,1,1,1,1}, {0,1,1,1,0,0,0}, {1,1,1,1,1,1,1}, {1,1,1,1,0,0,1}};
unsigned char display_bits[DPINS] = {PB0, PB1, PB2, PB3, PB4, PB5, PB6};
tipo_register display_ports[DPINS] = {PORTB, PORTB, PORTB, PORTB, PORTB, PORTB, PORTB};
tipo_register display_ddrs[DPINS] = {DDRB, DDRB, DDRB, DDRB, DDRB, DDRB, DDRB};

unsigned char n;

void putnumber() {
  unsigned char i;
  n %= 10;
  for(i = 0; i < DPINS; ++i) {
    display_ports[i] &= ~(1<<display_bits[i]);
    display_ports[i] |= (display[n][i]<<display_bits[i]); } }
(os DDR são inicializados no main neste caso; não se preocupem com a ordem dos 1s e dos 0s no exemplo, visto que depende da forma como o display está ligado)
Neste momento, como os registers de direcção e porta que uso são todos iguais, posso usar uma definição facilmente. Mas se quiser usar um display que usa mais ligações, de forma a que uma porta não seja suficiente, ou se tiver alguns dos pinos já ocupados, quero facilmente poder alterar alguns dos pinos da PORTB para PORTD por exemplo.
Usar macros funciona, e se usar sempre o mesmo número de pinos para o display, fica bastante portátil, mesmo que altere os pinos usados. Mas se mudar para displays que usem um número diferente de pinos, ou até se fizer, por exemplo, um contador binário com LEDs, com mais do que 7 pinos, tenho de alterar muito mais código.
Se desse para fazer uma macro em que se pudesse iterar, como por exemplo (este código não funciona, mas penso que demonstra o conceito):

Código: (c) [Seleccione]
#define DDR0 DDRA
#define DDR1 DDRB
...
#define DDR(n) DDR # n
...
for(i = 0; i < DPINS; ++i) {
  DDR(i) |= (1<<display_bits[i]); }
...

PS: Testei as macros que fizeste, e elas não funcionam com o avr-gcc :S só se estás a usar algum argumento diferente dos meus ...
« Última modificação: 29 de Setembro de 2010, 14:27 por Cynary »

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.733
  • Helpdesk do sitio
Re: Introdução ao avr-gcc usando o AvrStudio
« Responder #25 em: 29 de Setembro de 2010, 15:15 »
Vê o código da biblioteca para lcd's que eu meti ai em cima e podes ver como é que a pessoa que a fez usa as macros para isso.
Continuo a achar a tua solução muito arduinesca..
Acho que deves usar os portos na totalidade, porque assim não tens de andar a fazer ands e ors nos registos para só mexer um bit ou dois.
Avr fanboy

Offline Cynary

  • Mini Robot
  • *
  • Mensagens: 182
Re: Introdução ao avr-gcc usando o AvrStudio
« Responder #26 em: 29 de Setembro de 2010, 18:10 »
Estive a ver o código da biblioteca, e ajudou-me a pensar um pouco.
Afinal tinhas razão senso, um uint8_t (neste caso usei unsigned char, mas dá no mesmo xD) funciona como ponteiro para o register, só me tinha esquecido de fazer o casting -.-.
O código ficou assim:

Código: (c) [Seleccione]
#include <avr/io.h>
#include <util/delay.h>

#define DPINS 7

unsigned char display[10][DPINS] = {{1,1,1,1,1,1,0}, {0,1,1,1,0,0,0}, {0,1,1,0,1,1,1}, {0,1,1,1,1,0,1}, {1,0,1,1,0,0,1}, {1,1,0,1,1,0,1}, {1,1,0,1,1,1,1}, {0,1,1,1,0,0,0}, {1,1,1,1,1,1,1}, {1,1,1,1,0,0,1}};
unsigned char display_bits[DPINS] = {PB0, PB1, PB2, PB3, PB4, PB5, PB6};
unsigned char *display_ports[DPINS] = {(unsigned char *)&PORTB, (unsigned char *)&PORTB, (unsigned char *)&PORTB, (unsigned char *)&PORTB, (unsigned char *)&PORTB, (unsigned char *)&PORTB, (unsigned char *)&PORTB};
unsigned char *display_ddrs[DPINS] = {(unsigned char *)&DDRB, (unsigned char *)&DDRB, (unsigned char *)&DDRB, (unsigned char *)&DDRB, (unsigned char *)&DDRB, (unsigned char *)&DDRB, (unsigned char *)&DDRB};

unsigned char n;

void putnumber() {
  unsigned char i;
  n %= 10;
  for(i = 0; i < DPINS; ++i) {
    *display_ports[i] &= ~(1<<display_bits[i]);
    *display_ports[i] |= (display[n][i]<<display_bits[i]); } }

Em termos de eficiência, não me preocupei muito com isso ao fazer este código, porque tinha como objectivo aprender e experimentar (por exemplo, queria saber como podia guardar uma referência a um register arbitrário numa variável, agora sei :P), em vez de fazer uma aplicação final ...

Offline Njay

  • Mini Robot
  • *
  • Mensagens: 3.598
    • Tróniquices
Re: Introdução ao avr-gcc usando o AvrStudio
« Responder #27 em: 30 de Setembro de 2010, 00:09 »
(...) tinha como objectivo aprender e experimentar (...)

É mesmo a única razão que vejo para fazeres as coisas dessa forma.

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.733
  • Helpdesk do sitio
Re: Introdução ao avr-gcc usando o AvrStudio
« Responder #28 em: 01 de Outubro de 2010, 00:18 »
   Boa noite a todos, hoje vou continuar o tutorial falando-vos sobre a usart.
Mas o que é a usart(ou uart), a usart é um módulo de hardware que está dentro dos nossos atmegas, que permite ao nosso chip comunicar com outros dispositivos usando um protocolo serial, isto quer dizer que com apenas dois fios podemos enviar e receber dados.
   Um dos maiores usos da usart é a comunicação serial com o nosso computador, e para isso temos de configurar a usart para ela fazer exactamente aquilo que queremos.

   Esqueci-me de referir no anterior tutorial, mas um dos vossos melhores amigos quando programam um micro-controlador é o seu datasheet, no caso do atmega328p podem fazer o download do mesmo aqui:
Citar
http://www.atmel.com/dyn/resources/prod_documents/doc8271.pdf

   Sempre que programa-mos pode-mos manter um esqueleto básico para iniciar a programação, a partir de agora vou usar sempre este esqueleto, que tem os includes e a declaração do main:
Código: [Seleccione]
#define F_CPU 16000000UL //permite usar os delays calibrados
#include <avr/io.h> //definições gerais de pinos e registos
#include <util/delay.h> //local onde estão as funções de delay

int main(void){ //inicio da função main
//O vosso programa fica entre as chavetas

return 0; //toda a função não void tem de ter um return
}

   Sempre que quiserem programar podem usar este esqueleto que são sempre uns caracteres a menos que têm de escrever.
   Falando agora especificamente de como activar e usar a nossa usart para falar com o computador, neste tutorial em vez de deixar um monte de linhas de código perdidas no meio no nosso main vou antes criar algumas funções, pois assim podem copiar as funções e usar noutros programas, até porque fica tudo mais limpinho e separado.
Em pseudo código eis o que temos de fazer:
Código: [Seleccione]
Iniciar e configurar a usart
Criar uma função para enviar um byte/caracter
Criar uma função para receber um byte/caracter
Fazer um simples eco na função main

   Como não faço ideia de como a usart funciona o que devo fazer é pegar no datasheet e começar a ler, e como as pessoas na atmel até fizeram um bom trabalho a fazer este datasheet está tudo muito bem organizado com um indice e marcadores e facilmente descobrimos que a secção sobre a usart começa na página 177- Secção 19, e temos até código em C e assembly para configurar a usart, quer então dizer que o nosso trabalho está facilitado, e pouco mais temos que fazer que ler e passar para o nosso programa o código dado.
Vamos começar pela inicialização da nossa usart, tal como está no datasheet:
Código: [Seleccione]
void USART_init(void){

UBRR0H = (uint8_t)(BAUD_PRESCALLER>>8);
UBRR0L = (uint8_t)(BAUD_PRESCALLER);
UCSR0B = (1<<RXEN0)|(1<<TXEN0);
UCSR0C = (3<<UCSZ00);
}

   UBRR0H e UBRR0L são os registos onde colocamos um valor que depende do baud-rate e da frequência do oscilador que o nosso chip tem, temos duas opções para determinar este valor, ou vemos a tabela que está no datasheet ou usamos uma pequena fórmula que juntamos ao cabeçalho do nosso programa onde estão os outros includes e o compilador determina o valor BAUD_PRESCALLER baseado no baudrate que queremos e no valor de F_CPU, sendo esta formula a seguinte:
Código: [Seleccione]
#define BAUD 9600 //o baudrate que queremos usar
#define BAUD_PRESCALLER (((F_CPU / (BAUDRATE * 16UL))) - 1) //a formula que faz as contas para determinar o valor a colocar nos dois registos

   Isto não é magia nem nada que se pareça, no datasheet são dadas duas fórmulas, se juntarmos as duas é esta a formula com que ficamos.
   UCSR0B é o registo que nos permite activar os canais de recepção e transmissão de dados da usart assim como activar interrupts, mas isso não nos interessa por agora.
E em UCSR0C definimos que queremos 8 bits de dados, sem paridade e um stop bit, em vez de (3<<UCSZ00) podemos fazer ((1<<UCSZ00)|(1<<UCSZ01)) o resultado é precisamente o mesmo.

   Agora para inicializar-mos a nossa usart basta chamar a função USART_init no nosso main e temos a usart pronta a usar, mas ainda não somos capaz nem de enviar nem de receber dados.
Mais uma vez a datasheet tem uma solução funcional, que é a seguinte:
Código: [Seleccione]
void USART_send( unsigned char data){

while(!(UCSR0A & (1<<UDRE0)));
UDR0 = data;

}

   A primeira de linha de código pode parecer estranha, mas tudo tem a sua razão e a razão desta linha é que o atmega tem um buffer de 3 bytes em hardware e esta linha verifica se ainda existe espaço no buffer para colocar mais dados, se não espera que haja espaço, se sim, coloca os dados no buffer coisa que é tratada na segunda linha da função.
E com apenas duas linhas estamos prontos a enviar dados por serial!
Agora falta-nos apenas a função para receber dados, sendo esta mais uma função de duas linhas:
Código: [Seleccione]
unsigned char USART_receive(void){

while(!(UCSR0A & (1<<RXC0)));
return UDR0;

}
   Na primeira linha, usamos o while para esperar que existam dados recebidos no registo de recepção, quando esses dados chegam ao registo, simplesmenta returna-mos os dados e temos a nossa usart a ler dados por serial.
   Agora como extra, vou mostrar uma pequena função que permite enviar strings, pois muitas vezes queremos enviar mais que apenas um byte de informação de cada vez, a função para enviar strings tira partido do facto de em C uma string ser terminada por um caracter nulo(/null) e que é feita de muitos caracteres individuais, assim com um pequeno loop que é executado enquanto os dados a enviar são não nulos e vai enviando um caracter de cada vez.
Código: [Seleccione]
void USART_putstring(char* StringPtr){

while(*StringPtr != 0x00){ //Aqui fazemos a verificação de que não chegamos ao fim da string, verificando para isso se o caracter é um null
USART_send(*StringPtr); //Aqui usamos a nossa função de enviar um caracter para enviar um dos caracteres da string
StringPtr++;} //Aumentamos o indice do array de dados que contem a string

}

   O char* no inicio da função pode parecer estranho e chama-se um ponteiro, que é algo bastante util em C, mas por agora vamos simplificar as coisas, e imaginar as strings como arrays de caracteres, que é isso mesmo que elas são em C e que o ponteiro não é mais que o inicio desse mesmo array.

Agora, pegamos no nosso programa inicial em branco e juntamos tudo, ficando assim:
Código: [Seleccione]
#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>

#define BAUDRATE 9600
#define BAUD_PRESCALLER (((F_CPU / (BAUDRATE * 16UL))) - 1)

int main(void){

return 0;
}

void USART_init(void){

UBRR0H = (uint8_t)(BAUD_PRESCALLER>>8);
UBRR0L = (uint8_t)(BAUD_PRESCALLER);
UCSR0B = (1<<RXEN0)|(1<<TXEN0);
UCSR0C = (3<<UCSZ00);
}

unsigned char USART_receive(void){

while(!(UCSR0A & (1<<RXC0)));
return UDR0;

}

void USART_send( unsigned char data){

while(!(UCSR0A & (1<<UDRE0)));
UDR0 = data;

}

void USART_putstring(char* StringPtr){

while(*StringPtr != 0x00){
USART_send(*StringPtr);
StringPtr++;}

}

   E se tentar-mos usar as nossas funções o compilador vai dizer que elas não estão definidas e nós ficamos a olhar para ele com cara espantada, porque as nossas funções estão mesmo ali, por baixo do main, e é precisamente esse o problema, no arduino podemos declarar funções onde bem nos apetecer, e em C tambem, mas temos que declarar as funções, ou seja a primeira linha da função que tem o nome dela e que tipo de dados é o seu retorno e quais os seus argumentos têm de estar antes do main, para o compilador saber que as funções existem, ficando assim o nosso código com as declarações das funções antes do main:
Código: [Seleccione]
#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>

#define BAUDRATE 9600
#define BAUD_PRESCALLER (((F_CPU / (BAUDRATE * 16UL))) - 1)

//declaração das nossas funções
void USART_init(void);
unsigned char USART_receive(void);
void USART_send( unsigned char data);
void USART_putstring(char* StringPtr);

int main(void){

return 0;
}

void USART_init(void){

UBRR0H = (uint8_t)(BAUD_PRESCALLER>>8);
UBRR0L = (uint8_t)(BAUD_PRESCALLER);
UCSR0B = (1<<RXEN0)|(1<<TXEN0);
UCSR0C = (3<<UCSZ00);
}

unsigned char USART_receive(void){

while(!(UCSR0A & (1<<RXC0)));
return UDR0;

}

void USART_send( unsigned char data){

while(!(UCSR0A & (1<<UDRE0)));
UDR0 = data;

}

void USART_putstring(char* StringPtr){

while(*StringPtr != 0x00){
USART_send(*StringPtr);
StringPtr++;}

}

   Já que temos acesso a comunicação terminal podemos fazer um "Olá mundo" mais completo que apenas um led a piscar, então vamos usar as nossas funções para escrver a frase "Olá mundo!!!", mas falta-nos umas coisa, não temos um terminal serial, ou seja um programa que receba os dados da porta serial e nos mostre no ecrã do computador o que recebeu.
No meu caso, recomendo usar este terminal:
Citar
http://www.smileymicros.com/download/term20040714.zip?&MMN_position=42:42


   Foi feito por um menbro do AvrFreaks e acho-o simples de usar, tambem vai do gosto e existem milhares de terminais pela internet fora, escolham o que mais gostarem. Neste caso basta fazer o download e executar o ficheiro, podem já fazer isso e deixar o terminal aberto que vamos usa-lo mais tarde.

Vamos lá pegar então no nosso programa e completa-lo para o nosso "Olá mundo":
Código: [Seleccione]
#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>

#define BAUDRATE 9600
#define BAUD_PRESCALLER (((F_CPU / (BAUDRATE * 16UL))) - 1)

//declaração das nossas funções
void USART_init(void);
unsigned char USART_receive(void);
void USART_send( unsigned char data);
void USART_putstring(char* StringPtr);

char String[]="Olá mundo!!!"; //String[] que dizer que é um array, mas ao colocar-mos o texto entre "" indicamos ao compilador que é uma string e ele coloca automáticamente o terminador null e temos assim uma string de texto usavel

int main(void){
USART_init(); //Inicializar a usart

while(1){ //Loop infinito
USART_putstring(String); //Passamos a nossa string á função que a escreve via serial
_delay_ms(5000); //E a cada 5s re-enviamos o texto
}

return 0;
}

void USART_init(void){

UBRR0H = (uint8_t)(BAUD_PRESCALLER>>8);
UBRR0L = (uint8_t)(BAUD_PRESCALLER);
UCSR0B = (1<<RXEN0)|(1<<TXEN0);
UCSR0C = (3<<UCSZ00);
}

unsigned char USART_receive(void){

while(!(UCSR0A & (1<<RXC0)));
return UDR0;

}

void USART_send( unsigned char data){

while(!(UCSR0A & (1<<UDRE0)));
UDR0 = data;

}

void USART_putstring(char* StringPtr){

while(*StringPtr != 0x00){
USART_send(*StringPtr);
StringPtr++;}

}

   E tão simples como isto temos o nosso atmega a enviar dados.
Agora que se acabou a teoria vamos abrir o nosso AvrStudio e criar um projecto novo com o nome USART, primeiro carregam em "New project" aqui:


   Depois na janela seguinte o AvrStudio já se lembra da nossa pasta chamada AVR onde guarda-mos os nossos projectos, preencham o "Project name" com USART e não se esqueçam de escolher o Avr-gcc como compilador e das caixas de verificação:


   Depois de carregarem em Next escolham o vosso chip, que se for como anteriormente é o Atmega328p:


   Por fim carreguem em Finish e copiem o código completo para o editor de texto, e carreguem em F7 para compilar o vosso código, podem tambem carregar no botão que está marcado a verde nesta imagem:


Como podem ver o código compila sem erros e podemos iniciar a linha de comandos para fazer o upload do programa para o arduino, se não se lembrarem de como se faz, releiam o primeiro tutorial, vamos até á pasta que neste caso não se irá chamar blinky mas sim USART, e depois novamente até á pasta default que é onde estão os ficheiros gerados pelo compilador:


E agora voltamos a usar o nosso caro avrdude para fazer o upload do ficheiro .hex para o arduino, mais uma vez saliento para o facto de terem atenção á porta COM usada:


Com o upload do programa feito vamos agora abrir o nosso Terminal, e tal como com o avrdude têm de ter atenção á porta com que o vosso arduino usa, assim como ao baudrate escolhido, no caso deste exemplo é 9600 e a forma como a usart está configurada, no nosso caso, 8 bits de dados, 1 bit de stop e sem bit de paridade, nesta imagem mostro como configurar o terminal para receber dados do arduino:


Agora basta carregar em "Connect" e carregar no botão de reset do arduino para sincronizar o programa com arduino e deverão ver algo do género:


E está a comunicação serial a funcionar!
Agora deixo um desafio em aberto, usando o outro tutorial e este, desafio-vos a criarem um programa que acende o led do arduino quando recebe o caracter "a" e que o apague quando receber outro caracter qualquer, é algo bastate simples de se fazer, não precisam de nenhum hardware extre para além do arduino e assim aprendem como controlar algo usando dados via serial, para enviar um caracter usando ester terminal basta escrever o caracter na caixa marcada a verde da imagem de cima e carregar no enter.
Boa programação!!!
« Última modificação: 01 de Outubro de 2010, 01:07 por senso »
Avr fanboy

Offline metRo_

  • Administrator
  • Mini Robot
  • *****
  • Mensagens: 3.753
Re: Introdução ao avr-gcc usando o AvrStudio [segunda parte lançada]
« Responder #29 em: 01 de Outubro de 2010, 00:28 »
Só agora estive a ler este tópico com atenção e vir aqui só dar os parabens pelos tutoriais assim como a discussão que aqui vai até sinto que estou a fazer off-topic ;)