collapse

* Links de Robótica

* Posts Recentes

Medir Agua que está no Poço por filjoa
[Ontem às 20:58]


URGENTE - display de 7 segmentos com backpack por helderjsd
[20 de Setembro de 2017, 12:30]


Preços e fabricantes de pcb por Sérgio_Sena
[19 de Setembro de 2017, 10:20]


Palavras Cruzadas por Njay
[19 de Setembro de 2017, 02:24]


Isaac Asimov - I, Robot por senso
[18 de Setembro de 2017, 03:41]


Apresentação por TigPT
[17 de Setembro de 2017, 07:31]


ic SL440 da Plessey? por senso
[16 de Setembro de 2017, 13:11]


Compra Colectiva RS-Amidata por brunus
[15 de Setembro de 2017, 22:31]


Ideias para construir um quadrúpede simples por zordlyon
[15 de Setembro de 2017, 10:18]


Preparar bancada de testes por jm_araujo
[14 de Setembro de 2017, 10:24]

Autor Tópico: PWM, Potenciômetro e Servo; Com timer0, modo CTC e rodando assíncrono  (Lida 5136 vezes)

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

Offline Pinout

  • Mini Robot
  • *
  • Mensagens: 22
Olá pessoal,

fui implementar um código para mover um servo motor utilizando um potenciômetro e depois de analizar e testar o modo Fast PWM e CTC, achei que o modo CTC é muito melhor para implementar a movimentação desejada, uma vez que consigo fazer toda a implementação do sinal na interrupção gerada no modo CTC. E me possibilita também utilizar qualquer pino digital e não os restritos ao Fast PWM. Estou colocando o código aqui para que alguém com mais experiência possa ver e dizer se é equivocado implementar com o modo CTC ou se não há problema. No código que envio, utilizei apenas um potenciômetro, ligado ao pino PC0 e um servo motor ligado ao pino PD6. O ADC roda em modo contínuo, pois como se trata de apenas um potenciômetro, o valor do potenciômetro sempre estará disponível para a interrupção por comparação do timer0 atribuir ao servo motor, promovendo maior desempenho (na minha opinião).

Bom, segue o código:

Código: [Seleccione]
/*
 *
 * Created: 10/12/2014 09:29:27
 */
#include <avr/io.h>
#include <avr/interrupt.h>

#define SERVO (1 << PD6)

volatile char pulseCount = 0; // Essa é a nossa variável volatile compartilhada, que será usada como contador pulseCount

void ADC_init() { // inicia ADC em modo contínuo
    ADCSRA = (7 << ADPS0);
    ADMUX = (1 << REFS0);
ADCSRB &= ~(7 << ADTS0);
ADCSRA |= (1 << ADATE);
    ADCSRA |= (1 << ADEN);
    ADCSRA |= (1 << ADSC);
}

void CONFIG_servo() {
    DDRD = (SERVO); // seta pino como saída
    PORTD &= ~SERVO; // assegura nível lógico 0 para o pino
}

void timer0_init(void) {
    TCCR0A = (1<<WGM01); // modo CTC
    TCCR0B = ((1<<CS01)|(1<<CS00)); // prescaler 1:64
    OCR0A = 24; // interrupção à cada 0.1ms
    TIMSK0 = (1<<OCIE0A); // habilita interrupções no timer
sei(); // habilita interrupções globais
}

int main(void) {
    CONFIG_servo();
    ADC_init();
    timer0_init();   
    while(1);       
    return 1;
}

ISR(TIMER0_COMPA_vect) {
    pulseCount++; // incrementa o contador à cada 0.1ms
    if(pulseCount == 200) { // atende à condição à cada 20ms - frequência de 50Hz
        PORTD ^= SERVO; // inverte estado lógico do pino (sempre coloca em nível lógico 1)
    } else if(pulseCount >= (203 + (ADC / 44))) { // verifica valor do contador, compara com potenciômetro e, quanto iguais, limpa o pino
        PORTD ^= SERVO; // inverte estado lógico do pino (sempre coloca nível lógico 0)
        pulseCount = 0; // zera contador
    }
}
« Última modificação: 27 de Janeiro de 2015, 11:29 por Pinout »
A wise person listens and takes in more instruction;
A man of understanding acquires skillful direction

Offline jm_araujo

  • Mini Robot
  • *
  • Mensagens: 2.124
  • NERD!
Re: PWM para servo com timer0 e modo CTC
« Responder #1 em: 12 de Dezembro de 2014, 09:48 »
Como tens o código a frequência vai variar conforme tamanho do pulso do servo. Corrigir é fácil:
Código: [Seleccione]
ISR(TIMER0_COMPA_vect) {
    pulseCount++; // incrementa o contador à cada 0.1ms
    if(pulseCount == 200) { // atende à condição à cada 20ms - frequência de 50Hz
        PORTD &= ~SERVO; // coloca em nível lógico 0)
        pulseCount = 0; // zera contador
    } else if(pulseCount >= (197 - (ADC / 44))) { // verifica valor do contador, compara com potenciômetro e, quanto iguais, liga o pino
        PORTD |= SERVO; // coloca nível lógico 1)
    }
}

Mas é um preciosismo, os servo são tolerantes na frequência de entrada.

Outra recomendação é não usar o valor do ADC diretamente, fazer um passa baixo em sw (média das últimas leituras) faz maravilhas para reduzir o ruído (que na ADC de um micro é sempre algum).

Isto foi o que reparei numa análise superficial do código ;)


Edit: umas correções ao codigo. A estas horas ainda não tenho café suficiente no organismo para sair código bem à primeira :P
« Última modificação: 12 de Dezembro de 2014, 09:55 por jm_araujo »

Offline Pinout

  • Mini Robot
  • *
  • Mensagens: 22
Re: PWM para servo com timer0 e modo CTC
« Responder #2 em: 12 de Dezembro de 2014, 12:44 »
jm_araujo, coloquei daquela forma pois sempre li que o pwm para servo começa com uma borda de subida, não sei se entederá o termo, pois falo portguês do Brasil, mas ele começa com nível lógico 1 e o dutty cycle o mantém por tempo curto e depois vem a borda da descida. Calculei um contador de 24, que me gera uma interrupção à cada 0.1ms (para poder manipular facilmente o dutty cycle), ou seja depois de 200 interrupções terei um intervalo de tempo de 20ms - 50Hz, por isso estou incrementando o pulseCount na interrupção e verificando se ele atingiu 200, para gerar a frequência de 50Hz e depois verifico com o 'else if' o valor do potenciômetro, para me gerar um dutty cycle com base no valor do mesmo. Da forma como colocou o pwm começaria na borda da descida e o duty cycle só trabalharia com uma porcentagem muito pequena do potencial do servo.

Veja bem a expressão:  else if(pulseCount >= (203 + (ADC / 44)))  que implementa o dutty cycle, divide o valor convertido do potenciômetro, que é no máximo 1023 por 44, ou seja, gera
um número máximo de 23, somado à 203 (que no meu servo é o grau 0). Sendo assim, quendo o potenciômetro está gerando 0, o servo vai ficar em grau 0, e o duty cycle vai ser de 0.3ms e
quando o potenciômetro estiver no máximo, o duty cycle vai ser de 2.6ms. Esses valores de dutty cycle funcionam perfeitamente para os servos Tower Pro 9g.

O passa baixas com o ADC, realmente, é o melhor jeito de fazer, principalmente quando é um valor que queira colocar num lcd ou que exija um valor mais estável, porém, não tive esse cuidado, de fato os servos são tolerantes e não quis complicar muito o código, coloquei uns registradores que nem seriam necessários, mais pra ficar bem claro tudo que estou fazendo.

jm_araujo, obrigado pelo comentário e todas as críticas e sugestões são bem vindas.
« Última modificação: 12 de Dezembro de 2014, 12:52 por Pinout »
A wise person listens and takes in more instruction;
A man of understanding acquires skillful direction

Offline Njay

  • Mini Robot
  • *
  • Mensagens: 3.086
    • Tróniquices
Re: PWM, Potenciômetro e Servo; Com timer0, modo CTC e rodando assíncrono
« Responder #3 em: 12 de Dezembro de 2014, 15:04 »
Não dizes qual é a frequência do clock do AVR.

Offline jm_araujo

  • Mini Robot
  • *
  • Mensagens: 2.124
  • NERD!
Re: PWM, Potenciômetro e Servo; Com timer0, modo CTC e rodando assíncrono
« Responder #4 em: 12 de Dezembro de 2014, 15:40 »
Se aos 200 ciclos adicionas mais um número indeterminado dependente da ADC, não podes em rigor dizer que a frequência são 50Hz, pois varia consoante esses ciclos adicionados, mas é uma aproximação que os servos toleram( como já tinha dito).

Para o caso não é importante, mas quis deixar o comentário porque pode aparecer que reuse o código e depois encontre esta imprecisão.

Offline Pinout

  • Mini Robot
  • *
  • Mensagens: 22
Re: PWM, Potenciômetro e Servo; Com timer0, modo CTC e rodando assíncrono
« Responder #5 em: 12 de Dezembro de 2014, 16:03 »
Não dizes qual é a frequência do clock do AVR.

A frequência é de 16Mhz.
A wise person listens and takes in more instruction;
A man of understanding acquires skillful direction

Offline Pinout

  • Mini Robot
  • *
  • Mensagens: 22
Re: PWM, Potenciômetro e Servo; Com timer0, modo CTC e rodando assíncrono
« Responder #6 em: 12 de Dezembro de 2014, 16:06 »
Se aos 200 ciclos adicionas mais um número indeterminado dependente da ADC, não podes em rigor dizer que a frequência são 50Hz, pois varia consoante esses ciclos adicionados, mas é uma aproximação que os servos toleram( como já tinha dito).

Para o caso não é importante, mas quis deixar o comentário porque pode aparecer que reuse o código e depois encontre esta imprecisão.

É verdade, passou desapercebido. Entendi seu ponto, para ficar exato o código deveria ficar assim:


Código: [Seleccione]
ISR(TIMER0_COMPA_vect) {
    pulseCount++; // incrementa o contador à cada 0.1ms
    if(pulseCount == 200) { // atende à condição à cada 20ms - frequência de 50Hz
        PORTD ^= SERVO; // inverte estado lógico do pino (sempre coloca em nível lógico 1)
    } else if(pulseCount >= (203 + (ADC / 44))) { // verifica valor do contador, compara com potenciômetro e, quanto iguais, limpa o pino
        PORTD ^= SERVO; // inverte estado lógico do pino (sempre coloca nível lógico 0)
        pulseCount = 3 + (ADC / 44); // zera contador
    }
}
« Última modificação: 12 de Dezembro de 2014, 16:22 por Pinout »
A wise person listens and takes in more instruction;
A man of understanding acquires skillful direction

Offline jm_araujo

  • Mini Robot
  • *
  • Mensagens: 2.124
  • NERD!
Re: PWM, Potenciômetro e Servo; Com timer0, modo CTC e rodando assíncrono
« Responder #7 em: 12 de Dezembro de 2014, 16:17 »
Pensa melhor no que estás a dizer.
Não passam 200 ciclos entre cada vez que ligas o pino porque o reset do contador varia com o valor do ADC.
Por exemplo se o ADC estiver a 0:
Conta de 0 a 200, liga o pino, conta até 203, reset do contador e do pino, e volta a contar 200. Entre as duas vezes que ligaste o pino passaram 200+3 ciclos.
Se o ADC for 440, conta de 0 a 200, liga o pino, conta até 213, faz reset do contador e do pino, e só liga passado 200 ciclos. Total de ciclos: 200+13

Se num caso demora 203 e noutro 213, como é que a frequência é sempre a mesma? No PWM a frequencia é o inverso do tempo a 0 mais o tempo a 1!


Se queres que realmente seja assincrono com menos modificações que o meu código é substítuir o "pulseCount = 0;" por "pulseCount = pulseCount -200". Aí sim a duração é sempre 200 ciclos

« Última modificação: 12 de Dezembro de 2014, 16:19 por jm_araujo »

Offline Pinout

  • Mini Robot
  • *
  • Mensagens: 22
Re: PWM, Potenciômetro e Servo; Com timer0, modo CTC e rodando assíncrono
« Responder #8 em: 12 de Dezembro de 2014, 16:23 »
Pensa melhor no que estás a dizer.
Não passam 200 ciclos entre cada vez que ligas o pino porque o reset do contador varia com o valor do ADC.
Por exemplo se o ADC estiver a 0:
Conta de 0 a 200, liga o pino, conta até 203, reset do contador e do pino, e volta a contar 200. Entre as duas vezes que ligaste o pino passaram 200+3 ciclos.
Se o ADC for 440, conta de 0 a 200, liga o pino, conta até 213, faz reset do contador e do pino, e só liga passado 200 ciclos. Total de ciclos: 200+13

Se num caso demora 203 e noutro 213, como é que a frequência é sempre a mesma? No PWM a frequencia é o inverso do tempo a 0 mais o tempo a 1!


Se queres que realmente seja assincrono com menos modificações que o meu código é substítuir o "pulseCount = 0;" por "pulseCount = pulseCount -200". Aí sim a duração é sempre 200 ciclos

É verdade, não tinha percebido. Obrigado pela observação, meu caro.
A wise person listens and takes in more instruction;
A man of understanding acquires skillful direction

Offline Njay

  • Mini Robot
  • *
  • Mensagens: 3.086
    • Tróniquices
Re: PWM, Potenciômetro e Servo; Com timer0, modo CTC e rodando assíncrono
« Responder #9 em: 12 de Dezembro de 2014, 16:52 »
Neste caso parece-me que não é importante, mas também convém dizer qual é o AVR, porque existem algumas diferenças nos periféricos entre os vários modelos de AVR.

No código original a pulseCount vai a zero em alturas diferentes (200 + duty_cycle), portanto sim, a frequência não é constante, embora seja um jitter (variação de frequência) pequeno e o servo não se importe com isso.

A resolução de posição é que me parece grosseira (20 posições, num intervalo de 180º dá um passo de 9º), mas provavelmente serve para muitos casos. Na minha opinião o código deveria estar preparado para fazer os valores tradicionais dos servos no que diz respeito ao ciclo activo, ou seja, impulso a high durante 0.5ms para 0º, 1.5ms para 90º e 2ms para 180º, e depois ter um parametro para ajustar a gama de posições (um deslocamento, offset) a cada servo (há diferenças entre servos).

Quanto ao código em si posso tecer alguns comentários no que diz respeito a práticas de programação.

Antes de mais eu faria e sem pensar 2 vezes como fez o jm_araujo: se é para meter a zero, mete-se explicitamente a zero e o mesmo para a um. Fazer com toggle é facilitar a vida ao Murphy.

A configuração dos registos deveria estar melhor comentada, incluindo menção aos cálculos. Por exemplo, em vez de apenas
  // prescaler 1:64
deveria ser qualquer coisa como
  // prescaler 1:64 => 16MHz sys clock / 64 = 250KHz
Na configuração do ADC não há nenhum comentário; a "regra" geral deve ser "ao ler o código, quanto menos precisar de olhar para a datasheet ou outro documento, melhor".

A variável pulseCount, como só é usada dentro do ISR, pode ser declarada lá dentro, assim:

ISR(...
{
    static uint8_t  pulseCount = 0;
    ...
}


Mais uma vez, ao ler o código desta rotina ficamos logo sem dúvidas se a variável é usada noutro sítio e como. Isto acelera e facilita a leitura do código, e ainda pode permitir ao compilador efectuar melhores optimizações, resultando em menor tamanho e maior velocidade.
Não é preciso usar volatile porque a variável só é usada dentro da routina.
É melhor usar o tipo uint8_t (ou unsigned char na pior das hipóteses), porque o tipo char pode ter sinal (agora não me lembro se no gcc para AVR tem, mas como o teu código funciona, não deve ter) e nesse caso o teu if ia falhar porque estarias a comparar a variável com valores que ela não pode ter; um (signed) char não pode ter valores maiores que 127, logo nunca é maior que 203 + qualquer_coisa.

A indentação deve ser coerente, há sítios que tens espaços e outros que tens tabs.
« Última modificação: 12 de Dezembro de 2014, 17:00 por Njay »

Offline Pinout

  • Mini Robot
  • *
  • Mensagens: 22
Re: PWM, Potenciômetro e Servo; Com timer0, modo CTC e rodando assíncrono
« Responder #10 em: 12 de Dezembro de 2014, 17:30 »
Neste caso parece-me que não é importante, mas também convém dizer qual é o AVR, porque existem algumas diferenças nos periféricos entre os vários modelos de AVR.

No código original a pulseCount vai a zero em alturas diferentes (200 + duty_cycle), portanto sim, a frequência não é constante, embora seja um jitter (variação de frequência) pequeno e o servo não se importe com isso.

A resolução de posição é que me parece grosseira (20 posições, num intervalo de 180º dá um passo de 9º), mas provavelmente serve para muitos casos. Na minha opinião o código deveria estar preparado para fazer os valores tradicionais dos servos no que diz respeito ao ciclo activo, ou seja, impulso a high durante 0.5ms para 0º, 1.5ms para 90º e 2ms para 180º, e depois ter um parametro para ajustar a gama de posições (um deslocamento, offset) a cada servo (há diferenças entre servos).

Quanto ao código em si posso tecer alguns comentários no que diz respeito a práticas de programação.

Antes de mais eu faria e sem pensar 2 vezes como fez o jm_araujo: se é para meter a zero, mete-se explicitamente a zero e o mesmo para a um. Fazer com toggle é facilitar a vida ao Murphy.

A configuração dos registos deveria estar melhor comentada, incluindo menção aos cálculos. Por exemplo, em vez de apenas
  // prescaler 1:64
deveria ser qualquer coisa como
  // prescaler 1:64 => 16MHz sys clock / 64 = 250KHz
Na configuração do ADC não há nenhum comentário; a "regra" geral deve ser "ao ler o código, quanto menos precisar de olhar para a datasheet ou outro documento, melhor".

A variável pulseCount, como só é usada dentro do ISR, pode ser declarada lá dentro, assim:

ISR(...
{
    static uint8_t  pulseCount = 0;
    ...
}


Mais uma vez, ao ler o código desta rotina ficamos logo sem dúvidas se a variável é usada noutro sítio e como. Isto acelera e facilita a leitura do código, e ainda pode permitir ao compilador efectuar melhores optimizações, resultando em menor tamanho e maior velocidade.
Não é preciso usar volatile porque a variável só é usada dentro da routina.
É melhor usar o tipo uint8_t (ou unsigned char na pior das hipóteses), porque o tipo char pode ter sinal (agora não me lembro se no gcc para AVR tem, mas como o teu código funciona, não deve ter) e nesse caso o teu if ia falhar porque estarias a comparar a variável com valores que ela não pode ter; um (signed) char não pode ter valores maiores que 127, logo nunca é maior que 203 + qualquer_coisa.

A indentação deve ser coerente, há sítios que tens espaços e outros que tens tabs.

Obrigado pela resposta Njay

Seguindo sua sugestão e a do jm_araujo, aqui vai o código:

Código: [Seleccione]
/*
 *
Cálculos:
Fosc: 16Mhz
Prescaler: 64

Primeiro converto para Hz o tempo que desejo ser realizada a interrupção (0.1ms): (1/0.1) * 1000 = 10000Hz ou 10Khz
Calculo, com base na frequência, o valor para o contador: (((16Mhz / 64) / 10000) -1) = 24

 * Created: 10/12/2014 09:29:27
 */
#include <avr/io.h>
#include <avr/interrupt.h>

#define SERVO (1 << PD6)

volatile uint8_t pulseCount = 0; // variável volatile compartilhada, que será usada como contador pulseCount

void ADC_init() { // inicia ADC em modo contínuo
    ADCSRA = (7 << ADPS0);
    ADMUX = (1 << REFS0);
    ADCSRB &= ~(7 << ADTS0);
    ADCSRA |= (1 << ADATE);
    ADCSRA |= (1 << ADEN);
    ADCSRA |= (1 << ADSC);
}

void CONFIG_servo() {
    DDRD = (SERVO); // seta pino como saída
    PORTD &= ~SERVO; // assegura nível lógico 0 para o pino
}

void timer0_init(void) {
    TCCR0A = (1<<WGM01); // modo CTC
    TCCR0B = ((1<<CS01)|(1<<CS00)); // prescaler 1:64
    OCR0A = 24; // interrupção à cada 0.1ms
    TIMSK0 = (1<<OCIE0A); // habilita interrupções no timer
    sei(); // habilita interrupções globais
}

int main(void) {
    CONFIG_servo();
    ADC_init();
    timer0_init();
    while(1);
    return 1;
}

ISR(TIMER0_COMPA_vect) {
    pulseCount++; // incrementa o contador à cada 0.1ms
    if(pulseCount == 200) { // atende à condição à cada 20ms - frequência de 50Hz
        PORTD ^= SERVO; // inverte estado lógico do pino (sempre coloca em nível lógico 1)
    } else if(pulseCount >= (203 + (ADC / 44))) { // verifica valor do contador, compara com potenciômetro e, quanto iguais, limpa o pino
        PORTD ^= SERVO; // inverte estado lógico do pino (sempre coloca nível lógico 0)
        pulseCount -= 200; // atribui ao contador valor para frequência de 50Hz subtraindo o que foi gerado no dutty cycle
    }
}

Com relação à variável pulseCount, realmente o char é signed e não me antentei ao range. Pelo visto ele é unsigned por padrão, senão jamais daria certo, mas coloquei o uint8_t, para ficar mais claro que é 1 byte unsigned, mas ela ser declarada dentro da ISR, não vejo como declará-la e incrementá-la a cada interrupção. Pode me dizer se há realmente um jeito?

« Última modificação: 27 de Janeiro de 2015, 11:30 por Pinout »
A wise person listens and takes in more instruction;
A man of understanding acquires skillful direction

Offline Njay

  • Mini Robot
  • *
  • Mensagens: 3.086
    • Tróniquices
Re: PWM, Potenciômetro e Servo; Com timer0, modo CTC e rodando assíncrono
« Responder #11 em: 12 de Dezembro de 2014, 17:35 »
Exactamente como exemplifiquei. Em C/C++, se colocares a keyword  static no inicio da declaração de uma variável local, ela deixa de ser local e passa a ser "global" (para ser rigoroso, passa a ser "estática", ou seja, existe sempre, não está na pilha), mas apenas visivel dentro do bloco ({...}) em que está declarada, e só é inicializada 1 vez, no inicio do programa (tal como uma variável "global").
« Última modificação: 12 de Dezembro de 2014, 17:42 por Njay »

Offline Pinout

  • Mini Robot
  • *
  • Mensagens: 22
Re: PWM, Potenciômetro e Servo; Com timer0, modo CTC e rodando assíncrono
« Responder #12 em: 12 de Dezembro de 2014, 17:40 »
Exactamente como exemplifiquei. Se colocares a keyword  static no inicio da declaração de uma variável local, ela deixa de ser local e passa a ser global, mas apenas visivel dentro do bloco ({...}) em que está declarada, e só é inicializada 1 vez, no inicio do programa (tal como uma variável global).

Maravilha!
« Última modificação: 12 de Dezembro de 2014, 17:49 por Pinout »
A wise person listens and takes in more instruction;
A man of understanding acquires skillful direction

Offline Pinout

  • Mini Robot
  • *
  • Mensagens: 22
Re: PWM, Potenciômetro e Servo; Com timer0, modo CTC e rodando assíncrono
« Responder #13 em: 12 de Dezembro de 2014, 17:49 »
fiquei na dúvida se havia diferença de performance, entre as duas abordagens e achei o texto abaixo:

- Making the variable static may incur a small cost on every call of the function determining if the object was already initialized, especially with C++11 where the initialization is thread-safe. Even if it doesn't need a check, the stack is likely to be in cached memory while a static variable is not.

- Making a variable global will increase the chances that it isn't in cached memory, i.e., there is a good chance that it will be slower (aside from adverse other potential like making it a good candidate to introduce data races).
Making a variable const may help if the compiler can compute the value as compile time.
A wise person listens and takes in more instruction;
A man of understanding acquires skillful direction

Offline Njay

  • Mini Robot
  • *
  • Mensagens: 3.086
    • Tróniquices
Re: PWM, Potenciômetro e Servo; Com timer0, modo CTC e rodando assíncrono
« Responder #14 em: 12 de Dezembro de 2014, 17:57 »
fiquei na dúvida se havia diferença de performance,
Não há, porque a tua variável já era "global". Na verdade, até é mais rápido declarado como estática dentro do ISR, pois o compilador vai poder fazer algumas optimizações que não pode fazer quando declaras a variável global (fora de funções). Mesmo declarando a variável global, podes ainda assim tornar o acesso mais rápido se ... adicionares static no inicio :) . A diferença entre uma variável global com static e sem static é que sem static ela pode ser acedida a partir de outro ficheiro de código (que também esteja a ser linkado na a tua aplicação), e com static ela só é visivel dentro do ficheiro onde foi declarada.

Mais ainda: podes também adicionar static à declaração de funções, podendo com isto tornar o código mais pequeno. A "desvantagem" é que não podes invocá-las a partir de outro ficheiro, mas se o teu programa só tem um (como é agora o caso), isso não é um problema.

Faz esta experiência: compila o teu código actual (pulseCount global) e vê o tamanho do código gerado, depois adiciona static à declaração da pulseCount, compila e compara o tamanho do código gerado com a versão sem static. (e também podes experimentar com e sem volatile).

Citar
entre as duas abordagens e achei o texto abaixo:

- Making the variable static may incur a small cost on every call of the function determining if the object was already initialized, especially with C++11 where the initialization is thread-safe. Even if it doesn't need a check, the stack is likely to be in cached memory while a static variable is not.
Não se aplica ao actual GCC para AVR, além de que threads não são suportadas nativamente.

Citar
- Making a variable global will increase the chances that it isn't in cached memory, i.e., there is a good chance that it will be slower (...)
Não se aplica ao AVR, o AVR não tem cache no CPU.
« Última modificação: 12 de Dezembro de 2014, 18:07 por Njay »