|
|
View previous topic :: View next topic |
Author |
Message |
williefeb_19
Joined: 21 Apr 2008 Posts: 18
|
Help optimizing code for LED scrolling sign |
Posted: Mon Apr 21, 2008 11:53 pm |
|
|
I am new to C programming and I am trying to make a led scrolling sign using a PIC16F690 and MAX6954APL driver connected via an SPI interface. I have 8 14-segment displays hooked up and functioning correctly. I want to know if there is an easier or more efficient way to be able to change messages and make it scroll. What I have works but it isn’t easy to change the message.
In the future want to add the ability to change the message using an interface with the PIC.
Code: | /*
Pins used on MAX6954APL for SPI communications
MAX_DO PIN_C7
MAX_CLK PIN_B6
MAX_DI PIN_B4
MAX_SEL PIN_C6
*/
#define MAX_SEL PIN_C6
void Display (INT adr, int chars) //Function to write to displays
{
output_low(MAX_SEL);
spi_write(adr);
spi_write(chars);
output_high(MAX_SEL);
}
int digit[] = //Array to address individual displays
{
0x20, //Digit 0
0x21, //Digit 1
0x22, //Digit 2
0x23, //Digit 3
0x24, //Digit 4
0x25, //Digit 5
0x26, //Digit 6
0x27 //Digit 7
};
int chars[] = //Array for charecters
{
0x41, // A
0x42, // B
0x43, // C
0x44, // D
0x45, // E
0x46, // F
0x47, // G
0x48, // H
0x49, // I
0x4A, // J
0x4B, // K
0x4C, // L
0x4D, // M
0x4E, // N
0x4F, // O
0x50, // P
0x51, // Q
0x52, // R
0x53, // S
0x54, // T
0x55, // U
0x56, // V
0x57, // W
0x58, // X
0x59, // Y
0x5A, // Z
0x30, // 0
0x31, // 1
0x32, // 2
0x33, // 3
0x34, // 4
0x35, // 5
0x36, // 6
0x37, // 7
0x38, // 8
0x39, // 9
0x20, // (space)
0x22, // "
0x24, // $
0x27, // '
0x2A, // *
0x2B, // +
0x2C, // ,
0x2D, // -
0x2E, // .
0x2F, // /
0x3B, // ,
0x3C, // <
0x3D, // =
0x3E, // >
0x3F, // ?
0x40, // @
};
int message[] = //Array for message to be stored
{
36, 36, 36, 36, //Spaces to blank out display at front of message
36, 36, 36, 36,
7, 4, //Message for use with the lets array (HELLO WORLD)
11, 11, 14, 36,
22, 14, 17, 11, 3,
36, 36, 36, 36, //Spaces to blank out display at end of message
36, 36, 36, 36
};
void main()
{
INT i=0, array;
//Setup SPI FOR serial communication to MAX6954APL
setup_spi (SPI_MASTER|SPI_H_TO_L|SPI_CLK_DIV_16);
delay_ms(150);
//Set Global Inensity to 76
Display(0x02, 0x13 );
//Set Configuration REGISTER
Display(0x04, 0x13 );
array=27-7;
for (i=0;i<array;i++)
{
//Set Displays and scroll
Display(digit[0], chars[message[i]]);
Display(digit[1], chars[message[i+1]]);
Display(digit[2], chars[message[i+2]]);
Display(digit[3], chars[message[i+3]]);
Display(digit[4], chars[message[i+4]]);
Display(digit[5], chars[message[i+5]]);
Display(digit[6], chars[message[i+6]]);
Display(digit[7], chars[message[i+7]]);
delay_ms(200);
if (i==array-1)
{
i=0;
delay_ms(150);
}
}
} |
|
|
|
Matro Guest
|
|
Posted: Tue Apr 22, 2008 2:15 am |
|
|
Below an example of what could be done to simplify.
Normally this code should work without modifications, but there is no warranty.
Tell me if you have problems with it.
Code: |
#include <16F690.h>
#use delay(clock=20000000)
#include <string.h>
/*
Pins used on MAX6954APL for SPI communications
MAX_DO PIN_C7
MAX_CLK PIN_B6
MAX_DI PIN_B4
MAX_SEL PIN_C6
*/
#define MAX_SEL PIN_C6
#define MAX_MSG_LENGTH 50 //maximum message length
#define DIGIT(x) 0x20+x //macro
void Display (INT adr, int chars) //Function to write to displays
{
output_low(MAX_SEL);
spi_write(adr);
spi_write(chars);
output_high(MAX_SEL);
}
char message[MAX_MSG_LENGTH];
void main()
{
int i,j;
//Setup SPI FOR serial communication to MAX6954APL
setup_spi (SPI_MASTER|SPI_H_TO_L|SPI_CLK_DIV_16);
delay_ms(150);
//Set Global Inensity to 76
Display(0x02, 0x13 );
//Set Configuration REGISTER
Display(0x04, 0x13 );
strcpy(message," Hello world! "); //initialization of message
while(1)
{
for(i=0;i<strlen(message)-7;i++)
{
//Set Displays and scroll
for(j=0;j<8;j++)
{
Display(DIGIT(j),message[i+j]);
}
delay_ms(200);
}
}
}
|
Matro |
|
|
williefeb_19
Joined: 21 Apr 2008 Posts: 18
|
|
Posted: Tue Apr 22, 2008 3:25 pm |
|
|
Thank You that code works great. I had a feeling there was an easier way of doing this.
I have some questions about the code. What’s converting the "Hello World!" to ASCII and is that a function of strcpy?
I am trying to understand the new code as best I can. |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Tue Apr 22, 2008 4:22 pm |
|
|
Code: | setup_spi (SPI_MASTER|SPI_H_TO_L|SPI_CLK_DIV_16); |
This configures the SPI port as mode 2, see the table below.
Code: | #define SPI_MODE_0 (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_1 (SPI_L_TO_H)
#define SPI_MODE_2 (SPI_H_TO_L)
#define SPI_MODE_3 (SPI_H_TO_L | SPI_XMIT_L_TO_H) |
According to Figure 3 of the max6954 datasheet it should be configured for mode 0 (read the SPI explanation at Wikipedia)
I'm surprised it works with the current setup, better would be to setup like: Code: | setup_spi (SPI_MASTER| SPI_MODE_0 |SPI_CLK_DIV_16); |
|
|
|
williefeb_19
Joined: 21 Apr 2008 Posts: 18
|
|
Posted: Tue Apr 22, 2008 5:06 pm |
|
|
I’ve changed the mode to MODE_0 and can’t really tell the difference from before so either way seems to work.
What limits the length of the strings? I can’t go past 70 or so is there a way to go beyond this. I am just curious and don’t know if and/or how it can be done.
Thank You
You have been really helpful
Last edited by williefeb_19 on Wed Apr 23, 2008 6:46 am; edited 1 time in total |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Tue Apr 22, 2008 7:18 pm |
|
|
williefeb_19 wrote: | I’ve changed the mode to MODE_0 and can’t really tell the difference from before so either way seems to work. | Either may seem to work, but mode0 is according to specifications and mode3 is by luck (a change to line capacitance, temperature, whatever, can cause it to fail).
Quote: | What limits the length of the strings? I can’t go past 70 or so is there a way to go beyond this. | The method you used for declaring the string stored the data in RAM. On a PIC16 the RAM memory is not contagious but is cut into pieces, banked memory, where the first part of most banks are occupied by general purpose registers. Depending on processor type, RAM bank number and other variables in your program the maximum size of a single string is limited to about 70 characters.
A PIC18 processor is only limited by the total RAM size because it has a different memory layout. Here the RAM still has memory banks but the general purpose registers are moved to the end of the address range, not dividing the RAM in small segments.
There are several ways to work around the 70 character limit but I don't have the time now to work that out. Maybe someone else can give examples? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
williefeb_19
Joined: 21 Apr 2008 Posts: 18
|
|
|
Matro Guest
|
|
Posted: Wed Apr 23, 2008 1:38 am |
|
|
williefeb_19 wrote: | Thank You that code works great. I had a feeling there was an easier way of doing this.
I have some questions about the code. What’s converting the "Hello World!" to ASCII and is that a function of strcpy?
I am trying to understand the new code as best I can. |
There is no conversion to do. The alpha characters are just a representation for human beings, and ASCII is the same but for a computer.
strcpy() just place the string in RAM so you can use it.
Actually there is no conversion (something based on mathematical calculations) but that's only the representation of the data that is different.
If you really want to see a conversion, so the compiler will transform the alpha-numeric string in ASCII (but at the computer level, the string is already an ASCII array). And on the other side, an LCD or a hyperterminal will transform the ASCII in alpha-numeric string.
I don't know if you understand but it's difficult for me to explain. You have to remove from your mind that a data string (like "Hello world!") and an ASCII array are 2 different things.
For exemple, this 3 examples will give the same thing :
Code: |
char string[] = "Hello" //this way of doing is supported by CCS under special conditions. Prefer the use of strcopy()
|
Code: |
char string[] = {'H','e','l','l','o'}
|
Code: |
char string[] = {0x48,0x65,0x6C,0x6C,0x6F}
|
Especially the 2 last examples are exactly the same thing for the MCU, because 'H' means "the value of character H in ASCII", and so on.
If it can help you to understand, I can add that in fact for the MCU (and the compiler), the types "char", "byte" and "unsigned int8" are exactly the same type of data. The different names are here for human understanding only. ;-)
Hope this make things more clear for you.
Matro. |
|
|
williefeb_19
Joined: 21 Apr 2008 Posts: 18
|
|
Posted: Wed Apr 23, 2008 6:54 am |
|
|
Matro,
That does help make things clearer.
Thanks again |
|
|
andrewg
Joined: 17 Aug 2005 Posts: 316 Location: Perth, Western Australia
|
|
Posted: Wed Apr 23, 2008 7:12 am |
|
|
Strings in C have null terminators, so the correct equivalents are: Code: | char string[] = "Hello";
char string[] = {'H','e','l','l','o',0};
char string[] = {0x48,0x65,0x6C,0x6C,0x6F,0}; |
_________________ Andrew |
|
|
Matro Guest
|
|
Posted: Wed Apr 23, 2008 7:18 am |
|
|
andrewg wrote: | Strings in C have null terminators, so the correct equivalents are: Code: | char string[] = "Hello";
char string[] = {'H','e','l','l','o',0};
char string[] = {0x48,0x65,0x6C,0x6C,0x6F,0}; |
|
Indeed.
And even to stay everywhere with the same format.
Code: | char string[] = "Hello";
char string[] = {'H','e','l','l','o','\0'};
char string[] = {0x48,0x65,0x6C,0x6C,0x6F,0x00}; |
Thanks for appending this correction.
Matro. |
|
|
williefeb_19
Joined: 21 Apr 2008 Posts: 18
|
|
Posted: Wed Apr 23, 2008 2:38 pm |
|
|
So, if I get an 18F series PIC the string will only be limited by the amount of memory available?
If I wanted to be able to change the message using an interface on the PIC (left, right, up, down and enter button) what would be the best direction to go in?
I know how to take input from buttons and use them in a program. What kind of routine would be used to edit the message in the string? |
|
|
Matro Guest
|
|
Posted: Thu Apr 24, 2008 1:41 am |
|
|
Maybe use the interrupt-on-change feature and create the appropriate ISR.
In this ISR, you can simply go through the ASCII table by incrementing or decrementing the value of each character.
For example, left and right key change the string index, up and down change the value at the current index.
The same way as you enter your name with the paddle of a video game console.
It should be a good start that you can customize when it will work.
Matro. |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Thu Apr 24, 2008 6:21 pm |
|
|
williefeb_19 wrote: | So, if I get an 18F series PIC the string will only be limited by the amount of memory available? | Yes, but take note of:
1) Make sure your compiler supports the 16-bit PIC18. See http://www.ccsinfo.com/content.php?page=Purchasing1
2) In your current design the maximum string length will be limited to the amount of RAM available, a maximum of about 3900 in the largest PIC18's.
I was thinking of alternative approach where you store the text in ROM, this would allow for larger texts even on the PIC16 but I see you want to be able to change the text. That complicates things a bit...
Do you want the modified text to be remembered when power is removed? |
|
|
|
|
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
|