/****************************************************************************
DC MOTOR SPEED CONTROL
PICUINO APPLICATION BOARD
https://sites.google.com/site/picuino
****************************************************************************/
#include <p18cxxx.h>
#include <stdio.h>
#define FOSC 20000000
#define BAUD 57600
#define DCMOT_TRIS_AN0 TRISAbits.TRISA0
#define DCMOT_TRIS_AN1 TRISAbits.TRISA1
#define DCMOT_TRIS_ENABLE TRISCbits.TRISC1
#define DCMOT_ENABLE LATCbits.LATC1
#define DCMOT_TRIS_IN1 TRISAbits.TRISA4
#define DCMOT_IN1 LATAbits.LATA4
#define DCMOT_TRIS_IN2 TRISAbits.TRISA5
#define DCMOT_IN2 LATAbits.LATA5
/****************************************************************************
DELAY FUNCTIONS
****************************************************************************/
void Delay_10us(unsigned int t) {
unsigned char i;
do {
i = 11;
while(--i);
} while(--t);
}
/****************************************************************************
ADC FUNCTIONS
****************************************************************************/
/*
Read Analog Input AN0 or AN1
*/
unsigned short adc_read(unsigned char channel) {
union {
struct {
unsigned char lob;
unsigned char hib;
};
unsigned short word;
} adc_val;
// Configure ADC
ADCON0 = 0b00000001 + (channel<<2); // ADC on
ADCON1 = 0b00001101; // Analog inputs = AN0, AN1
ADCON2 = 0b10010101; // TAD
// Make an ADC conversion
Delay_10us(1);
ADCON0bits.GO = 1; // ADC Hold and Start conversion
while (ADCON0bits.GO==1); // Conversion
// Configure ADC
ADCON0 = 0b00000000; // ADC off
ADCON1 = 0b00001111; // All pins to digital inputs
// Return ADC conversion
adc_val.lob = ADRESL;
adc_val.hib = ADRESH;
return adc_val.word;
}
/****************************************************************************
PWM FUNCTIONS
****************************************************************************/
/*
Initialize and configure PWM module
D = Duty cycle in range 0 .. 200
*/
void pwm1_init(unsigned char D) {
CCP1CON = 0b00001100;
T2CON = 0b00000100; // Timer2 on, prescaler = 1
PR2 = 200; // PWM Period = [(PR2) + 1] • TCY •(TMR2 Prescale Value)]
CCPR1L = D;
TRISCbits.TRISC2 = 0;
}
/****************************************************************************
RS232 FUNCTIONS
****************************************************************************/
/*
Initialize USART for RS232 comunications
*/
void rs232_init(void) {
BAUDCONbits.BRG16 = 0; // BRG16: 16-Bit Baud Rate Register Enable bit
SPBRGH = 0;
SPBRG = (FOSC/(16*BAUD))-1; // Real Baud = FOSC/(16*(SPBRG+1))
TXSTA = (char)
(0<<7) // CSRC: 1 = Syncronous Master mode
+ (0<<6) // TX9: 1 = Selects 9-bit transmission
+ (1<<5) // TXEN: 1 = Transmit enabled
+ (0<<4) // SYNC: 1 = Synchronous mode
+ (0<<3) // SENDB: 1 = Asynchronous mode: Send Sync Break on next transmission (cleared by hardware upon completion)
+ (1<<2) // BRGH: 1 = Asynchronous mode: High speed
+ (1<<1) // TRMT: 1 = TSR empty
+ (0<<0); // TX9D: Ninth bit of Transmit Data
RCSTA = (char)
(1<<7) // SPEN: 1 = Serial port enabled
+ (0<<6) // RX9: 1 = Selects 9-bit reception
+ (0<<5) // SREN: 1 = Enables single receive in Master Synchronous mode
+ (1<<4) // CREN: 1 = Enables Continuous Receive
+ (0<<3) // ADDEN: 1 = Enables address detection (RX9 = 1)
+ (0<<2) // FERR: 1 = Framing error
+ (0<<1) // OERR: 1 = Overrun error (can be cleared by clearing bit CREN)
+ (0<<0); // RX9D: Ninth bit of Received Data
TRISCbits.TRISC6 = 0; // Enable TX output
PIE1bits.TXIE = 0; // Disable RS232 interrupts
}
/****************************************************************************
MAIN PROGRAM
****************************************************************************/
void main(void) {
int Vref, Vmot, Err, Integ, Vo;
int _Vref, _Vmot, _Err, _Integ, _Vo;
char st1;
//*********************************
// Initialize
//*********************************
rs232_init();
CMCON = 0b00000111;
ADCON1 = 0b00001111;
DCMOT_IN1 = 0;
DCMOT_IN2 = 0;
DCMOT_ENABLE = 0;
DCMOT_TRIS_IN1 = 0;
DCMOT_TRIS_IN2 = 0;
DCMOT_TRIS_ENABLE = 0;
DCMOT_TRIS_AN0 = 1;
DCMOT_TRIS_AN1 = 1;
fprintf(_H_USART
, (const rom far
char *)"\r\nSystem OK.\r\n");
//*********************************
// DC MOTOR SPEED CONTROL
//*********************************
Integ = 0;
st1 = 0;
while(1) {
//*********************************
// PID Speed control
//*********************************
Vref = 50;
Err = Vref - Vmot;
Integ += Err;
if (Integ>30000) Integ = 30000;
if (Integ<-30000) Integ = -30000;
Vo = Vref/5 + Err/5 + Integ/16;
//*********************************
// Debug PID values
//*********************************
switch (st1++) {
case 1: _Vref = Vref;
_Vmot = Vmot;
_Err = Err;
_Integ = Integ;
_Vo = Vo;
break;
case 2: fprintf(_H_USART
, "Vm=%3d ", _Vmot
); break;
case 3: fprintf(_H_USART
, "Err=%3d ", _Err
); break;
case 4: fprintf(_H_USART
, "Intg=%5d ", _Integ
); break;
case 5: fprintf(_H_USART
, "Vo=%-3d", _Vo
); break;
st1 = 0;
break;
}
//*********************************
// PWM driver output
//*********************************
if (Vo>100) pwm1_init(100);
else if (Vo<0) pwm1_init(0);
else pwm1_init(Vo);
Delay_10us(800);
//*********************************
// BACK EMF SENSE
//*********************************
DCMOT_ENABLE = 0;
Delay_10us(80);
Vmot = adc_read(0);
DCMOT_ENABLE = 1;
}
}