Patita - Petite jambe - little leg 16f877 pwm
Je recommand la suivant page http://msmvps.com/blogs/coad/archive/2005/03/23/SerialPort-_2800_RS_2D00_232-Serial-COM-Port_2900_-in-C_2300_-.NET.aspx pour la conexion c sharp a com port avec serialport1
http://opencv.willowgarage.com/wiki/
tambien revisar openglES 2 http://duriansoftware.com/joe/An-intro-to-modern-OpenGL.-Chapter-2.2:-Shaders.html
http://www.ozone3d.net/tutorials/opengl_vbo.php?lang=2
http://www.lighthouse3d.com/opengl/glsl/
http://www.3dshaders.com/home/
http://developer.amd.com/archive/gpu/rendermonkey/pages/default.aspx
Avec le prochain code je peux controle un servo avec interruption 21 Décembre 2010. Le source d'origen es ex_patg.c de ccs:
/////////////////////////////////////////////////////////////////////////
//// patita16f877a.c ////
//// ////
//// Céegep Gerald-Godin ////
//// 21 décembre 2010 ////
//// PIC 16f877a clack= 20MHz ////
//// ////
//// ////
//// Autor: Mauricio Emilio Gomez ////
//// Hardware: http://www.diveng.net/disprod.htm ////
//// ////
/////////////////////////////////////////////////////////////////////////
#if defined(__PCM__)
#include <16F877.h>
#include <stdlib.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
#elif defined(__PCH__)
#include <18F452.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#endif
#define NUM_OUTPUTS 3
int wave_period[NUM_OUTPUTS] = {50,50,50};
int16 lect0=0;
int16 lect1=0;
int16 lect2=0;
int32 suma=45;
// This interrupt is used to output the waveforms. The interrupt
// is automatically called ever 200us.
#INT_TIMER1
void wave_timer() {
long i;
set_timer1(0x7fff); // sets timer to interrupt in 200us
output_bit(PIN_C5,0);
output_bit(PIN_C4,0);
output_bit(PIN_C3,0);
for(i=0; i<lect0+suma;i++) // sets up next output for each pin
{
output_bit(PIN_C5,1);
}
output_bit(PIN_C5,0);
for(i=0; i<lect1+suma;i++) // sets up next output for each pin
{
output_bit(PIN_C4,1);
}
output_bit(PIN_C4,0);
for(i=0; i<lect2+suma;i++) // sets up next output for each pin
{
output_bit(PIN_C3,1);
}
output_bit(PIN_C3,0);
}
void main() {
setup_adc_ports(ALL_ANALOG);
setup_adc(ADC_CLOCK_INTERNAL); // Initialisation du conv A/N
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8); // setup interrupts
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);
output_bit(PIN_C5,0);
output_bit(PIN_C4,0);
output_bit(PIN_C3,0);
char value;
while(TRUE) // loop forever
{
set_adc_channel(2);
delay_us(40);
lect0=read_adc();
set_adc_channel(4);
delay_us(40);
lect1=read_adc();
set_adc_channel(6);
delay_us(40);
lect2=read_adc();
if (kbhit()) {
value=getc();
printf("entro %s\n\r",value);
}
printf("%Lu %Lu %Lu %s\n\r",lect0,lect1,lect2, value);
}
}
Historic develope, il ne function pasm mais ce un bon reference.
Historico de desarrollo, Esto no funciona pero es una buena referencia.
El objetivo es construir una patita de un robot hexapod desde el principio:
Primero utilizaremos como hardware un pic18f4550:
colocar los fusibles correctamente:
mi primer programa en 18f4550 utilizando el compilador ccs:
Nota importante: Estoy trabajando con un cristar de 20Mhz
#include <18F4550.h>
#use delay (clock=48000000)
#include <gg_lcd_2009.h>
#fuses hspll,nowdt,noprotect,nolvp,nodebug,usbdiv,pll5,cpudiv1,vregen
#use rs232(baud=9600, XMIT=PIN_C6, RCV=PIN_C7) // Initialisation du port RS232
#byte portD = 0xF83
#bit adfm = 0xFC1.7
void main(void)
{
output_d (0xff);
}
Segundo programita
#include <18F4550.h>
#use delay (clock=48000000)
#include <gg_lcd_2009.h>
#fuses hspll,nowdt,noprotect,nolvp,nodebug,usbdiv,pll5,cpudiv1,vregen
#use rs232(baud=9600, XMIT=PIN_C6, RCV=PIN_C7) // Initialisation du port RS232
#byte portD = 0xF83
#bit adfm = 0xFC1.7
void main(void)
{
setup_adc(ADC_CLOCK_INTERNAL); // Initialisation du conv A/N
setup_adc_ports(AN0_TO_AN3); // RP1,RP2,RP3 EN RÉFÉRENCE SUR 5V
adfm = 1;
while(1)
{
char lect;
set_adc_channel(0);
lect=read_adc();
//delay_ms(10);
output_d (lect);
}
}
Tercer programa:
Para comenzar a cuadrar los tiempos de los pwm cambio el programa de la siguente manera
void main(void)
{
char pwm1;
setup_adc(ADC_CLOCK_INTERNAL); // Initialisation du conv A/N
setup_adc_ports(AN0_TO_AN3); // RP1,RP2,RP3 EN RÉFÉRENCE SUR 5V
adfm = 1;
while(1)
{
char lect;
set_adc_channel(0);
lect=read_adc();
//delay_ms(10);
pwm1=0x00;
output_d (pwm1);
pwm1=0xff;
output_d (pwm1);
}
}
Asi tal cual cuando miro en el osciloscopio me da una medida de 5.5 cuadritos cada uno de 20 microsegundos que nos da un total de 110 microsegundos
pero necesitamos ciclos de 20 milisegundos.
Calculo de la ecuacion para un servomotor con un microcontrolador 18f4550
Con el siguiente programa logro los 20 milisegundos:
void main(void)
{
char pwm1;
setup_adc(ADC_CLOCK_INTERNAL); // Initialisation du conv A/N
setup_adc_ports(AN0_TO_AN3); // RP1,RP2,RP3 EN RÉFÉRENCE SUR 5V
adfm = 1;
int var;
int lect;
while(1)
{
set_adc_channel(0);
lect=read_adc();
pwm1=0x00;
var=200;
delay_us(var);
output_d (pwm1);
pwm1=0xff;
delay_us(var);
output_d (pwm1);
}
}
ahora tengo que aplicar la ecuacion para cambiar los tiempos utiles.
ciclo en alto:
(y2-y1)=m(x2-x1)
255-0=m(255-0)
m=-1
y=mx+b
y=-1*x+b
b=y+x
b=255
ciclo en bajo:
(y2-y1)=m(x2-x1)
0-255=m(0-255)
m=1
y=mx+b
y=mx+b
y=1*x+b
b=y-x
b=255
ciclo en bajo
y luego de todas las graficas el programa que realmente me funciono fue:
void main(void)
{
char pwm1;
setup_adc(ADC_CLOCK_INTERNAL); // Initialisation du conv A/N
setup_adc_ports(AN0_TO_AN3); // RP1,RP2,RP3 EN RÉFÉRENCE SUR 5V
adfm = 1;
int var;
float lect;
int lectprocesada=0.0;
int lectprocesada2=0.0;
while(1)
{
set_adc_channel(0);
lect=read_adc();
lectprocesada=(int)(-1)*lect+255;
lectprocesada2=(int)(1)*lect-255;
pwm1=0xff;
var=200;
delay_us(lectprocesada2);
output_d (pwm1);
pwm1=0x00;
delay_us(lectprocesada);
output_d (pwm1);
}
}
A estas alturas del cuento se me ocurrio cambiar la tecnica a contadores y banderas para poder manejar un mayor numero de servomotores y funciono, aqui dejo el codigo pero aun sin explicacion.
#include <18F4550.h>
#use delay (clock=48000000)
#include <gg_lcd_2009.h>
#fuses hspll,nowdt,noprotect,nolvp,nodebug,usbdiv,pll5,cpudiv1,vregen
#use rs232(baud=9600, XMIT=PIN_C6, RCV=PIN_C7) // Initialisation du port RS232
#byte portD = 0xF83
#bit adfm = 0xFC1.7
void main(void)
{
// char pwm1;
setup_adc(ADC_CLOCK_INTERNAL); // Initialisation du conv A/N
setup_adc_ports(AN0_TO_AN3); // RP1,RP2,RP3 EN RÉFÉRENCE SUR 5V
adfm = 1;
//int var;
int lect=0;
int contadorglobal=0;
//int lectprocesada=0.0;
//int lectprocesada2=0.0;
int banderapwm1=1;
set_adc_channel(0);
while(1)
{
if (contadorglobal<=5)
{
banderapwm1=1;
}
if (contadorglobal>lect)
{
banderapwm1=0;
}
if (contadorglobal==120)
{
contadorglobal=0;
}
if (banderapwm1==1)
{
output_d(0xff);
}
if (banderapwm1==0)
{
output_d(0x00);
}
contadorglobal++;
set_adc_channel(0);
lect=read_adc();
}
}
Con el anterior codigo puedo manejar cuantos motores como quiera porque son banderas, sin embargo hay que ver como se comportan varios if. :(
copio el ultimo codigo que aun no funciona solo por documentacion de este dia de trabajo 27 noviembre 2010
#include <18F4550.h>
#use delay (clock=20000000)
//#include <gg_lcd_2009.h>
#fuses hspll,nowdt,noprotect,nolvp,nodebug,usbdiv,pll5,cpudiv1,vregen
//#use rs232(baud=9600, XMIT=PIN_C6, RCV=PIN_C7) // Initialisation du port RS232
//#use rs232 (baud = 9600, xmit = pin_c6, rcv = pin_c7) // doit etre apres #include et #use delay
//#use rs232(baud=9600,xmit=PIN_C6, rcv=PIN_C7,ERRORS) // Preprocessor directive that includes RS232 libraries
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
#byte portD = 0xF83
#bit adfm = 0xFC1.7
void main(void)
{
// set_tris_c
// char pwm1;
// setup_adc(ADC_CLOCK_INTERNAL); // Initialisation du conv A/N
// setup_adc_ports(AN0_TO_AN3); // RP1,RP2,RP3 EN RÉFÉRENCE SUR 5V
// adfm = 1;
//int var;
int lect1=0;
int lect2=0;
int lect3=0;
int lect4=0;
int lect5=0;
int lect6=0;
int lect7=0;
int lect8=0;
int lect9=0;
int lect10=0;
int lect11=0;
int lect12=0;
int lect13=0;
int lect14=0;
int lect15=0;
int lect16=0;
int lect17=0;
int lect18=0;
int contadorglobal=0;
//int lectprocesada=0.0;
//int lectprocesada2=0.0;
int banderapwm1=1;
int banderapwm2=1;
int banderapwm3=1;
int banderapwm4=1;
int banderapwm5=1;
int banderapwm6=1;
int banderapwm7=1;
int banderapwm8=1;
int banderapwm9=1;
int banderapwm10=1;
int banderapwm11=1;
int banderapwm12=1;
int banderapwm13=1;
int banderapwm14=1;
int banderapwm15=1;
int banderapwm16=1;
int banderapwm17=1;
int banderapwm18=1;
int banderapwm1B=1;
int banderapwm2B=1;
int banderapwm3B=1;
int banderapwm4B=1;
int banderapwm5B=1;
int banderapwm6B=1;
int banderapwm7B=1;
int banderapwm8B=1;
int banderapwm9B=1;
int banderapwm10B=1;
int banderapwm11B=1;
int banderapwm12B=1;
int banderapwm13B=1;
int banderapwm14B=1;
int banderapwm15B=1;
int banderapwm16B=1;
int banderapwm17B=1;
int banderapwm18B=1;
char choix=0;
int sortie=0x00;
set_adc_channel(0);
//puts("T"); // Affichage du menu
//printf("bonjourd");
//choix=getc(); // Attendre le choix de l'usager
while(1)
{
// Affichage du menu
printf("%d",1); // On utilise printf pour garder le curseur sur la même ligne
// choix=getc(); // Attendre le choix de l'usager
// printf("voila %s",choix);
//lect1=read_adc();
// lect1=12;
if (contadorglobal<=2)
{
banderapwm1=1;
banderapwm2=1;
banderapwm3=1;
banderapwm4=1;
banderapwm5=1;
banderapwm6=1;
banderapwm7=1;
banderapwm8=1;
banderapwm9=1;
banderapwm10=1;
banderapwm11=1;
banderapwm12=1;
banderapwm13=1;
banderapwm14=1;
banderapwm15=1;
banderapwm16=1;
banderapwm17=1;
banderapwm18=1;
banderapwm1B=1;
banderapwm2B=1;
banderapwm3B=1;
banderapwm4B=1;
banderapwm5B=1;
banderapwm6B=1;
banderapwm7B=1;
banderapwm8B=1;
banderapwm9B=1;
banderapwm10B=1;
banderapwm11B=1;
banderapwm12B=1;
banderapwm13B=1;
banderapwm14B=1;
banderapwm15B=1;
banderapwm16B=1;
banderapwm17B=1;
banderapwm18B=1;
}
if (contadorglobal>lect1)
{
banderapwm1=0;
}
/* if (contadorglobal>lect2&&banderapwm2B==1)
{
banderapwm2=0;
sortie=sortie^0x02;
banderapwm2B=0;
}*/
if (contadorglobal>lect3)
{
banderapwm3=0;
}
if (contadorglobal>lect4)
{
banderapwm4=0;
}
if (contadorglobal>lect5)
{
banderapwm5=0;
}
if (contadorglobal>lect6)
{
banderapwm6=0;
}
if (contadorglobal>lect7)
{
banderapwm7=0;
}
if (contadorglobal>lect8)
{
banderapwm8=0;
}
if (contadorglobal>lect9)
{
banderapwm9=0;
}
if (contadorglobal>lect10)
{
banderapwm10=0;
}
if (contadorglobal>lect11)
{
banderapwm11=0;
}
if (contadorglobal>lect12)
{
banderapwm12=0;
}
if (contadorglobal>lect13)
{
banderapwm13=0;
}
if (contadorglobal>lect15)
{
banderapwm15=0;
}
if (contadorglobal>lect16)
{
banderapwm16=0;
}
if (contadorglobal>lect17)
{
banderapwm17=0;
}
if (contadorglobal>lect18)
{
banderapwm18=0;
}
if (contadorglobal==100)
{
contadorglobal=0;
}
/* if (banderapwm1==0&&banderapwm1B==1) {sortie=0x01^sortie;banderapwm1B=0;}
if (banderapwm2==0&&banderapwm2B==1) {sortie=0x02^sortie;banderapwm2B=0;}
output_d(sortie);*/
if (banderapwm1==1) {output_d(0xff);}
if (banderapwm1==0) {output_d(0x00);}
contadorglobal++;
//set_adc_channel(0);
//lect1=read_adc();
lect1=30;
// output_d(0xff);
// output_d(0x00);
}
}
voila, ici la dernier version du logiciel, 3 servo controle par 3 ADC:
/**********************************************************************
// NOM DU PROGRAMME
// Programme Prototype des controle des moteurs et des capteurs de présence
//
// AUTEUR:
// Estefan Apablaza-Arancibia - Mauricio Gomez
//
// DATE DE CRÉATION: 15 février 2011
//
//
**********************************************************************/
//#include <p33Fxxxx.h>
#include "p33FJ128GP802.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include<outcompare.h>
#include<timer.h>
#ifndef __DELAY_H
#define FOSC 48000000LL // clock-frequecy in Hz with suffix LL (64-bit-long), eg. 32000000LL for 32MHz
#define FCY (FOSC/2) // MCU is running at FCY MIPS
#define delay_us(x) __delay32(((x*FCY)/1000000L)) // delays x us
#define delay_ms(x) __delay32(((x*FCY)/1000L)) // delays x ms
#define __DELAY_H 1
#include <libpic30.h>
#endif
#if defined (__dsPIC33F__)
// set chip configuration bits
_FGS(GSS_OFF & GWRP_OFF);
_FOSCSEL(FNOSC_FRCPLL & IESO_OFF);
_FOSC(FCKSM_CSDCMD & OSCIOFNC_OFF & POSCMD_NONE); // this sets I/O on OSC2 pin
_FWDT(FWDTEN_OFF);
#endif
//#define _TRISD3 TRISDbits.TRISD3
unsigned int temp_count;
/* Allocation memoire des buffers et drivers */
void Delay( unsigned int delay_count )
{
temp_count = delay_count +1;
asm volatile("outer: dec _temp_count");
asm volatile("cp0 _temp_count");
asm volatile("bra z, done");
asm volatile("do #3200, inner" );
asm volatile("nop");
asm volatile("inner: nop");
asm volatile("bra outer");
asm volatile("done:");
}
int read_adc1=2500;
int read_adc2=2500;
int read_adc3=2500;
int Canal=1;
int suma1=1400;
int suma2=1400;
int suma3=1400;
void Init_ADC( int amask )
{
AD1PCFGL = amask;//select channel
//bit 10 AD12B: 10-Bit or 12-Bit Operation Mode bit
//1 = 12-bit, 1-channel ADC operation
//0 = 10-bit, 4-channel ADC operation
//bit 7-5 SSRC<2:0>: Sample Clock Source Select bits
//111 = Internal counter ends sampling and starts conversion (auto-convert)
//110 = Reserved
//101 = Reserved
//100 = GP timer (Timer5 for ADC1) compare ends sampling and starts conversion
//011 = Reserved
//010 = GP timer (Timer3 for ADC1) compare ends sampling and starts conversion
//001 = Active transition on INT0 pin ends sampling and starts conversion
//000 = Clearing sample bit ends sampling and starts conversion
AD1CON1 = 0b0000010011100000; // automatic conversion start after sampling
//AD1CON1 = 0b0000010000000000; // automatic conversion start after sampling
AD1CSSL = 0b11111111; // scanning required
//bit 10 CSCNA: Scan Input Selections for CH0+ during Sample A bit
//1 = Scan inputs
//0 = Do not scan inputs
//bit 9-8 CHPS<1:0>: Selects Channels Utilized bits
//When AD12B = 1, CHPS<1:0> is: U-0, Unimplemented, Read as ‘0’
//1x = Converts CH0, CH1, CH2 and CH3
//01 = Converts CH0 and CH1
//00 = Converts CH0
AD1CON2 = 0b0000000000000000;
AD1CON3 = 0b0001111100000010; // Tsamp = 32 x Tad; Tad=125ns
AD1CON1bits.ADON = 1; // turn on the ADC
}
int readADC( int ch)
{
Delay(1);
AD1CHS0 = ch; // 1. select analog input channel
AD1CON1bits.SAMP = 1; // 2. start sampling
Delay(1);
while (!AD1CON1bits.DONE); // 5. wait for the conversion to complete
return ADC1BUF0; // 6. read the conversion result
} // readADC
int writeSPI1( int data)
{
SPI1BUF = data; // write to buffer for TX
while( !SPI1STATbits.SPIRBF); // wait for transfer to complete
return SPI1BUF; // read the received value
}//writeSPI2
void _ISR __attribute__((__no_auto_psv__)) _T2Interrupt(void) {
TMR2 = 0;
int i;
int j;
int k;
int ch_sel;
char mystring[12]={' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
PORTBbits.RB9=0; //pour le pwm
for(i=0; i<=(read_adc1+suma1);i++) // sets up next output for each pin
{
PORTBbits.RB9=1;//pour le pwm
}
PORTBbits.RB9=0;//pour le pwm
Delay(1);
PORTBbits.RB8=0; //pour le pwm
for(j=0; j<=(read_adc2+suma2);j++) // sets up next output for each pin
{
PORTBbits.RB8=1;//pour le pwm
}
PORTBbits.RB8=0;//pour le pwm
Delay(1);
PORTBbits.RB7=1; //pour le pwm
for(k=0; k<=(read_adc3+suma3);k++) // sets up next output for each pin
{
PORTBbits.RB7=1;//pour le pwm
}
PORTBbits.RB7=0;//pour le pwm
Delay(1);
//T2IF: Timer2 Interrupt Flag Status bit //1 = Interrupt request has occurred
//0 = Interrupt request has not occurred
IFS0bits.T2IF = 0;
ch_sel=0b00000001;
Init_ADC(ch_sel);
read_adc1=readADC(ch_sel);
ch_sel=0b00000100;
Init_ADC(ch_sel);
read_adc2=readADC(ch_sel);
ch_sel=0b00000101;
Init_ADC(ch_sel);
read_adc3=readADC(ch_sel);
read_adc3=4095-read_adc3;
sprintf(mystring,"<%i>",read_adc3);
PORTBbits.RB15=0;//pour le SPI enable
writeSPI1( mystring[1]);
writeSPI1( mystring[2]);
writeSPI1( mystring[3]);
writeSPI1( mystring[4]);
for(k=0; k<=500;k++) // sets up next output for each pin
{
}
PORTBbits.RB15=1;
}
#define SPI_MASTER 0x0120
#define SPI_ENABLE 0x8000
volatile unsigned char adc_lcd_update;
int main (void)
{
I2C1CONbits.I2CEN=0;
TRISBbits.TRISB15=0;//0 salida
TRISBbits.TRISB14=0;//salida SPI CLK hacia display
TRISBbits.TRISB13=0;//salida SPI hacia display
TRISBbits.TRISB12=1;//1 entrada SPI
TRISBbits.TRISB6=0;
TRISBbits.TRISB7=0;
TRISBbits.TRISB8=0;
TRISBbits.TRISB9=0;
TRISBbits.TRISB2=1;//entrada A/D conversor
TRISBbits.TRISB3=1;//entrada A/D conversor
TRISAbits.TRISA0=1;//entrada A/D conversor
TRISAbits.TRISA1=1;//entrada A/D conversor
//SPI ramappable pic selection
_RP13R=0b00111;//pin 13 RPn tied to SPI1 Data Output
RPINR20bits.SDI1R=0xc; //SPI1 Data Input SDI1 RPINR20 SDI1R<4:0> pin 23 rp12
_RP14R=0b01000; //SCK1 01000 RPn tied to SPI1 Clock Output
SPI1CON1 = SPI_MASTER;
SPI1STAT = SPI_ENABLE; // enable the peripheral
SPI1CON1bits.PPRE=0b11;
PORTBbits.RB15=1;
/* Initialisation du timer 2 */
T2CONbits.TON= 1;// active timer1
T2CONbits.TCKPS = 3;// bit 5-4 TCKPS<1:0>: Timer1 Input Clock Prescale Select bits
//11 = 1:256
T2CONbits.TON= 1;// active timer1
T2CONbits.TCS= 0; // Slectionne la source
PR2 =1825;// période
// Clear counter
T2CONbits.TON= 1;// active timer2
TMR2 = 0;
IPC1bits.T2IP = 2;// Interrupt priority 2 (med-low)
IEC0bits.T2IE = 1;// active interrupt
/*******************************************/
//Init_ADC();
PORTBbits.RB15=0;
writeSPI1( 0x76);
Delay(1);
PORTBbits.RB15=1;
Delay(2);
PORTBbits.RB15=0;
writeSPI1( 0x7a);
writeSPI1( 0x00);
Delay(1);
PORTBbits.RB15=1;
Delay(2);
while(1)
{
}
}//main