Author Topic: Making A Cylon Eye  (Read 7923 times)

0 Members and 1 Guest are viewing this topic.

Offline LanceTopic starter

  • Frequent Contributor
  • **
  • Posts: 317
  • Country: 00
  • Resistance if futile if R<1Ohm
Making A Cylon Eye
« on: February 20, 2011, 05:32:07 am »
I'm trying to make 8 leds run like a cylon eye. Because the leds cover two different port ranges, I decided to try and make a little bitfield which I could then set the ports with. It failed horribly.

The idea is to have 8 unsigned integers, one representing each light. Then just use some bitwise shifts to move the light around.
Code: [Select]
void Cylon(void)
{
unsigned int counter=0;
unsigned long i=0;

struct light
{
unsigned int light0:1;
unsigned int light1:1;
unsigned int light2:1;
unsigned int light3:1;
unsigned int light4:1;
unsigned int light5:1;
unsigned int light6:1;
unsigned int light7:1;
}

union light_union
{
struct light x;
} Lights;

Lights.x=(0b00000000u);
}

Actually trying to set the bits is being problematic, I get this error message:

Code: [Select]
illegal conversion between types unsigned int -> struct lightI'm not sure what to do here.
#include "main.h"
//#include <killallhumans.h>
 

Offline RayJones

  • Frequent Contributor
  • **
  • Posts: 490
    • Personal Website
Re: Making A Cylon Eye
« Reply #1 on: February 20, 2011, 06:29:07 am »
You are close, but not quite right! (as you've probably figured!)

You need to add an int to your union, and keep your struct as you have already.

Ala

Code: [Select]
union light_union {
  int x;
  struct light bits;
} Lights;

You can then access x as you desire, and the magic of the union will set the bits broadside as you desire, likewise read them back.

If you want change a bit, use

Code: [Select]
Lights.bits.light0 = 1; (or 0)
 

Offline LanceTopic starter

  • Frequent Contributor
  • **
  • Posts: 317
  • Country: 00
  • Resistance if futile if R<1Ohm
Re: Making A Cylon Eye
« Reply #2 on: February 20, 2011, 06:37:27 am »
You are close, but not quite right! (as you've probably figured!)

You need to add an int to your union, and keep your struct as you have already.

Ala

Code: [Select]
union light_union {
  int x;
  struct light bits;
} Lights;

You can then access x as you desire, and the magic of the union will set the bits broadside as you desire, likewise read them back.

If you want change a bit, use

Code: [Select]
Lights.bits.light0 = 1; (or 0)

I see. Could you please explain to me why this is necessary?
#include "main.h"
//#include <killallhumans.h>
 

Offline RayJones

  • Frequent Contributor
  • **
  • Posts: 490
    • Personal Website
Re: Making A Cylon Eye
« Reply #3 on: February 20, 2011, 06:39:23 am »
BTW, I've been coding for far too long, and still the union caught me with my pants down the other day.

I knew what I wanted to achieve, but still made minced meat of it.  :'(

The secret is each line in the union specifies a element, the largest element determines the end size of the union (space used in memory).
Other elements will occupy the same memory space, but be interpreted according to their type, ie a bit field in your application.

Other tricks could be

Code: [Select]
union {
  int AsInt;
  float AsFloat;
}

This allows you to write a float value, then grab the byte form equivalent for transfer/storage.

When digging down to byte level though you need to be careful of the endian order of your processor as to where the LSB lives in memory for a 16 or 32 bit value.

My personal fave is

Code: [Select]
union {
  int Word;
  struct {
     char LSB;
     char MSB;
  } bytes;
}

This is used to rip a 16 bit value into the HIWORD/LOWORD far more efficiently than the typical mask and shift operations used.
Once again, take care with the endianess of your processor.
 

Offline RayJones

  • Frequent Contributor
  • **
  • Posts: 490
    • Personal Website
Re: Making A Cylon Eye
« Reply #4 on: February 20, 2011, 06:44:32 am »
I should also add, using int is processor specific as to how many bits it is.

The native register size of the processor is usually adopted.

ie for a 16 bit processor, ints will be 16 bits, likewise 32 bits for a 32 bit processor.
to control the sizes better, you should use shorts or longs (16 or 32)
char is invariably 8 bits, but not always!

Having said this, you should realise my examples above are flawed, instead of int I should use long in the float example, and short in the HIWORD/LOWORD example.
« Last Edit: February 20, 2011, 06:47:09 am by RayJones »
 

Offline LanceTopic starter

  • Frequent Contributor
  • **
  • Posts: 317
  • Country: 00
  • Resistance if futile if R<1Ohm
Re: Making A Cylon Eye
« Reply #5 on: February 20, 2011, 06:51:15 am »
Yeah, and for my specific program the x should be an unsigned integer. Well then, now I just need to make the shift logic work.

If I remember correctly it should go something like this:

Code: [Select]
var<<var;

If I want to shift bits one to the left.
#include "main.h"
//#include <killallhumans.h>
 

Offline RayJones

  • Frequent Contributor
  • **
  • Posts: 490
    • Personal Website
Re: Making A Cylon Eye
« Reply #6 on: February 20, 2011, 06:53:10 am »
Actually, I should have used unsigned char in the first answer.

This would be an unsigned 8 bit value - which is the same size as your structure.

When it comes to bit fields, they have been a traditional sore point in compilers of old, hopefully better now, especially when some processors have bit wise opcodes built in.
Also I'd suspect a lot of compliers would only be happy with an "int : X" specification (or "unsigned int : X")

Hopefully you now have a bitt more knowledge to get the job done, but it may take a while for the details to settle in the brain.
The combination of bit fields and unions is indeed pretty ambitious - many points for trying  :)

 

Offline RayJones

  • Frequent Contributor
  • **
  • Posts: 490
    • Personal Website
Re: Making A Cylon Eye
« Reply #7 on: February 20, 2011, 06:54:45 am »
Yeah, and for my specific program the x should be an unsigned integer. Well then, now I just need to make the shift logic work.

If I remember correctly it should go something like this:

Code: [Select]
var<<var;

If I want to shift bits one to the left.

No,

use

Code: [Select]
var<<1;

your example would shift the bits by whatever value var was - definitely not what you want  ;)
 

Offline LanceTopic starter

  • Frequent Contributor
  • **
  • Posts: 317
  • Country: 00
  • Resistance if futile if R<1Ohm
Re: Making A Cylon Eye
« Reply #8 on: February 20, 2011, 07:02:44 am »
Yeah, and for my specific program the x should be an unsigned integer. Well then, now I just need to make the shift logic work.

If I remember correctly it should go something like this:

Code: [Select]
var<<var;

If I want to shift bits one to the left.

No,

use

Code: [Select]
var<<1;

your example would shift the bits by whatever value var was - definitely not what you want  ;)
Yeah, that didn't work out to well for me. On the plus side between that failure and your reply I made a little binary counter. It's all red and pretty.

I tried what you suggested, and it's currently content to sit there with the first light on:

Code: [Select]
if(first)
{
Lights.x=0x01;
first=0;
}

Lights.x<<1;
for(i=0;i<10000;i++)
{

}

It's like it's not even shifting...
#include "main.h"
//#include <killallhumans.h>
 

Offline RayJones

  • Frequent Contributor
  • **
  • Posts: 490
    • Personal Website
Re: Making A Cylon Eye
« Reply #9 on: February 20, 2011, 07:04:17 am »
Actually, if you do the right shift, you will see the difference between unsigned and signed chars:

If var is a signed char (normal char) and you you start with the MSB set (ie -ve value), you will propagate the MSB to the right using var>>1;
eg (char)0x80 >> 1 = 0xc0;

If var is unsigned char, it will work as you expect, a zero being shifted into the MSB
eg (unsigned char)0x80 >> 1 = 0x40;

Your simple cylon eye has plenty of "traps for young players" (and old ones too)

Will your cylon look like Tricia Helfer(#6) or Alessandra Toressani (Zoe Graystone)?
 

Offline RayJones

  • Frequent Contributor
  • **
  • Posts: 490
    • Personal Website
Re: Making A Cylon Eye
« Reply #10 on: February 20, 2011, 07:07:13 am »

I tried what you suggested, and it's currently content to sit there with the first light on:

Code: [Select]
if(first)
{
Lights.x=0x01;
first=0;
}

Lights.x<<1;
for(i=0;i<10000;i++)
{

}

It's like it's not even shifting...

You are only manipulating the internal memory.
To change the LEDs you will need to write to the port with the new X value....
 

Offline LanceTopic starter

  • Frequent Contributor
  • **
  • Posts: 317
  • Country: 00
  • Resistance if futile if R<1Ohm
Re: Making A Cylon Eye
« Reply #11 on: February 20, 2011, 07:15:47 am »
Actually, if you do the right shift, you will see the difference between unsigned and signed chars:

If var is a signed char (normal char) and you you start with the MSB set (ie -ve value), you will propagate the MSB to the right using var>>1;
eg (char)0x80 >> 1 = 0xc0;

If var is unsigned char, it will work as you expect, a zero being shifted into the MSB
eg (unsigned char)0x80 >> 1 = 0x40;

Your simple cylon eye has plenty of "traps for young players" (and old ones too)

Will your cylon look like Tricia Helfer(#6) or Alessandra Toressani (Zoe Graystone)?
I wish.

It's gonna look more like this:


I know I have to set the ports, I omitted that part of the code. Incidentally it's still not working:

Code: [Select]
union light_union
{
unsigned int x;
struct light bits;
} Lights;


if(!first)
{
Lights.x=0x01;
first=1;
}

Lights.x>>1;
for(i=0;i<6000;i++)
{

}

As usual it sits there with the first light on. I checked to make sure it wasn't running through the if(first) statement, and it's not. Oh, and the variables I'm working with are unsigned integers.

EDIT: I GOT IT!

Lights.x=Lights.x<<1;

That's how it should be! The bit shift is an operation like addition or subtraction. It was doing the calculation, just not storing the result anywhere.
« Last Edit: February 20, 2011, 07:20:47 am by Lance »
#include "main.h"
//#include <killallhumans.h>
 

Offline RayJones

  • Frequent Contributor
  • **
  • Posts: 490
    • Personal Website
Re: Making A Cylon Eye
« Reply #12 on: February 20, 2011, 07:22:50 am »
Yeah not as sexy as the on screen models!

First off, change to an unsigned char. I presume you are accessing an 8 bit port?

As stated earlier, this will always correctly line up with your structure's internal memory representation.

There is always the possibility that the bit fields and union used in conjunction are conspiring against you, as I alluded to earlier.
Can your compiler give you ASM code for what it has generated, and does that gel with your intents?

 

Offline LanceTopic starter

  • Frequent Contributor
  • **
  • Posts: 317
  • Country: 00
  • Resistance if futile if R<1Ohm
Re: Making A Cylon Eye
« Reply #13 on: February 20, 2011, 07:28:54 am »
Yeah not as sexy as the on screen models!

First off, change to an unsigned char. I presume you are accessing an 8 bit port?

As stated earlier, this will always correctly line up with your structure's internal memory representation.

There is always the possibility that the bit fields and union used in conjunction are conspiring against you, as I alluded to earlier.
Can your compiler give you ASM code for what it has generated, and does that gel with your intents?


It's an 8 bit port. I'm using a PIC16F917. I'm not sure if my compiler can export assembly, how to do such a thing, and I don't really want to at this moment. I don't know assembly. Although I would like to learn. I just don't have the spare time now.

I guess you must have missed the edit, but it's working now. It's all red and pretty and does not want to kill all humans. Thanks for the help!

Code: [Select]
/******************************************************************************
Header Includes
******************************************************************************/
#include "main.h"
#include <pic.h>
//#include <pic16f917.h>
#include <killallhumans.h>
Oops...
« Last Edit: February 20, 2011, 08:35:15 pm by Lance »
#include "main.h"
//#include <killallhumans.h>
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf