INTERPRETACION DEL CODIGO #include #use delay (clock=8MHZ) Estas
2 primeras instrucciones describen el microcontrolador a utilizar
(en este caso el 16f690, pero se puede elegir el que se desee
utilizar) .luego la frecuencia del oscilador
(cristaldecuarzo,osciladorinternoquealgunospicdisponen,circuitoRC,cualquier
fuente que genere los pulsos para sincronizar las operaciones
internas) Unsigned int8 n_pls, r_pls, Kp,Ki; Unsigned long duty,
r_value, k; Signed long uc, e_pls, Iold, Inew; Luego de las
instrucciones anteriores proseguimos a declarar las variables que
vamos a utilizar, en este caso son variables globales, es decir se
pueden obtener sus valores en cualquier parte del programa, no estn
restringidas a un espacio (como por ejemplo una funcin).Lo ms
importante que hay que saber es que mediante la declaracin de
variables reservamos espacio en la memoria. SIGNIFICADO DE CADA
VARIABLE: UNSIGNED INT8n_pls, r_pls, Kp, Ki
Unsignedint8defineunavariablesinsigno(Unsigned),generalmenteseest
hablandodevalorespositivosnuncanegativos,eltamaodeestavariableesun
entero de 8 bits (int8). n_pls
Comoseutilizaunencoderparapodersensarlavelocidaddemotor,es
necesario conocer la cantidad de pulsos que genera el encoder en un
tiempo determinado (tiempo de muestreo), esa cantidad de pulsos de
almacenanen esta variable. n_pls significa o es un acrnimo
denmero(n) de pulsos (pls). r_pls
Lavelocidaddelmotorsemodificamedianteunpotencimetro(entradade
referencia).Este potencimetro va conectado a uno de los conversores
del pic (ADC),deestamaneraasociamosunvalordelpotencimetroconuna
determinadavelocidad.RecordarqueenelcasodelosADCdelpic16f690
tienenunaresolucinde10bits,estoquieredecirquepuedoobtener1024
valores. Por lo tanto podemos decir: 5 voltios (valor mximo)es
igual 1024 0 voltios(valor mnimo) es igual a 0 De esta manera
podemos asociar cualquier voltaje del potencimetro con su
respectivo valor digital. r_pls significa o es un acrnimo de pulsos
(pls) de referencia(r).Lo que trae la idea que mediante el
potencimetro le comunico al pic cuantos pulsos quiero
quecomiencearegistraroacontarelencoder,todoestosetraducea:que
velocidad del motor deseo. KP,KI
EstasvariablessonlosparmetrosdelcontroladorPI.Laconstante
proporcional (KP) y la constante integral (KI). UNSIGNED LONG duty,
r_value, k;
Unsignedlongdefineunavariablesinsigno(Unsigned),generalmenteseest
hablandodevalorespositivosnuncanegativos,eltamaodeestavariableesun
entero de 16 bits (long), tambin pudo ser int16 (es lo mismo). Duty
Esta variable hace referencia al ciclo de trabajo (duty cicle) de
la seal PWM,
necesariaparamodificarlavelocidaddelmotor(enrealidadelobjetivode
todoelprogramaespodervariarautomticamenteestevalorsegn convenga).
r_value Esta variable almacena o toma los valores del potencimetro
despus de haber convertido el nivel de voltaje a un valor numrico
(digital).Es decir y como ya haba mencionado antes:
Sielvoltajeenelpotencimetroes5voltiossuequivalenteen digital seria
1024.Por lo tanto r_value sera igual a 1024. r_value=1024y as con
los dems valores K La variable k solo se utiliza para poder contar
y poder visualizar el nmero de interrupciones que se estn
produciendo desde el momento en que comience
afuncionartodoelprograma.Suvalornoesmuyimportanteparael
funcionamiento detodoelprograma.Cmo dijees paradarme una idea de
cuantasveceselpicsehadetenidoaleersuentradadereferenciayactuar
conforme a ello (para esto son las interrupciones). SIGNED LONG uc,
e_pls, Iold,Inew Signed long define una variable consigno (Signed),
estamoshablando de valores positivos onegativos, el tamao de esta
variable es un entero de 16 bits (long), tambin pudo ser int16 (es
lo mismo). UC
EstavariableeslaaccindecontroldelcontroladorPI,seutilizapara
almacenar el resultadode la accin proporcional y la accin integral.
Es el resultado total de todo el cdigo del programa (mejor dicho
todo se basa en obtener este valor, por qu es quien modifica el
ciclo de trabajo de la seal PWM) e_pls
e_plssignificaoesunacrnimodepulsos(pls)deerror(e).Enestavariable
almacenamos el error obtenido entre mi entrada de referencia
(r_pls) y el valor obtenido en el encoder (n_pls). Iold,Inew
Enestasdosvariablesalmacenamoselvalordelaaccinintegral.Lanueva
accin integral (Inew) y la antigua o anterior accin integral
(Iold).Las dos estn relacionadas, ya que el nuevo valor de la accin
integral se logra calcular con el valor anterior de la accin
integral. #int_TIMER1 VoidTIMER1_isr (void){ INSTRUCCIONES A
EJECUTAR } La directiva#int_Timer1 esla funcin de interrupcin, es
decir elespacio del programa en donde yo, voy a describir
(programar) que es lo que va hacer el microcontrolador cada cierto
tiempo (tiempo de muestreo).Mejor dicho el pic se va a detener cada
cierto tiempo para realizar lo que hay dentro de esta funcin
(instrucciones a ejecutar), luego de haberse ejecutado, seguir con
su normal funcionamiento y as todo el tiempo. Para saber dnde
comienzayacabaestebloquetengoqueidentificarlasllaves({}),queinicializany
terminan esta parte. La parte voidTIMER1_isr (void) describe lo
siguiente: Elprimervoid(vaco)significaquelafuncindeinterrupcinnovaa
devolverningnvalor,esdecirqueningnvalordealgunavariableo
resultadoqueseencuentredentrodeestebloque,sevapasaraotra funcin,
para que sea utilizada.
Elsegundovoid(vaco),elqueestentreparntesissignificaquela
funcinnovaarecibirningnparmetroovalorprovenientedeotra funcin.
TIMER1_isr, es el nombre que quieres que lleve la funcin (puedes
poner cualquier nombre como identificador).El nombre que aparece
aqu, es el que te pone por defecto pic c.
AHORAVAMOSADESCRIBIRQUEHAYENELINTERIORDELAFUNCINEXPLICADA
ANTERIORMENTE (INSTRUCCIONES A EJECUTAR): output_high(PIN_C0); Esta
instruccin que significa poner en alto el pin C0 del
microcontrolador, sirve para
podervisualizarodetectarcuandoseproducelasinterrupcionesycuntotiempo
duran (menciono cuanto tiempo duran porque al final de la funcin de
interrupcinsevisualizaotrainstruccincontrariaaesta,llamadaoutput_low(PIN_C0);quelo
que hace es poner en bajo el pin C0 del microcontrolador. As queyo
puedo medir el tiempo que dura o hay entre su estado alto y bajo
del pin C0.Por ejemplo mediante un osciloscopio. Si nocoloco esta
instruccin afecta en algo el funcionamiento del programa? No, ya
que solo es una manera para comprobar que los tiempos de
interrupcin son correctos. set_timer1(40535); // Init timer1 to get
Fm = 10 Hz. Tm = 0.1 sec Esta instruccin me permite definir el
tiempo de muestreo. El timer 1 del pic 16f690 (que es el que se ha
utilizado en este caso) tiene una resolucin de 16 bits es decir que
puede tomar 65535 valores posibles. Pero valores de qu? En este
caso de tiempo Cunto dura cada valor?
Dependedelvalordelosciladorautilizar.Cuandoyasehadefinidoelvalordel
oscilador (4MHZ, 8MHZ, etc.), se tiene que necesariamente dividir
este valor entre
4.Hechoesto,elresultadoeseltiempoqueduracadaunodelos65535posibles
valores del timer 1. NOTA ANTES DE SEGUIR: LA INSTRUCCINPOR DEFECTO
ES: Set_timer_1 (PRE_CARGA) Para este caso PRE_CARGA=40535 Ejemplo:
1.Utilizo un cristal de cuarzo de f=4MHZ 2.Lo divido entre 4 ,que
sera f_1=1MHZ 3.Convierto esta frecuencia en tiempo T=
_=
= 1 us Este es el valor de cada uno de los 65535 valores del
timer 1: 1 microsegundo Por lo que deducimos que el timer 1 puede
contar hasta: 65535x1 us=65535 us Eleccin de la PRE_CARGA
Supongamos que ya defin o determine el valor que quiero como tiempo
de muestreo Tm=0.1 us (para este caso). Aplico la siguiente
relacin: Tm=_ ( _) El PRE-ESCALADOR es un factor de divisin de
frecuencia. Para TIMER1 puede tomar valores de: 1, 2, 4 y 8, y para
TIMER2 valores de 1, 4 o 16.
Reemplazandotiempodemuestreo,frecuenciadeosciladoryescogiendoel
pre_escalador igual a 8, obtenemos: PRE_CARGA=40535 n_pls =
get_timer0(); // READ AND RESET ITMER0 El nmero de pulsos del
encoder se leenmediante el timer 0 del pic. Esta instruccin me dice
que el timer 0 va a contar el nmero del pulsos (flancos de una onda
cuadrada) del encoder y el valor obtenido se almacenara en la
variable n_pls. El timer 0 del pic (16f690), tiene una resolucin de
8 bits, por lo tanto 255 valores o cuentas como mximo.
set_timer0(0); Esta instruccin inicializa el timer 0 en cero, lo
que significa ceros pulsos contados por el timer. Cada vez que se
produce una interrupcin el timer registra en nmero de pulsos,
utilizalainformacinyluegoinicializamoseltimeracero,paracomenzarunanueva
cuenta, as sucesivamente. r_value = read_adc(); // read reference
volts Esta instruccin me indica que el valor obtenido del
potencimetro se almacenara en la variabler_value.read_adc ()
significa leo el valor del ADC. r_pls = (unsigned int8)(r_value/5);
El timer 0, habamos dicho que cuenta hasta una mximo de 255(hay que
tenerlo en cuenta, ya que es la razn de porque la divisin entre 5)
El valor digital mximo obtenido del potencimetro es 1024. Ahorayo
tendr que hacer la tarea que esos 1024 valores posibles del
potencimetropuedan entrar en 8 bits (que es la mxima resolucin del
timer 0), todo se hace con el objetivo de poder comparar el nmero
de pulsos (n_pls) ledos por el timer 0 y el valor ledo por el
potencimetro (r_value). As que divido el valor ledo por el
potencimetro entre 5, yasignoel resultado a la variable a r_pls.
e_pls =(signed long)r_pls - (signed long)n_pls; // error en nmero
de pulsos Aqu calculo el error que hay entre mi referencia (r_pls)
y los pulsos contados por el timer 0 (n_pls).
Lapalabraqueestaentreparntesisantesdecadavariable(Signedlong),mevaa
permitir convertirlas variables enteras de 8 bitsr_pls y n_pls
tomen el formato de variables con signo de 16 bits. Esto se hace
porque la variable e_pls tiene ese formato y tenemos que asegurar
que la resta de r_pls y n_pls den como resultado un valor de tipo
Signed long. Inew = Iold + Ki*e_pls/10; // implementar el termino
integral if(Inew > 400) // stop wind up Inew = 400; Toda esta
parte describe la accin integral del controlador: Inew = Iold +
Ki*e_pls/10;
Comovemoslanuevaaccinintegral(Inew)dependedelvaloranterior(Iold),dela
constante integral (Ki) y del error (e_pls).La divisin entre 10
forma parte del diseo del
controlador,asqueesposiblecambiarestevalorparaajustarelcontroladorsegn
convenga. La condicin: Por qu si Inew es mayor a 400 su valor ser
de Inew = 400? El ciclo de trabajo de la seal pwm o mejor dicho el
tiempo en el cual la seal esta en alto tiene como valor mximo
400(es el 100%).As que para asegurarnos, que en caso Inew alcance
valores mayores a este, le asignamos el valor mximo. If (Inew >
400) Inew = 400; Por qu 400 y no otro valor? Puede tomar otro
valor, pero para este caso ha sido configurado como valor mximo del
ciclo de trabajo (duty cicle) del pwm en 400.
Cmoseobtuvoestevalor?Severmsadelanteenlaconfiguracindelpwmdel
microcontrolador. uc = Kp * e_pls + Inew; // implementar
controlador PI Esta parte es la expresin completa del controlador,
es decir es la accin del controlador. Iold = Inew;
Cadavezqueseterminadeejecutaruc(accindecontrol),laaccinintegralcalculada
(Inew),pasaaserlaantiguaoanterioraccinintegral(Iold),estoesdebidoaquenuevamente
se tendr calcular una nueva accin integral. printf("# = %Lu UC =
%Ld \r\n",k,uc);
MepermitevisualizarelvalordeKydeUCpormediodelpuertoserial(enproteus
conecto un terminal virtual y podre observar peridicamente estos
valores)
if(uc < 0) // uc no puede ser negativo ni mayor de 400 uc =
0; if(uc > 400) uc = 400; Como haba visto anteriormente el ciclo
de trabajo del pwm no puede ser mayor de 400 y tampoco ser menor a
cero, con estas condiciones nos aseguramosque se cumpla. duty = uc;
//d= 0%equ a duty = 00, d = 100%is duty = 400 Al final la accin de
control (uc), se asigna como valor del ciclo de trabajo de la seal
pwm. Lo que quiere decir que uc modifica el tiempo en el cual la
seal pwm se mantiene en alto. set_pwm1_duty(duty);Por ultimo
mediante esta instruccin hacemos efectiva el cambio de la seal pwm
segn el valor de duty. Esta instruccin nos dice que establecemos el
valor del ciclo de trabajo de la seal pwm segn los valores que
adquiere duty.
printf(" Ref= %u N de P. Med. = %uError = %Ld Duty = %Lu
\n\r",r_pls, n_pls, e_pls, duty); Nuevamente con esta instruccin
podremos visualizar por medio del puerto serial los valores que
adquieren peridicamente las variables: r_pls, n_pls, e_pls, duty.
output_low(PIN_C0); k = k +1; Estn explicadas al comienzo. AHORA
PASAREMOS A EXPLICAR LA PARTE QUE CORRESPONDE A LA CONFIGURACION
DEL MICROCONTROLADOR void main() { CONFIGURACIONWhile (1) { } }
Esta es la funcin principal de todo programa hecho en pic. Todo
programa debe tener un void main (), es lo primero queejecuta el
microcontrolador al encenderse. El inicio y fin de esta funcin estn
dadas por las llaves ({}).
ElWhile(1){},esparacrearunbucleinfinito(queserepitacontinuamente),su
significadoesmientrasseaverdadero(1),quesigaejecutndoseloquesehaya
definido que haga el microcontrolador. CONFIGURACION DEL CONVERSOR
ANALOGICO-DIGITAL setup_adc_ports( sAN0|VSS_VDD ); Con esta
instruccin configuro el conversor analgico-digital del pic
(ADC).Como
unpicpuedetenervariosADCenvariospinesdelmicrocontrolador,conesta
instruccin le indico que voy a utilizar soloel ADC 0 (sAN0).
setup_adc(ADC_CLOCK_INTERNAL ); El ADC funciona con una seal de
reloj, la fuente o de donde proviene esta seal se indica mediante
esta instruccin:
Paraestecasoestamosindicamosquevamosutilizarlasealde reloj interna
del pic (ADC_CLOCK_INTERNAL). Tambin puede ser externa(de algn
circuito externo que genere una seal de reloj:ADC_CLOCK_EXTERNAL)
set_adc_channel( 0 ); Habilito el ADC 0 o mejor dicho el canal 0.
CONFIGURACION DEL TIMER 0
setup_timer_0(RTCC_EXT_L_TO_H|RTCC_DIV_2);
Conestainstruccinconfiguramoseltimer0.Eltimer0seutilizaenestecasopara
contar pulsos generados por el encoder (ondas cuadradas).Pero lo
que el realmente cuenta o detecta son los flancos de bajada o
subida de los pulsos. Entonces el pic detecta o bien el flanco de
subida o el flanco de bajada. Cmo le digo que flanco detecte? Esto
se hace con la instruccin: RTCC_EXT_L_TO_H.
Estainstruccinindicaqueeltimer0vaadetectarflancosexternos(EXT),quevan
desde alto a bajo (L_TO_H), es decir un flanco de bajada. La
instruccin RTCC_DIV_2, indica que cada 2 flancos se van a contar
como uno (DIV_2) set_timer0(0); Inicializo el timer 0 a cero
CONFIGURACION DEL TIMER 1 setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
T1_INTERNAL;indicaqueutilizaremoslasealderelojinternadelpic
(INTERNAL), la cual equivale a la frecuencia del oscilador dividido
entre 4. set_timer1(40535); // Fm = 10 Hz. Tm = 0.1 sec; Esta
explicado anteriormente.
CONFIGURACION DEL TIMER 2 Los registros del timer 2 se utilizan
para configurar el mdulo PWM.Asi que tendremos
quedeterminarlafrecuenciadelasealpwm,superiodoyelduty cicleociclode
trabajo de la seal(es decir el rango que puede tomar elduty cicle).
Para lo cual utilizaremos las siguientes expresiones: PRESCALER:
para TIMER2 valores de 1, 4 o 16. Tosc = 1/Fosc Dnde: Tosc periodo
de la oscilador utilizado, Foscfrecuencia del oscilador utilizado
setup_timer_2(T2_DIV_BY_1,99,1); La instruccin por defecto es:
setup_timer_2 (T2_DIV_BY_1, PR2, PRESCALER); Ahora lo que tengo que
hacer es solo reemplazarlos valores de PR2 y del PRESCALER
CONFIGURACION DEL MODULO CCP El pic contiene un mdulo llamado CCP
(comparador, captura y pwm).Por lo tanto puede trabajar a la vez
con solo una de esas funciones. As que: setup_ccp1(CCP_PWM); Indico
que el mdulo CCP, trabajara como PWM. set_pwm1_duty(200L);
Inicializo el ciclo de trabajo delpwm en la mitadde su valor mximo
(400), es decir 200.Lo que equivale a decir que el ciclo de trabajo
est al 50% de su valor. OTRAS CONFIGURACIONES
enable_interrupts(INT_TIMER1); enable_interrupts (GLOBAL); La
primera instruccin me permite habilitar la interrupcin del timer 1.
Conlasegundainstruccinhabilitolasinterrupcionesglobales (siempreque
sevayaautilizarcualquierinterrupcinsetienenecesariamentequeponer
esta instruccin. setup_oscillator(OSC_8MHZ); Esta instruccin ndica
que voy a utilizar el oscilador interno del pic, es decir que no
voy a utilizar ningn cristal u oscilador externo. Esto es posible
solo en algunos microcontroladores, en este caso el 16f690, si lo
permite. En caso se quiera utilizar un cristal, esta instruccin no
se coloca. // TODO: USER CODE!! Kp = 5; Ki = 5; Iold = 0; Inew = 0;
k = 1;De esta manera inicializamos las variables Kp, Ki, Iold,
Inew, K HASTAAQUESTODO