|
|
View previous topic :: View next topic |
Author |
Message |
Andrew83
Joined: 16 Sep 2008 Posts: 51
|
Problem with IR transmitter project |
Posted: Mon Jan 12, 2009 11:45 am |
|
|
Hello 2 all !
I'm trying to design a IR transmitter using pic18f452 @ 10 Mhz and CCS C compiler version 4.057.
Unfortunately, the code doesn't work as it should and i don't know where the problem lies.
So....any input is more than welcomed.
I wish to say that i've researched the problem for over 1 week and the solution eludes me ...for the moment.
So...i get a character from the serial port, i convert it to binary form and then modulate the waveform.
Assuming i'm transmitting a command like : 00000010 (0x02) i aspect that the output should be under the form :
Code: |
___ ___ ___ ___ ___ ___ ______
| | | | | | | | | | | | | |
| | | | | | | | | | | | | |
----- ----- ----- ----- ----- ----- --------- -----
| | | | | | | | |
|bit 1=0|bit 2=0|bit 3=0|bit 4=0|bit 5=0|bit 6=0|bit 7=1|bit 8=0|
| |
As you can see:
- a logic bit "0" is represented as a portion of 0,842 ms "HIGH" and a portion of 0,842 ms "LOW"
- a logic bit "1" represented as a portion of 0,842 ms "LOW" and a portion of 0,842 ms "HIGH"
Here is the code of the application (i haven't used the PWM module for simplicity):
Code: |
#include <18F452.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=10000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
char i,c,d;
#INT_TIMER0
void timer0_isr( )
{
boolean led_on0,led_on1;
switch(d)
{
case '0':
if (led_on0)
{
set_timer0(131);
led_on0 = false;
output_low(pin_b1); //for debuging purposes only
}
else
{
set_timer0(131);
led_on0 = true ;
output_high(pin_b1); //for debuging purposes only
}
break;
case '1':
if (led_on1)
{
set_timer0(131);
led_on1 = false;
output_high(pin_b2); //for debuging purposes only
}
else
{
set_timer0(131);
led_on1 = true ;
output_low(pin_b2); //for debuging purposes only
}
break;
default: output_high(pin_b7);
}
}
//==================================
void main()
{
char c,i,d, buffer[9];
unsigned int16 timeout;
output_toggle(pin_b0);
setup_timer_0(RTCC_INTERNAL |RTCC_8_BIT | RTCC_DIV_16);
do {
while(!kbhit() && (++timeout< (5000)))
delay_us(10);
if(kbhit())
{
c=getc();
for(i = 0; i < 8; i++)
{
if(c & 0x80)
d='1';
else
d='0';
c <<= 1;
buffer[i]=d;
}
buffer[8]=0;
}
enable_interrupts(GLOBAL);
enable_interrupts(INT_TIMER0);
set_timer0(131);
} while(true);
}
|
Thank you very much !! |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Mon Jan 12, 2009 6:10 pm |
|
|
There are several problems in your code.
First of all, make reading to us easier by getting the indentation right. This will get you quicker and better responses.
Code: | while(!kbhit() && (++timeout< (5000)))
delay_us(10);
| Timeout is never initialised, so the first time you have an undefined timeout and for all the next loops the timeout will be much larger than you expected.
Why do you have this loop of 50ms here anyway?
Code: | #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) | at 9600 baud characters will be received at about 1 char per ms. With the delay of 50ms there is a good chance of the hardware UART receive buffer overflowing (it can only buffer up to 3 characters). At overflow the UART will top receiving until the error condition is reset.
Add the 'ERRORS' directive to the above RS232 setup so the CCS compiler will add code for resetting the error condition. Code: | #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, errors) |
The variable 'd' in the interrupt handler is not the same 'd' as used in main. One is global and the other local.
There are some more problems involved with the way you are trying to use the interrupt, for example the value of 'd' never changes after the first interrupt, so how do you want to generate a pulse train?
Why do you want to use interrupts? Your code would be much easier if you forget about interrupts and implement the delays using delay_us() instead. |
|
|
Andrew83
Joined: 16 Sep 2008 Posts: 51
|
|
Posted: Tue Jan 13, 2009 3:54 am |
|
|
Thank you ckielstra !
You were absolutely right about everything.
I've managed to obtain the desired output using the delay_us() function.
However, there is a small problem.
First of all, i have to mention that i don't have a oscilloscope at hand (i am a highschool student) so my means of verifying the correct operation are relatively small. However, i'm using a pic simulator from OSHON (version 2.55). The simulation results, show that when i set the value: delay_us(842), the actual duration is close to 800 uS, so i've loaded a value of 845 and got a duration of about 836 uS wich is close enough to 842 uS (i think).
So, knowing this, i've tryed to use interrupts in the hope that i could get as close to 842 uS as possible.
I'm sorry for the foolish code i posted last night ...it was late.
Today, i've modified the code in the following way (BUT IT STILL ISN'T WORKING THE WAY IT SHOULD) :
Code: |
#include <18F452.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=10000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
char buffer[9];
#INT_TIMER0
void timer0_isr( )
{
boolean led_on0, led_on1;
char n;
for(n=0; n<8 ;n++)
{
switch(buffer[n])
{
case '0':
if (led_on0 ) //Logic ZERO
{
set_timer0(128); //Logic ZERO
led_on0 = false; //Logic ZERO
//setup_ccp1(ccp_off); //Logic ZERO
output_low(pin_b1); //Logic ZERO
}
else
{
set_timer0(128); //Logic ZERO
led_on0 = true ; //Logic ZERO
//setup_ccp1(CCP_PWM); //Logic ZERO
output_high(pin_b1); //Logic ZERO
}
case '1':
if (led_on1) //Logic ONE
{
set_timer0(128); //Logic ONE
led_on1 = true ; //Logic ONE
//setup_ccp1(CCP_PWM); //Logic ONE
output_high(pin_b1); //Logic ONE
}
else
{
set_timer0(128); //Logic ONE
led_on1 = false; //Logic ONE
//setup_ccp1(ccp_off); //Logic ONE
output_low(pin_b1); //Logic ONE
}
}
}
}
//==================================
void main()
{
char c,d,i;
setup_timer_2(T2_DIV_BY_1, 65, 1);
set_pwm1_duty(32);
setup_timer_0(RTCC_INTERNAL |RTCC_8_BIT | RTCC_DIV_16);
while(1)
{
if(kbhit())
{
c=getc();
for(i = 0; i < 8; i++)
{
if(c & 0x80)
d='1';
else
d='0';
c <<= 1;
buffer[i]=d;
}
buffer[8]=0;
enable_interrupts(INT_TIMER0);
enable_interrupts(GLOBAL);
set_timer0(255);
output_toggle(pin_b0);
}
}
}
|
Please verify the following statements and correct me, where i'm wrong:
1. If a character is transmitted over serial, i get it and store it in "char c".
2. I convert the variable c, into binary form, and store the result into a array "buffer[9]" wich is declared as a global, because i have tu use it also in the interrupt.
3. As soon as the conversion is done, i have to go to the ISR. So..i eneble the interrupt and load the timer with a value of 255 to imediately go to the ISR routine.
4. In the ISR routine, i go through the buffer and compare each of it's elements with the character '0', respectively '1'.
5. I modulate the waveform accordingly.
Where is my mistake ?? Please help me to understand the correct way of doing these things ! |
|
|
|
|
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
|