Hi all, I can not find any reference to the use of timer 2 in GCB. It does not seem to have support for the post scaler. And it does not seem to work correctly with all the prescaler values, anybody have any experience with this ? Regards, Ed.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Not documented but It looks like support is there in timer.h for tmr2 and tmr3. There are only three choices for timer2 prescale, at least for the data sheet I'm looking at. Have you tried something like InitTimer2 (16, 16)? Here is the init sub call from timer.h.
Sub InitTimer2 (In TMR2Pres, In TMR2Post)
…
…
Worst comes to worst, set it up manually using timer.h as a guide. Set individual register bits ON or Off (e.g. Set T2OUTPS3 On:Set T2OUTPS2 ON ….etc.). Toggle the timer2 on and off by setting and clearing the TMR2ON bit (e.g. Set TMR2ON ON). Then read the TMR2 register itself for the value Timer2Value = TMR2.
Kent
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Kent thanks, I have packed up my goodies for the day so I will have to do more testing tomorrow. Thanks for the pointer will take a look at it. I have been using a 12F683. I think I have found another problem in the chip data files for for all the 12F devices regarding interrupts. I do not know if this is contributing to my problem or not!
For GCB code:
InitTimer2 Osc, PS2_1 'Select timer 2 clock, prescale 1,4,16
T2CON = b'00000000' ‘Clear Timer 2
.asm file
;Start of the main program
banksel TRISIO
bcf TRISIO,0
bcf TRISIO,1
bcf TRISIO,2
movlw 1
banksel TMR2PRES
movwf TMR2PRES
clrf TMR2POST
call INITTIMER2
clrf T2CON
movlw 178
movwf TIME_DELAY
movwf TMR2
banksel PIE1
bsf PIE1,T2IE-------note name
from chip data file for 12F683
Timer2Overflow:T2IE,T2IF----- note name
From chip data file 16F88
Timer2Overflow:TMR2IE,TMR2IF
What you get when you modify the chip data for the 12F683 to match 16F88
.asm file
;Start of the main program
banksel TRISIO
bcf TRISIO,0
bcf TRISIO,1
bcf TRISIO,2
movlw 1
banksel TMR2PRES
movwf TMR2PRES
clrf TMR2POST
call INITTIMER2
clrf T2CON
movlw 178
movwf TIME_DELAY
movwf TMR2
banksel PIE1
bsf PIE1,TMR2IE---- it is now correct!
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Time_Delay = 255 - 100 + 23 'set to 20 us and compensate for interrupt service delays (+23)
TMR2 = Time_delay 'Set Time delay
On Interrupt Timer2Overflow call TimerCont ‘Send a pulse out on overflow
Main: ‘Turn on timer 2
set T2CON.TMR2ON = On
Goto Main
Sub TimerCont
set test_timer = on 'Measure 200 ns pulse width - OK
set test_timer = off ‘This minimizes extra delays in service routine
TMR2 = Time_delay 'Reset Time delay
Return
Here is what I found
11-02-09
InitTimer2 Osc, PS2_1/1 same as InitTimer2 Osc, PS2_1 = 49895 Hz
InitTimer2 Osc, PS2_4 and 16 does not work!
Changing Timer2Overflow:T2IE,T2IF to Timer2Overflow:TMR2IE,TMR2IF
Has no effect.
Direct setting of T2CON does not work right either!
T2CON = b'00000000' = 49895 Hz - OK
T2CON = b'00000001' = 14805 Hz – OK should be 12473 Hz
T2CON = b'00000011' = No operation!
T2CON = b'01000001' = Nop
T2CON = b'00100001' = Nop
T2CON = b'00001001' = Nop
Conclusion
It appears that GCB has some problems with timer 2.
There is also a problem with direct control of T2CON bits with the 12F683
What am I doing wrong here?
Kent have any more ideas?
Thanks Ed.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi Ed, that was a real head scratcher. For the most part, the problem seemed to be turning on the timer2 everytime in Main:. It definetely killed the pre and postscale action. There still may be more work to get it into the form you are looking for.
Kent
'A test program to check out TMR2
#chip 12f683,20
#define test_timer GPIO.1
dir GPIO.1 out
Time_Delay = 255 - 100 + 23 'set to 20 us and compensate for interrupt service delays (+23)
TMR2 = Time_delay 'Set Time delay
On Interrupt Timer2Overflow call TimerCont
count = 0
Set T2CKPS0 On 'Set prescale to 4, options 1,4, 16
SeT TOUTPS3 ON 'Set postscale to 8, options 1-16
set TMR2ON On
start:
NOP
goto start
Sub TimerCont
count = ! count
test_timer = count
TMR2 = Time_delay
end sub
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Kent, you are a genius! That solved the problem. Timer 2 is quite flexible with the pre and post scalers as well as the PR2 register.
I am trying to generate very precise pulse widths for calibrating test measurements. I have one working with timer 1. When I moved on to timer 2 is when I got bogged down.
Can you explain what this is supposed to do and how it works?
Sub TimerCont
count = ! count
test_timer = count
end sub
It looks like it is high except for one clock. I wanted a short + going pulse so I used
Sub TimerCont
set test_timer = on 'Measure 200 ns
set test_timer = off
TMR2 = Time_delay
Return
Thanks for your help as usual.
BTW, the latest release solved all my complaints. Great job Hugh!
Best regards Ed.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Genius, absolutely not: Sometimes motivated or determined then yes.
The referenced code was a bad attempt to toggle the output pin. It did not work as planned, but provided proof of pre/post scale operations. Not sure what you would call the waveform in the analog world, but it is ugly looking.
Did you work any more with the negative numbers and your PID? Was needing to revisit this for a buck converter voltage feedback loop.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Kent, I found an old file that was "tested" on 02-21-09. The issue of negative numbers require a reverse of subtration order to prevent negative numbers. Also one has to swap "old and "new" data. The code is not very readable. I would now use the else fucntion to make it clearer. I would like to be able to psot the code like your example. If I just post the code by a "copy" "paste" it look like crap on my screen.
Here it the crappy code:
'A PID controller with PWM output
'Tested 02-21-09
'Use at your own risk!
'Chip model
#chip 16F88, 8
#config INTRC_IO
'Set the pin directions
dir portA.0 in 'input feedback on pin #17 from rc filter
dir portB.0 out 'set pwm output on pin #6 filter with 10k and 10uF capacitor to simulate a 1 second plant
'Set parameters
Pg = 3 'set proportional gain
Ig = 1 'set integral gain-used to control steady stae error left by the proportional term
Dg = 1 'set dervitive gain- used to control overshoot
command = 127 'set command input - drive to this value
Iterm = command 'set integrator init set command to minimize errors
Ioutn = 0 'Set integrator init use 0 initally will update on first cycle
PWMon
for rampcmd = 0 to command 'Ramp input to command control systems do not like step inputs
HPWM 1, 10, rampcmd
wait 100 ms
if rampcmd = command then goto Ready
next
Ready:
resp = readad(an0) 'get new data
If resp > command then test=true 'Test input polarity
'Generate Pterm
If test = false then
errorn = command - resp
Pterm = errorn * Pg + command 'For resp<command
end if
if test = true then
errorn = command -(resp - command) 'For resp>command
Pterm = command - (command -errorn)*pg
end if
'Generate Iterm I*dt
if test = true then
Iterm = errorn*Ig + Ioutn 'For resp<command
end if
if test=false then
errorn = resp-command
Iterm = ioutn - errorn*Ig 'For resp>command
end if
'Generate Dterm D/dt
If test=false then
Dterm = (errorn-erroro)*Dg 'For resp<command
erroro = errorn 'set previous error
end if
If test=true then
errorn = resp-command 'For resp>command
Dterm = (erroro-errorn)*Dg
erroro = errorn 'set previous error
end if
output = Pterm + Iterm + Dterm 'generate output
Ioutn = Iterm 'set previuos int value
HPWM 1, 10, output 'output PWM
wait 1 ms 'set sample rate = dt
goto ready
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Thanks Ed, it came through fine from the monitor by email option. To make it work on the forum post, the 101/010 icon needs to be clicked from the toolbar,….then paste or write code in the bluish box.
When fooling with your PID code, and Santiago's negative number library, it was taking some pretty wild swings when resolving to steady state. Also, made a very brief, and unsuccessful try ,with Hugh's 'dim as Integer', but didn't really follow up. Will have another look, and post on a different thread if more help needed.
Kent
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Kent, tuning a PID can be difficult. Here is how I do it. Set Iterm and Dterm to zero. Then adjust the Pterm until you get an overshoot to a small step input. Then use the Dterm ti damp out the overshoot. You only need to use the Iterm if there is a large steady state error. The steady state error with Iterm = 0 is about 1/Pterm so if Pterm is >100 you have less than 1% error. I wil try your "101/010" trick
<pre><code> 'A PID controller with PWM output
'Tested 02-21-09
'Use at your own risk!
'Chip model
#chip 16F88, 8
#config INTRC_IO
'Set the pin directions
dir portA.0 in 'input feedback on pin #17 from rc filter
dir portB.0 out 'set pwm output on pin #6 filter with 10k and 10uF capacitor to simulate a 1 second plant
'Set parameters
Pg = 3 'set proportional gain
Ig = 1 'set integral gain-used to control steady stae error left by the proportional term
Dg = 1 'set dervitive gain- used to control overshoot
command = 127 'set command input - drive to this value
Iterm = command 'set integrator init set command to minimize errors
Ioutn = 0 'Set integrator init use 0 initally will update on first cycle
PWMon
for rampcmd = 0 to command 'Ramp input to command control systems do not like step inputs
HPWM 1, 10, rampcmd
wait 100 ms
if rampcmd = command then goto Ready
next
Ready:
resp = readad(an0) 'get new data
If resp > command then test=true 'Test input polarity
'Generate Pterm
If test = false then
errorn = command - resp
Pterm = errorn * Pg + command 'For resp<command
end if
if test = true then
errorn = command -(resp - command) 'For resp>command
Pterm = command - (command -errorn)*pg
end if
'Generate Iterm I*dt
if test = true then
Iterm = errorn*Ig + Ioutn 'For resp<command
end if
if test=false then
errorn = resp-command
Iterm = ioutn - errorn*Ig 'For resp>command
end if
'Generate Dterm D/dt
If test=false then
Dterm = (errorn-erroro)*Dg 'For resp<command
erroro = errorn 'set previous error
end if
If test=true then
errorn = resp-command 'For resp>command
Dterm = (erroro-errorn)*Dg
erroro = errorn 'set previous error
end if
output = Pterm + Iterm + Dterm 'generate output
Ioutn = Iterm 'set previuos int value
HPWM 1, 10, output 'output PWM
wait 1 ms 'set sample rate = dt
goto ready>
Kent is does not look as "pretty" as yours, but better. Let me know if you need more help on this . Ed.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Kent, I cleaned up the PID to make it "look better" Also corrected a small error. I still can not get the code box to work right. What is the secret?
See:
'A PID controller with PWM output
'Neg_signed 02-21-09
'Use at your own risk!
'Chip model
#chip 16F88, 8
#config INTRC_IO
'Set the pin directions
dir portA.0 In 'input feedback on pin #17 from rc filter
dir portB.0 Out 'set pwm output on pin #6 filter with 10k and 10uF capacitor to simulate a 1 second plant
'Set parameters
Pg = 3 'set proportional gain
Ig = 1 'set integral gain-used to control steady stae error left by the proportional term
Dg = 1 'set dervitive gain- used to control overshoot
command = 127 'setCommand input - drive to this value
Iterm =Command 'set integrator init setCommand to minimize errors
Iout_new = 0 'Set integrator init use 0 initally will update on first cycle
PWMon
for Rampcmd = 0 to Command 'Ramp input toCommand control systems do not like step inputs
HPWM 1, 10, Rampcmd
wait 100 ms
if Rampcmd = Command then goto Ready
next
Ready:
Response = readad(an0) 'get new data
If Response > Command then Neg_sign=true 'Neg_sign input polarity true is negative problem
If Neg_sign = true Then
error_new = Response -Command
Else
error_new = Command - Response
end if
'Generate Terms
If Neg_sign = False then
Pterm = error_new * Pg + Command 'Pterm For Response<command
Iterm = error_new*Ig + Iout_new 'Iterm For Response<command
Dterm = (error_new-error_old)*Dg 'DTerm For Response<command
Else
Pterm = Command - error_new*pg 'Pterm For Response>command
Iterm = Iout_new - error_new*Ig 'Iterm For Response>command
Dterm = (error_old-error_new)*Dg 'Dterm For Response>command
end if
error_old = error_new 'set previous error
Output = Pterm + Iterm + Dterm 'generate output
Iout_new = Iterm 'set previuos int value
HPWM 1, 10, Iutput 'output PWM
wait 1 ms 'set sample rate = dt
goto ready
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Ed, that's weird. Didn't see any of your code in the blue box using IE8 beta2. Using Firefox 3.53, the first line of the code is in a blue code box, then plain text, then back to blue code box for the last five lines. So maybe the browser has some effect, but haven't had any problems in posting from either browser.
The preview should show you exactly how the post is formatted. Be careful when using 'two' carriage returns, or a new paragraph, once inside the blue code box (because, the code tags will stop and normal format will resume). Best if everything goes in on one paste, or be cognizant of the restriction and start a new code box. So what I am saying is, writing code in the blue code box is terrible, pasting code in is alright.
Kent
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi all, I can not find any reference to the use of timer 2 in GCB. It does not seem to have support for the post scaler. And it does not seem to work correctly with all the prescaler values, anybody have any experience with this ? Regards, Ed.
Not documented but It looks like support is there in timer.h for tmr2 and tmr3. There are only three choices for timer2 prescale, at least for the data sheet I'm looking at. Have you tried something like InitTimer2 (16, 16)? Here is the init sub call from timer.h.
Sub InitTimer2 (In TMR2Pres, In TMR2Post)
…
…
Worst comes to worst, set it up manually using timer.h as a guide. Set individual register bits ON or Off (e.g. Set T2OUTPS3 On:Set T2OUTPS2 ON ….etc.). Toggle the timer2 on and off by setting and clearing the TMR2ON bit (e.g. Set TMR2ON ON). Then read the TMR2 register itself for the value Timer2Value = TMR2.
Kent
Kent thanks, I have packed up my goodies for the day so I will have to do more testing tomorrow. Thanks for the pointer will take a look at it. I have been using a 12F683. I think I have found another problem in the chip data files for for all the 12F devices regarding interrupts. I do not know if this is contributing to my problem or not!
For GCB code:
InitTimer2 Osc, PS2_1 'Select timer 2 clock, prescale 1,4,16
T2CON = b'00000000' ‘Clear Timer 2
.asm file
;Start of the main program
banksel TRISIO
bcf TRISIO,0
bcf TRISIO,1
bcf TRISIO,2
movlw 1
banksel TMR2PRES
movwf TMR2PRES
clrf TMR2POST
call INITTIMER2
clrf T2CON
movlw 178
movwf TIME_DELAY
movwf TMR2
banksel PIE1
bsf PIE1,T2IE-------note name
from chip data file for 12F683
Timer2Overflow:T2IE,T2IF----- note name
From chip data file 16F88
Timer2Overflow:TMR2IE,TMR2IF
What you get when you modify the chip data for the 12F683 to match 16F88
.asm file
;Start of the main program
banksel TRISIO
bcf TRISIO,0
bcf TRISIO,1
bcf TRISIO,2
movlw 1
banksel TMR2PRES
movwf TMR2PRES
clrf TMR2POST
call INITTIMER2
clrf T2CON
movlw 178
movwf TIME_DELAY
movwf TMR2
banksel PIE1
bsf PIE1,TMR2IE---- it is now correct!
Kent here is the code I am using. I want to set a pulse string out with a 20 us period using timer 2
'Chip model
#chip 12f683, 20
'Set the pin directions
Dir GPIO.1 Out 'test pulse pin 6
'Set initial parameters
#define Test_timer GPIO.1
'T2CON = b'00001001' can be used to select T2CON bits manually
InitTimer2 Osc, PS2_1,PS2_2 'Select timer 2 clock, prescale 1,4,16
dim Time_Delay as Byte
Time_Delay = 255 - 100 + 23 'set to 20 us and compensate for interrupt service delays (+23)
TMR2 = Time_delay 'Set Time delay
On Interrupt Timer2Overflow call TimerCont ‘Send a pulse out on overflow
Main: ‘Turn on timer 2
set T2CON.TMR2ON = On
Goto Main
Sub TimerCont
set test_timer = on 'Measure 200 ns pulse width - OK
set test_timer = off ‘This minimizes extra delays in service routine
TMR2 = Time_delay 'Reset Time delay
Return
Here is what I found
11-02-09
InitTimer2 Osc, PS2_1/1 same as InitTimer2 Osc, PS2_1 = 49895 Hz
InitTimer2 Osc, PS2_4 and 16 does not work!
Changing Timer2Overflow:T2IE,T2IF to Timer2Overflow:TMR2IE,TMR2IF
Has no effect.
InitTimer2 Osc, (1,1) produces “Timer2F675.txt (20): Error: Invalid variable name: (1”
InitTimer2 Osc, (PS2_1,PS2_1) “Timer2F675.txt (20): Error: Invalid variable name: (0”
InitTimer2 Osc, PS2_1,PS2_1 works =49895 Hz
InitTimer2 Osc, PS2_4,PS2_1 does not work! =49895 Hz
InitTimer2 Osc, PS2_1,PS2_2 does not work! =49895 Hz
.asm file for InitTimer2 Osc, PS2_1,PS2_2
movlw 1
banksel TMR2PRES
movwf TMR2PRES
clrf TMR2POST------- Is clearing not setting to 2
call INITTIMER2
Changing .asm file to
movlw 1
banksel TMR2PRES
movwf TMR2PRES
movlw 2
banksel TMR2POST
movwf TMR2POST
call INITTIMER2
Results in Nop!
Direct setting of T2CON does not work right either!
T2CON = b'00000000' = 49895 Hz - OK
T2CON = b'00000001' = 14805 Hz – OK should be 12473 Hz
T2CON = b'00000011' = No operation!
T2CON = b'01000001' = Nop
T2CON = b'00100001' = Nop
T2CON = b'00001001' = Nop
Conclusion
It appears that GCB has some problems with timer 2.
There is also a problem with direct control of T2CON bits with the 12F683
What am I doing wrong here?
Kent have any more ideas?
Thanks Ed.
Hi Ed, that was a real head scratcher. For the most part, the problem seemed to be turning on the timer2 everytime in Main:. It definetely killed the pre and postscale action. There still may be more work to get it into the form you are looking for.
Kent
'A test program to check out TMR2
#chip 12f683,20
#define test_timer GPIO.1
dir GPIO.1 out
Time_Delay = 255 - 100 + 23 'set to 20 us and compensate for interrupt service delays (+23)
TMR2 = Time_delay 'Set Time delay
On Interrupt Timer2Overflow call TimerCont
count = 0
Set T2CKPS0 On 'Set prescale to 4, options 1,4, 16
SeT TOUTPS3 ON 'Set postscale to 8, options 1-16
set TMR2ON On
start:
NOP
goto start
Sub TimerCont
count = ! count
test_timer = count
TMR2 = Time_delay
end sub
Kent thanks for the help, will try it tomorrow. Regards, Ed.
Kent, you are a genius! That solved the problem. Timer 2 is quite flexible with the pre and post scalers as well as the PR2 register.
I am trying to generate very precise pulse widths for calibrating test measurements. I have one working with timer 1. When I moved on to timer 2 is when I got bogged down.
Can you explain what this is supposed to do and how it works?
Sub TimerCont
count = ! count
test_timer = count
end sub
It looks like it is high except for one clock. I wanted a short + going pulse so I used
Sub TimerCont
set test_timer = on 'Measure 200 ns
set test_timer = off
TMR2 = Time_delay
Return
Thanks for your help as usual.
BTW, the latest release solved all my complaints. Great job Hugh!
Best regards Ed.
Genius, absolutely not: Sometimes motivated or determined then yes.
The referenced code was a bad attempt to toggle the output pin. It did not work as planned, but provided proof of pre/post scale operations. Not sure what you would call the waveform in the analog world, but it is ugly looking.
Did you work any more with the negative numbers and your PID? Was needing to revisit this for a buck converter voltage feedback loop.
Kent, I found an old file that was "tested" on 02-21-09. The issue of negative numbers require a reverse of subtration order to prevent negative numbers. Also one has to swap "old and "new" data. The code is not very readable. I would now use the else fucntion to make it clearer. I would like to be able to psot the code like your example. If I just post the code by a "copy" "paste" it look like crap on my screen.
Here it the crappy code:
'A PID controller with PWM output
'Tested 02-21-09
'Use at your own risk!
'Chip model
#chip 16F88, 8
#config INTRC_IO
'Set the pin directions
dir portA.0 in 'input feedback on pin #17 from rc filter
dir portB.0 out 'set pwm output on pin #6 filter with 10k and 10uF capacitor to simulate a 1 second plant
'Set parameters
Pg = 3 'set proportional gain
Ig = 1 'set integral gain-used to control steady stae error left by the proportional term
Dg = 1 'set dervitive gain- used to control overshoot
command = 127 'set command input - drive to this value
Iterm = command 'set integrator init set command to minimize errors
Ioutn = 0 'Set integrator init use 0 initally will update on first cycle
PWMon
for rampcmd = 0 to command 'Ramp input to command control systems do not like step inputs
HPWM 1, 10, rampcmd
wait 100 ms
if rampcmd = command then goto Ready
next
Ready:
resp = readad(an0) 'get new data
If resp > command then test=true 'Test input polarity
'Generate Pterm
If test = false then
errorn = command - resp
Pterm = errorn * Pg + command 'For resp<command
end if
if test = true then
errorn = command -(resp - command) 'For resp>command
Pterm = command - (command -errorn)*pg
end if
'Generate Iterm I*dt
if test = true then
Iterm = errorn*Ig + Ioutn 'For resp<command
end if
if test=false then
errorn = resp-command
Iterm = ioutn - errorn*Ig 'For resp>command
end if
'Generate Dterm D/dt
If test=false then
Dterm = (errorn-erroro)*Dg 'For resp<command
erroro = errorn 'set previous error
end if
If test=true then
errorn = resp-command 'For resp>command
Dterm = (erroro-errorn)*Dg
erroro = errorn 'set previous error
end if
output = Pterm + Iterm + Dterm 'generate output
Ioutn = Iterm 'set previuos int value
HPWM 1, 10, output 'output PWM
wait 1 ms 'set sample rate = dt
goto ready
Thanks Ed, it came through fine from the monitor by email option. To make it work on the forum post, the 101/010 icon needs to be clicked from the toolbar,….then paste or write code in the bluish box.
When fooling with your PID code, and Santiago's negative number library, it was taking some pretty wild swings when resolving to steady state. Also, made a very brief, and unsuccessful try ,with Hugh's 'dim as Integer', but didn't really follow up. Will have another look, and post on a different thread if more help needed.
Kent
Kent, tuning a PID can be difficult. Here is how I do it. Set Iterm and Dterm to zero. Then adjust the Pterm until you get an overshoot to a small step input. Then use the Dterm ti damp out the overshoot. You only need to use the Iterm if there is a large steady state error. The steady state error with Iterm = 0 is about 1/Pterm so if Pterm is >100 you have less than 1% error. I wil try your "101/010" trick
<pre><code> 'A PID controller with PWM output
'Tested 02-21-09
'Use at your own risk!
'Chip model
#chip 16F88, 8
#config INTRC_IO
'Set the pin directions
dir portA.0 in 'input feedback on pin #17 from rc filter
dir portB.0 out 'set pwm output on pin #6 filter with 10k and 10uF capacitor to simulate a 1 second plant
'Set parameters
Pg = 3 'set proportional gain
Ig = 1 'set integral gain-used to control steady stae error left by the proportional term
Dg = 1 'set dervitive gain- used to control overshoot
command = 127 'set command input - drive to this value
Iterm = command 'set integrator init set command to minimize errors
Ioutn = 0 'Set integrator init use 0 initally will update on first cycle
PWMon
for rampcmd = 0 to command 'Ramp input to command control systems do not like step inputs
HPWM 1, 10, rampcmd
wait 100 ms
if rampcmd = command then goto Ready
next
Ready:
resp = readad(an0) 'get new data
If resp > command then test=true 'Test input polarity
'Generate Pterm
If test = false then
errorn = command - resp
Pterm = errorn * Pg + command 'For resp<command
end if
if test = true then
errorn = command -(resp - command) 'For resp>command
Pterm = command - (command -errorn)*pg
end if
'Generate Iterm I*dt
if test = true then
Iterm = errorn*Ig + Ioutn 'For resp<command
end if
if test=false then
errorn = resp-command
Iterm = ioutn - errorn*Ig 'For resp>command
end if
'Generate Dterm D/dt
If test=false then
Dterm = (errorn-erroro)*Dg 'For resp<command
erroro = errorn 'set previous error
end if
If test=true then
errorn = resp-command 'For resp>command
Dterm = (erroro-errorn)*Dg
erroro = errorn 'set previous error
end if
output = Pterm + Iterm + Dterm 'generate output
Ioutn = Iterm 'set previuos int value
HPWM 1, 10, output 'output PWM
wait 1 ms 'set sample rate = dt
goto ready>
Kent is does not look as "pretty" as yours, but better. Let me know if you need more help on this . Ed.
Kent, I cleaned up the PID to make it "look better" Also corrected a small error. I still can not get the code box to work right. What is the secret?
See:
'A PID controller with PWM output
'Neg_signed 02-21-09
'Use at your own risk!
'Chip model
#chip 16F88, 8
#config INTRC_IO
'Set the pin directions
dir portA.0 In 'input feedback on pin #17 from rc filter
dir portB.0 Out 'set pwm output on pin #6 filter with 10k and 10uF capacitor to simulate a 1 second plant
'Set parameters
Pg = 3 'set proportional gain
Ig = 1 'set integral gain-used to control steady stae error left by the proportional term
Dg = 1 'set dervitive gain- used to control overshoot
command = 127 'setCommand input - drive to this value
Iterm =Command 'set integrator init setCommand to minimize errors
Iout_new = 0 'Set integrator init use 0 initally will update on first cycle
PWMon
for Rampcmd = 0 to Command 'Ramp input toCommand control systems do not like step inputs
HPWM 1, 10, Rampcmd
wait 100 ms
if Rampcmd = Command then goto Ready
next
Ready:
Response = readad(an0) 'get new data
If Response > Command then Neg_sign=true 'Neg_sign input polarity true is negative problem
If Neg_sign = true Then
error_new = Response -Command
Else
error_new = Command - Response
end if
'Generate Terms
If Neg_sign = False then
Pterm = error_new * Pg + Command 'Pterm For Response<command
Iterm = error_new*Ig + Iout_new 'Iterm For Response<command
Dterm = (error_new-error_old)*Dg 'DTerm For Response<command
Else
Pterm = Command - error_new*pg 'Pterm For Response>command
Iterm = Iout_new - error_new*Ig 'Iterm For Response>command
Dterm = (error_old-error_new)*Dg 'Dterm For Response>command
end if
error_old = error_new 'set previous error
Output = Pterm + Iterm + Dterm 'generate output
Iout_new = Iterm 'set previuos int value
HPWM 1, 10, Iutput 'output PWM
wait 1 ms 'set sample rate = dt
goto ready
Ed, that's weird. Didn't see any of your code in the blue box using IE8 beta2. Using Firefox 3.53, the first line of the code is in a blue code box, then plain text, then back to blue code box for the last five lines. So maybe the browser has some effect, but haven't had any problems in posting from either browser.
The preview should show you exactly how the post is formatted. Be careful when using 'two' carriage returns, or a new paragraph, once inside the blue code box (because, the code tags will stop and normal format will resume). Best if everything goes in on one paste, or be cognizant of the restriction and start a new code box. So what I am saying is, writing code in the blue code box is terrible, pasting code in is alright.
Kent