|
|
View previous topic :: View next topic |
Author |
Message |
test153
Joined: 09 Feb 2009 Posts: 28
|
12F629, LEDs and serial |
Posted: Mon Feb 09, 2009 6:36 pm |
|
|
Would it be possible to use RS232 (soft uart) and updating LEDs all in the same time using the 12F629 microcontroller and CCS. I basically would like to have a main loop updating the LEDs and be able to receive from the serial port. The serial interface will be used to change how many LEDs will be updated. I suppose it would involve some kind of a interrupt.
Is it doable without using assembler and what would I have to think about? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Feb 09, 2009 7:11 pm |
|
|
What are the LEDs doing ? Are they simply turned on/off by a serial
port command, or are they blinking in patterns, and the patterns are
controlled by serial port commands ?
Are the LEDs in fact 7-segment displays ? |
|
|
test153
Joined: 09 Feb 2009 Posts: 28
|
|
Posted: Tue Feb 10, 2009 4:32 am |
|
|
The LEDs are connected in a double matrix allowing 12 LEDs to be controlled using only five pins, therefore only one LED can be on at a time so the processor needs to switch the LEDs on and off continuously. The serial port will be used to control how many of the 12 LEDs will be on. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Feb 10, 2009 5:18 pm |
|
|
Here's a demo program. Pin A3 has to be used for serial reception
because it's an input-only pin, and you need the other five pins to drive
your LEDs. If you need anything beyond this, you should write the code
for it. I didn't test this in hardware, but it will probably work.
Code: | #include <12F629.h>
#fuses INTRC_IO,NOWDT,NOBROWNOUT,NOPROTECT,NOMCLR
#use delay(clock=4000000)
#use rs232(baud=9600, rcv=PIN_A3)
#define write_OLED(x) \
output_bit(PIN_A0, x & 1); \
output_bit(PIN_A1, x & 2); \
output_bit(PIN_A2, x & 4); \
output_bit(PIN_A4, x & 8); \
output_bit(PIN_A5, x & 0x10)
//===============================
void main()
{
char command;
write_OLED(0); // Initialize LEDs to all off
while(1)
{
command = getc(); // Wait for char
write_OLED(command); // Update the LED display
}
} |
|
|
|
test153
Joined: 09 Feb 2009 Posts: 28
|
|
Posted: Tue Feb 10, 2009 5:34 pm |
|
|
Thank you!
I only asked if it was possible but you were kind enough to even post a demo code. Thank you again. |
|
|
test153
Joined: 09 Feb 2009 Posts: 28
|
|
Posted: Tue Feb 10, 2009 8:01 pm |
|
|
I have put together the code below and it's working well except that I need to send two characters through the serial port. If I only send one the main loop will not continue, as if the processor was still stuck in the interrupt routine...
Code: | #include <12F629.h>
#fuses INTRC_IO,NOWDT,NOBROWNOUT,NOPROTECT,NOMCLR
#use delay(clock=4000000)
#use rs232(baud=9600, rcv=PIN_A3)
#define ALL_IN 0xff //address for your chip
char command;
//===============================
#INT_RA
void serialis_isr(void)
{
disable_interrupts(INT_RA);
command = getc(); // Wait for char
clear_interrupt(INT_RA);
enable_interrupts(INT_RA);
}
void led1() {
set_tris_a(ALL_IN);
output_low(PIN_A0);
output_high(PIN_A5);
}
void led2() {
set_tris_a(ALL_IN);
output_low(PIN_A5);
output_high(PIN_A0);
}
void main()
{
enable_interrupts(INT_RA3);
enable_interrupts(GLOBAL);
while(1)
{
if (command==49) {led1();}
if (command==50) {led1(); led2();}
}
} |
|
|
|
Ttelmah Guest
|
|
Posted: Wed Feb 11, 2009 3:42 am |
|
|
First, get rid of the enable/disable & clear interrupt lines in the interrupt. Not needed. The hardware disables all interrupts while an interrupt is being serviced, and the compiler automatically clears interrupts for you when the handler finishes.
Change INT_RA, to INT_RA3, which is the pin receiving the serial data. Otherwise if the pins are floating (they all are at times), interrupts can trigger from the other pins, and you will then sit in the interrupt waiting, till the serial data arrives - this is probably what is happening.
Get rid of your 'ALL_IN' fiddling with TRIS. Tris is being set automatically for you by the compiler, making the pins you drive as outputs, into outputs. You are changing them to inputs, before the compiler does this. Because of this, RA, will trigger on the pins (it triggers when an input changes level, if they are left as outputs, this won't happen).
Best Wishes |
|
|
test153
Joined: 09 Feb 2009 Posts: 28
|
|
Posted: Wed Feb 11, 2009 6:19 am |
|
|
The pin A0-A2 & A4-A5 need to be inputs, otherwise no current can flow back through them.
Anyway using "#INT_RA3" gives me a compiler error - "Invalid pre-processor directive".
Bellow is the final program and it works as intended but I need all those if statments in the interrupt routine otherwise nothing will happen as if it didn't return back to the main loop.
Code: |
#include <12F629.h>
#fuses INTRC_IO,NOWDT,NOBROWNOUT,NOPROTECT,NOMCLR
#use delay(clock=4000000)
#use rs232(baud=9600, rcv=PIN_A3)
char command;
//===============================
void resetPorts() {
input(PIN_A0);
input(PIN_A1);
input(PIN_A2);
input(PIN_A4);
input(PIN_A5);
}
void led1() {
resetPorts();
output_low(PIN_A0);
output_high(PIN_A5);
}
void led2() {
resetPorts();
output_low(PIN_A5);
output_high(PIN_A0);
}
void led3() {
resetPorts();
output_low(PIN_A1);
output_high(PIN_A5);
}
void led4() {
resetPorts();
output_low(PIN_A5);
output_high(PIN_A1);
}
//Next matrix line
void led5() {
resetPorts();
output_low(PIN_A0);
output_high(PIN_A4);
}
void led6() {
resetPorts();
output_low(PIN_A4);
output_high(PIN_A0);
}
void led7() {
resetPorts();
output_low(PIN_A1);
output_high(PIN_A4);
}
void led8() {
resetPorts();
output_low(PIN_A4);
output_high(PIN_A1);
}
//Next matrix line
void led9() {
resetPorts();
output_low(PIN_A0);
output_high(PIN_A2);
}
void led10() {
resetPorts();
output_low(PIN_A2);
output_high(PIN_A0);
}
void led11() {
resetPorts();
output_low(PIN_A1);
output_high(PIN_A2);
}
void led12() {
resetPorts();
output_low(PIN_A2);
output_high(PIN_A1);
}
void main()
{
enable_interrupts(INT_RA3);
enable_interrupts(GLOBAL);
resetPorts();
while(1)
{
if (command==49) {led1();}
if (command==50) {led1(); led2();}
if (command==51) {led1(); led2(); led3();}
if (command==52) {led1(); led2(); led3(); led4();}
if (command==53) {led1(); led2(); led3(); led4(); led5();}
if (command==54) {led1(); led2(); led3(); led4(); led5(); led6();}
if (command==55) {led1(); led2(); led3(); led4(); led5(); led6(); led7();}
if (command==56) {led1(); led2(); led3(); led4(); led5(); led6(); led7(); led8();}
if (command==57) {led1(); led2(); led3(); led4(); led5(); led6(); led7(); led8(); led9();}
if (command==58) {led1(); led2(); led3(); led4(); led5(); led6(); led7(); led8(); led9(); led10();}
if (command==59) {led1(); led2(); led3(); led4(); led5(); led6(); led7(); led8(); led9(); led10(); led11();}
if (command==60) {led1(); led2(); led3(); led4(); led5(); led6(); led7(); led8(); led9(); led10(); led11(); led12();}
}
}
#int_ra
void int_rb_isr(void)
{
command = getc(); // Wait for char
if (command==49) {led1();}
if (command==50) {led1(); led2();}
if (command==51) {led1(); led2(); led3();}
if (command==52) {led1(); led2(); led3(); led4();}
if (command==53) {led1(); led2(); led3(); led4(); led5();}
if (command==54) {led1(); led2(); led3(); led4(); led5(); led6();}
if (command==55) {led1(); led2(); led3(); led4(); led5(); led6(); led7();}
if (command==56) {led1(); led2(); led3(); led4(); led5(); led6(); led7(); led8();}
if (command==57) {led1(); led2(); led3(); led4(); led5(); led6(); led7(); led8(); led9();}
if (command==58) {led1(); led2(); led3(); led4(); led5(); led6(); led7(); led8(); led9(); led10();}
if (command==59) {led1(); led2(); led3(); led4(); led5(); led6(); led7(); led8(); led9(); led10(); led11();}
if (command==60) {led1(); led2(); led3(); led4(); led5(); led6(); led7(); led8(); led9(); led10(); led11(); led12();}
}
|
Last edited by test153 on Wed Feb 25, 2009 3:26 pm; edited 1 time in total |
|
|
Ttelmah Guest
|
|
Posted: Wed Feb 11, 2009 10:57 am |
|
|
INT_RA3 giving an error, implies you have a fairly old compiler.
You will need to handle this all yourself then.
Basically, you need to read the whole port in the interrupt, and check that the A3 pin has dropped. If it has, call the getc, otherwise just exit the interrupt.
Done like this, you no longer need all the tests in the interrupt, and the interrupt will return, except when a character is received.
As it currently stands, interrupts will be disabled for most of the time, since calling a function both inside, and outsid an interrupt, results in interrupts being disabled in this function....
All your pins will currently stay as outputs, once used.
If you want to control the TRIS, then use 'fast_io', and control it for each operation.
Best Wishes |
|
|
test153
Joined: 09 Feb 2009 Posts: 28
|
|
Posted: Wed Feb 11, 2009 11:18 am |
|
|
I don't think I'm using an old compiler, the version I'm using is 4.084.
All the pins are rest to input in the beginning of every ledX() routine by calling resetPorts(). I still want to return from the interrupt routine even if I get a character.
I have modifed the interrupt routine but it's not working at all now.
Code: | #int_ra
void int_rb_isr(void)
{
if (input_state(pin_A3)==1) {
//command=60; // This works great
command = getc(); // This doesn't work
}
} |
Edit: Changing "input_state(pin_A3)==1" to "input_state(pin_A3)==0" did the trick. It seems to work now, will get back after running some more tests... |
|
|
Ttelmah Guest
|
|
Posted: Wed Feb 11, 2009 1:52 pm |
|
|
The start bit of a serial character is a _low_, not a high.
Your test is the wrong way round.
Best Wishes |
|
|
test153
Joined: 09 Feb 2009 Posts: 28
|
|
Posted: Wed Feb 11, 2009 4:28 pm |
|
|
Thank you for your assistance. |
|
|
|
|
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
|