View previous topic :: View next topic |
Author |
Message |
ericchee
Joined: 03 Dec 2008 Posts: 12
|
#int rda and set_pwm1_duty() |
Posted: Wed Dec 03, 2008 2:09 am |
|
|
I have used the ex_sisr.c codes and I have no problem to send string from pc to PIC. I have no problem displaying the string back on the pc by sending back from PIC to pc. What I actually want is to send a three digit number but since I am sending data through the serial port, it needs to be in a string. These 3 digit numbers needed to be inputted into pwm so I have changed the string to int. But it's not working. Any help will be appreciated!
Code: |
#include <16F877A.h>
#include <string.h>
#use delay(clock=20000000)
#fuses hs, noprotect, nowdt,nolvp
#byte PORTB=6
#byte PORTC=7
#define door PIN_B2
#define window PIN_B1
#define bumper PIN_B3
#define INTS_PER_SECOND 76 // (20000000/(4*256*256))
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#define ChannelA PIN_A0
#define ChannelB PIN_A1
#define DIRECTION PIN_D3
#define REDLED PIN_B4
#define GREENLED PIN_B6
#define YELLOWLED PIN_B3
#include <input.c>
//#define STRING_SIZE 51
#include <stdlib.h>
#define STRING_SIZE 40
#define BUFFER_SIZE 32
BYTE buffer[BUFFER_SIZE];
BYTE next_in = 0;
BYTE next_out = 0;
#define bkbhit (next_in!=next_out)
byte bgetc()
{
byte c;
while(!bkbhit) ;
c=buffer[next_out];
next_out=(next_out+1) % BUFFER_SIZE;
return(c);
}
#int_rda
void serial_received()
{
int asdf;
char input_str[STRING_SIZE];
int t;
buffer[next_in]=getc();
t=next_in;
next_in=(next_in+1) % BUFFER_SIZE;
if(next_in==next_out)
next_in=t; // Buffer full !!
strcpy (input_str , bgetc()); // i type 100 from pc and copy to input_str
printf("\n\rYou typed: %s \n\r\n\r", input_str); //100 display at pc
output_high(REDLED);
asdf = atoi(input_str); // convert string to int
set_pwm1_duty(asdf);
output_high(YELLOWLED);
}
void main()
{
BYTE time;
BYTE time1;
BYTE abc;
BYTE string;
output_low(GREENLED);
output_low(REDLED);
output_low(YELLOWLED);
setup_timer_2(T2_DIV_BY_4, 127, 1);
setup_ccp1(CCP_PWM);
set_pwm1_duty(128);
setup_counters( RTCC_EXT_H_TO_L, RTCC_DIV_1 );
set_rtcc(0);
setup_timer_1 ( T1_EXTERNAL | T1_DIV_BY_1 );
set_timer1(0);
enable_interrupts(INT_RTCC);
enable_interrupts(INT_TIMER1);
EXT_INT_EDGE(L_TO_H);
ENABLE_INTERRUPTS(INT_EXT);
ENABLE_INTERRUPTS(INT_RDA);
enable_interrupts(GLOBAL);
set_tris_b(0b00110001);
portb=0;
}
|
|
|
|
ericchee
Joined: 03 Dec 2008 Posts: 12
|
|
Posted: Wed Dec 03, 2008 2:34 am |
|
|
I just read 'receive ASCII string and convert to int' by coderchick. I think my problem exactly the same with hers. Also I have tried get_string() but still not working. Actually I don't quite understand how get_string works. Can anyone explain its operation? tq |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Dec 03, 2008 2:09 pm |
|
|
Do you need to use interrupts ? I suggest that you write a version of
your program that doesn't use interrupts.
In a while() loop, in main(), call the get_string() function. Use the atoi()
or atol() function to convert the input number into a integer. Then use
the integer to set the pwm duty cycle. This is easy to do, without using
interrupts.
Remove all unnecessary code from your program. Remove the counter
and timer1, and LED stuff. Remove the #int_rda code. Remove the
enabling of interrupts. You should be able to make a really stripped down
program that uses get_string() and pwm. |
|
|
ericchee
Joined: 03 Dec 2008 Posts: 12
|
|
Posted: Sun Dec 28, 2008 4:16 am |
|
|
counter, timer, #int_rda and led is for other function in my program. my computer is sending string to PIC. is that possible just using your suggested method to read the string without using interrupt? |
|
|
dyeatman
Joined: 06 Sep 2003 Posts: 1934 Location: Norman, OK
|
|
Posted: Sun Dec 28, 2008 7:57 am |
|
|
Much of your code is missing so we do not know what you are doing. You
don't even show the main program while(1) loop.
One thing is for sure. It definitely will not work with you trying to do all that
"stuff" inside the ISR. Get the character, put it in the buffer and get out as
quickly as possible. Use BGETC() to process the input buffer from the main
while(1) loop. It's been said numerous times in this forum that an
interrupt routine MUST be as short and fast as possible.
As PCM said earlier, use the interrupt only if you must. Since the character
input will be slow you may be better off testing KBHIT() in the main loop and
getting the character when it is available iin the UART buffer. An interrupt is
likely going to interfere with any time critical processes you have going on.
You are enabling interrupts that have no matching ISR routine and also
doing port setups AFTER enabling the interrupts. Both of these are
an invitation for disaster. I can only assume you have the ISRs
somewhere. Enabling interrupts should always be the LAST thing you
do before entering the main loop. Otherwise it may jump straight to
an interrupt before finishng the setup. |
|
|
ericchee
Joined: 03 Dec 2008 Posts: 12
|
|
Posted: Fri Jan 02, 2009 3:24 am |
|
|
Okay. I have my things reorganize but still not working.
what i am trying to do here is to read data from two timers and send the data to pc. pc will proceses the data and will send back response to PIC. The data from pc which is in a form of string will be used to set the pwm.
dyeatman, i do not understand by "enabling interrupts that have no matching ISR routine". i do not understand how the program to read the input by disabling the int_rda. anyway i will give it a try and i'll tell you the result
Code: |
#include <16F877A.h>
#include <string.h>
#use delay(clock=20000000)
#fuses hs, noprotect, nowdt,nolvp
#byte PORTB=6
#byte PORTC=7
#define door PIN_B2
#define window PIN_B1
#define bumper PIN_B3
#define INTS_PER_SECOND 76 // (20000000/(4*256*256))
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#define ChannelA PIN_A0
#define ChannelB PIN_A1
#define DIRECTION PIN_D3
#define REDLED PIN_B4
#define GREENLED PIN_B6
#define YELLOWLED PIN_B3
#include <input.c>
#include <stdlib.h>
#define STRING_SIZE 40
#define BUFFER_SIZE 32
BYTE buffer[BUFFER_SIZE];
BYTE next_in = 0;
BYTE next_out = 0;
#define bkbhit (next_in!=next_out)
byte bgetc()
{
byte c;
while(!bkbhit) ;
c=buffer[next_out];
next_out=(next_out+1) % BUFFER_SIZE;
return(c);
}
#int_rda
void serial_received()
{
int t;
buffer[next_in]=getc();
t=next_in;
next_in=(next_in+1) % BUFFER_SIZE;
if(next_in==next_out)
next_in=t; // Buffer full !!
}
#int_ext
void interrupt()
{
BYTE time3;
set_tris_b(0b00000001);
output_high(bumper);
time3 = get_timer0();
time3 += -1;
set_timer0(time3);
//DISABLE_INTERRUPTS(INT_EXT);
}
#int_rtcc // This function is called every time
void clock_isr()
{ // the RTCC (timer0) overflows (255->0).
BYTE seconds; // A running seconds counter
BYTE int_count; // Number of interrupts left before a second has elapsed
// For this program this is apx 76 times
if(--int_count==0) { // per second.
++seconds;
int_count=INTS_PER_SECOND;
}
}
void main()
{
BYTE abc;
BYTE string;
int PwM;
char input_str[STRING_SIZE];
set_tris_b(0b00110001);
portb=0;
setup_timer_2(T2_DIV_BY_4, 127, 1);
setup_ccp1(CCP_PWM);
setup_counters( RTCC_EXT_H_TO_L, RTCC_DIV_1 );
set_rtcc(0);
setup_timer_1 ( T1_EXTERNAL | T1_DIV_BY_1 );
set_timer1(0);
enable_interrupts(INT_RTCC);
enable_interrupts(INT_TIMER1);
EXT_INT_EDGE(L_TO_H);
ENABLE_INTERRUPTS(INT_EXT);
ENABLE_INTERRUPTS(INT_RDA);
enable_interrupts(GLOBAL);
do
{
printf("%2x",get_rtcc()); //send data to computer
printf("%2x\n\r",get_timer1()); //send data to computer
while(bkbhit)
{
PwM==atoi(bgetc());
set_pwm1_duty(PwM);
}
}while(TRUE);
}
|
Cheers, |
|
|
Ttelmah Guest
|
|
Posted: Fri Jan 02, 2009 3:44 am |
|
|
Repeat after me fifteen times:
"I must _never_ enable an interrupt without a handler present".
You are enabling INT_TIMER1, without a handler.
Best Wishes |
|
|
ericchee
Joined: 03 Dec 2008 Posts: 12
|
|
Posted: Fri Jan 02, 2009 4:41 am |
|
|
oh, i should add #INT_TIMER1 routine into to my code. |
|
|
ericchee
Joined: 03 Dec 2008 Posts: 12
|
|
Posted: Mon Jan 05, 2009 9:12 pm |
|
|
I got it now. Here's the code:
Code: | #include <16F877A.h>
#include <string.h>
#use delay(clock=20000000)
#fuses hs, noprotect, nowdt,nolvp
#byte PORTB=6
#byte PORTC=7
#define door PIN_B2
#define window PIN_B1
#define bumper PIN_B3
#define INTS_PER_SECOND 76 // (20000000/(4*256*256))
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#define ChannelA PIN_A0
#define ChannelB PIN_A1
#define DIRECTION PIN_D3
#define REDLED PIN_B4
#define GREENLED PIN_B6
#define YELLOWLED PIN_B3
#include <input.c>
#include <stdlib.h>
#define STRING_SIZE 40
#define BUFFER_SIZE 32
BYTE buffer[BUFFER_SIZE];
BYTE next_in = 0;
BYTE next_out = 0;
#define bkbhit (next_in!=next_out)
char cmd_str[20];
byte bgetc()
{
byte c;
while(!bkbhit) ;
c=buffer[next_out];
next_out=(next_out+1) % BUFFER_SIZE;
return(c);
}
void get_cmd_str(char * s, int max) {
int len;
char c;
max--;
len = 0;
do {
c = bgetc();
if(c > 0x00) {
if(len < max) {
s[len++] = c;
}
}
}
while(bkbhit);
s[len]= 0x00;
}
#int_rda
void serial_received()
{
int t;
buffer[next_in]=getc();
t=next_in;
next_in=(next_in+1) % BUFFER_SIZE;
if(next_in==next_out)
next_in=t; // Buffer full !!
}
#int_ext
void interrupt()
{
BYTE time3;
set_tris_b(0b00000001);
output_high(bumper);
time3 = get_timer0();
time3 += -1;
set_timer0(time3);
//DISABLE_INTERRUPTS(INT_EXT);
}
#int_rtcc
void timer0_isr()
{
BYTE tmr1;
tmr1 = get_timer1();
tmr1 = tmr1 - 255 + 1;
set_timer1(tmr1);
}
#int_timer1
void timer1_isr()
{
BYTE tmr0;
tmr0 = get_rtcc();
tmr0 = tmr0 - 255 + 1;
set_timer0(tmr0);
}
void main()
{
int PwM;
set_tris_b(0b00110001);
portb=0;
output_low(GREENLED);
output_low(REDLED);
output_low(YELLOWLED);
setup_timer_2(T2_DIV_BY_4, 127, 1);
setup_ccp1(CCP_PWM);
set_pwm1_duty(0);
setup_counters( RTCC_EXT_H_TO_L, RTCC_DIV_1 );
set_rtcc(0);
setup_timer_1 ( T1_EXTERNAL | T1_DIV_BY_1 );
set_timer1(0);
enable_interrupts(INT_RTCC);
enable_interrupts(INT_TIMER1);
EXT_INT_EDGE(L_TO_H);
ENABLE_INTERRUPTS(INT_EXT);
ENABLE_INTERRUPTS(INT_RDA);
enable_interrupts(GLOBAL);
main_program:
do
{
if(bkbhit)
{
delay_ms(50); //Delay allows full string to arrive
get_cmd_str(cmd_str, 10);
output_high(YELLOWLED);
}
PwM=atoi(cmd_str);
set_pwm1_duty(PwM);
printf("---------------->%d\n\r",PwM);
}while(TRUE);
goto main_program;
}
|
|
|
|
ericchee
Joined: 03 Dec 2008 Posts: 12
|
|
Posted: Mon Jan 19, 2009 11:48 am |
|
|
hey guys,
i encounter a problem. here is the new code added.
Code: |
PwM=atoi(cmd_str);
if(PwM >= 129)
{
printf("---------------->%d 1 \n\r",PwM);
PwM -= 129;
set_pwm1_duty(PwM);
output_high(DIRECTION);
}
if(PwM <= 128)
{
printf("---------------->%d 2 \n\r",PwM);
set_pwm1_duty(PwM);
output_low(DIRECTION);
}
[quote]
Whatever number i send, i get low output for DIRECTION. The upper 'if' code seems not working. Can anyone point out what mistake i have made? tq[/quote] |
|
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Mon Jan 19, 2009 12:22 pm |
|
|
Another classic one...
The upper code is working, but before you 'can blink an eye', the lower code is reached where the 'if-statement' now is also true and is executed as well.
(an int8 - 129 is always <= 128).
Change the second if-statement to an else-if. |
|
|
ericchee
Joined: 03 Dec 2008 Posts: 12
|
|
Posted: Wed Jan 21, 2009 7:51 am |
|
|
You have just saved my day. This problem have been spinning my head for few days. Thank you very much.
Regards,
Eric |
|
|
ericchee
Joined: 03 Dec 2008 Posts: 12
|
|
Posted: Fri Feb 27, 2009 6:51 pm |
|
|
hi,
May i know the formula to find speed of 9600 baud rate. I have been using 76800 baud rate before and it works but lately my project is not working. after changing back to 9600, it works.
Code: |
if(bkbhit)
{
delay_ms(50); //Delay allows full string to arrive
get_cmd_str(cmd_str, 10);
output_high(YELLOWLED);
} |
What is the minimum delay i can put? I encounter data loss when when i used 10. Is there anything to do with baud rate? Is there anything document regarding the speed of each code. tq
rgds,
eric |
|
|
|