![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
jjacob
Joined: 08 Mar 2008 Posts: 54 Location: PORTUGAL (PORTO)
|
PWM, Timer0, Timer2 in 12F615 |
Posted: Sat Jul 18, 2009 9:59 am |
|
|
Hello.
I'm using :
Compiler Version : 4.057
PIC12F615
5V power supply
Internal Oscillator ...
I need to count the frequency of the input signal... 0 ... 50Hz ... and make it in a 0 ... 5V signal.
I've tested this software in 18F452 and it worked ... but it's a big PIC ... so I want to put this working in a 12F615...
This the code :
Code: |
#include <12F615.H>
#fuses INTRC_IO,NOWDT,NOPROTECT,NOMCLR,NOBROWNOUT
#use delay(clock=4000000)
#define in PIN_A3
int sec, N1;
int16 pwm, count;
//http://www.ccsinfo.com/forum/viewtopic.php?p=118216
#int_RTCC
void RTCC_isr(void) {
sec++;
if(sec>=2){
// Instead of calculate pwm to 1023, i limit to 1000... for easier math...
// Max. freq. is 50Hz
// 0Hz - 0V. For 50Hz - 5V.
// pwm=(N*1000)/50, where N is the frequency value...
// As i sample every 2 seconds, freq=count/2;
pwm=((((count)/(int16)2)*(int16)1000)/((int16)50));
count=0;
sec=0;
N1=1;
}
}
// I do software 'debouncing', because the input of the pic, comes from a
// LM311 and sometimes is has some 'garbage' ... so i complete with software...
void wait_for_low() {
int count=0;
while(count<100 && !N1){ /* debouncing... */
if(!input(in)) count++;
delay_us(100);
}
}
void wait_for_high() {
int count=0;
while(count<100 && !N1){ /* debouncing... */
if(input(in)) count++;
delay_us(100);
}
}
// ************************************
// RTCC is the same as TIMER0 !!!!!
// ************************************
void main(){
setup_adc_ports(ADC_OFF);
delay_us(10); // A small delay is necessary
setup_timer_2(T2_DIV_BY_4, 255, 1);
setup_ccp1(CCP_PWM); // Configure CCP1 as a PWM
// I get an interrupt each 2 seconds ...
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_16);
enable_interrupts(INT_RTCC);
enable_interrupts(GLOBAL);
count=0;
sec=0;
N1=0;
set_pwm1_duty(512);
while(1){
wait_for_low();
wait_for_high();
count++;
if (N1){
set_pwm1_duty(pwm);
//printf("\n\r count = %Lu pwm = %Lu", count, pwm);
N1=0;
}
}
}
|
For test the 12F615, I made a simple software : ReadADC put in PWM.
It worked fine, if I varied the input voltage in the ADC the PWM changed in the same way.
With the above code, I made some debug, commenting lines and I always had the same PWM (50%) because of the line before the 'while(1)' in the end of my code.
When I uncomment the line :
Code: | enable_interrupts(GLOBAL); |
The PWM goes to zero and nothing change on the PWM output, even with a 50Hz input !!!
Any idea ?? PWM works with Timer2 ... my interrupts are with Timer0 ... any problem with this ? I'm using the internal oscillator. Is this a problem ?
Thank you for your attention
Jacob |
|
![](templates/subSilver/images/spacer.gif) |
jjacob
Joined: 08 Mar 2008 Posts: 54 Location: PORTUGAL (PORTO)
|
|
Posted: Sat Jul 18, 2009 12:35 pm |
|
|
Hi all
I found the problem ...
Timer0 in 18F452 is a 8/16 bit (i was using as a 16bits...).
Timer0 in 12F615 is a 8 bit !! So the migration was not direct !!!
I change the code and use timer1 to do the 2 seconds 'tick'... I think that the calculations are correct. I have an interrupt ... near every 2 seconds ...
To see that i use a 'led'
Still, i haven't understand why i have to put 'sec>=8' instead of 'sec>=4' for the 2 seconds pwm refresh value ??!!!
Here is the code :
Code: |
#include <12F615.H>
#fuses INTRC_IO,NOWDT,NOPROTECT,NOMCLR,NOBROWNOUT
#use delay(clock=4000000)
#define in PIN_A3
#define led PIN_A4
int sec, N1;
int16 pwm, count;
//http://www.ccsinfo.com/forum/viewtopic.php?p=118216
// Timer1 interrupt is called every 0.524288 segundos
// 'timer1' é de 4MHz/4 = 1MHz = 1us
// 1us*2^16*8 = 0.524288 seconds ???????? why 'sec>=8'
// With this math, it would be 'sec>=4' ???????
#int_timer1
void timer1_isr(void) {
sec++;
if(sec>=8){
// Instead of calculate pwm to 1023, i limit to 1000... for easier math...
// Max. freq. is 50Hz
// 0Hz - 0V. For 50Hz - 5V.
// pwm=(N*1000)/50, where N is the frequency value...
// As i sample every 2 seconds, freq=count/2;
pwm=((((count)/(int16)2)*(int16)1000)/((int16)50));
output_toggle(led);
//printf("count : %Lu pwm = %Lu\n\r", count, pwm);
count=0;
sec=0;
N1=1;
}
}
// I do software 'debouncing', because the input of the pic, comes from a
// LM311 and sometimes is has some 'garbage' ... so i complete with software...
void wait_for_low() {
int count=0;
while(count<100 && !N1){ /* debouncing... */
if(!input(in)) count++;
delay_us(100);
}
}
void wait_for_high() {
int count=0;
while(count<100 && !N1){ /* debouncing... */
if(input(in)) count++;
delay_us(100);
}
}
// ************************************
// RTCC is the same as TIMER0 !!!!!
// ************************************
void main(){
setup_adc_ports(ADC_OFF);
delay_us(10); // A small delay is necessary
setup_timer_2(T2_DIV_BY_4, 255, 1);
setup_ccp1(CCP_PWM); // Configure CCP1 as a PWM
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);
count=0;
sec=0;
N1=0;
set_pwm1_duty(512);
output_low(led);
while(1){
wait_for_low();
wait_for_high();
count++;
if (N1){
set_pwm1_duty(pwm);
//printf("\n\r count = %Lu pwm = %Lu", count, pwm);
N1=0;
}
}
}
|
Now i have a PWM refresh rate of about 2 seconds ...
But i would like to do the EXACT math ... i've looked into 12F615 datasheet 'TIMER1 BLOCK DIAGRAM' but cant' figure out if the clock source is FOsc or FOsc/4. For my code i would say that is FOsc ... but i can't understand ...
Can anyone help me ??
Thank you
Jacob |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Jul 18, 2009 3:21 pm |
|
|
Quote: |
setup_timer_1(T1_INTERNAL | T1_DIV_BY_8);
but can't figure out if the clock source is FOsc or FOsc/4.
|
The PIC data sheet says this:
Quote: |
REGISTER 6-1: T1CON: TIMER1 CONTROL REGISTER
bit 1 TMR1CS: Timer1 Clock Source Select bit
1 = External clock from pin RC0/T1OSO/T1CKI (on the rising edge)
0 = Internal clock (FOSC/4) |
You have configured the Timer for T1_INTERNAL, therefore the clock
is Fosc/4. |
|
![](templates/subSilver/images/spacer.gif) |
jjacob
Joined: 08 Mar 2008 Posts: 54 Location: PORTUGAL (PORTO)
|
|
Posted: Sat Jul 18, 2009 4:24 pm |
|
|
Thank you PCM programmer for your simple explanation
In the datasheet that i've download it is writen :
bit 1 TMR1CS: Timer1 Clock Source Select bit
1 = External clock from T1CKI pin (on the rising edge)
0 = Internal clock (FOSC/4) or system clock (FOSC)(3)
(3) is a note :
3: See T1ACS bit in CMCON1 register.
In CMCON1 :
bit 4 T1ACS: Timer1 Alternate Clock Select bit
1 = Timer 1 Clock Source is System Clock (FOSC)
0 = Timer 1 Clock Source is Instruction Clock (FOSC\4)
CCS is a 'high level' language, how can i know what is the state of bit 4 in T1ACS ?
Thank you for your attention
Jacob |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Jul 18, 2009 4:32 pm |
|
|
I'm not at my regular computer so I didn't have access to the 12F615
data sheet. I used the 16F877 data sheet.
To see what the compiler is loading into the Timer1 registers:
Go to the Project / Build Options menu in your IDE, and set the List file
format to Symbolic. Then re-compile and look at the .LST file. Find the
line for setup_timer_1(), and you'll see the register settings in ASM code. |
|
![](templates/subSilver/images/spacer.gif) |
jjacob
Joined: 08 Mar 2008 Posts: 54 Location: PORTUGAL (PORTO)
|
|
Posted: Sat Jul 18, 2009 5:10 pm |
|
|
No problem
Here is part of my .lst :
Code: |
.................... setup_ccp1(CCP_PWM); // Configure CCP1 as a PWM
00EA: BCF 05.2
00EB: BCF 03.5
00EC: BCF 05.2
00ED: MOVLW 0C
00EE: MOVWF 15
00EF: CLRF 16
.................... setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
00F0: MOVLW B5
00F1: MOVWF 10
.................... enable_interrupts(INT_TIMER1);
|
It's been a long long time that I don't program in ASM ... and really don't understand what is what
If you would be so kind and patient to explain me ... I would appreciate.
Thank you for you help
Jacob |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Jul 18, 2009 5:28 pm |
|
|
You didn't put it in Symbolic List file format. It's still in normal CCS format.
But, it doesn't matter. Here's the explanation:
Quote: | ...... setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
00F0: MOVLW B5
00F1: MOVWF 10 // T1CON |
It's moving 0xB5 into the T1CON register. Converting 0xB5 to binary
gives: 1011 0101
Look in the Timer1 section of the 12F615 data sheet. It has a section
that describes the functions controlled by each bit in the T1CON register.
Look the binary value above (Bit 7 is on the left, and bit 0 is on the right)
and see what the settings mean.
It's easier if you print that page in the data sheet, and write in the bit
values below the register diagram: 10110101
Then study the explanations below them. |
|
![](templates/subSilver/images/spacer.gif) |
jjacob
Joined: 08 Mar 2008 Posts: 54 Location: PORTUGAL (PORTO)
|
|
Posted: Sat Jul 18, 2009 5:46 pm |
|
|
OK ...
I have in my .lst :
This means that register '1C' (CMCON1 register) is cleared. So :
Code: |
bit 4 T1ACS: Timer1 Alternate Clock Select bit
1 = Timer 1 Clock Source is System Clock (FOSC)
0 = Timer 1 Clock Source is Instruction Clock (FOSC\4)
|
I have bit4 cleared, so, as you said, i have FOSC\4 for timer1 ...
UFFF ... it was 'hard' to understand ... if what i've said is write, i think that i've learned VERY MUCH with this post
Thank you very much ... but please tell me if i'm wrong ...
Jacob |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Jul 18, 2009 6:56 pm |
|
|
Yes, that's correct. It uses Fosc/4. |
|
![](templates/subSilver/images/spacer.gif) |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|