📄 cerebv2.c
字号:
/* Version Information:
This is Version 2, so it's for the new Cerebellum in which Btn1 is connected to B0
and the motor direction is now B1 instead of B0.
*/
/* Cereb.c is the main helper file for Cerebellum Programming.
See the API for details of how to use this stuff.
Much of original code is courtesy of Kwanjee Ng
Illah Nourbakhsh 2002
*/
/* things to add later -illah- :
1 Add CMUcam communication functionality in the form of a cmucam.c include.
*/
// API provided for cerebv2 //////////////////////
//
// call init_cerebellum() first in your main
// turn on an led with set_bit(PORTB, (GREEN|YELLOW)); turn off with clear_bit
// (PORTB & BTNn) is true if button n is depressed and false otherwise
//
// To output on a digital pin on portD, use set_bit(PORTD, n); where n is 0-7 (and clear_bit)
// These are the pins to generally use for digital output.
// But if you're using the Servoes, you will have to set the mask for the servoes
// appropriately so that you can preserve some of the pins for your own digital out
// purposes. Read the Servoes section below.
//
// call ser_init(SER_115200) to set up hardware serial port
// ser_tx(char c) sends a character out over the serial line
// ser_putstring(const char *text) writes a CONST string out the serial line
// ser_writechar(char c) writes out a character in decimal (good for debugging!)
// ser_rcv() is a blocking receive char call that returns a char
// note that if the input buffer has overflowed it dumps the buffer
// and continues waiting for a new character to return!
// ser_rcv_nb() is a nonblocking receive char call that returns a char
// or if there is nothing waiting, returns a 0. Does NOT check for
// frame error and overflow conditions!!!
// to save memory, if not using the serial port, don't call ser_init() and then
// don't use any of the above functions.
//
// to use servoes, begin by calling servo_init() in your main.
// then before expecting servoes to get used make servo_state=1;
// servoes use interrupts, so make sure you're starting interrupts:
// set_bit(INTCON, GIE);
// then command a servo by commanding servo_pos[n]=p. This will drive
// the servo on port Dn to position p. If p is zero, it deactivates the servo.
// to save memory, if not using servoes don't call servo_init(), do not
// put "set_bit(INTCON, GIE);" in your code, and also
// go to cereb.c and find void interrupt(void) and comment out the line that
// calls do_servo().
//
// to use some servoes and other portD lines for direct digital outputs, note
// the variable servo_mask. This defaults to 11111111b, which means all pins
// on portD are configured for servo output use. If you want to have D0,D1
// and D3 be servo pins and the rest controlled directly by you, using set_bit,
// then in Main() you would include the line: "servo_mask = 00000111b;"
// Then the servo controller would ignore pins D3 - D7 and you can set them
// as desired. For example you could set pin3 to be high: "set_bit(PORTD,3);"
// Note the tristate is still configuring ALL of portD for digital output (not input).
//
// to use the analog-digital input lines, first in main you must initialize
// with the command: ADCON1=0;
// to read analog input channel ch, use adc_read(ch) which returns a char
// ch should be 0-7 inclusive. numbering on cerebellum goes from A0 as channel
// zero, left-to-right and top-to-bottom, so that E2 is analog channel 7
//
// to use the motor PWM outputs, first call pwm_init() in your code.
// if both commands are in there, call ser_init() first. The motor command
// is pwm_setvel8(n,dir,duty) where n=0 or 1 (0 means Motor1 on Cerebellum
// and 1 means Motor2 on Cerebellum). dir is direction (0 or 1) and duty is
// a char, with 0 meaning off and 255 meaning full-on.
// To save memory, if you are not using motor PWM then comment out pwm_init() in
// main().
// //
////////////////////
//
// Below code is for implementing the hardware serial port //
char ser_tmp;
char SSPCON@0x14;
char PIR1@0x0c;
char PIE1@0x8c;
char TRISC@0x87;
char TRISD@0x88;
char TXSTA@0x98;
char RCSTA@0x18;
char SPBRG@0x99;
char RCREG@0x1a;
char TXREG@0x19;
char PORTD@0x08;
char myOption_Reg@0x81;
// call ser_init to initial hardware serial as: ser_init(SER_115200) //
void ser_init(char spbrg_val) {
SSPCON = 0;
PIR1 = 0; // this ensures also RCIF = TXIF = 0;
clear_bit(PIE1,5); //RCIE = 0;
clear_bit(PIE1,4); //TXIE = 0;
TRISC = TRISC | 0xC0; // setup TRISC for USART use
SPBRG = spbrg_val;
TXSTA = 000100100b; // txen, brgh
RCSTA = 010010000b; // spen and cren, the rest all off
ser_tmp = RCREG; // flush the rx buffer
ser_tmp = RCREG;
ser_tmp = RCREG;
}
// low-level call to send a character serially.
void ser_tx(char c) {
//wait for txif to go hi
while (!(PIR1 & 16)) ; //while (!TXIF);
//disable_interrupt(GIE); //?
TXREG = c;
//enable_interrupt(GIE); //?
}
void ser_putstring(const char* text) {
char i = 0;
while( text[i] != 0 )
ser_tx( text[i++] );
}
// writes a character out the serial port as a 3 digit number
void ser_writechar(char data) {
ser_tx( '0' + data/100 );
ser_tx( '0' + (data%100)/10 );
ser_tx( '0' + data%10 );
}
// this is a blocking receive //
char ser_rcv(void) {
while (1) {
if (RCSTA & 2) { // RCSTA bit 1 is overflow error
// overflow error
clear_bit(RCSTA,CREN); // CREN is RCStatus bit 4 //
ser_tmp = RCREG; // flush the rx buffer
ser_tmp = RCREG;
ser_tmp = RCREG;
set_bit(RCSTA,CREN); // CREN = 1;
}
else if (RCSTA & 4) { // RCSTA bit 2 is framing error
// framing error
ser_tmp = RCREG;
}
else if (PIR1 & 32) { // PIR1 bit 5 is RCIF
ser_tmp = RCREG;
return ser_tmp;
}
}
}
// nonblocking receive returns 0 for any error, including nothing to read
char ser_rcv_nb(void) {
if (PIR1 & 32) {
ser_tmp = RCREG;
return ser_tmp;
} else {
return 0;
}
}
// this next section is for servo control /////////////
char servo_state = 0;
char servo_curr = 0;
char servo_mask = 11111111b; // default that all of portD will be
// used for servo operations rather
// than direct digital output twiddling
char servo_switch = 1;
char servo_pos[8] = {0,0,0,0,0,0,0,0};
char _servo_free = 0;
void servo_init(void) {
OPTION_REG = 132; // bit 7 = 1 for portB pull-up and bit2 is for prescaler
// TMR0 @ 1:32, prescaler to timer0 (for servo control)
TRISD = 0; // port D as outputs for servo commands!
// in fact we already do this in init_cerebellum(); we do it again for //
// redundancy only here //
set_bit(INTCON, T0IE); //T0IE = 1 ie enable TMR0 overflow bit - T0IE is bit 5
delay_ms(1);
}
void do_servo(void) {
clear_bit(_servo_free,0); // the bit 0 of servo_free = 0;
if (servo_state == 1) {
// next intr in 0.6 ms
TMR0 = 153;
//TMR0 = 145;
if ((servo_pos[servo_curr] != 0) && ((servo_mask & servo_switch) != 0))
PORTD |= servo_switch; // output hi to specific servo pin out
servo_state = 2;
set_bit(_servo_free,0); // the bit servo_free = 1;
}
else if (servo_state == 2) {
TMR0 = 255 - servo_pos[servo_curr];
servo_state = 3;
}
else if (servo_state == 3) {
if ((servo_mask & servo_switch) != 0)
PORTD &= ~servo_switch; // output lo to this servo bit, but
// preserve all other digital hi's on port D
TMR0 = servo_pos[servo_curr];
servo_curr = servo_curr + 1;
servo_curr = servo_curr & 0x07; // increment to next servo, mod 8 //
servo_switch = servo_switch << 1;
if (servo_switch == 0) servo_switch = 1; // increment to next servo port bit //
servo_state = 1;
}
clear_bit(INTCON, 2); // clear T0IF = 0;
}
// end of servo control
// Analog-digital converter code //////////////////
char ADCON0@0x1f;
char ADRESH@0x1e;
char ADCON1@0x9f;
// this is called with a character 0 through 7 and returns
// an analog-digital reading
char adc_read(char ch) {
ADCON0 = (ch << 3) & 56; // shift ch to correct bit position
ADCON0 |= 0x81; // Tad = Fosc/32, ADC on.
delay_us(12); // wait for Tacq
ADCON0 |= 4; // acquire go!
while (ADCON0 & 4); // wait for AD to complete
delay_us(4); // wait for 2Tad
return ADRESH; // return captured value
}
// End of Analog-Digital conversion code //////////////
// PWM Motor code //////////////
//globals for motor PWM control//
char ccpcon;
char CCP1CON@0x17;
char CCP2CON@0x1d;
char TMR2@0x11;
char PR2@0x92;
char CCPR1L@0x15;
char CCPR2L@0x1b;
char T2CON@0x12;
char PORTC@0x07;
void pwm_init(void) {
// init hardware PWM
CCP1CON = 0; // CCP off
CCP2CON = 0;
TMR2 = 0;
PR2 = 0xff; // 0x3f: 78kHz, 0xff: 19.5kHz
CCPR1L = 0; // actually, I don't think the output is inverted! 0 = stop.
CCPR2L = 0;
TRISC = TRISC & 11011000b; // set DC motor pins to output
clear_bit(TRISB,1); // clear for motor direction output lines - chnged 0 to 1 illah 1/16/03
clear_bit(TRISA,4); // clear for motor direction output lines
ccpcon = 00111100b; // setup reg mask
CCP1CON = ccpcon; // CCP module to PWM mode
CCP2CON = ccpcon;
set_bit(T2CON,TMR2ON);
}
// parameters are motor number (0 or 1), direction (0 or 1) and speed //
// presumes that port c, bits 5 and 0 are being used for this.
void pwm_setvel8(char n, char d, char c) {
if (n == 0) {
if (d == 0) { //set_bit(PORTC,5);
set_bit(PORTC,5);
clear_bit(PORTB,1); // changed 0 to 1 illah 1/16/2003
}
else { //clear_bit(PORTC,5);
clear_bit(PORTC,5);
set_bit(PORTB,1); // changed 0 to 1 illah 1/16/2003
}
CCPR1L = c;
}
else if (n==1) {
if (d == 0) { //set_bit(PORTC,0);
set_bit(PORTC,0);
clear_bit(PORTA,4);
}
else { //clear_bit(PORTC,0);
clear_bit(PORTC,0);
set_bit(PORTA,4);
}
CCPR2L = c;
}
}
// END of PWM Motor Code ///////////////////////
// interrupt handler code
// variables for saving state during interrupt handling
int save_w;
int save_status;
//the actual interrupt handler function itself.
void interrupt(void) {
//store current state of processor
asm {
movwf _save_w
swapf STATUS,W
bcf STATUS,5
bcf STATUS,6
movwf _save_status
} // end asm
if (INTCON & 36) do_servo();
// in other words if (TOIE & TOIF) then do_servo() //
// restore processor state
asm {
swapf _save_status,W
movwf STATUS
swapf _save_w,F
swapf _save_w,W
} // end asm
}
// this initializes the buttons and leds on cerebellum //
// this also initializes PortD digital as outputs, for servoes and digital outs //
void init_cerebellum(void)
{
TRISB &= 207; // make port B pins 4 and 5 write-out able for LED's by setting
// tristate bits 4 and 5 to zero
PORTB &= 207; // turn off yellow and green LED's
TRISD = 0; // port D as outputs for Servo cmds and digital output settings
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -