Olá, estou há alguns dias estudando o funcionamento do Arduino Uno e, para questão de estudo, gostaria de ajuda em um sketch para geração de pulsos quadrados PWM, que sejam lidos pelo terminal para que eu possa gerar gráficos de Tensão X Tempo. Este gerado pelas ondas quadradas como mostram os exemplo de inúmeros livros. No entanto, esses programas são criados para serem lidos com ajudo de um osciloscópio. Eu, no caso, gostaria de gerar dados no terminal, salvá-los em .txt e gerar esses gráficos em Origin ou Excel, como na figura em anexo.

Para critério de estudo, estou jogando o valor de 255 (5V) no pino ~6 e lendo o valor da tensão no pino A0, transformando o valor digital em analógico por meio de um fio de cobre ligando os dois pinos.

Com um pouco de pesquisa em sites e em livros, acabei tendo algumas ideias para gerar um sketch simples, onde posso mudar os valores dos ciclos, entre 25%, 50% e 75%, para que eu possa vizualizá-los na forma de gráficos, pegando os valores de tempo e tensão pelo serial do Arduino.

Para isso, criei a varável micro, onde defino o valor do ciclo de pulso em 5V e o restante em 0V. Nesse exemplo, quero gerar um pulso com 10% em 5V e 90% em 0V.

Eu havia lido que a função analogRead() retorna valores entre 0 e 1023, sendo 0 correspondente a 0V e 1023, a 5V. Assim, para converter os valores lidos, divido por 204.6, que vem da divisão 1023/5.

int analogPin = A0; //pino analogico
int pwmPin = 6; //pino PWM
int micro = 100; // 100 ~ 10% DutyCycle
void setup()
{
pinMode(pwmPin, OUTPUT);
Serial.begin(9600);
}

void loop()
{
float mili = millis();
int dutyCycle = 255; // 5V
analogWrite(pwmPin, dutyCycle);
int rawReading = analogRead(analogPin);
float volts = rawReading / 204.6; // transformando o valor para 5V
Serial.print(mili); // pegando o valor do tempo
Serial.print(" ");
Serial.println(volts); // pegando o valor da tensao
delayMicroseconds(micro); // valor do ciclo em 5V
mili = millis();
dutyCycle = 0;
analogWrite(pwmPin, dutyCycle);
rawReading = analogRead(analogPin);
volts = rawReading / 204.6;
Serial.print(mili);
Serial.print(" ");
Serial.println(volts);
delayMicroseconds(1000-micro); // valor do ciclo em 0V
}

Problemas: a função millis(), não me traz valores exatos de tempo (para o gráfico Tensão x Tempo) e, mesmo que eu mude os valores da varável micro, parece que os gráficos ficam todos iguais. Gostaria de enxergar o valor do ciclo (10%, 25%, 50%...) mudando conforme eu mude os valores de micro. Como nunca mexi com a função millis(), posso estar fazendo algo bem errado...

Alguém tem alguma sugestão?

Obrigado!

Exibições: 425

Anexos

Responder esta

Respostas a este tópico

Eu fiz um outro código, agora utilizando um laço for, definindo com variáveis tempo o início e o fim dos sinais de 5V e o 0V. Por hora, funciona, mas sinto que não é bem este o caminho, pois estou forçando o Arduino a me fornecer estes sinais por meio do analogWrite() e analogRead(), e não pegando os valores dos pulsos, uma vez que o padrão dos "analogs" é de 500Hz. Neste código com for, eu estou definindo o tempo de 0 a 100, mas queria que isso fosse realmente em milissegundos. Não sei se estou sendo claro, nem sei se isso é possível... O código novo e o resultado estão abaixo:

int analogPin = A0; //pino analogico
int pwmPin = 6; //pino PWM
int tempoI = 0;
int tempoP = 50; // 50%
int tempoF = 100;

void setup()
{
pinMode(pwmPin, OUTPUT);
Serial.begin(9600);
}

void loop()
{
for (tempoI = 0; tempoI <= tempoP; tempoI++)
{
int dutyCycle = 255; // 5V
analogWrite(pwmPin, dutyCycle);
int rawReading = analogRead(analogPin);
float volts = rawReading / 204.6;
Serial.print(tempoI);
Serial.print(" ");
Serial.println(volts);
}
for (tempoF = tempoI; tempoF <= 100; tempoF++)
{
int dutyCycle = 0;
analogWrite(pwmPin, dutyCycle);
int rawReading = analogRead(analogPin);
float volts = rawReading / 204.6;
Serial.print(tempoF);
Serial.print(" ");
Serial.println(volts);
}
}

0 5.00
1 5.00
2 5.00
3 5.00
4 5.00
5 5.00
6 5.00
7 5.00
8 5.00
9 5.00
10 5.00
11 5.00
12 5.00
13 5.00
14 5.00
15 5.00
16 5.00
17 5.00
18 5.00
19 5.00
20 5.00
21 5.00
22 5.00
23 5.00
24 5.00
25 5.00
26 5.00
27 5.00
28 5.00
29 5.00
30 5.00
31 5.00
32 5.00
33 5.00
34 5.00
35 5.00
36 5.00
37 5.00
38 5.00
39 5.00
40 5.00
41 5.00
42 5.00
43 5.00
44 5.00
45 5.00
46 5.00
47 5.00
48 5.00
49 5.00
50 5.00
51 0.00
52 0.00
53 0.00
54 0.00
55 0.00
56 0.00
57 0.00
58 0.00
59 0.00
60 0.00
61 0.00
62 0.00
63 0.00
64 0.00
65 0.00
66 0.00
67 0.00
68 0.00
69 0.00
70 0.00
71 0.00
72 0.00
73 0.00
74 0.00
75 0.00
76 0.00
77 0.00
78 0.00
79 0.00
80 0.00
81 0.00
82 0.00
83 0.00
84 0.00
85 0.00
86 0.00
87 0.00
88 0.00
89 0.00
90 0.00
91 0.00
92 0.00
93 0.00
94 0.00
95 0.00
96 0.00
97 0.00
98 0.00
99 0.00
100 0.00

Mas queria utilizar um contator em tempo real do Arduino.

Obrigado!
Eu fiz um outro código, agora utilizando um laço for, definindo com variáveis tempo o início e o fim dos sinais de 5V e o 0V. Por hora, funciona, mas sinto que não é bem este o caminho, pois estou forçando o Arduino a me fornecer estes sinais por meio do analogWrite() e analogRead(), e não pegando os valores dos pulsos, uma vez que o padrão dos "analogs" é de 500Hz. Neste código com for, eu estou definindo o tempo de 0 a 100, mas queria que isso fosse realmente em milissegundos. Não sei se estou sendo claro, nem sei se isso é possível... O código novo e o resultado estão abaixo:

int analogPin = A0; //pino analogico
int pwmPin = 6; //pino PWM
int tempoI = 0;
int tempoP = 50; // 50%
int tempoF = 100;

void setup()
{
pinMode(pwmPin, OUTPUT);
Serial.begin(9600);
}

void loop()
{
for (tempoI = 0; tempoI <= tempoP; tempoI++)
{
int dutyCycle = 255; // 5V
analogWrite(pwmPin, dutyCycle);
int rawReading = analogRead(analogPin);
float volts = rawReading / 204.6;
Serial.print(tempoI);
Serial.print(" ");
Serial.println(volts);
}
for (tempoF = tempoI; tempoF <= 100; tempoF++)
{
int dutyCycle = 0;
analogWrite(pwmPin, dutyCycle);
int rawReading = analogRead(analogPin);
float volts = rawReading / 204.6;
Serial.print(tempoF);
Serial.print(" ");
Serial.println(volts);
}
}

0 5.00
1 5.00
2 5.00
3 5.00
4 5.00
5 5.00
6 5.00
7 5.00
8 5.00
9 5.00
10 5.00
11 5.00
12 5.00
13 5.00
14 5.00
15 5.00
16 5.00
17 5.00
18 5.00
19 5.00
20 5.00
21 5.00
22 5.00
23 5.00
24 5.00
25 5.00
26 5.00
27 5.00
28 5.00
29 5.00
30 5.00
31 5.00
32 5.00
33 5.00
34 5.00
35 5.00
36 5.00
37 5.00
38 5.00
39 5.00
40 5.00
41 5.00
42 5.00
43 5.00
44 5.00
45 5.00
46 5.00
47 5.00
48 5.00
49 5.00
50 5.00
51 0.00
52 0.00
53 0.00
54 0.00
55 0.00
56 0.00
57 0.00
58 0.00
59 0.00
60 0.00
61 0.00
62 0.00
63 0.00
64 0.00
65 0.00
66 0.00
67 0.00
68 0.00
69 0.00
70 0.00
71 0.00
72 0.00
73 0.00
74 0.00
75 0.00
76 0.00
77 0.00
78 0.00
79 0.00
80 0.00
81 0.00
82 0.00
83 0.00
84 0.00
85 0.00
86 0.00
87 0.00
88 0.00
89 0.00
90 0.00
91 0.00
92 0.00
93 0.00
94 0.00
95 0.00
96 0.00
97 0.00
98 0.00
99 0.00
100 0.00

Mas queria utilizar um contator em tempo real do Arduino.

Obrigado!
Eu fiz um outro código, agora utilizando um laço for, definindo com variáveis tempo o início e o fim dos sinais de 5V e o 0V. Por hora, funciona, mas sinto que não é bem este o caminho, pois estou forçando o Arduino a me fornecer estes sinais por meio do analogWrite() e analogRead(), e não pegando os valores dos pulsos, uma vez que o padrão dos "analogs" é de 500Hz. Neste código com for, eu estou definindo o tempo de 0 a 100, mas queria que isso fosse realmente em milissegundos. Não sei se estou sendo claro, nem sei se isso é possível... O código novo e o resultado estão abaixo:

int analogPin = A0; //pino analogico
int pwmPin = 6; //pino PWM
int tempoI = 0;
int tempoP = 50; // 50%
int tempoF = 100;

void setup()
{
pinMode(pwmPin, OUTPUT);
Serial.begin(9600);
}

void loop()
{
for (tempoI = 0; tempoI <= tempoP; tempoI++)
{
int dutyCycle = 255; // 5V
analogWrite(pwmPin, dutyCycle);
int rawReading = analogRead(analogPin);
float volts = rawReading / 204.6;
Serial.print(tempoI);
Serial.print(" ");
Serial.println(volts);
}
for (tempoF = tempoI; tempoF <= 100; tempoF++)
{
int dutyCycle = 0;
analogWrite(pwmPin, dutyCycle);
int rawReading = analogRead(analogPin);
float volts = rawReading / 204.6;
Serial.print(tempoF);
Serial.print(" ");
Serial.println(volts);
}
}

0 5.00
1 5.00
2 5.00
3 5.00
4 5.00
5 5.00
6 5.00
7 5.00
8 5.00
9 5.00
10 5.00
11 5.00
12 5.00
13 5.00
14 5.00
15 5.00
16 5.00
17 5.00
18 5.00
19 5.00
20 5.00
21 5.00
22 5.00
23 5.00
24 5.00
25 5.00
26 5.00
27 5.00
28 5.00
29 5.00
30 5.00
31 5.00
32 5.00
33 5.00
34 5.00
35 5.00
36 5.00
37 5.00
38 5.00
39 5.00
40 5.00
41 5.00
42 5.00
43 5.00
44 5.00
45 5.00
46 5.00
47 5.00
48 5.00
49 5.00
50 5.00
51 0.00
52 0.00
53 0.00
54 0.00
55 0.00
56 0.00
57 0.00
58 0.00
59 0.00
60 0.00
61 0.00
62 0.00
63 0.00
64 0.00
65 0.00
66 0.00
67 0.00
68 0.00
69 0.00
70 0.00
71 0.00
72 0.00
73 0.00
74 0.00
75 0.00
76 0.00
77 0.00
78 0.00
79 0.00
80 0.00
81 0.00
82 0.00
83 0.00
84 0.00
85 0.00
86 0.00
87 0.00
88 0.00
89 0.00
90 0.00
91 0.00
92 0.00
93 0.00
94 0.00
95 0.00
96 0.00
97 0.00
98 0.00
99 0.00
100 0.00

Mas queria utilizar um contator em tempo real do Arduino.

Obrigado!

Oi FC, boa tarde.

Não entendi muito bem a sua ideia de aplicar o sinal de PWM nas entradas analógicas.

Se no momento da leitura o PWM estiver em HIGH, vai ler 1023, e se estiver em LOW vai ler 0.

Acho que pode simplificar o seu "leitor" de PWM, e nem precisa usar as entradas analógicas.

Vou explicar:

O PWM roda "livre", pois é controlado por um timer do arduino, e este timer (quando ativado pelo PWM) 

recebe os pulsos de incremento vindo do oscilador do arduino.

"The frequency of the PWM signal on most pins is approximately 490 Hz...."

 "On the Uno and similar boards pins 5 and 6 have a frequency of approximately 980 Hz.... "

Ok?

O programador pode modificar o "Duty cycle" do PWM, (% do tempo em HIGH).

 

Agora você pode pegar este sinal e aplicar no port 2 ou 3.

Usando o recurso de interrupt, você tem varias opções de escrever uma rotina.

Vou sugerir uma:

Usando HIGH do interrupt, você começa a contar o tempo no momento em que o pulse fica LOW (sai do interrupt)

e ao ficar HIGH novamente você salva este tempo, e  saberá quanto tempo durou o LOW. como sabe  

a frequencia, fica fácil saber quanto durou o HIGH e cacular o %.

Outra maneira:

Use RISING do interrupt, ao subir vai pra rotina de interrupt, e lá inverta para interromper em FALLING.

Conte o tempo entre uma ocorrência e outra, e terá o valor do Duty Cycle.

Rui

Oi FC, bom dia.

Este code abaixo foi escrito baseado na forma que te falei no meu texto.

Teste o e depois coloque aqui se ele atendeu sua necessidade.

Rui

http://pastebin.com/jBCismJC

Oi FC,

testei este code e medi com o analisador lógico.

Está correta a medida dos tempos.

Testei com PWM no Port 6(960 HZ)  e no Port 9 (480 Hz).

Rui

RSS

© 2024   Criado por Marcelo Rodrigues.   Ativado por

Badges  |  Relatar um incidente  |  Termos de serviço