I’m considering building an electric scooter; considering it probably putting it lightly.. I have almost everything I need for it. Interested? Why type so much when you can just watch my proof of concept!
If you’re following along and want to use the same hardware (warning totally untested… ):
Controller found on the TAUTC Tindie Store
Search on eBay for “24VDC scooter motor” ..
..and pick up a MOSFET that’ll pull off a couple 20 amps and saturates at or below 5VDC.
…what am I talking about? Try google or read this.
To the important stuff, the code:
/*
* File: main.c
* Author: Charles M Douvier
* Contact at: http://iradan.com
*
* Created on March 27, 2014, 4:12 PM
*
* Target Device:
* 18F26K22 on TAUTIC Dev Board
*
* Project:
* Electric Scooter
*.. a real hack job, comment, delete garbage, etc.
*
* Version:
* 0.1
*
*/
#ifndef _XTAL_FREQ
#define _XTAL_FREQ 4000000 //4Mhz FRC internal osc
#define __delay_us(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000000.0)))
#define __delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))
#endif
#include
#include
#include
#include
//config bits
#pragma config FOSC=INTIO67, WDTEN=OFF, PWRTEN=OFF, CP0=OFF, CP1=OFF, BOREN=ON
#pragma config STVREN=ON, LVP=OFF, HFOFST=OFF, IESO=OFF, FCMEN=OFF
//WRT=OFF, FOSC=INTOSC, MCLRE=ON
#define _XTAL_FREQ 4000000 //defined for delay
//clean up on isle 2..
int an9_value; //value for a/d
char buf[10]; //buff for iota
long int fvar; //long for format math
long int tens; //left of decm
long int decm; //decimal places
int tempi; //to add leadign zeros..
int vtxdata; //volts int for TX
int itxdata;
volatile unsigned int uart_data; // use 'volatile' qualifer as this is changed in ISR
/*
*
*/
void interrupt ISR() {
if (PIR1bits.RCIF) // see if interrupt caused by incoming data
{
uart_data = RCREG; // read the incoming data
PIR1bits.RCIF = 0; // clear interrupt flag
}
}
void init_io(void) {
TRISAbits.TRISA0 = 0; // output
TRISAbits.TRISA1 = 0; // output
TRISAbits.TRISA2 = 0; // output
TRISAbits.TRISA3 = 0; // output
TRISAbits.TRISA4 = 0; // output
TRISAbits.TRISA5 = 0; // output
TRISAbits.TRISA6 = 0; // output
TRISAbits.TRISA7 = 0; // output
ANSELA = 0x00; // all port A pins are digital I/O
TRISBbits.TRISB3 = 1; // AN9
TRISBbits.TRISB4 = 0; // RB4 = nc
TRISBbits.TRISB5 = 1; // RB5 = nc
TRISBbits.TRISB6 = 0; // RB6 = nc
TRISBbits.TRISB7 = 0; // RB7 = nc
ANSELB = 0b00001000; //RB3, AN9
TRISCbits.TRISC0 = 0; // output
TRISCbits.TRISC1 = 0; // output
TRISCbits.TRISC2 = 0; // output
TRISCbits.TRISC3 = 0; // output
TRISCbits.TRISC4 = 0; // output
TRISCbits.TRISC5 = 0; // output
TRISCbits.TRISC6 = 1; // input
TRISCbits.TRISC7 = 1; // input
ANSELC = 0x00; // all port C pins are digital I/O
}
void pwm_init(){
// PSTR1CONbits.STR1A
//hackhackhackhack... TODO
// CCPR1L = 0x120;
CCPR1Lbits.CCPR1L = 0xFE;
PR2 = 0xFE;
CCPTMRS0bits.C1TSEL = 0; //CCP TMR2 Selection
CCP1CONbits.P1M = 0x00;
CCP1CONbits.DC1B = 0x00;
PWM1CONbits.P1RSEN = 0;
T2CONbits.T2CKPS = 1; //1:2 Prescale
T2CONbits.TMR2ON = 1; //timer 2 go
CCP1CON = 0x0C; //PWM (CCP)1 ON
}
void uart_xmit(unsigned int mydata_byte) {
while(!TXSTA1bits.TRMT); // make sure buffer full bit is high before transmitting
TXREG = mydata_byte; // transmit data
}
void serial_init(void)
{
//9600 8N1
// calculate values of SPBRGL and SPBRGH based on the desired baud rate
//
// For 8 bit Async mode with BRGH=0: Desired Baud rate = Fosc/64([SPBRGH:SPBRGL]+1)
// For 8 bit Async mode with BRGH=1: Desired Baud rate = Fosc/16([SPBRGH:SPBRGL]+1)
TXSTA1bits.BRGH=1; // select low speed Baud Rate (see baud rate calcs below)
TXSTA1bits.TX9=0; // select 8 data bits
TXSTA1bits.TXEN = 1; // enable transmit
RCSTA1bits.SPEN=1; // serial port is enabled
RCSTA1bits.RX9=0; // select 8 data bits
RCSTA1bits.CREN=1; // receive enabled
SPBRG1=25; // here is calculated value of SPBRGH and SPBRGL
SPBRGH1=0;
PIR1bits.RCIF=0; // make sure receive interrupt flag is clear
PIE1bits.RCIE=1; // enable UART Receive interrupt
INTCONbits.PEIE = 1; // Enable peripheral interrupt
INTCONbits.GIE = 1; // enable global interrupt
__delay_ms(50); // give time for voltage levels on board to settle
uart_xmit('R'); // transmit some data "restart" notification
}
int main(void) {
init_io();
serial_init();
LATCbits.LATC2 = 0;
pwm_init();
// set up oscillator control register, using internal OSC at 4MHz.
OSCCONbits.IRCF = 0x05; //set OSCCON IRCF bits to select OSC frequency 4MHz
OSCCONbits.SCS = 0x02; //set the SCS bits to select internal oscillator block
ADCON0 = 0b00100101; //select AN9 and enable
ADCON1 = 0b00000000; //speed Vref=AVdd, VssRef=AVss
ADCON2 = 0b00111011; //ledft justified, 20RAD, FRC
__delay_us(5);
//loop
while (1) {
PORTAbits.RA0 = 1; //blinky i'm alive.
__delay_ms(140);
PORTAbits.RA0 = 0;
__delay_ms(140);
GO = 1;
while (GO) continue; //wait for conversion
an9_value = ADRESH; //AN9 value
fvar = an9_value; //this is hacked off another project but works
fvar = fvar * 10749; //calibration
fvar = fvar / 256;
tens = fvar / 100;
//tens = tens % 10;
decm = fvar % 100;
vtxdata = fvar / 43; //because I'm lazy... I'll change this later.
uart_xmit(vtxdata);
CCPR1Lbits.CCPR1L = vtxdata;
}
return (EXIT_SUCCESS);
}