Eu li um artigo no site do arduino muito interessante falando sobre manipulação de portas: Arduino Playground - PortManipulation
Minha pergunta é a seguinte: Porque não estão todas nesse artigo? Vi num tópico aqui no fórum que existem mais, como a TCCR0A, que pelo entendi, serve pra mudar a frequência do PWM.
Penso que não viu esta parte:
Generally speaking, doing this sort of thing is not a good idea.
Se quiser todas, pode sempre ler o datasheet:
Tem 448 páginas para procurar todo o tipo de "portas"
.
O objectivo desta plataforma é tornar o microcontroladores fáceis para que qualquer pessoa (como diz o lema hobbyists and artists) os possam utilizar sem que para isso seja necessário ter muitos conhecimentos de electrónica e/ou programação. Se fosse necessário utilizar os registos especiais do microcontrolador, isso deixava de ser assim. No entanto, se quiser (e principalmente se tiver conhecimentos para isso), pode sempre programar o Arduino utilizando um IDE diferente e mesmo uma linguagem de programação diferente (por exemplo Assembler), porque o hardware mantém-se o mesmo.
Bom dia FabioCarpi.
Tenho passado pelos mesmos problemas que vc para manipular registradores internos do Atmega. Aconselho que vc faça como eu fiz, baixe o datasheet do atmega que vc usa, e então baixe algum livro sobre AVR ou ARM, vai te ajudar e elucidar muita coisa. Baixei alguns livros, não lembro onde salvei no meu PC, quando achar eu posto aqui.
Sds.
Eu achei a lista de registradores. Mas esperava que tivesse explicação de pra que serve cada um e de como usar.... ![]()
No datasheet que eu postei está lá tudo explicado.
Se tiver um exemplo prático talvez haja alguém que o consiga ajudar. Volto a chamar a atenção para a parte de:
Generally speaking, doing this sort of thing is not a good idea.
Desculpe, eu não vi seu post
Eu até entendo os riscos de mexer nos registradores. Eu só queria saber por curiosidade mesmo. Mas qual o perigo de eu ficar limitado só as portas descritas no site do Arduino Playground - PortManipulation?
Os perigos, são descritos também no artigo:
- The code is much more difficult for you to debug and maintain, and is a lot harder for other people to understand. It only takes a few microseconds for the processor to execute code, but it might take hours for you to figure out why it isn't working right and fix it! Your time is valuable, right? But the computer's time is very cheap, measured in the cost of the electricity you feed it. Usually it is much better to write code the most obvious way.
- The code is less portable. If you use digitalRead() and digitalWrite(), it is much easier to write code that will run on all of the Atmel microcontrollers, whereas the control and port registers can be different on each kind of microcontroller.
- It is a lot easier to cause unintentional malfunctions with direct port access. Notice how the line DDRD = B11111101; above mentions that it must leave pin 1 as an input pin. Pin 1 is the receive line on the serial port. It would be very easy to accidentally cause your serial port to stop working by changing pin 1 into an output pin! Now that would be very confusing when you suddenly are unable to receive serial data, wouldn't it?
Basicamente, usando o acesso directo aos registos de memória que controlam as portas (ou outra coisa qualquer), perdem-se as grandes vantagens deste sistema - a facilidade de programação e a portabilidade (este último ponto quer dizer o quê? Quer dizer que eu posso escrever um sketch para o Arduino UNO e descarregá-lo para o MEGA que ele vai funcionar igual, se eu usar o acesso directo pode não funcionar - certamente não vai funcionar, diria até)
A pergunta original estava relacionada com o registo TCCR0A. Procurando referencias sobre este registo no datasheet (que coloquei na primeira resposta), chega-se ao ponto 14.9.1 da página 106. Lendo-se isto, chega-se à conclusão que este registo não tem nada a ver com portas, mas sim com Temporizadores/Contadores. Como o artigo, apenas faz referencia aos registos dedicados às portas, este registo não está contemplado nesse artigo.
Se quer ver como as coisas funcionam "por dentro", pode deitar um olho aos ficheiros da pasta (por exemplo):
INSTALAÇÃO/hardware/arduino/avr/cores/arduino
Procura por AVR Application Notes.
La tem exemplos sobre como mexer nos registos internos. Tem cuidado que registos nao sao portas... ![]()
Olá!
Veja se isto ajuda:
Abraço.
Fernando Garcia
Então me surgiu 2 duvidas:
- Pelo texto dito:
It is a lot easier to cause unintentional malfunctions with direct port access. Notice how the line DDRD = B11111101; above mentions that it must leave pin 1 as an input pin. Pin 1 is the receive line on the serial port. It would be very easy to accidentally cause your serial port to stop working by changing pin 1 into an output pin! Now that would be very confusing when you suddenly are unable to receive serial data, wouldn't it?
Qual seria a diferença do exemplo dado, DDRD = B11111101 para o pinMode(1, INPUT)?
- A descoberta desses registradores tinha me dado uma luz pro que eu queria fazer, que é enviar os estados de todos os pinos pelo I2C. Sem usar o registrador, como mandar os estados como um byte?
FabioCarpi:
Qual seria a diferença do exemplo dado, DDRD = B11111101 para o pinMode(1, INPUT)?
Do ponto de vista prático, nenhuma. As duas instruções iriam ter o mesmo efeito. No entanto não é isso que o texto diz. Por exemplo, se o a alteração a DDRD for feita utilizando o resultado de uma cálculo e se por algum motivo esse cálculo introduzir um bit " 1 " naquele espaço xxxxxx1x a placa deixa de receber dados utilizando a porta série. Utilizando a função pinMode() isso tem muito menos probabilidades de acontecer.
FabioCarpi:
A descoberta desses registradores tinha me dado uma luz pro que eu queria fazer. Que é enviar os estados de todos os pinos pelo I2C. Sem usar o registrador, como mandar os estados como um byte?
A parte boa da programação é que há sempre uma maneira de dar a volta à situação, seja ela fácil ou difícil.
A 1ª questão é: "enviar os estados" não é alterar os estados;
A 2ª questão é: "mandar os estados como um byte" para quê (estou a pensar num byte genérico, por exemplo o TCCR0A? para quê?) Quer fazer um debuger ou alguma coisa desse género por sua conta? Não acha que é demais?
A 3ª questão é: para saber o "estados de todos os pinos", não é necessário ir aos registos, basta usar a função digitalRead(). Faça um vector, com os números de todos os pinos que quer ler, depois com um ciclo for consegue percorrer todo esse vector e ler o estado dos pinos, conforme o estado dos pinos, pode activar (ou desactivar) um bit numa variável.
Acho que entendi a questão da serial...
Estou fazendo um sistema de automação e o slave tem que informar os estados dos pinos para o master.
Minha idéia era fazer tipo Wire.write(PIND)
Dessa forma, eu enviaria os estados dos pinos 0 a 7 num único byte.
Se eu fosse fazer via digitalRead, eu iria mandar um byte para cada pino (do jeito que eu sei)
Wire.write(digitalRead(0));
Wire.write(digitalRead(1));
Wire.write(digitalRead(2));
Iria enviar 3 bytes...
Se tiver uma maneira de fazer isso...
O que eu estou a dizer, é uma coisa deste género:
const int pinos[] = {0, 1, 2, 3, 4, 5, 6, 7}; // porto D (por acaso bate certo com os números)
void setup() {
for (int i = 0; i < 8; i++) {
pinMode(pinos[i], INPUT);
}
}
void loop() {
byte byteEstado;
byte bitEstado;
for (int i = 7; i >=0; i++) {
bitEstado = digitalRead(pinos[i]);
byteEstado = (byteEstado<<1) | bitEstado;
}
Wire.write(byteEstado);
}
Não sei se está certo ou se tem algum problema, mas penso que dá para perceber a ideia. (também não fui ver se HIGH=1 e se LOW=0, mas estou a partir desse princípio; estou a partir do princípio que a board é a do UNO)
FabioCarpi:
Acho que entendi a questão da serial...
Estou fazendo um sistema de automação e o slave tem que informar os estados dos pinos para o master.
Minha idéia era fazer tipo Wire.write(PIND)
Dessa forma, eu enviaria os estados dos pinos 0 a 7 num único byte.
Se eu fosse fazer via digitalRead, eu iria mandar um byte para cada pino (do jeito que eu sei)
Wire.write(digitalRead(0));
Wire.write(digitalRead(1));
Wire.write(digitalRead(2));
Iria enviar 3 bytes...
Se tiver uma maneira de fazer isso...
Qual é a duvida sobre usar o PIND? Usa e pronto, acho a questão de usar as funções nativas do core(digitalRead...) levam em consideração que geralmente haverá a liberação e replicação do projeto por outras pessoas, aí um usa o Uno, outro o Mega, outro o Leonardo... e em cada um deles os pinos Arduino são diferentes do PORTs... ai para um novato fica dificil entender o problema do programa dele não funcionar...
Era isso mesmo que tinha em mente. Obrigado a todos que ajudaram. Dei karma a todos ^^
Eu não sou da opinião do fabio_h.
Deixe os "conceitos avançados" para quando o seu nível seja avançado (e penso que até lá ainda falta muito tempo). Comece pelo básico e resolva os problemas dessa forma. Utilize para se basear os exemplo que acompanham o IDE, que são o suficiente para começar.
Por exemplo, quando estava a pesquisar para escrever o exemplo do meu post anterior, apercebi-me que há portas que apenas têm 2 pinos como saídas físicas da placa Arduino. Isso leva-me a concluir aquilo que eu já tinha em mente, que é, o facto de a sua pretensão não fazer grande sentido. Penso que não faz grande sentido querer saber o estado de "todos os pinos da porta" D, por exemplo. Por acaso (e porque eu fiz por isso) a porta D, na placa do Arduino UNO até tem todos os pinos ligados ao exterior, mas por exemplo a porta B já não.
Eu entendi. A porta B6 e B7 são do cristal...
Não só.
Para escrever o exemplo, usei o ficheiro pins_arduino.h da pasta INSTALAÇÃO/hardware/arduino/avr/variants/standard. Neste ficheiro, existe a parte seguinte:
// ATMEL ATMEGA8 & 168 / ARDUINO
//
// +-\/-+
// PC6 1| |28 PC5 (AI 5)
// (D 0) PD0 2| |27 PC4 (AI 4)
// (D 1) PD1 3| |26 PC3 (AI 3)
// (D 2) PD2 4| |25 PC2 (AI 2)
// PWM+ (D 3) PD3 5| |24 PC1 (AI 1)
// (D 4) PD4 6| |23 PC0 (AI 0)
// VCC 7| |22 GND
// GND 8| |21 AREF
// PB6 9| |20 AVCC
// PB7 10| |19 PB5 (D 13)
// PWM+ (D 5) PD5 11| |18 PB4 (D 12)
// PWM+ (D 6) PD6 12| |17 PB3 (D 11) PWM
// (D 7) PD7 13| |16 PB2 (D 10) PWM
// (D 8) PB0 14| |15 PB1 (D 9) PWM
// +----+
//
Então, por exemplo, a porta B, não está completa, e a C também não, apenas tem a D completa, por isso questiono a relevância da sua ideia/solução. Não seria muito mais interessante que a sua aplicação (caso fosse implementada com o UNO) tivesse, por exemplo, 2 módulos de entradas/saídas digitais de 8 bits, e um módulo de 4 bits de entradas analógicas? Mas para ser assim, não pode "ligar" ao que os pinos são fisicamente (a que porta a que eles pertencem) tem que os tratar de maneira diferente.
Penso que a minha sugestão lhe permite fazer isso, uma vez que uma saída apenas é um valor escrito num array e não interessa o que ele é fisicamente.
Bom dia. Gostaria de saber quando eu mudo a referência da porta analógica usando o comando
analogReference (INTERNAL), consigo manipular uma única porta analógica ou muda todas as portas?
Os testes que eu fiz não foram convincentes, se puderem me indicar algum artigo ou uma explicação fico grato!
Att; Igor Alves