Author Topic: strings on avr  (Read 24695 times)

0 Members and 1 Guest are viewing this topic.

Online madires

  • Super Contributor
  • ***
  • Posts: 8474
  • Country: de
  • A qualified hobbyist ;)
Re: strings on avr
« Reply #25 on: September 11, 2013, 12:22:25 pm »
Code: [Select]
/* chars data is which segments should be lit up when wanting to display a number for example:
 * the number 0 needs "ABCDEF" segments to be lit
 * the number 1 needs "BC" segments to be lit
 * in the array there are two extra entries equating to numbers 10 and 11
 * 10 is used for a blank display and 11 is used to display a negative symbol
 */
char chars[12][8] = {"ABCDEF", "BC", "ABDEG", "ABCDG", "BCFG", "ADCFG", "ACDEFG", "ABC", "ABCDEFG", "ABCFG", "X", "G"};

Ouch! :-) Simply make each segment a bit in a byte:
segment A = 0b00000001
segment B = 0b00000010
segment C = 0b00000100

To create a "1" OR the bitmaks:
segment B = 0b00000010
segment C = 0b00000100
"1"             = 0b00000110 = 6

And you'll need just a single byte for each number.

Since the port pins don't match the order of the segments we change the bitmasks according to the wiring:

Code: [Select]
A segments connected to pin: PC1
B segments connected to pin: PC0
C segments connected to pin: PC3
D segments connected to pin: PB4
E segments connected to pin: PB5
F segments connected to pin: PB2
G segments connected to pin: PB3
P segments connected to pin: PC2 (P is decimal point)

We got 2 ports with 4 pins each. Port C is 0-3 and port B is 2-5. So we select following scheme for the bitmasks:
 C3 C2 C1 C0 B5 B4 B3 B2

segment B = 0b00010000
segment C = 0b10000000
"1"             = 0b1001000 = 72

For displaying a number we extract the segment pattern for each port. So we take the top 4 bits for port C, i.e. shifting the byte 4 times to the right:
  output = chars[number] >> 4;
Then write that to the port and go to port B. For port B we take the lower 4 bits and shift them 2 times to the left to match the I/O pins:
  output = chars[number] & 0b00001111;
  output << 2;

Much better and more efficient, isn't it?
 

Offline carbon dude oxideTopic starter

  • Frequent Contributor
  • **
  • Posts: 429
  • Country: gb
Re: strings on avr
« Reply #26 on: September 11, 2013, 12:33:06 pm »
im mid way converting the array of arrays into just an 8 bit byte as there is enough places on it to accommodate all the segments :D

though of it before i read the post! yay! although i may need a little help, give me a bit to finish it off and see if it works though :)
-----
Everything Should Be Made as Simple as Possible, But Not Simpler
-----
 

Offline carbon dude oxideTopic starter

  • Frequent Contributor
  • **
  • Posts: 429
  • Country: gb
Re: strings on avr
« Reply #27 on: September 11, 2013, 12:42:17 pm »
is there a more efficant way of saying this?

void SEG(char ID)
{
   //determine which segments to light up and then light it.
   if ((ID & 0x80) == 0x80) {PORTC = (1 << PORTC1);}
   if ((ID & 0x40) == 0x40) {PORTC = (1 << PORTC0);}
   if ((ID & 0x20) == 0x20) {PORTC = (1 << PORTC3);}
   if ((ID & 0x10) == 0x10) {PORTB = (1 << PORTB4);}
   if ((ID & 0x08) == 0x08) {PORTB = (1 << PORTB5);}
   if ((ID & 0x04) == 0x04) {PORTB = (1 << PORTB2);}
   if ((ID & 0x02) == 0x02) {PORTB = (1 << PORTB3);}
   if ((ID & 0x01) == 0x01) {PORTC = (1 << PORTC2);}
}

sorry forgot to say it checks to see if 1 of the bits in the byte is 1 and if it is turn a pin on
« Last Edit: September 11, 2013, 12:45:40 pm by carbon dude oxide »
-----
Everything Should Be Made as Simple as Possible, But Not Simpler
-----
 

Offline carbon dude oxideTopic starter

  • Frequent Contributor
  • **
  • Posts: 429
  • Country: gb
Re: strings on avr
« Reply #28 on: September 11, 2013, 01:26:43 pm »
ok i ahve got it working again now, except the I2C :(

Code: [Select]
/*
 * PSUFrontDisplay.c
 *
 *  Created: 02/09/2013 14:07:34
 *   Author: carbon dude oxide
 * Avr used: ATMega328p
 */

/* Circuit Structure

7-Segment layout:
Common Anode displays

      A
    ------
F  |      |  B
   |  G   |
    ------
E  |      |  C
   |  D   |
    ------ .P (DP)

Circuit is laid out like so:
the line above each 7-segment display shows which pin on the AVR the common anode is connected to,
the number in brackets corresponds to the ID number of each display used in arrays (index number) and for loops.
There are two sets of 4 displays with all their A segments connected together and all the B segments
together to perform a multiplexing task.

---------------------------------
 PD1 (0) PD0 (1) PD7 (2) PD6 (3)
|  ---  |  ---  |  ---  |  ---  |
| |   | | |   | | |   | | |   | |
|  ---  |  ---  |  ---  |  ---  |
| |   | | |   | | |   | | |   | |
|  ---  |  ---  |  ---  |  ---  |
---------------------------------
 PD5 (4) PD4 (5) PD3 (6) PD2 (7)
|  ---  |  ---  |  ---  |  ---  |
| |   | | |   | | |   | | |   | |
|  ---  |  ---  |  ---  |  ---  |
| |   | | |   | | |   | | |   | |
|  ---  |  ---  |  ---  |  ---  |
---------------------------------

each AVR pin used to control the segments is wired to an NPN transistor which in turn pulls each cathode
of the 7-Segment display low allowing the LED to light

A segments connected to pin: PC1
B segments connected to pin: PC0
C segments connected to pin: PC3
D segments connected to pin: PB4
E segments connected to pin: PB5
F segments connected to pin: PB2
G segments connected to pin: PB3
P segments connected to pin: PC2 (P is decimal point)

*/

#define F_CPU 16000000UL  // 16 MHz clock frequency

#define DIG_PORT PORTD  //digits on portd
#define DIG0 (1<<1)  //dig0 on pin1
#define DIG1 (1<<0)  //dig1 on pin0
#define DIG2 (1<<7)  //dig1 on pin7
#define DIG3 (1<<6)  //dig1 on pin6
#define DIG4 (1<<5)  //dig1 on pin5
#define DIG5 (1<<4)  //dig1 on pin4
#define DIG6 (1<<3)  //dig1 on pin3
#define DIG7 (1<<2)  //dig7 on pin2

#define DIG_ON(digs)  DIG_PORT |= (digs) //turn on digs
#define DIG_OFF(digs) DIG_PORT &=~(digs) //turn off digs

#include <avr/io.h> //standard library loaded
#include <util/delay.h> //needed for delay on multiplexing
#include <stdio.h> //used for current method of displaying data
#include <custom/CarbonWire/twi.h> //modified Wire library from Arduino

// displayout each byte represents the output segments to light up for each digit in the format: ABCDEFGP - 00000000
char displayout[8] = {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02};
/* chars data is which segments should be lit up when wanting to display a number for example:
 * the number 0 needs "ABCDEF" segments to be lit
 * the number 1 needs "BC" segments to be lit
 * in the array there are two extra entries equating to numbers 10 and 11
 * 10 is used for a blank display and 11 is used to display a negative symbol
 */
//char chars[12][8] = {"ABCDEF", "BC", "ABDEG", "ABCDG", "BCFG", "ACDFG", "ACDEFG", "ABC", "ABCDEFG", "ABCFG", "X", "G"};
char charsout[12] = {0xFC, 0x60, 0xDA, 0xF2, 0x66, 0xB6, 0xBE, 0xE0, 0xFE, 0xE6, 0x00, 0x02};

void receiveEvent(int howMany) //custom function to be called when I2C slave address is acknowledged and is receiving bytes of data
{
while(twiavailable() > 4) //check to see if there are 5 bytes available in storage
{
/*
-----structure of incoming bytes-----
Ba is currently unused (will be for negative numbers data)
Bb Bit 0+1 is position of DP on 7 segment display 1 and bit 2-7 is upper bits for display 1.
Bc lower bits for display 1 ( put together to make a 16bit display 1 number to show between 0 and 9999.
Bd Bit 0+1 is position of DP on 7 segment display 2 and bit 2-7 is upper bits for display 2.
Be lower bits for display 2 ( put together to make a 16bit display 2 number to show between 0 and 9999.
*/
 
char Ba = twiread(); // receive byte as a character
char Bb = twiread(); // receive byte as a character
char Bc = twiread(); // receive byte as a character
char Bd = twiread(); // receive byte as a character
char Be = twiread(); // receive byte as a character
if (Ba == 0xFF)
{
//reset display info by setting displays arrays to X (blank display)
for (int i=0; i<8; i++) {displayout[i] = 0x00;} //reset display data
 
// determine dp position by adding a mask and bit shifting to give a value between 0-3 to represent which digit to have the dp on
// look at structure of incoming bytes to see why i bit shift and stuff
char dpp = Bb & 0xC0; // remove number data and leave DP position data
dpp = dpp >> 6; //bit shift to leave dp digit position a binary value between 0-3 (corresponding to which digit to display the DP on)
int idpp = 3 - dpp; // invert the displayID (as it is the wrong way round) and convert into a int corresponding to the 4 displays on the 1st block of displays (ID's 0-3)
displayout[idpp] = 0x01; // add the decimal point into the display array
Bb = Bb & 0x3F; //remove DP Position data and leave number data to we can calculate what number to be displays on the digits
 
short lb = (Bb << 8) | Bc; // combine upper and lower byte to form 16bit number data (so that we can have a number between 0 and 9999)
// set up individual numbers for each of the 4 displays in the 1st of the 2 blocks of 4 displays
int fbT;
int fbh;
int fbt;
int fbu;
if (lb <= 9999) //if received data wants to display number larger than 9999 then display ----
{
//decode binary into 4 individual digits.
short lbT = lb/1000;
fbT = lbT;
if ((fbT >= 10) || (fbT <= 0)) {fbT = 10;}
short lbh = (lb-(lbT*1000))/100;
fbh = lbh;
short lbt = (lb-(lbh*100)-(lbT*1000))/10;
fbt = lbt;
short lbu = (lb-(lbh*100)-(lbt*10)-(lbT*1000));
fbu = lbu;
}
else
{
//set digits as ---- because 11 corresponds to G segment being lit (view chars[11] array)
fbT = 11;
fbh = 11;
fbt = 11;
fbu = 11;
}


// determine dp position (for second block of displays) by adding a mask and bit shifting to give a value between 0-3 to represent which digit to have the dp on
// look at structure of incoming bytes to see why i bit shift and stuff
short dppb = Bd & 0xC0; // remove number data and leave DP position data
dppb = dppb >> 6; //bit shift to leave dp digit position a binary value between 0-3 (corresponding to which digit to display the DP on)
int idppb = 7 - dppb; // invert the displayID (as it is the wrong way round) and convert into a int corresponding to the 4 displays on the 2nd block of displays (ID's 4-7)
displayout[idppb] = 0x01; // add the decimal point into the display array
Bd = Bd & 0x3F;  //remove DP Position data and leave number data to we can calculate what number to be displays on the digits
 
short lbb = (Bd << 8) | Be; // combine upper and lower byte to form 16bit number data (so that we can have a number between 0 and 9999)
// set up individual numbers for each of the 4 displays in the 2nd of the 2 blocks of 4 displays
int fbTb;
int fbhb;
int fbtb;
int fbub;

if (lbb <= 9999)//if received data wants to display number larger than 9999 then display ----
{
//decode binary into 4 individual digits.
short lbTb = lbb/1000;
fbTb = lbTb;
if ((fbTb >= 10) || (fbTb <= 0)) {fbTb = 10;}
short lbhb = (lbb-(lbTb*1000))/100;
fbhb = lbhb;
short lbtb = (lbb-(lbhb*100)-(lbTb*1000))/10;
fbtb = lbtb;
short lbub = (lbb-(lbhb*100)-(lbtb*10)-(lbTb*1000));
fbub = lbub;
}
else
{
//set digits as ---- because 11 corresponds to G segment being lit (view chars[11] array)
fbTb = 11;
fbhb = 11;
fbtb = 11;
fbub = 11;
}
 
/* add character data for each digit in both displays
* This works by getting the segment data from the chars array according to the number calculated for each digit from the incoming I2C data
* It is then added onto the existing data that is already in dispays (the strcat() function) and then finaly is then inserted into the displays
* array where it replaces the existing data (hence the need to copy the existing data and add it to the new data before replacing it
*/
 
displayout[0] |= charsout[fbu]; //inset number display data
displayout[0] |= charsout[fbt]; //inset number display data
displayout[0] |= charsout[fbh]; //inset number display data
displayout[0] |= charsout[fbT]; //inset number display data
displayout[0] |= charsout[fbub]; //inset number display data
displayout[0] |= charsout[fbtb]; //inset number display data
displayout[0] |= charsout[fbhb]; //inset number display data
displayout[0] |= charsout[fbTb]; //inset number display data
}
}
}

void SEG(char ID)
{
//determine which segments to light up and then light it.
if ((ID & 0x80) == 0x80) {PORTC |= 0x02;}
if ((ID & 0x40) == 0x40) {PORTC |= 0x01;}
if ((ID & 0x20) == 0x20) {PORTC |= 0x08;}
if ((ID & 0x10) == 0x10) {PORTB |= 0x10;}
if ((ID & 0x08) == 0x08) {PORTB |= 0x20;}
if ((ID & 0x04) == 0x04) {PORTB |= 0x04;}
if ((ID & 0x02) == 0x02) {PORTB |= 0x08;}
if ((ID & 0x01) == 0x01) {PORTC |= 0x04;}
}

int main(void)
{
/* Set all used pins to outputs
* PD1, PD0, PD7, PD6, PD5, PD4, PD3 and PD2 for anodes for each of the 8 7-segment displays and
* PC1, PC0, PC3, PB4, PB5, PB2, PB3 and PC2 for NPN transistor for each segment of the 7-segment displays
*/
DDRB = (1 << PORTB0) | (1 << PORTB1) | (1 << PORTB2) | (1 << PORTB3) | (1 << PORTB4) | (1 << PORTB5);
DDRC = (1 << PORTC0) | (1 << PORTC1) | (1 << PORTC2) | (1 << PORTC3);
DDRD = (1 << PORTD0) | (1 << PORTD1) | (1 << PORTD2) | (1 << PORTD3) | (1 << PORTD4) | (1 << PORTD5) | (1 << PORTD6) | (1 << PORTD7);
//initiate the I2C Protocol
// twibegin(2);                // join i2c bus with address #2
// twionReceive(receiveEvent); // register event to handle requests
//the loop function for multiplexing
while(1)
{
for (int dID=0; dID<8; dID++) //cycle through display ID's 0-7 :D
{
PORTB &= 0xC0; // set all ports except PORTB6 and PORTB7 low
PORTC &= 0xF0; // set all ports except PORTC4, PORTB5, PORTC6 and PORTB7 low
PORTD = 0x00; // set all ports low

switch (dID)
{
case 0: DIG_OFF(DIG7); SEG(displayout[dID]); DIG_ON(DIG0); break; //light up digit 0
case 1: DIG_OFF(DIG0); SEG(displayout[dID]); DIG_ON(DIG1); break; //light up digit 1
case 2: DIG_OFF(DIG1); SEG(displayout[dID]); DIG_ON(DIG2); break; //light up digit 2
case 3: DIG_OFF(DIG2); SEG(displayout[dID]); DIG_ON(DIG3); break; //light up digit 3
case 4: DIG_OFF(DIG3); SEG(displayout[dID]); DIG_ON(DIG4); break; //light up digit 4
case 5: DIG_OFF(DIG4); SEG(displayout[dID]); DIG_ON(DIG5); break; //light up digit 5
case 6: DIG_OFF(DIG5); SEG(displayout[dID]); DIG_ON(DIG6); break; //light up digit 6
case 7: DIG_OFF(DIG6); SEG(displayout[dID]); DIG_ON(DIG7); break; //light up digit 7
}
_delay_ms(1); //delay 1ms so that it does not go too crazy and lights up the segments correctly
}
}
}


and there are no strings! :D
-----
Everything Should Be Made as Simple as Possible, But Not Simpler
-----
 

Online madires

  • Super Contributor
  • ***
  • Posts: 8474
  • Country: de
  • A qualified hobbyist ;)
Re: strings on avr
« Reply #29 on: September 11, 2013, 02:10:26 pm »
is there a more efficant way of saying this?

Code: [Select]
void SEG(char ID)
{
//determine which segments to light up and then light it.
if ((ID & 0x80) == 0x80) {PORTC = (1 << PORTC1);}
if ((ID & 0x40) == 0x40) {PORTC = (1 << PORTC0);}
if ((ID & 0x20) == 0x20) {PORTC = (1 << PORTC3);}
if ((ID & 0x10) == 0x10) {PORTB = (1 << PORTB4);}
if ((ID & 0x08) == 0x08) {PORTB = (1 << PORTB5);}
if ((ID & 0x04) == 0x04) {PORTB = (1 << PORTB2);}
if ((ID & 0x02) == 0x02) {PORTB = (1 << PORTB3);}
if ((ID & 0x01) == 0x01) {PORTC = (1 << PORTC2);}
}

sorry forgot to say it checks to see if 1 of the bits in the byte is 1 and if it is turn a pin on

Based on my example (see post above) you just need to get the current logic level of the non-segment pins, set the extracted segment pattern and write that to the port.

Port C (segments at 0-3):
Code: [Select]
bitmask = PORTC;
bitmask &= 0b11110000;     /* keep the non-segments */
bitmask |= output;                /* set segment pattern */
PORTC = bitmask;

Port B (segments at 2-5):
Code: [Select]
bitmask = PORTB;
bitmask &= 0b11000011;     /* keep the non-segments */
bitmask |= output;                /* set segment pattern */
PORTB = bitmask;

Before writing to a port you have to get "output" (the segment pattern) for that port.
 

Offline carbon dude oxideTopic starter

  • Frequent Contributor
  • **
  • Posts: 429
  • Country: gb
Re: strings on avr
« Reply #30 on: September 11, 2013, 02:20:38 pm »
the one i posted turned ut not to work properly :/

i have replaced it with this and it works :D

Code: [Select]
if ((ID & 0x80) == 0x80) {PORTC |= 0x02;}
if ((ID & 0x40) == 0x40) {PORTC |= 0x01;}
if ((ID & 0x20) == 0x20) {PORTC |= 0x08;}
if ((ID & 0x10) == 0x10) {PORTB |= 0x10;}
if ((ID & 0x08) == 0x08) {PORTB |= 0x20;}
if ((ID & 0x04) == 0x04) {PORTB |= 0x04;}
if ((ID & 0x02) == 0x02) {PORTB |= 0x08;}
if ((ID & 0x01) == 0x01) {PORTC |= 0x04;}
-----
Everything Should Be Made as Simple as Possible, But Not Simpler
-----
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: strings on avr
« Reply #31 on: September 11, 2013, 04:59:37 pm »
Code: [Select]
if ((ID & 0x80) == 0x80) {PORTC |= 0x02;}
That presumes that those corresponding pins are all clear. Otherwise, it is safer to do this:
Code: [Select]
if (ID & 0x80) PORTC |= 0x20; else PORTC &=~0x20;
Or if you prefer access to individual pins (via bit fields) you can do this:

Code: [Select]
SEG_A = (ID & 0x80)?1:0;
where SEG_A is a pin.
================================
https://dannyelectronics.wordpress.com/
 

Offline carbon dude oxideTopic starter

  • Frequent Contributor
  • **
  • Posts: 429
  • Country: gb
Re: strings on avr
« Reply #32 on: September 11, 2013, 05:34:32 pm »
Code: [Select]
if ((ID & 0x80) == 0x80) {PORTC |= 0x02;}
That presumes that those corresponding pins are all clear. Otherwise, it is safer to do this:
Code: [Select]
if (ID & 0x80) PORTC |= 0x20; else PORTC &=~0x20;

but they are all clear? they were cleared just before this function was called when it restarts its loop again :D
-----
Everything Should Be Made as Simple as Possible, But Not Simpler
-----
 

Offline IanB

  • Super Contributor
  • ***
  • Posts: 12609
  • Country: us
Re: strings on avr
« Reply #33 on: September 11, 2013, 05:41:11 pm »
i did that because its going to be an array with multiple characters within each entry (up to 10) and each one could contain all the letters so i did it this way? again like i said before i will be converting to pgmemory soon

You can use PROGMEM (flash) to hold static data for initialization, but you cannot use it as dynamic memory for working storage. For that you need to continue using RAM.

 

Offline Kremmen

  • Super Contributor
  • ***
  • Posts: 1289
  • Country: fi
Re: strings on avr
« Reply #34 on: September 11, 2013, 07:55:54 pm »
Quote


i am unsure what you mean by Remove the static port setups unfortunately... could you give me an example?
Sorry that was a brainfart from my side. I read those carelessly as port direction setups which they are not. Ignore.
Nothing sings like a kilovolt.
Dr W. Bishop
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: strings on avr
« Reply #35 on: September 11, 2013, 10:19:15 pm »
Code: [Select]
SEG_A = (ID & 0x80)?1:0;
One way to use that is to define a bit field, like this:

Code: [Select]
typedef struct {
unsigned char RP0:1;
unsigned char RP1:1;
unsigned char RP2:1;
unsigned char RP3:1;
unsigned char RP4:1;
unsigned char RP5:1;
unsigned char RP6:1;
unsigned char RP7:1;
} PIN_DEF;

#define SEG_A ((volatile PIN_DEF *) (&PORTD))->RP1 //seg on portd.1
#define SEG_B ((volatile PIN_DEF *) (&PORTE))->RP7 //seg on porte.7
...
#define SEG_P ((volatile PIN_DEF *) (&PORTA))->RP0 //seg on porta.0


Later on in  your code, you can simply reference SEG_A/B/.../P to set or clear them.

This is a convenient but typically slow approach.


================================
https://dannyelectronics.wordpress.com/
 

Offline Kremmen

  • Super Contributor
  • ***
  • Posts: 1289
  • Country: fi
Re: strings on avr
« Reply #36 on: September 12, 2013, 07:46:24 am »
I haven't followed every post so this may already be somewhere in the thread but nevertheless, a suggestion:
Typically (but not always) a 7 segment display is used to show digits and a small(ish) number of characters. Why not #define the byte (bit pattern) for each digit and character and then create a constant array of those patterns. uint8_t pattDigits[10] = {...}; would be one of them. that way you can index the digits directly from the array. Characters are a bit different but i have usually done a similar array for the ones i use. Works well enough, since you hardly ever try to display free form text with this kind of display.
Nothing sings like a kilovolt.
Dr W. Bishop
 

Online madires

  • Super Contributor
  • ***
  • Posts: 8474
  • Country: de
  • A qualified hobbyist ;)
Re: strings on avr
« Reply #37 on: September 12, 2013, 10:20:07 am »
I haven't followed every post so this may already be somewhere in the thread but nevertheless, a suggestion:
Typically (but not always) a 7 segment display is used to show digits and a small(ish) number of characters. Why not #define the byte (bit pattern) for each digit and character and then create a constant array of those patterns. uint8_t pattDigits[10] = {...}; would be one of them. that way you can index the digits directly from the array. Characters are a bit different but i have usually done a similar array for the ones i use. Works well enough, since you hardly ever try to display free form text with this kind of display.

Please see https://www.eevblog.com/forum/microcontrollers/strings-on-avr/msg289982/#msg289982 :-) That way you can also simplify the output function (switching the segments).
 

Offline Kremmen

  • Super Contributor
  • ***
  • Posts: 1289
  • Country: fi
Re: strings on avr
« Reply #38 on: September 12, 2013, 01:25:03 pm »
Yep, you got it already.
Nothing sings like a kilovolt.
Dr W. Bishop
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf