Hallo zusammen, ich versuche seit einem Monat die Spannung die durch den Poti auf meinem mikrocontroller angezeigt wird zu reglen denn es zappelt an der letzte Ziffer um +/-1 und verusacht somit somit das Zappeln an der Position der Abgasegegendruckklappe (das Programm-das eigentlich wenn eine Spannung an mikrocontroller anliegt, interpretiert es als position und fährt/stellt die Abgasegegendruckklappe- habe ich nicht selber geschrieben aber ich muss das erweitern um dieses Zappeln wegzubekommen d.h die Spannung so filtern dass es nach dem Einstellen durch den Poti ein fester Wert zeigt und somit als feste position interpretiert wird)...Manchmal bleit eine gewisse Zeit die Spannung Konstant aber die Position ändert sich troztdem. Ich bin kein expert in C (code ist in C geschrieben) auch nicht in Sachen Mikrocontroller aber ich dachte mir dass ich nur einen Tiefpass reinprogrammieren soll und das wärs aber es tut dann gar nicht filtern das Zappelt genauso wie vorher...Ich bin auch jetzt sehr neugierig wie ich das Problem lösen kann und für Eure Antworte/Fragen sehr dankbar. PS: Beim Tiefpass() was soll ich da genauer beachten ? Grüße Robin
:
Verschoben durch User
Robin schrieb: > ich dachte mir dass ich nur einen Tiefpass reinprogrammieren soll > und das wärs aber es tut dann gar nicht filtern das Zappelt > genauso wie vorher... Wie sieht denn dein Code aus? Meinst du nur das Zappeln auf dem letzten Bit? > denn es zappelt an der letzte Ziffer um +/-1 und verusacht somit > somit das Zappeln an der Position der Abgasegegendruckklappe Ja, da ist dann wohl zuviel Verstärkung oder P-Anteil in der Regelstrecke. Denn auf das letzte Bit eines ADCs kann man sich nicht verlassen. Das steht aber im Datenblatt...
hier ist das Hauptprogramm //Pre-Processor Directives: //Provide pre-processor directives to include Device header files and //any application specific header files. Path locations to the Device //header files are set up within the MPLAB Project>>BuildOptions>>Project //dialog box. The path should point to X:\\MPLAB C30\support\h\, where //"X:" is the folder where the MPLAB C30 tools are installed. #include <p30fxxxx.h> //"p30fxxxx.h" is a generic header file for dsPIC30F //devices. This file will in turn select the actual //device header file, based on the device selected //by the MPLAB workspace/project. Using the p30fxxxx.h //file makes it easy to migrate a project from one //dsPIC device to another. #define _USE_MATH_DEFINES #include "math.h" #include "system.h" //"system.h" is a header file defined for this //application. //Macros for Configuration Fuse Registers: //Invoke macros to set up device configuration fuse registers. //The fuses will select the oscillator source, power-up timers, watch-dog //timers, BOR characteristics etc. The macros are defined within the device //header files. The configuration fuse registers reside in Flash memory. _FOSC(CSW_FSCM_OFF & XT_PLL8); //Run this project using an external crystal //routed via the PLL in 8x multiplier mode //For the 7.3728 MHz crystal we will derive a //throughput of 7.3728*10^6*8/4 = 14.7456 MIPS(Fcy) //,~68 nanoseconds instruction cycle time(Tcy). _FWDT(WDT_OFF); //Turn off the Watch-Dog Timer. _FBORPOR(MCLR_EN & PWRT_OFF); //Enable MCLR reset pin and turn off the //power-up timers. _FGS(CODE_PROT_OFF); //Disable Code Protection //Declaration to Link External Functions & Variables: //Declare functions being used that are defined outside this file, or //elsewhere in this MPLAB project. extern SPI_Init(void); extern UpdateDisplayBuffer(void); //extern WriteUART_to_RS232(void); extern WriteSPI_to_LCD(void); //extern UART_Init(void); extern ADC_Init(void); extern INTx_Init(void); extern Timer2_Init(void); extern CAN_Init( int pos); unsigned int position; //Variable für Stellerposition extern int Potentiometer; //Variable für ADC-Wert von dem Poti unsigned int potivorher=0; unsigned int geglaetteterwert=0; //Functions and Variables with Global Scope: //Declare functions in this file that have global scope. int main (void); //Code execution automatically reaches the main() function after //two events have occurred; //1. A Reset event triggered by hardware or software //2. The execution of the C Start up library functions, present // in the crt0.o file in the libpic30-coff.a library file unsigned int Tiefpass() { float i =0; float T=0.00001; int fg=2000000; float q,p,gefilterterwert; q=2*3.14*fg*T; p=exp(-q); for (i=0;i<=T;i+0.0000005) { gefilterterwert=q*Potentiometer + p*potivorher; potivorher=(int)gefilterterwert; } return potivorher; } int main (void) { ADPCFG = 0xFFFF; //After reset all port pins multiplexed //with the A/D converter are configred analog. //We will reconfigure them to be digital //by writing all 1's to the ADPCFG register. //Note: All dsPIC registers are memory mapped. //The address of ADPCFG and other registers //are defined in the device linker script //in your project. //Function Delay5ms() available in file, Delay.s Delay5ms(100); //Provide 500ms delay for the LCD to start-up. //Function SPI_Init() available in file, SPI_for_LCD.c SPI_Init(); //Initialize the SPI module to communicate with //the LCD. //Function UART_Init() available in file, UART.c //UART_Init(); //Initialize the UART module to communicate //with the COM port on the Host PC via an //RS232 cable and the DB9 connector. //Function ADC_Init() available in file, A_to_D_Converter.c ADC_Init(); //Initialize the A/D converter to convert //signals from the Temperature Sensor and the //Potentiometer. //Function INTx_IO_Init() available in file, INTx_IO_pins.c INTx_IO_Init(); //Initialize the External interrupt pins and //some I/O pins to accept input from the //switches, S5 and S6 and drive the LEDs, D3 //and D4. //Function Timer1_Init() & Timer2_Init() available in file, Timers.c //Timer1_Init(); //Initialize Timer1 to provide "blinking" time //for the LEDs. Timer2_Init(); //Initialize Timer2 and Timer3 as a 32-bit //Timer to be used for updating data sent to //the LCD(SPI) and COM(UART) interfaces. while (1) //Main Loop of Code Executes forever { //Spannung 0-5 V am RB3, Umschaltung vom Poti auf Messgalgensignal: Jumper H13 unsigned int Potentiometer = potivorher; CAN_Init(Potentiometer/4); //Aufruf der CAN-Funktion zum Senden des Signals ADC-Wert/4 als Übergabeparameter (ADC_Wert: 0x000-0xFFF) //Die Position muss kontinuierlich über CAN geschickt werden position=Potentiometer/4; //Variable Position für die Ausgabe am Display while (IFS0bits.T3IF == 1) //Wait until 32-bit Timer { //interrupt flag bit is set. IFS0bits.T3IF = 0; //Clear 32-bit timer interrupt //flag bit T2CONbits.TON = 0; //Stop 32-bit Timer //Function UpdateDisplayBuffer() available //in file, DisplayRoutines.c UpdateDisplayBuffer(); //Write the most recent //temperature and potentiometer //values into display buffer //Function WriteSPI_to_LCD() in file, SPI_for_LCD.c WriteSPI_to_LCD(); //Update the LCD via SPI T2CONbits.TON = 1; //Start 32-bit Timer again } } return 0; //Code never reaches here! }
Hi! Ein Tiefpass bringt hier wenig. Durch den Tiefpass wird das Zappeln langsamer, aber weg geht es nicht. Du kannst eine Hysterese einbauen. Das heißt du merkst dir den Wert des letzten Samples in einer Variablen und vergleichst ihn mit dem aktuellen gesampleten Wert. Wenn der Unterschied größer als 1 Bit ist, dann speicherst du den den aktuellen Wert in der Variable. Wenn der Unterschied kleiner ist, dann behälst du den Wert in der Variable bei. Ansonsten hilft die Formartierung mit [ c] und [/c] (ohne Leerzeichen) ungemein bei der Lesbarkeit des Codes. Gruß Stefan
Nachtrag: Wenn du die Hysterese verwendest, benötigst du keinen Tiefpass.
Nachnachtrag: Wie lange dauert eine Periode des Timers bzw. Wie oft wird der ADC ausgelesen und das Display aktualisiert?
Wooschder schrieb: > Nachnachtrag: > > Wie lange dauert eine Periode des Timers bzw. Wie oft wird der ADC > ausgelesen und das Display aktualisiert? //Functions: //ADC_Init() is used to configure A/D to scan and convert 2 input channels //per interrupt. The A/D is set up for a total sampling rate of 8KHz //or 4KHz per channel. The internal counter in the A/D is used to provide //Acquisition time delay. The input pins being scanned are AN2 and AN3. //AN2 and AN3 are connected to the Temperature Sensor and the Potentiometer //on the dsPICDEM2 board. void ADC_Init(void) { //ADCON1 Register //Set up A/D for Automatic Sampling, Auto-Convert //All other bits to their default state ADCON1bits.SSRC = 7; ADCON1bits.ASAM = 1; //ADCON2 Register //Set up A/D for interrupting after 2 samples get filled in the buffer //Also, enable Channel scanning //All other bits to their default state ADCON2bits.SMPI = 1; ADCON2bits.CSCNA = 1; //ADCON3 Register //Set up Acquisition time (Tacq) for 31 Tad periods //where, Tad = A/D conversion clock time. //Set up Tad period to be 20.5 Tcy (Tcy = instruction cycle time) //Given that each conversion takes 14*Tad (=Tconv) periods, //Total Sample Time = Acquisition Time + Conversion Time // = (31 + 14)*Tad = 45*Tad periods // = 45 * 20.5 * Tcy = 922.5*Tcy periods //At 7.3728 MIPS, Tcy = 135 ns = Instruction Cycle Time //So Tsamp = Tacq + Tconv = 45*Tad(in this example)= 125.1 microseconds //So Fsamp = Sampling Rate ~= 8 KHz //All other bits to their default state ADCON3bits.SAMC = 31; ADCON3bits.ADCS = 40; //ADCHS Register //When Channel scanning is enabled (ADCON2bits.CSCNA=1) //AND Alternate mux sampling is disabled (ADCON2bits.ALTS=0) //then ADCHS is a "don't care" ADCHS = 0x0000; //ADCSSL Register //Scan channels AN2, AN3 fas part of scanning sequence ADCSSL = 0x000C; //ADPCFG Register //Set up channels AN2, AN3 as analog inputs and leave rest as digital //Recall that we configured all A/D pins as digital when code execution //entered main() out of reset ADPCFGbits.PCFG2 = 0; ADPCFGbits.PCFG3 = 0; //Clear the A/D interrupt flag bit IFS0bits.ADIF = 0; //Set the A/D interrupt enable bit IEC0bits.ADIE = 1; //Turn on the A/D converter //This is typically done after configuring other registers ADCON1bits.ADON = 1; } //_ADCInterrupt() is the A/D interrupt service routine (ISR). //The routine must have global scope in order to be an ISR. //The ISR name is chosen from the device linker script. void __attribute__((_interrupt_)) _ADCInterrupt(void) { //Copy the A/D conversion results from ADCBUFn to variables- //"Potentiometer" and "TempSensor". //Since ADCON2bits.SMPI = 1, only the first two (i.e. SMPI+1) ADCBUFn //locations are used by the module to store conversion results Potentiometer = ADCBUF0; TempSensor = ADCBUF1; //Clear the A/D Interrupt flag bit or else the CPU will //keep vectoring back to the ISR IFS0bits.ADIF = 0; } meinst du das ?? es gibt auch noch die Funktion delay.s ;Symbol/Literal/Immediate Operand Definitions: ;".equ" directives are similar to "#define" pre-processor directives in C .equ NANOSEC125, 2 ;125ns approx = 2*TCY at 14.7 MIPS .equ MICROSEC, 8*NANOSEC125 ;8*125ns =1us .equ MILLISEC, 1000*MICROSEC ;1000*1us = 1000*8*125ns = 1ms ;Global Declarations for Functions and variables: .global _Delay5us .global _Delay5ms ;Code Sections: ;Code sections are named ".text" .section .text _Delay5us: ;Function Prototype for C: ; void Delay5us(int Count) ; Note: "_" prefixed to the function name is not used when calling the ; function from a C file. ; Function Execution Time when Count=1 is 5 microseconds at 14.74 MIPS ; push w1 ;Store w1 on to stack mov #MICROSEC, w1 ;w1 = MICROSEC dec w1, w1 ;w1 = w1 - 1 bra nz, $-2 ;If w1 != 0 then Branch to previous instruction dec w0, w0 ;else w0 = w0 - 1 bra nz, $-8 ;If w0 != 0 then Branch back 4 instructions pop w1 ;else restore w1 from stack return ;Return to calling routine _Delay5ms: ;Function Prototype for C: ; void Delay5ms(int Count) ; Note: "_" prefixed to the function name is not used when calling the ; function from a C file. ; Function Execution Time when Count=1 is 5 milliseconds at 14.74 MIPS push w1 ;Store w1 on to stack mov #MILLISEC, w1 ;w1 = MILLISEC dec w1, w1 ;w1 = w1 - 1 bra nz, $-2 ;If w1 != 0 then Branch to previous instruction dec w0, w0 ;else w0 = w0 - 1 bra nz, $-8 ;If w0 != 0 then Branch back 4 instructions pop w1 ;else restore w1 from stack return ;Return to calling routine .end ;End of File
Wooschder schrieb: > Nachtrag:Wenn du die Hysterese verwendest, benötigst du keinen Tiefpass. Danke ich werde dann die hysterese googlen... aber bei meinem TP unsigned int Tiefpass() { float i =0; float T=0.00001; int fg=2000000; float q,p,gefilterterwert; q=2*3.14*fg*T; p=exp(-q); while (i<=T) { gefilterterwert=q*Potentiometer + p*potivorher; potivorher=(int)gefilterterwert; i=i+0.0000005; } return potivorher; } Stimmt überhaupt dieser tp () ?? die filterordnung habe gar nicht berücksichtig und Werte von T und fg habe ich willkürlich angenommen...wollte wissen wie ich diese 3 Werte (filterordnung,fg,T) richtig bestimmen kann und ob man ein TP überhaupt so programmiert... Vielen Dank !!
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.