|
|
View previous topic :: View next topic |
Author |
Message |
jcerbaro
Joined: 23 Jun 2016 Posts: 2
|
RS 232 error |
Posted: Thu Jun 23, 2016 11:36 pm |
|
|
Hello! I have a problem when trying to communicate via RS232 with my PC.
I'm using PIC16F877A. It's a PID Speed Control of a DC motor.
I've already tested the RS232 with a simpler code, and it worked fine, but in my code it's not!
In this code, the variable "velocidade" is not coming out.
If I use the command "putc('x');", it works, but when i use "putc(velocidade);", it doesn't.
PLEASE, IGNORE THE PORTUGUESE COMENTS, the code is self explanatory for you guys.
my code is this:
Code: | #include <16F877A.h>
#include <string.h>
#include <stdlib.h>
#use delay(clock=12000000)
#fuses HS, PUT, NOWDT, NOBROWNOUT, NOLVP
#define TX PIN_C6
#define RX PIN_C7
#use rs232(baud=9600, xmit=TX, rcv=RX, bits=8, parity=N, ERRORS)
//************************//
//*** VARIÁVEIS DO PID ***//
//************************//
int kp, ki, kd; //Constantes do PID.
int p; //Parcela proporcional no sinal de controle.
int i; //Parcela integral no sinal de controle.
int i_anterior = 0; //Parcela integral no sinal de controle no instante anterior.
int d; //Parcela derivativa no sinal de controle.
//******************************//
//*** VARIÁVEIS DE USO GERAL ***//
//******************************//
unsigned int ready1 = 0; //Variável que é habilitada a cada x ms, para entrar na atualização do PID.
unsigned int ready2 = 0; //Variável que é habilitada a cada x ms, para enviar um dado pela serial.
unsigned int pulsos = 0; //Conta quantos pulsos o encoder envia.
int erro = 0; //Diferença entre a velocidade atual e o setpoint, em pulsos.
int erro_anterior = 0; //Diferença no momento anterior.
unsigned int duty_cicle = 127; //Tamanho do duty_cicle.
unsigned int velocidade = 0; //RPS medido. (pulsos / 32 * 20)
unsigned int setpoint = 0; //RPS recebida pela serial.
int diferenca = 0; //diferença de RPS entre recebida e medida.
int contador1 = 0; //ajuste do timer0.
int contador2 = 0; //ajuste da porta serial.
int j = 0; //Contador do recebimento.
//***************************//
//*** VARIÁVEIS PARA UART ***//
//***************************//
char uart_recebido[4]; //String recebida pela serial.
//***************************//
//*** INTERRUPÇÃO DA UART ***//
//***************************//
#int_rda
void uart_read(void)
{
//Interrupção toda a vez que tem algo pra ser lido. Lê 4 vezes e aí atribui para o destino.
uart_recebido[j] = getc();
j++;
if (j==4)
{
j=0;
setpoint = (int)uart_recebido[0];
kp = (int)uart_recebido[1];
ki = (int)uart_recebido[2];
kd = (int)uart_recebido[3];
}
}
//***********************************//
//*** INTERRUPÇÃO DO MODO CAPTURA ***//
//***********************************//
//Sim, do jeito que eu usei fica a mesma coisa que uma interrupção externa, mas funciona mesmo assim...
#int_ccp2
void encoder()
{
pulsos++; //Conta quantos pulsos dá.
}
//*****************************//
//*** INTERRUPÇÃO DO TIMER0 ***//
//*****************************//
#int_timer0
void habilitador(void)
{
//Calculado para setar "ready1" a cada 10ms para atualizar o PID.
contador1++;
if (contador1 == 15)
{
ready1 = 1;
contador2++;
contador1 = 0;
}
//A cada 5 atualizações, habilita "ready2" para enviar pela serial.
if (contador2 == 5)
{
ready2 = 1;
contador2 = 0;
}
set_timer0(131 - get_timer0());
}
//***********************************//
//*** FUNÇÃO DO SINAL DE CONTROLE ***//
//***********************************//
void PID (void)
{
velocidade = pulsos / 32 * 20;
diferenca = setpoint - velocidade;
erro = diferenca * 250 / 100; //muda de tipo RPS para tipo duty cicle. VERIFICAR!
//erro = setpoint - velocidade;
p = kp * erro;
i = ki * (i_anterior + erro);
d = kd * (erro - erro_anterior);
duty_cicle = p + i + d;
i_anterior = i;
pulsos = 0;
}
//*******************//
//*** FUNÇÃO MAIN ***//
//*******************//
void main(void)
{
//Timer0 controla o tempo de amostragem. Calculado para dar 50ms.
setup_timer_0(RTCC_INTERNAL | RTCC_DIV_16);
set_timer0(131);
//Timer1 para o modo de captura em CCP2.
setup_timer_1(T1_INTERNAL);
setup_ccp2(CCP_CAPTURE_RE);
//Timer2 para o PWM em CCP1.
setup_timer_2(T2_DIV_BY_4,255,1);
setup_ccp1(CCP_PWM);
set_pwm1_duty(duty_cicle);
enable_interrupts(GLOBAL);
enable_interrupts(INT_CCP2);
enable_interrupts(INT_TIMER0);
enable_interrupts(INT_RDA);
//Inicializa as constantes do PID, até receber outras da serial.
setpoint = 20;
kp = 10;
ki = 10;
kd = 0;
while(TRUE)
{
if (ready1 == 1)
{
PID();
set_pwm1_duty(duty_cicle);
ready1 = 0;
if (ready2 == 1)
{
putc(velocidade); //ESSA TRANQUEIRA NÃO FUNCIONA DE JEITO NENHUM!
ready2=0;
}
}
}
} |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Jun 23, 2016 11:50 pm |
|
|
Quote: | unsigned int pulsos = 0;
velocidade = pulsos / 32 * 20; |
In CCS for your PIC, an unsigned int is 8 bits. It can have a value
from 0 to 255. You are dividing it by 640. This will always give a
result of 0.
You should edit your program, and everywhere that you want an
unsigned 16-bit integer, you should change it to 'int16'. Example:
If pulsos is made into a 2-byte variable, then to be safe, before using it,
you should disable interrupts and copy it to another variable. Example:
Code: | int16 captured_pulsos;
disable_interrupts(GLOBAL);
captured_pulsos = pulsos;
enable_interrupts(GLOBAL);
velocidade = captured_pulsos / 32 * 20; |
In most places where you have 'int', you really want 'signed int16'.
Example:
Code: | signed int16 kp, ki, kd;
signed int16 p;
signed int16 i;
signed int16 i_anterior = 0;
signed int16 d; |
|
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|