Trabalho 3 – Unidade II 2021/2 - MICROCONTROLADORES : construir um sistema de controle de temperatura em malha fechada com o módulo de temperatura do PICSimLab.
Descrição do funcionamento. O sinal de entrada deve ser ajustado no PICSimLab no potenciômetro P1. O PIC recebe o sinal de entrada e a temperatura via AD, calcula o erro entre o valor da temperatura de referência (entrada) e a saída da planta (temperatura lida pelo sensor na planta – LM35), processa com modelo do controlador e gera um sinal de controle (ton do PWM) que deve ser aplicado no atuador(resistor). Um sinal de distúrbio também poderá ser aplicado a planta via potenciômetro P2. Os sinais de entrada, saída, distúrbio, controle (ton) e o erro devem ser enviado ao Processing (ou outra interface desenvolvido pelo aluno) onde são apresentado na forma de gráficos de linha:
Funções
1. O operador
Poderá modificar o sinal de referência ou temperatura desejada via potenciômetro P1.
Poderá inserir um distúrbio no sistema através do mini ventilador (cooler). Esse distúrbio também deve ter a intensidade controlada via potenciômetro P2.
Características gerais
1. O conversor AD deve ser configurado em 10bits para aumentar a precisão.
2. Devem ser utilizados PWM para acionamento do resistor (atuador) e do cooler (distúrbio).
3. Deve ser utilizado o LM32 (sensor de temperatura) da placa para obter a temperatura de saída
4. Os gráficos devem ter indicações nos eixos.
5. Deve ser realizado o experimento em malha aberta para determinar os parâmetros P, I e D do controlador PID. Usar a metodologia de Ziegler-Nichols apresentada em sala de aula.
6. A comunicação entre o PICSimLab e o Processing deve ser via porta serial virtual.
Resolução:
Código feito em CCS C Compiler
Arquivo temp.c
#include <temp.h>
#include "biblioteca\mod_lcd.c"
char grau = 223; // Pega o simbolo "º", grau
float temperatura_Atual = 0.0,
temperatura_Antiga = 0.0,
Disturbio = 0;
double ref, // Referencia desejada
error, // Diferenca entre temperatura desejada e temperatura atual
kP = 70,
kI = 2,
kD = 0,
P, I, D,
pid;
double process(){
// Implementação PID
//Proporcional
P = error * kP;
//Integrador
I = I + (error * kI);
//Derivador
D = (temperatura_Antiga - temperatura_Atual) * kD;
temperatura_Antiga = temperatura_Atual;
// Soma tudo
pid = P + I + D;
return pid;
}
void main(){
setup_adc(ADC_CLOCK_DIV_16); // ADC Module uses its internal oscillator
setup_adc_ports(AN0_AN1_AN2_AN3_AN4); // Configuracao de portas analogicas
enable_interrupts(INT_RTCC);
enable_interrupts(GLOBAL);
setup_timer_2(T2_DIV_BY_16,255,1); //819 us overflow, 819 us interrupt 255+1 = 256 *4 = 1024
setup_ccp1(CCP_PWM); // Configura a porta CCP1 como PWM
setup_ccp2(CCP_PWM); // Configura a porta CCP2 como PWM
lcd_ini(); // Inicializa LCD
delay_ms(10);
while(TRUE) {
set_adc_channel(0); // Seleciona o canal ANA0
delay_ms(10); // Tempo para ativacao
ref = read_adc() * 0.0489 + 20; // Pega a leitura do ANA0
set_adc_channel(2);
delay_ms(10);
temperatura_Atual = ((read_adc() * 5)/1023.0)/0.010;
if (temperatura_Atual >=1) {
error = ref - temperatura_Atual;
process();
if(pid>1023) { pid=1023; } else if (pid<=0) { pid=0; }
if (error >0) { set_pwm2_duty((int16)pid); }
else if (error <=0) { set_pwm2_duty(0); }
set_adc_channel(1);
delay_ms(10);
disturbio = read_adc();
SET_PWM1_DUTY((int16) disturbio);
// Escreve na Tela
printf (lcd_escreve,"\fTemp= %f %cC",temperatura_Atual, grau); // Temperatura
printf (lcd_escreve,"\n\rRef= %f %cC",ref, grau); // Referencia
delay_ms(1000);
}
} // While
} // Main
_______________________//___________________
Arquivo mod_lcd.c
// As defininições es a seguir s�o utilizadas para acesso aos pinos do display
// caso o pino RW n�o seja utilizado, comente a defini��o lcd_rw
#ifndef lcd_enable
#define lcd_enable pin_e1 // pino enable do LCD
#define lcd_rs pin_e0 // pino rs do LCD
//#define lcd_rw pin_e2 // pino rw do LCD
#define lcd_d4 pin_d4 // pino de dados d4 do LCD
#define lcd_d5 pin_d5 // pino de dados d5 do LCD
#define lcd_d6 pin_d6 // pino de dados d6 do LCD
#define lcd_d7 pin_d7 // pino de dados d7 do LCD
#endif
#define lcd_type 2 // 0=5x7, 1=5x10, 2=2 linhas
#define lcd_seg_lin 0x40 // Endere�o da segunda linha na RAM do LCD
// a constante abaixo define a seq��ncia de inicializa��o do m�dulo LCD
byte CONST INI_LCD[4] = {0x20 | (lcd_type << 2), 0xf, 1, 6};
byte lcd_le_byte()
// l� um byte do LCD (somente com pino RW)
{
byte dado;
// configura os pinos de dados como entradas
input(lcd_d4);
input(lcd_d5);
input(lcd_d6);
input(lcd_d7);
// se o pino rw for utilizado, coloca em 1
#ifdef lcd_rw
output_high(lcd_rw);
#endif
output_high(lcd_enable); // habilita display
dado = 0; // zera a vari�vel de leitura
// l� os quatro bits mais significativos
if (input(lcd_d7)) bit_set(dado,7);
if (input(lcd_d6)) bit_set(dado,6);
if (input(lcd_d5)) bit_set(dado,5);
if (input(lcd_d4)) bit_set(dado,4);
// d� um pulso na linha enable
output_low(lcd_enable);
output_high(lcd_enable);
// l� os quatro bits menos significativos
if (input(lcd_d7)) bit_set(dado,3);
if (input(lcd_d6)) bit_set(dado,2);
if (input(lcd_d5)) bit_set(dado,1);
if (input(lcd_d4)) bit_set(dado,0);
output_low(lcd_enable); // desabilita o display
return dado; // retorna o byte lido
}
void lcd_envia_nibble( byte dado )
// envia um dado de quatro bits para o display
{
// coloca os quatro bits nas saidas
output_bit(lcd_d4,bit_test(dado,0));
output_bit(lcd_d5,bit_test(dado,1));
output_bit(lcd_d6,bit_test(dado,2));
output_bit(lcd_d7,bit_test(dado,3));
// d� um pulso na linha enable
output_high(lcd_enable);
output_low(lcd_enable);
}
void lcd_envia_byte( boolean endereco, byte dado )
{
// coloca a linha rs em 0
output_low(lcd_rs);
// aguarda o display ficar desocupado
//while ( bit_test(lcd_le_byte(),7) ) ;
// configura a linha rs dependendo do modo selecionado
output_bit(lcd_rs,endereco);
delay_us(100); // aguarda 100 us
// caso a linha rw esteja definida, coloca em 0
#ifdef lcd_rw
output_low(lcd_rw);
#endif
// desativa linha enable
output_low(lcd_enable);
// envia a primeira parte do byte
lcd_envia_nibble(dado >> 4);
// envia a segunda parte do byte
lcd_envia_nibble(dado & 0x0f);
}
void lcd_ini()
// rotina de inicializa��o do display
{
byte conta;
output_low(lcd_d4);
output_low(lcd_d5);
output_low(lcd_d6);
output_low(lcd_d7);
output_low(lcd_rs);
#ifdef lcd_rw
output_high(lcd_rw);
#endif
output_low(lcd_enable);
delay_ms(15);
// envia uma seq��ncia de 3 vezes 0x03
// e depois 0x02 para configurar o m�dulo
// para modo de 4 bits
for(conta=1;conta<=3;++conta)
{
lcd_envia_nibble(3);
delay_ms(5);
}
lcd_envia_nibble(2);
// envia string de inicializa��o do display
for(conta=0;conta<=3;++conta) lcd_envia_byte(0,INI_LCD[conta]);
}
void lcd_pos_xy( byte x, byte y)
{
byte endereco;
if(y!=1)
endereco = lcd_seg_lin;
else
endereco = 0;
endereco += x-1;
lcd_envia_byte(0,0x80|endereco);
}
void lcd_escreve( char c)
// envia caractere para o display
{
switch (c)
{
case '\f' : lcd_envia_byte(0,1);
delay_ms(2);
break;
case '\n' :
case '\r' : lcd_pos_xy(1,2);
break;
case '\b' : lcd_envia_byte(0,0x10);
break;
default : lcd_envia_byte(1,c);
break;
}
}
char lcd_le( byte x, byte y)
// le caractere do display
{
char valor;
// seleciona a posi��o do caractere
lcd_pos_xy(x,y);
// ativa rs
output_high(lcd_rs);
// l� o caractere
valor = lcd_le_byte();
// desativa rs
output_low(lcd_rs);
// retorna o valor do caractere
return valor;
}
|
Saída ggerada no PicSimlab |
Créditos para: Fábio Pereira