collapse

* Posts Recentes

Circuito Microfone que funcione por almamater
[Hoje às 17:14]


Emulador NES em ESP32 por dropes
[22 de Abril de 2024, 14:14]


Arame de Estendal por almamater
[18 de Abril de 2024, 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]


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]

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

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

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.733
  • Helpdesk do sitio
Usar mais micros fica mais caro, mas liberta tempo de processamento ao cérebro ao mesmo tempo que oferece mais espaço para programas e mais possibilidades e recursos que se podem usar, eu usaria SPI, é bastante simples de usar e em 8 clocks do SPI mandas e recebes 8bits.
Avr fanboy

Offline Capeleiro

  • Mini Robot
  • *
  • Mensagens: 127
(...) eu usaria SPI, é bastante simples de usar e em 8 clocks do SPI mandas e recebes 8bits.
Pois, realmente é muito mais rápido. É mesmo isso que vou usar!  ;D

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.733
  • Helpdesk do sitio
   Boa noite a todos, hoje vamos falar de algo um pouco diferente do normal até aqui, o tema hoje abordado serão os operadores lógicos binários e de salientar que são binários(em inglês bitwise, pois eles operam bit a bit e não num numero como um todo, mas em cada bit que cria o numero), não são apenas úteis para o nosso atmega/arduino, mas para qualquer micro-controlador e até programas feitos para correr no nosso pc, pois saber dominar os operados lógicos pode-nos poupar trabalho a fazer variadas operações, sendo um dos exemplos as divisões e as multiplicações.

   Para começar vamos introduzir os operadores e os respectivos símbolos/comandos que os invocam:
Código: [Seleccione]
AND &
OR |
NOT ~
XOR ^
Shift left <<
Shift right >>

   Para ajudar á sua compreensão vou descrever as tabelas da verdade para cada um dos operadores, as tabelas da verdade servem para mostrar qual é o resultado de um dado operador conforme as entradas variam, vamos definir também que a partir daqui, o valor lógico HIGH será representado por '1' e o valor lógico LOW será representado por '0'.
Código: [Seleccione]
Tabela da verdade do AND:
0 AND 0 = 0
0 AND 1 = 0
1 AND 0 = 0
1 AND 1 = 1

Tabela da verdade do OR:
0 OR 0 = 0
0 OR 1 = 1
1 OR 0 = 1
1 OR 1 = 1

Tabela da verdade do XOR:
0 XOR 0 = 0
0 XOR 1 = 1
1 XOR 0 = 1
1 XOR 1 = 0

Tabela da verdade do NOT:
NOT 0 = 1
NOT 1 = 0

Tabela da verdade para o Shift left aplicado a uma variável de 8 bits:
0x01<<0 = 0b00000001
0x01<<1 = 0b00000010
0x01<<2 = 0b00000100
0x01<<3 = 0b00001000
0x01<<4 = 0b00010000
0x01<<5 = 0b00100000
0x01<<6 = 0b01000000
0x01<<7 = 0b10000000

Tabela da verdade para o Shift right aplicado a uma variável de 8 bits:
0x80>>0 = 0b10000000
0x80>>1 = 0b01000000
0x80>>2 = 0b00100000
0x80>>3 = 0b00010000
0x80>>4 = 0b00001000
0x80>>5 = 0b00000100
0x80>>6 = 0b00000010
0x80>>7 = 0b00000001

Tabela para converter de binário para hexadecimal:
Binário    Hexadecimal Decimal
0000 = 0     =    0
0001 = 1     =    1
0010 = 2     =    2
0011 = 3     =    3
0100 = 4     =    4
0101 = 5     =    5
0110 = 6     =    6
0111 = 7     =    7
1000 = 8     =    8
1001 = 9     =    9
1010 = A     =    10
1011 = B     =    11
1100 = C     =    12
1101 = D     =    13
1110 = E     =    14
1111 = F     =    15
Numeração dos bits numa variável de 8bits:
0b00000000
  ||||||||
  |||||||bit0
  ||||||bit1
  |||||bit2
  ||||bit3
  |||bit4
  ||bit5
  |bit6
  bit7

   Depois, para montarmos um numero de 8 bits em binário para decimal é simples, fazemos assim:
   0b10101001 dividimos este numero em duas partes e removemos o 0b que só está lá para dizer ao nosso compilador que é um numero binário, e vamos ficar com 1010 e 1001, depois é só olhar para a tabela de cima e escrever 0x que diz ao compilador que é um numero em hexadecimal e juntamos a tradução dos 4 bits no numero ou letra que lhe corresponde e no caso do exemplo que estou a dar fica 0xA9.
   De notar que nas tabelas de verdade para o shift right e o shift left apenas usei um valor em cada uma, mas posso colocar lá outro valor(no caso do shift left não tem de ser sempre 0x01 e no caso do shift right não tem de ser sempre 0x80, usei esses números pois são o que me dão um bit sozinho á direita ou á esquerda respectivamente).

   Então vamos aprofundar os nosso conhecimentos sobre os nossos operadores lógicos, se repararem e por vezes para simplificar o nosso raciocinio e até foi assim que eu memorizei os operadores, é que podemos olhar para o AND como uma multiplicação entre os dois valores, mas atenção que não podemos usar o AND como alternativa ao * porque como referi em cima, este operadores operam individualmente sobre cada bit, o OR pode ser encarado como uma adição, o XOR como um detector de diferenças, pois se reparar-mos na tabela de verdade do XOR vê-mos que quando os bits são diferentes ele tem 1 como resultado e quando são iguais o seu resultado é 0, os shifts esses sim podem ser usados para multiplicar, usando um Shift Left, e para dividir usando um Shift Right, mas temos de ter em atenção que eles só dividem e multiplicam em potencias de dois, no caso de uma variável de 8 bits só podemos usa-los para multiplicar ou dividir por 2,4,8,16,32,64,128 e 256, e no caso da divisão não ficamos com números fraccionários nem com resto nem nada.
   As aplicações dos operadores lógicos binários são mais que muitas, e vou agora listar algumas das mais úteis para os nosso micro-controladores.
   
Código: [Seleccione]
unsigned char variavel = 0; //Aqui está a nossa variável inicializada a 0
   Para colocar o bit0 a 1 usamos o OR do seguinte modo:
   
Código: [Seleccione]
variavel = variavel | 0x01;   O 0x01 é a chamada de Máscara(em inglês MASK ou BITMASK ) e como podemos constatar pela tabela da verdade do OR o valor que irá ser guardado na nossa variável será 0x01, e agora podemos tirar partido dos operados compostos(na verdade não sei bem o nome disto em português, em ingles chamam-se compound assignments) e podemos escrever algo mais compacto e rápido de se escrever e que tem precisamente o mesmo efeito:
   
Código: [Seleccione]
variavel |= 0x01;    Isto não tem qualquer diferença a nível de código gerado, é apenas mais rápido de escrever-mos, podem usar o modo que quiserem.
   Agora, se quiser-mos voltar a colocar o bit0 a 0 não usamos o OR mas sim o AND:
   
Código: [Seleccione]
variavel =  variavel & ~0x01;    Como podem ver agora estamos a usar não apenas o AND mas também o NOT,mas não era suposto termos de usar só o AND?
   Sim, era e é, mas nós gostamos de olhar para o nosso código e perceber em que bit vamos mexer e assim é facil de reconhecer que vamos mexer no bit0, mas como esta máscara só serve para colocar bits a 1, temos de fazer o NOT da mesma e depois fazer o AND do resultado com a nossa variável.
   Vou mostrar-vos como é que isto funciona:
   
Código: [Seleccione]
variavel tem o valor 0x01 = 0b00000001
a mascara é 0b00000001
~0b00000001 = 0b11111110 -> a mascara fica assim após o NOT
variavel AND mascara =
0b00000001
       &0b11111110
------------------
0b00000000 -> e colocamos o bit0 a 0
   É claro que também podíamos fazer:
   
Código: [Seleccione]
variavel = variavel & 0xFE;   Mas não seria de todo tão perceptível á primeira vista reparar que íamos colocar o bit0 a 0, tal como o OR podemos usar o operador composto e o código fica assim:
   
Código: [Seleccione]
variavel &= ~0x01;   Também podemos usar o AND para saber se um bit está a 0 ou a 1 por exemplo para um if(), e de que modo?
   
Código: [Seleccione]
if(variavel & 0x04){
// Se o bit 2 estiver a 1 o if é executado
}
else{
//Se o bit 2 estiver a 0 o else é executado
}
   Atenção numa coisa, se o bit2 for 0, a condição do if é zero, mas se o bit2 for 1 o valor é DIFERENTE de 0, mas não é necessariamente 1, vai ser um valor igual ou superior a 1, se fizerem:
   
Código: [Seleccione]
if((variavel & 0x04) == 1)   Não se admirem que o vosso código não funciona como querem, porque ele vai funcionar tal e qual lhe estão a pedir, têm de ter atenção nestes pormenores, o primeiro exemplo funciona perfeitamente, não precisam de colocar nenhum ==.

   Agora o operador XOR, para que será que o queremos usar?
   Bem, é útil para fazer um bit mudar de 0 para 1 e de 1 para 0, quando nós não sabemos e/ou não queremos sequer saber de qual o valor do bit que queremos fazer mudar de estado, por exemplo para fazer o led do pino 13 do arduino piscar, basta usar o XOR, e não uma cadeia de if/else's ou coisas ainda mais estranhas.
   Vamos supor que temos um ciclo infinito(loop) em que queremos mudar o estado do bit0 a cada iteração que fazemos nesse loop, basta-nos usar:
   
Código: [Seleccione]
variavel = variavel ^0x01;   Ou mais uma vez a versão reduzida:
   
Código: [Seleccione]
variavel ^= 0x01;

   Ao longo de um programa, podemos acabar por ter mascaras de bits algo complexas que não queremos estar a re-escrever sempre que as queremos usar, por isso, podemos usar um #define, e em vez de usar-mos 0x01 sempre que queremos usar a nossa máscara escrevemos MASK, exemplo:
   
Código: [Seleccione]
#define MASK 0x01
//O nosso main começa aqui, temos umas quantas linhas de código até que precisamos da nossa máscara
variavel |= MAKS
   E agora os Shifts, que podem ser usados para várias coisas, por exemplo queremos colocar o bit5 a 1, em vez de vermos como se escreve isso em binário, usamos um shift left para criar a nossa máscara, deste modo:
   
Código: [Seleccione]
variavel |= (1<<5);   Para o AND, o XOR e o NOT o funcionamento é precisamente o mesmo, usamos (1<<x), em que x varia de 0 até 7 consoante o bit que queremos alterar ou comparar usando um if, pode-se usar o Shift left á vontade que tudo continua a funcionar certinho, e se quiser-mos fazer por exemplo uma multiplicação por dois, podemos usar o shift left para a fazer, eis um exemplo:
   
Código: [Seleccione]
2<<1 = 4 mas como?
2 em binário é 0b00000010
0b00000010 << 2 = 0b00000100 que é 4
   Não esquecer que estamos em base 2, logo fazemos um shift left para multiplicar por 2, dois shifts para multiplicar por 4, ou seja estamos a multiplicar por 2^(numero de shifts left), neste caso o ^ não quer dizer XOR mas sim elevado a. Atenção que qualquer valor que passe para a "frente" do bit7 é perdido, e a isso chama-se overflow, podemos por exemplo prevenir isto usando um int que tem 16 bits em vez de um char/unsigned char/uint8_t que tem apenas 8.
   
   A divisão é igual, apenas podemos dividir por potencias de dois e se o resultado devia dar algum numero com virgula o mesmo não é criado, ficamos apenas com o resultado inteiro e não o fraccionário, por exemplo 7/2:
   
Código: [Seleccione]
7 em binário é 0b00000111
0b00000111>>1 = 0b00000011
0b00000011 em decimal é 3
   Mas nós sabemos que 7/2 = 3.5 mas como já referi anteriormente, qualquer numero que passe para "trás" do bit 0 é perdido e a isto chama-se underflow e não é possível recuperar o bit perdido, podemos encarar os Shift Rights como divisões por 2^(numero de shifts right).

   Por agora é tudo, e espero que tenham ficado a compreender um pouco melhor toda esta confusão de operadores bitwise e de todo o seu poder apesar da sua aparente simplicidade podem tornar o vosso código mais rápido e eficiente e depois de estudarem isto um bocadinho e fazer as contas no papel recorrendo ás tabelas de verdade quando têm duvidas ajuda muito.
   Bom estudo pessoal ;)
   
   Tiago Ângelo
   15/10/2010
Avr fanboy

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.733
  • Helpdesk do sitio
Então, sugestões?
Avr fanboy

Offline GnGz

  • Mini Robot
  • *
  • Mensagens: 665
Até aprendemos aqui C...

Offline CBX

  • Mini Robot
  • *
  • Mensagens: 1.315
boas

excelente tutorial, têm-me ajudado bastante

tenho uma duvida: se eu usar _delay_ms(1000); o delay não deveria ser de 1s? é que assim o blink dura 10s...

estou a usar um atmega16L a 8mhz com um usbasp...

cumps

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.733
  • Helpdesk do sitio
Fizeste
#define F_CPU 8000000UL
O fuse CKDIV8 está desligado?
Imagino que estejas a correr com o oscilador interno, e se não mexeste nos fuses ele vem de origem com com o CKDIV8 ligado, que divide o clock por 8 e ficas efectivamente com um clock de 1Mhz.
Outra coisa,  é que com clocks muito elevados, ou mesmo delays muito longos não são possiveis, tenho ideia que a 16Mhz a máximo são de 600ms, para evitar isso podes fazer esta pequena função:

Código: [Seleccione]
void my_delay(int delay){
while(delay){
   _delay_ms(1);
   delay--; }

E na declaração das funções antes do main metes:
Código: [Seleccione]
void my_delay(int delay);
« Última modificação: 19 de Outubro de 2010, 14:13 por senso »
Avr fanboy

Offline CBX

  • Mini Robot
  • *
  • Mensagens: 1.315
sim fiz #define F_CPU 8000000UL, não mexi foi nos fuses, possivelmente é isso...

como é que mexo nos fuses?

cumps e obrigado

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.733
  • Helpdesk do sitio
Para alterar os fuses, primeiro aconselho usar isto:
http://www.engbedded.com/fusecalc/

Depois, terás de usar o avrdude para os mudar, mas antes de os mudares mostra aqui que fuses queres alterar para vermos se não estás a desligar o spi ou coisas assim e ficas com o chip bloquado.
Um tutorial sobre fuses:
http://electrons.psychogenic.com/modules/arms/art/14/AVRFusesHOWTOGuide.php

Mais uma coisa, um fuse ligado é represantado por 0 e um desligado é representado por 1, isto por vezes causa muitos problemas e leva a que pessoas bloqueiem os seus chips pois desligam a programação via ISP, e coisas assim.
Avr fanboy

Offline CBX

  • Mini Robot
  • *
  • Mensagens: 1.315
obrigado, vou ler o tutorial depois digo alguma coisa

Offline CBX

  • Mini Robot
  • *
  • Mensagens: 1.315
bem segundo percebi tenho que alterar nos fuse low bits os CKSEL de 3 a 0 que por default estão a 0001, que segundo a datasheet (pág. 25) para utilizar um cristal externo o valor será 1010 certo?

nos fuse high bits tenho de mexer no CKOPT de 1 para 0, mas aqui fiquei na duvida...

então:

low default 1110 0001 é alterado para 1110 1010
high defaul 1001 1001 é alterado para 1000 1001

que na calculadora dá: 0xEA 0x89

é isto?


informação correcta na pág. seguinte
« Última modificação: 19 de Outubro de 2010, 18:48 por CBX »

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.733
  • Helpdesk do sitio
O 1010 é mesmo para cristal externo, ou oscilador externo? são coisas diferentes.
Avr fanboy

Offline CBX

  • Mini Robot
  • *
  • Mensagens: 1.315
segundo a datasheet: External Crystal/Ceramic Resonator 1111 - 1010

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.733
  • Helpdesk do sitio
Sim, parece-me ser isso, mas nunca mexi nos fuses não te posso dizer que é com 100% de certeza, irás usar que frequencia de cristal?
É que se for 16Mhz tens de escolher Crystal/ressonator High frequency.
Avr fanboy

Offline CBX

  • Mini Robot
  • *
  • Mensagens: 1.315
8mhz pois é o máximo do mega16l

Crystal/ressonator High frequency é aplicável a partir de quantos mhz?