Author Topic: Atmega bit shifting  (Read 8866 times)

0 Members and 1 Guest are viewing this topic.

Offline yalectTopic starter

  • Regular Contributor
  • *
  • Posts: 123
Atmega bit shifting
« on: December 30, 2017, 07:24:20 am »
Hello,
I would like to ask you that I want make program shift bits to the right or the left I found one but my query is to shift bits 8 time the program shift bits one time I don't know why this is my example :
void main() {
int bits = 100, count, DATA;
    DDRC |= 0xff;

  while(1)
 {

  for (count = 0; count < 8; count++);
 
  {
  DATA |=(bits >> count);/* shift right, then mask bottom bit*/

      PORTC |= DATA;
      Delay_ms(3000);

       }
      }
      }
« Last Edit: December 30, 2017, 09:12:26 am by yalect »
 

Offline sleemanj

  • Super Contributor
  • ***
  • Posts: 3024
  • Country: nz
  • Professional tightwad.
    • The electronics hobby components I sell.
Re: Atmega bit shifting
« Reply #1 on: December 30, 2017, 08:30:17 am »
Your english is confusing as to exactly what you are trying to achieve, but I think your problem is ` >> count ` should be ` >> 1 `
~~~
EEVBlog Members - get yourself 10% discount off all my electronic components for sale just use the Buy Direct links and use Coupon Code "eevblog" during checkout.  Shipping from New Zealand, international orders welcome :-)
 
The following users thanked this post: djacobow

Offline yalectTopic starter

  • Regular Contributor
  • *
  • Posts: 123
Re: Atmega bit shifting
« Reply #2 on: December 30, 2017, 09:10:34 am »
Hello,
sorry, really that was an error I modified the program I want to shift bits 8 times not one time as it does
void main() {
int bits = 100, count, DATA;
    DDRC |= 0xff;

  while(1)
 {

  for (count = 0; count < 8; count++);

  {
  DATA |=(bits >> 1);/*shift right, then mask bottom bit*/

      PORTC |= DATA;
      Delay_ms(3000);

       }
      }
      }
 

Offline Bruce Abbott

  • Frequent Contributor
  • **
  • Posts: 627
  • Country: nz
    • Bruce Abbott's R/C Models and Electronics
Re: Atmega bit shifting
« Reply #3 on: December 30, 2017, 09:54:53 am »
There are several mistakes in your code:-

Code: [Select]
for (count = 0; count < 8; count++);
In C a semicolon terminates a statement, so this line does nothing except count from 0 to 7.

Code: [Select]
int bits = 100 ... // binary 0011 0000 0011 1001
Binary 0011000000111001 = decimal 1234, not 100. If a comment doesn't match the code it's worse than useless!

Code: [Select]
    DDRC |= 0xff;
    ...
    DATA |=(bits >> count);// shift right, then mask bottom bit
    ...
    PORTC |= DATA;

The '|=' operator means '(bitwise)OR equals', not 'equals'. 

And again the comment doesn't match the code. Nothing is 'masking the bottom bit'.

Here is what I think you actually wanted:-

Code: [Select]
void main()
{
  int bits = 100; // = binary number 00000000 01100100
  int count, DATA;
  DDRC = 0xff;
  while(1)
  {
    for (count = 0; count < 8; count++)
    {
      DATA = (bits >> count);  // output = number shifted right * count
      PORTC = DATA;
      Delay_ms(3000);
    }
  }
}
 

Offline yalectTopic starter

  • Regular Contributor
  • *
  • Posts: 123
Re: Atmega bit shifting
« Reply #4 on: December 30, 2017, 10:39:15 am »
Thank you Bruce
you mean that program will shift the bits to the right 8 times and make the bits or the byte on the PORTC each time (because my Porgram I Post, it shift the bits one time and make them on PORTC), what if we replace count with 1, and write then DATA =(bits >> 1), it will work?
Thank you
 

Offline Nusa

  • Super Contributor
  • ***
  • Posts: 2416
  • Country: us
Re: Atmega bit shifting
« Reply #5 on: December 30, 2017, 11:28:42 am »
I recognize those now-disconnected comments from a code sample I gave you in another of your threads. https://www.eevblog.com/forum/microcontrollers/pin-to-send-data/msg1383938/#msg1383938

Your problems with this seem to be at a very basic level. Try reading and understanding this: https://en.wikipedia.org/wiki/Bitwise_operations_in_C. There are many tutorials out there if that's not enough.
 

Offline Bruce Abbott

  • Frequent Contributor
  • **
  • Posts: 627
  • Country: nz
    • Bruce Abbott's R/C Models and Electronics
Re: Atmega bit shifting
« Reply #6 on: December 30, 2017, 06:59:56 pm »
what if we replace count with 1, and write then DATA =(bits >> 1), it will work?
No. If you do this then then DATA will always be 'bits' shifted right by 1, and the output will be a stationary bit pattern.

Assuming you want the bits to 'scroll' across the output pins, there are two ways to do it:-

1. Always calculate DATA from the original number, with 'count' being the amount of shift required. The first time through the loop 'count' = 0 so there is no shift, second time shifted right 1 place, 3rd time 2 places etc. The value of DATA is regenerated each time.  This is how my code works.

2. Load the number into DATA, then shift it right 1 place each time through the loop (after outputting it). So DATA holds the next value to be output, and gets progressively shifted right. Do do this you need to make the following changes:-

Code: [Select]
    DATA = bits;    // load number into DATA _before_ entering the loop
    for (count = 0; count < 8; count++)
    {
      PORTC = DATA;        // output current contents of DATA
      DATA = (DATA >> 1);  // shift DATA right * 1 (will be output next time through the loop)
      Delay_ms(3000);
    }
  }

Method 2 is slightly more efficient on the ATmega because it doesn't have a barrel shifter, so shifting by more than 1 place has to be implemented as multiple 1 bit shifts.

 
 

Online rstofer

  • Super Contributor
  • ***
  • Posts: 9889
  • Country: us
Re: Atmega bit shifting
« Reply #7 on: December 31, 2017, 04:12:17 pm »
Or, you can use the C switch statement inside the for () and not even mess with shifting.

Code: [Select]
for (i = 0; i < 8; i++) {
     switch(i) {
        case 0 : PORTC = 0x01;
                     break;
        case 1 : PORTC = 0x02;
                     break;
        ...
        case 7 : PORTC = 0x80;
                     break;
        default : break;
      }
      delay(3000);
}

Clean and straightforward.
 

Offline phil from seattle

  • Super Contributor
  • ***
  • Posts: 1029
  • Country: us
Re: Atmega bit shifting
« Reply #8 on: December 31, 2017, 05:15:55 pm »
For a lot less code (at least, C code).
Code: [Select]
uint8_t bitmap[8] = { 0x1,0x2,0x4,0x8,0x10,0x20,0x40,0x80};

for(i=0;i<8;i++){
    PORTC = bitmap[i];
//  PORTC = 1<<i;  // as an alternative, which ever gens the least code.
}
not sure the point of that sequence, though.
« Last Edit: December 31, 2017, 05:29:20 pm by phil from seattle »
 

Offline Bruce Abbott

  • Frequent Contributor
  • **
  • Posts: 627
  • Country: nz
    • Bruce Abbott's R/C Models and Electronics
Re: Atmega bit shifting
« Reply #9 on: January 01, 2018, 06:34:34 am »
Total code size with the algorithms presented so far (GCC 4.3.2 optimization level 0s):-

My algo #1,
Code: [Select]
    for (count = 0; count < 8; count++)
    {
      DATA = (bits >> count);// shift right * count
      PORTC = DATA;
    }
104 bytes

My algo #2,
Code: [Select]
for (count = 0; count < 8; count++)
    {
      PORTC = DATA;        // output current contents of DATA
      DATA = (DATA >> 1);  // shift DATA right * 1 (will be output next time through the loop)
    }
94 bytes

rstofer,
Code: [Select]
for (count = 0; count < 8; count++) {
     switch(count) {
        case 0 : PORTC = 0x01;
                     break;
        case 2 : PORTC = 0x02;
                     break;
        case 3 : PORTC = 0x04;
                     break;
        case 4 : PORTC = 0x08;
                     break;
        case 5 : PORTC = 0x10;
                     break;
        case 6 : PORTC = 0x40;
                     break;
        case 7 : PORTC = 0x80;
                     break;
        default : break;
      }
}
174 bytes

phil from seattle #1,
Code: [Select]
uint8_t bitmap[8] = { 0x1,0x2,0x4,0x8,0x10,0x20,0x40,0x80};

for(count=0;count<8;count++){
    PORTC = bitmap[count];
}
156 bytes

phil from seattle #2,
Code: [Select]
for(count=0;count<8;count++){
    PORTC = 1<<count; 
}
104 bytes

However, neither rstofer's nor phil from seattle's code does what is required, which is shifting an arbitrary bit pattern (eg. 1100100 or 11000000111001) progressively right. The case statements or array contents could be adjusted to suit a particular bit pattern, but modifying all those 'magic numbers' would be time-consuming and easy to mess up.

Burying a shift operation in case statements or array elements are examples of 'tricky' coding that should be avoided.  Unless you desperately need the fastest possible execution and/or smallest footprint, programs should be written for readability and understanding first, then optimized only if necessary. If shifting right is what you want to do, use the >> operator. Don't be afraid to use intermediate variables, spread statements over several lines, or break complex code up into simpler functions which make your intention clearer and the code easier to expand or modify. Avoid 'magic' numbers. Let the compiler take care of optimizing your code.
   
 
 

Offline Bruce Abbott

  • Frequent Contributor
  • **
  • Posts: 627
  • Country: nz
    • Bruce Abbott's R/C Models and Electronics
Re: Atmega bit shifting
« Reply #10 on: January 01, 2018, 06:46:29 am »
The case statements or array contents could be adjusted to suit a particular bit pattern, but modifying all those 'magic numbers' would be time-consuming and easy to mess up.
And as an example of 'messing up', in copy/pasting I missed a case statement!

The correct rstofer code is:-
Code: [Select]
for (count = 0; count < 8; count++) {
     switch(count) {
        case 0 : PORTC = 0x01;
                     break;
        case 1 : PORTC = 0x02;
                     break;
        case 2 : PORTC = 0x04;
                     break;
        case 3 : PORTC = 0x08;
                     break;
        case 4 : PORTC = 0x10;
                     break;
        case 5 : PORTC = 0x20;
                     break;
        case 6 : PORTC = 0x40;
                     break;
        case 7 : PORTC = 0x80;
                     break;
        default : break;
      }
  }
which increased total code size to 182 bytes.

 

Offline phil from seattle

  • Super Contributor
  • ***
  • Posts: 1029
  • Country: us
Re: Atmega bit shifting
« Reply #11 on: January 01, 2018, 04:52:00 pm »
...
Burying a shift operation in case statements or array elements are examples of 'tricky' coding that should be avoided.  Unless you desperately need the fastest possible execution and/or smallest footprint, programs should be written for readability and understanding first, then optimized only if necessary. If shifting right is what you want to do, use the >> operator. Don't be afraid to use intermediate variables, spread statements over several lines, or break complex code up into simpler functions which make your intention clearer and the code easier to expand or modify. Avoid 'magic' numbers. Let the compiler take care of optimizing your code.
   

I was simply responding to the prior posting with case statements. The code is nonsense because it just pumps changing bits out a data port with no explicit timing.

I disagree with your assessment of the coding style. Data driven schemes are perfectly fine and quite understandable to someone moderately skilled in programming and able to hold a couple of simultaneous thoughts in their head. It's a staple of FSMs. One could argue that bit shifting is equally confusing. I suppose you are against the use of pointers, subclassing, virtual functions and so on. In addition, comments should be placed to make it clear what's going on.

And, I don't disagree with "let the compiler optimize" sentiment but too many hack programmers don't understand that they need to get the algorithm right first.  Let the optimizer take care of allocating registers and such.
 

Offline Bruce Abbott

  • Frequent Contributor
  • **
  • Posts: 627
  • Country: nz
    • Bruce Abbott's R/C Models and Electronics
Re: Atmega bit shifting
« Reply #12 on: January 03, 2018, 08:46:36 am »
I was simply responding to the prior posting with case statements
Fair enough.

Quote
One could argue that bit shifting is equally confusing.
When the intention is to shift bits? I think not.

Where bit shifting would be confusing is when you really wanted to (for example) divide a number by 2. Perhaps in that case a bit shift operation would be more efficient, but you should write the code you want and let the compiler decide how to implement it

Quote
I suppose you are against the use of pointers,
Pointers are an abomination!

 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3140
  • Country: ca
Re: Atmega bit shifting
« Reply #13 on: January 04, 2018, 05:58:43 am »
The correct rstofer code is:-
Code: [Select]
for (count = 0; count < 8; count++) {
     switch(count) {
        case 0 : PORTC = 0x01;
                     break;
        case 1 : PORTC = 0x02;
                     break;
        case 2 : PORTC = 0x04;
                     break;
        case 3 : PORTC = 0x08;
                     break;
        case 4 : PORTC = 0x10;
                     break;
        case 5 : PORTC = 0x20;
                     break;
        case 6 : PORTC = 0x40;
                     break;
        case 7 : PORTC = 0x80;
                     break;
        default : break;
      }
  }

Even The Queen couldn't make the code more complicated. This is equivalent to:

Code: [Select]
PORTC = 0x01;
PORTC = 0x02;
PORTC = 0x04;
PORTC = 0x08;
PORTC = 0x10;
PORTC = 0x20;
PORTC = 0x40;
PORTC = 0x80;
 

Offline yalectTopic starter

  • Regular Contributor
  • *
  • Posts: 123
Re: Atmega bit shifting
« Reply #14 on: January 04, 2018, 06:01:35 pm »
Thank you Bruce
talking about shifting to the right if we take state of bit for Var within the program let's say bits if we want to read it we will make & operation or mask it so I wrote this program to detect state of that bit 1 or 0 with PIND0 and 1 of PORTD but the program didn't work well as I expected might I don't understand how it works if we  shift right number 100 my result was (for detecting the first bit of bits) :
**************************************************
Number shifted  *  1st bit  *   detected bit
***************************************
11100100      *          0       *       1
00110010      *          0       *       0
00011001      *          1       *       0
00001100      *          0       *       1
00000110      *          0       *       0
00000011      *          1       *       0
00000001      *          1       *       1
********************************************
it doesn't make sense?!

void main() {
  int bits = 100;
  int compare = 0x0000001;
  int count, DATA;
  DDRC = 0xff;
  DDRD = (1<< PIND0);
  DDRD = (1<< PIND1);
  while(1)
  {
    for (count = 0; count < 8; count++)
    {
      DATA = (bits >> count);  // output = number shifted right * count
      PORTC = DATA;
      Delay_ms(1000);
      if ((bits >> count) & compare)
     {
     PORTD = (1<< PIND0);
     }
     else
    {
     PORTD = (1<< PIND1);
     }
    }

  }
}
maybe you have an Idea?
thank you
« Last Edit: January 04, 2018, 06:04:56 pm by yalect »
 

Offline Nusa

  • Super Contributor
  • ***
  • Posts: 2416
  • Country: us
Re: Atmega bit shifting
« Reply #15 on: January 04, 2018, 06:49:23 pm »
Off by one. Try moving your delay to the bottom of the for loop so the port C and D results happen at the same time.
 

Online rstofer

  • Super Contributor
  • ***
  • Posts: 9889
  • Country: us
Re: Atmega bit shifting
« Reply #16 on: January 04, 2018, 10:15:45 pm »
The case statements or array contents could be adjusted to suit a particular bit pattern, but modifying all those 'magic numbers' would be time-consuming and easy to mess up.
And as an example of 'messing up', in copy/pasting I missed a case statement!

The correct rstofer code is:-
Code: [Select]
for (count = 0; count < 8; count++) {
     switch(count) {
        case 0 : PORTC = 0x01;
                     break;
        case 1 : PORTC = 0x02;
                     break;
        case 2 : PORTC = 0x04;
                     break;
        case 3 : PORTC = 0x08;
                     break;
        case 4 : PORTC = 0x10;
                     break;
        case 5 : PORTC = 0x20;
                     break;
        case 6 : PORTC = 0x40;
                     break;
        case 7 : PORTC = 0x80;
                     break;
        default : break;
      }
  }
which increased total code size to 182 bytes.

No it isn't and this leads to another claimed error as the code not having a delay.  My original code had a delay at the bottom of the 'for' loop.

It's one thing to count emitted code, it's another to count cycles actually taken.  Both the table lookup and the case statement take consistent time to execute (and the table is better,  by far!) while m >> n takes n shifts because the Atmega doesn't have a barrel shifter and both m and n are arbitrary (presumably).  All the compiler can do is emit looping code over a single shift.  That may be just the right solution!  Or not...

I thought the original problem was to display some kind of pattern on the output.  If that's not true then the case statement might be a poor choice.  OTOH, if the output is more or less random depending on the count (and it's hard to tell from the original code) then a case statement is ideal.  There need be no relationship between outputs of successive cases.  The case statement also allows for feature creep.  When count = 3, for example. Maybe when that pattern comes up I need to launch an internet connection.  Who knows?

I CHOSE a right-to-left pattern.  It could have been left-to-right or it could have been any other pattern.  Maybe I want 2,3,5,7,11,13,17,19 - the first 8 prime numbers.  It's a little awkward to do with >>.

The case statement doesn't have to be inside a for loop.  It could be some kind of state machine with very little effort.  A super loop and a state variable is all it takes.

But if the goal is actually m >> n, just say so.  The compiler knows full well how to implement this.

« Last Edit: January 04, 2018, 10:24:44 pm by rstofer »
 

Offline NivagSwerdna

  • Super Contributor
  • ***
  • Posts: 2495
  • Country: gb
Re: Atmega bit shifting
« Reply #17 on: January 04, 2018, 10:37:01 pm »
but my query is to shift bits 8 time the program shift bits one time
I'm a bit late to the party but the OP's question was how to shift 8 bits at a time.

unsigned long bigNumber = 0xAABBCCDD;
 
  byte lsb;
 
  lsb = bigNumber & 0xff;
  Serial.println(lsb,HEX);
 
  bigNumber >>= 8;
  lsb = bigNumber & 0xff;
  Serial.println(lsb,HEX);

  bigNumber >>= 8;
  lsb = bigNumber & 0xff;
  Serial.println(lsb,HEX);

  bigNumber >>= 8;
  lsb = bigNumber & 0xff;
  Serial.println(lsb,HEX);

DD
CC
BB
AA


 

Online rstofer

  • Super Contributor
  • ***
  • Posts: 9889
  • Country: us
Re: Atmega bit shifting
« Reply #18 on: January 05, 2018, 02:13:02 am »
but my query is to shift bits 8 time the program shift bits one time
I'm a bit late to the party but the OP's question was how to shift 8 bits at a time.

If this is as simple as breaking up a 32 bit value into 8 bit bytes, there is no need to shift.  You can 'union' the 32 bit value with an array of 4 each 8-bit values and be done with it.

Code: [Select]
#include <stdio.h>
#include <stdint.h>

int main(void)
{
union {
uint32_t word;
uint8_t  bytes[4];
} u;

u.word = 0x11223344;

for (int i = 3; i >= 0; i--) {
printf("%4x\n",u.bytes[i]);
}
}

This prints
Code: [Select]
  11
  22
  33
  44

ETA:  To print the bytes LSB first, change the for loop:

Code: [Select]
for (int i = 0; i < 4; i++)

The printf() part stays the same.
« Last Edit: January 05, 2018, 02:54:11 am by rstofer »
 

Offline Bruce Abbott

  • Frequent Contributor
  • **
  • Posts: 627
  • Country: nz
    • Bruce Abbott's R/C Models and Electronics
Re: Atmega bit shifting
« Reply #19 on: January 05, 2018, 04:38:45 am »
I wrote this program to detect state of that bit 1 or 0 with PIND0 and 1 of PORTD but the program didn't work well as I expected might I don't understand how it works if we  shift right number 100 my result was (for detecting the first bit of bits) :
**************************************************
Number shifted  *  1st bit  *   detected bit
***************************************
11100100      *          0       *       1
00110010      *          0       *       0
00011001      *          1       *       0
00001100      *          0       *       1
00000110      *          0       *       0
00000011      *          1       *       0
00000001      *          1       *       1
********************************************
it doesn't make sense?!
I think your problem is here,
Code: [Select]
  DDRD = (1<< PIND0);
  DDRD = (1<< PIND1);
The first line makes only D0 an output and all other pins inputs. The second line makes only D1 an output and all others (including D0) inputs. The result is only D1 is an output.

To make both D0 and D1 outputs, do this:-
Code: [Select]
DDRD = (1<<PIND0)|(1<<PIND1); // D0 and D1 are outputs, all others inputsor this:-
Code: [Select]
DDRD = (1<<PIND0); // D0 is output, all others input
DDRD |=(1<<PIND1); // D1 is output, all others unchanged




 

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 2803
  • Country: nz
Re: Atmega bit shifting
« Reply #20 on: January 05, 2018, 10:42:54 am »
Although not of any importance in this case, one thing to be careful of when using I/O ports is that reading the value of a port does not always return the last value written to the Port's output registers, it reads the state of the port's input buffer.

This is especially tricky when masking off bits... "PORTD |= 1;" might end up clearing other bits in the output register as an unintended side effect.

All sorts of ugly problems lurk here - especially when you need to update ports during an interrupt, giving rise to all sorts of hard to debug race conditions.
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 

Online rstofer

  • Super Contributor
  • ***
  • Posts: 9889
  • Country: us
Re: Atmega bit shifting
« Reply #21 on: January 05, 2018, 05:56:22 pm »
Although not of any importance in this case, one thing to be careful of when using I/O ports is that reading the value of a port does not always return the last value written to the Port's output registers, it reads the state of the port's input buffer.

This is especially tricky when masking off bits... "PORTD |= 1;" might end up clearing other bits in the output register as an unintended side effect.

All sorts of ugly problems lurk here - especially when you need to update ports during an interrupt, giving rise to all sorts of hard to debug race conditions.

For some CPUs, it is better to keep a shadow copy of what has been sent to the register in a variable.  Manipulate the variable as desired and then send it to the port.  Never read-modify-write if you can avoid it.  Work from the shadow copy.

 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3140
  • Country: ca
Re: Atmega bit shifting
« Reply #22 on: January 05, 2018, 07:30:54 pm »
For some CPUs, it is better to keep a shadow copy of what has been sent to the register in a variable.  Manipulate the variable as desired and then send it to the port.  Never read-modify-write if you can avoid it.  Work from the shadow copy.

PICs have built-in shadow variables called LAT.
 

Online rstofer

  • Super Contributor
  • ***
  • Posts: 9889
  • Country: us
Re: Atmega bit shifting
« Reply #23 on: January 05, 2018, 08:56:16 pm »
For some CPUs, it is better to keep a shadow copy of what has been sent to the register in a variable.  Manipulate the variable as desired and then send it to the port.  Never read-modify-write if you can avoid it.  Work from the shadow copy.

PICs have built-in shadow variables called LAT.

Some do, the PIC 16F family does not.

Section 9.2 for example

http://ww1.microchip.com/downloads/en/devicedoc/33023a.pdf

The PIC 18 series does have the LAT registers.

Page 3-18 for example

http://ww1.microchip.com/downloads/en/DeviceDoc/39500a.pdf

This whole read-modify-write issue really started with the PIC 16 series (AFAIK).  It was corrected in the PIC 18 series.  It is important to read the datasheet to find out what side effects a read-modify-write will cause.  It is not wise to just assume that you are reading the latch when, in fact, you are reading the pin.

 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3140
  • Country: ca
Re: Atmega bit shifting
« Reply #24 on: January 05, 2018, 11:19:16 pm »
Some do, the PIC 16F family does not.

Most of PIC16Fs do. The ones without LATs are old, obsolete, overpriced and, in addition to missing LATs, have lots of other problems. These are better forgotten. Newer PIC16s (the part numbers starting from PIC16F1) not only have LAT but they have lots of serious improvements. Not to mention they're much cheaper.
 

Offline yalectTopic starter

  • Regular Contributor
  • *
  • Posts: 123
Re: Atmega bit shifting
« Reply #25 on: January 14, 2018, 12:42:28 pm »
Hello,
thank you for your reply
I made this modification for my program where it makes checking for first bit status if it's 1 PIND0 = 1 if it's 0 PIND1 = 1 but it doesn't work well where it works for first bit status of 0 or PIND1 = 1 only, maybe you have an Idea.
 void main() {
  int bits = 100;
  int compare = 0x00000001;
  int count, DATA,
  DDRC = 0xff;
  DDRD = (1<<PIND0)|(1<<PIND1);
  while(1)
  {
    for (count = 0; count < 8; count++)
    {
      DATA = (bits >> count);  // output = number shifted right * count
      PORTC = DATA;
      if( DATA & compare)
     {
     PORTD = (1<< PIND0);
     }
     else
    {
     PORTD = (1<< PIND1);
     }

     Delay_ms(1000);
    }
 }
}

thank you
 

Online rstofer

  • Super Contributor
  • ***
  • Posts: 9889
  • Country: us
Re: Atmega bit shifting
« Reply #26 on: January 14, 2018, 04:10:00 pm »
All of your variables are 8 bit quantities living in at least a 16 bit data type. 

From the declaration of 'compare', it seems like you are using a 32 bit CPU yet the ports are 8 bits.  I'm confused...  What processor are you using?

I would declare all the variables as 8 bit unsigned values.  Either as uint8_t or unsigned char.  I prefer uint8_t.

There is a missing ; after DATA in the declaration

Code: [Select]
int main(void)
{
  uint8_t bits = 0b01100100;          //use an unsigned 8 bit data type
  unsigned char compare = 0b00000001; // another style of unsigned 8 bit data type
  uint8_t count, data;

  DDRC = 0xff;
  DDRD = (1 << PIND0) | (1 << PIND1);  // see below re: PIND0 and PIND1

  while(1)
  {
    for (count = 0; count < 8; count++)
    {
      data = (bits >> count);
      PORTC = data;
      if (data & compare)
      {
        // I don't know how PIND0 and PIND1 are defined.
        // If they are defined as a mask instead of a count,
        // we should probably use something like:
        // PORTD = (1 << 0);
        // and
        // PORTD = (1 << 1);
        PORTD = (1 << PIND0);
      }
      else
      {
        PORTD = (1 << PIND1);
      }
      // Delay_ms(1000); // not declared in my Arduino setup
    }
  }
  return 0; // never returns but keep the compiler happy
}

I have no way to test the code, I don't know what processor you are using.  It does compile...

I am really unclear on how PIND0 and PIND1 are defined.  Your code doesn't mention a header file and I probably don't have it anyway.  If PIND1 is a mask like 0b00000010 instead of a count like 0b00000001 then the output will be in the wrong bit position.

You will need to remove the // in front of Delay_ms().
« Last Edit: January 14, 2018, 04:19:35 pm by rstofer »
 

Offline yalectTopic starter

  • Regular Contributor
  • *
  • Posts: 123
Re: Atmega bit shifting
« Reply #27 on: January 14, 2018, 06:21:18 pm »
thank you
yes, I simulated that code with Proteus simulation software and it works normally as I said the problem it's not checking state of 1 for first bit or PIND0 not working.
thank you
 

Online rstofer

  • Super Contributor
  • ***
  • Posts: 9889
  • Country: us
Re: Atmega bit shifting
« Reply #28 on: January 14, 2018, 06:41:44 pm »
Written for the Arduino UNO, the code looks like this:

Code: [Select]
void setup() {
DDRC = 0xff;
DDRD = (1 << PIND0) | (1 << PIND1);
}

void loop() {
uint8_t bits = 0b01100100;          //use an unsigned 8 bit data type
unsigned char compare = 0b00000001; // another style of unsigned 8 bit data type
uint8_t count, data;

for (count = 0; count < 8; count++)
{
data = (bits >> count);
PORTC = data;
if (data & compare)
{
PORTD = (1 << PIND0);
}
else
{
PORTD = (1 << PIND1);
}
delay(1000);
}
}

I can watch PORTD and it does something reasonable but PORTC isn't complete and I didn't bother to try to watch it.  A project for the reader...

This was tested using the vMicro plug-in to Microsoft Visual Studio Community Edition.

The definitions for PIND0 and PIND1 are fine.

 

Online rstofer

  • Super Contributor
  • ***
  • Posts: 9889
  • Country: us
Re: Atmega bit shifting
« Reply #29 on: January 14, 2018, 06:56:36 pm »
thank you
yes, I simulated that code with Proteus simulation software and it works normally as I said the problem it's not checking state of 1 for first bit or PIND0 not working.
thank you

Simulation isn't hardware and, in my view, cheap hardware and an oscilloscope (or even LEDs) are better.  PORTC isn't completely available on the Arduino UNO but it is available on the Arduino Mega 2560.  On the UNO, only bits 0..5 are available.

Don't overlook the possibility that the simulator has more problems than the code.
 

Online rstofer

  • Super Contributor
  • ***
  • Posts: 9889
  • Country: us
Re: Atmega bit shifting
« Reply #30 on: January 14, 2018, 09:32:07 pm »
If you were expecting to see the very first bit in PIND0 or PIND1, you won't.  You have shifted bits before you got that far in your code.  You can do the output first and then the shift, something like this.

Code: [Select]
void setup() {
 DDRC = 0xff;
 DDRD = (1 << PIND0) | (1 << PIND1);
}

void loop() {
 uint8_t bits = 0b01100100;          //use an unsigned 8 bit data type
 unsigned char compare = 0b00000001; // another style of unsigned 8 bit data type
 uint8_t count, data;
 
 data = bits;   // set up the initial value in 'data'
 for (count = 1; count < 8; count++)  // we will already see the zeroth pattern
 {
  PORTC = data;  // send data to output
  if (data & compare)  // set up least significant bit
  {
   PORTD = (1 << PIND0);
  }
  else
  {
   PORTD = (1 << PIND1);
  }
  delay(1000);             // let the user see the pattern
  data = (bits >> count);  // finally, shift the pattern
 }
}

You can clever up the for statement to include initializing data:
Code: [Select]
for (data = bits, count = 1; count < 8; count++)
« Last Edit: January 14, 2018, 09:40:42 pm by rstofer »
 

Offline Nusa

  • Super Contributor
  • ***
  • Posts: 2416
  • Country: us
Re: Atmega bit shifting
« Reply #31 on: January 14, 2018, 10:00:46 pm »
Ok, I pulled out real hardware (Atmega328p uno board) and tried it. I'm using the Arduino IDE found at www.arduino.cc . I've never even looked at Protuse, so ask me no questions about that.

First off, the comma instead of a semi-colon comes out as a compile error for me, because it results in an attempt to redefine DDRC. Fix that. I don't know why your environment doesn't flag it.

Second, the compiler wasn't happy with void main(), so I changed it to int main() as the easiest solution.

Third, I discovered what is probably your core problem. When you use a main() function (instead of the setup/loop functions this IDE prefers), YOU become responsible for hardware initialization. It's not done for you! Calling init() at the top of main() should do it. init() sets up the system timers, which is important for correct delay times. Also, which is quite important in this case, it disconnects TX and RX from the UART used to program the board. Those happen to be the two pins on port D you're using for the LED outputs!

Last, my uploads failed at first. I'd only used 220 ohm resistors on the LED's, and that was enough of a load to disrupt the UART communications. I was too lazy to switch resistors, so I just unplugged the LED's during the upload, then plugged them back in.

After that, the code worked as written.
 

Offline yalectTopic starter

  • Regular Contributor
  • *
  • Posts: 123
Re: Atmega bit shifting
« Reply #32 on: January 15, 2018, 10:04:18 am »
thank you
yes, if we try to realize that code with arduino we face that problems but my project not based on arduino but for using Atmega32 as processor with other base components so the problem it differs.
 

Offline Nusa

  • Super Contributor
  • ***
  • Posts: 2416
  • Country: us
Re: Atmega bit shifting
« Reply #33 on: January 15, 2018, 11:01:08 am »
Don't get hung up on the word Arduino. The hardware is not much more than a breakout board for the processor, regardless of which processor is actually implemented on a particular board.

Atmega32 is certainly part of the family, extremely similar to the Atmega328 in function. So much so that TX and RX are on the same pins of port D on both chips. They both have clocks that need initializing. If you have a UART on TX/RX, then that's the same too.

 

Online rstofer

  • Super Contributor
  • ***
  • Posts: 9889
  • Country: us
Re: Atmega bit shifting
« Reply #34 on: January 15, 2018, 04:40:07 pm »
The code I posted in Reply #28 should work for the ATmega32 - it doesn't presuppose the Arduino infrastructure.

No doubt there will need to be some #include statements to pull in header files but your code didn't show those.  The code in Reply #28 shifts before display so you might want to use the concepts in Reply #30 if you want to see the initial pattern before shifting.
 

Offline phil from seattle

  • Super Contributor
  • ***
  • Posts: 1029
  • Country: us
Re: Atmega bit shifting
« Reply #35 on: January 15, 2018, 05:41:47 pm »
First off, the comma instead of a semi-colon comes out as a compile error for me, because it results in an attempt to redefine DDRC. Fix that. I don't know why your environment doesn't flag it.

I believe that is legal C but not C++.  It's a bad coding style in general as it is easy to overlook when reading a for loop. Best to keep only for-loop related stuff in the for(;;) statement.
 

Online rstofer

  • Super Contributor
  • ***
  • Posts: 9889
  • Country: us
Re: Atmega bit shifting
« Reply #36 on: January 15, 2018, 07:06:17 pm »
First off, the comma instead of a semi-colon comes out as a compile error for me, because it results in an attempt to redefine DDRC. Fix that. I don't know why your environment doesn't flag it.

I believe that is legal C but not C++.  It's a bad coding style in general as it is easy to overlook when reading a for loop. Best to keep only for-loop related stuff in the for(;;) statement.

The semi-colon referenced by Nusa above was the one missing after the declaration of 'data'.  That definitely caused a compiler error.

I'm not real fond of the comma separator either.  That is actually the first and only time I have ever written it that way.  I don't tend to use the '? :' conditional pair either.  Nevertheless, they are valid C and if you are to know the language it is worth knowing that they exist.

I could make the argument that the comma separator in the for ( ; ; ) is good practice because it clearly shows what is initialized at the beginning of the loop.  I'm not sure I'll try...


« Last Edit: January 15, 2018, 08:59:17 pm by rstofer »
 

Offline phil from seattle

  • Super Contributor
  • ***
  • Posts: 1029
  • Country: us
Re: Atmega bit shifting
« Reply #37 on: January 15, 2018, 08:13:56 pm »
Man, I hate those emojis that inadvertently warp a programming language construct.
 

Online rstofer

  • Super Contributor
  • ***
  • Posts: 9889
  • Country: us
Re: Atmega bit shifting
« Reply #38 on: January 15, 2018, 09:00:01 pm »
Man, I hate those emojis that inadvertently warp a programming language construct.

I didn't notice that earlier.  Kind of a PITA.  Anyway, I had too many semicolons..
 

Offline Bruce Abbott

  • Frequent Contributor
  • **
  • Posts: 627
  • Country: nz
    • Bruce Abbott's R/C Models and Electronics
Re: Atmega bit shifting
« Reply #39 on: January 16, 2018, 06:30:42 am »
I made this modification for my program where it makes checking for first bit status if it's 1 PIND0 = 1 if it's 0 PIND1 = 1 but it doesn't work well where it works for first bit status of 0 or PIND1 = 1 only, maybe you have an Idea.
I changed the comma after DATA to a semicolon and compiled it with AVR GCC in Atmel Studio 4, then stepped through the code in the simulator.  As far as I can tell the code works perfectly (bit 0 is 0 so D1 goes high, bit 1 is 0 so D1 stays high, bit 2 is 1 so D1 goes low and D0 goes high etc.)
 

Offline yalectTopic starter

  • Regular Contributor
  • *
  • Posts: 123
Re: Atmega bit shifting
« Reply #40 on: January 16, 2018, 08:04:58 pm »
Hi,
thank you bruce
I want to ask that you just changed the comma after DATA to a semicolon from first program or you make other modifications and which simulator you are using?
thank you
 
 

Offline Bruce Abbott

  • Frequent Contributor
  • **
  • Posts: 627
  • Country: nz
    • Bruce Abbott's R/C Models and Electronics
Re: Atmega bit shifting
« Reply #41 on: January 17, 2018, 01:08:14 pm »
Hi,
thank you bruce
I want to ask that you just changed the comma after DATA to a semicolon from first program or you make other modifications and which simulator you are using?
thank you
No other changes apart from renaming Delay_ms to _delay_ms. Compiler was AVR GCC 4.3.3 and I used the AVR simulator that comes with Atmel Studio 4.
 

Offline paulca

  • Super Contributor
  • ***
  • Posts: 4032
  • Country: gb
Re: Atmega bit shifting
« Reply #42 on: January 17, 2018, 02:58:06 pm »
Slight off topic, but I had gave myself a challenge last night and almost got it working before I was too tired to solve the bug and had to go to bed.

Given an 8 bit byte print (serial) groups of bits whether 0 or 1.

Say for example the byte is an IC status register and you want to print something like:

Data Rate:  1001

When given the byte:

00010010

And the datasheet exert:

Bits   Purpose
===========
7-5: Status
4-1:  Data Rate
0:  Other Stuff

You want to just print:  1001
"What could possibly go wrong?"
Current Open Projects:  STM32F411RE+ESP32+TFT for home IoT (NoT) projects.  Child's advent xmas countdown toy.  Digital audio routing board.
 

Online rstofer

  • Super Contributor
  • ***
  • Posts: 9889
  • Country: us
Re: Atmega bit shifting
« Reply #43 on: January 17, 2018, 05:31:18 pm »
mask = 0b00010000 // mask the high order bit first
for bit = 0 to 3
  if (value & mask)
    print 1
  else
    print 0
  mask >>= 1 // mask the next lower bit
end for
 

Offline paulca

  • Super Contributor
  • ***
  • Posts: 4032
  • Country: gb
Re: Atmega bit shifting
« Reply #44 on: January 17, 2018, 06:17:32 pm »
Mine was a little more generic and ambitious, but flawed.  This is actually version two.

Code: [Select]
void printBits(byte myByte, byte mask){
  for(int pos = 7; pos >= 0; pos--){
 
    byte maskBit = (mask << pos);
    if( maskBit & 0x80 ) {     
        byte shifted = (myByte << pos);
     
        if( shifted & 0x80 ) {
          Serial.print('1');
        } else {
          Serial.print('0');
        }
     }
  }
}

Bizarrely it prints all the right bits and the right values, but in the wrong order.

So:
printBits( b10000000, b11100000 )
Prints: 001

As an academic I'm curious to figure out how to get it working.  As a practicallist/professional I am going to something different:

void printBit( byte theByte, int theBit ) {
    theByte >>= theBit;
    if( theByte & 0x1 ) {
       Serial.print("1")
    } else {
       Serial.print("0")
    }
}

I'm sure there is probably an arduino function for it.  There is an instruction to test a bit in register in AVR ASM.

Then call it multiple times.

It's less elegant and less pedantic, less formal and less smarty pants, but it's 100 times faster to write and 100 time easier to understand.  Get the job done.

EDIT: What kicked this off was trying to print a debug function which human readibly formats the contents of an ADC config register.
Code: [Select]
Config register: 10000101 10000011 = 1000010110000011
Status: 1
Multiplex: 000
PGA: 010
Mode: 1
Data Rate: 001
Comparator Mode: 0
Comparator Polarity: 0
Comparator latch: 0
Comparator queue: 11

You can see the bug.
« Last Edit: January 17, 2018, 06:24:08 pm by paulca »
"What could possibly go wrong?"
Current Open Projects:  STM32F411RE+ESP32+TFT for home IoT (NoT) projects.  Child's advent xmas countdown toy.  Digital audio routing board.
 

Online rstofer

  • Super Contributor
  • ***
  • Posts: 9889
  • Country: us
Re: Atmega bit shifting
« Reply #45 on: January 17, 2018, 06:50:49 pm »
Why wouldn't you use a set of bit fields in a struct?  You can then name the fields and deal with them as a normal entity.

https://docs.microsoft.com/en-us/cpp/c-language/c-bit-fields

https://www.geeksforgeeks.org/bit-fields-c/

That doesn't solve the printing of the bit fields in left to right order but my pseudo code above does that.  The only issue is that I assume a constant width of 4 bits and that isn't the right answer for variable width fields.
 

Online rstofer

  • Super Contributor
  • ***
  • Posts: 9889
  • Country: us
Re: Atmega bit shifting
« Reply #46 on: January 17, 2018, 06:53:59 pm »
Maybe add a parallel struct with the same field names (different variable name, of course) where each entry is an unsigned char and contains the width of the named field.

print_my_stuff(bitfield_struct.field, field_width_struct.field) to print the named bitfield a specific width.

in print_my_stuff, have a mask initialized to 0x01 and shift it left field_width - 1 places before you start the for loop.
Each time through the loop, shift the mask right 1 position.
« Last Edit: January 17, 2018, 06:56:01 pm by rstofer »
 

Offline Bruce Abbott

  • Frequent Contributor
  • **
  • Posts: 627
  • Country: nz
    • Bruce Abbott's R/C Models and Electronics
Re: Atmega bit shifting
« Reply #47 on: January 17, 2018, 08:15:52 pm »
Why wouldn't you use a set of bit fields in a struct?  You can then name the fields and deal with them as a normal entity.
Two reasons:-

1. Bitfields are not portable. The bits can be stored in whatever order and alignment the compiler sees fit.

This probably isn't important when referencing hardware registers in an MCU, because the compiler should be designed to match the hardware and the code is not portable anyway. However it might be an issue if porting code from from one compiler/platform to another (I remember having this problem on the Amiga, where two different compilers allocated the bits in different directions).

2. It's not generic.

Structures are defined at compile time, so you would need a separate structure for each bitfield size and position you wanted to print. Again this probably wouldn't be a problem for hardware registers which are predefined.

I am currently porting code for a GAL programmer which stores up to 5892 bits in an array. The PC program simply used 1 Byte per bit, but the ATmega328 doesn't have enough RAM for that so the bits are packed into bytes. The bits need to be accessed individually, sometimes in natural order and sometimes reversed, and may also be bit-pair or byte-reversed. Each GAL type has a different bit map, so to use structures I would need several to suit each chip. Instead the program has arrays of bit numbers which are used to index the bits according to the patterns required, and functions that set and test each bit individually.

 

Offline paulca

  • Super Contributor
  • ***
  • Posts: 4032
  • Country: gb
Re: Atmega bit shifting
« Reply #48 on: January 17, 2018, 09:16:52 pm »
where two different compilers allocated the bits in different directions).

I did my entire GCSE Computer Science in reverse order to what we were taught.  I remembered when I got home and thought I'd failed.  Obviously the examiner understood endian-ness.  Luckily I had written my bit values in that order in my working out in the first question.  I passed.

On "Endian".  I absolutely hate that term.  It requires the concept of an "end".  Is that the left end or the right end?  Big left or MSB first.  Big right, MSB last would be better.

Anyway, my code ended up working.  I split it in two to make it easier to track what was wrong.  I can recombine it into one function later if I want to.  It certainly helped as I had quite a few issues getting the ADC set up.  I spend an hour wondering why the config register was not reading back what I set, until I went back to the data sheet and found the first bit "Status" going 0 means it's working LOL.  I had the logic analyser out and everything.  DOH!
« Last Edit: January 17, 2018, 09:19:08 pm by paulca »
"What could possibly go wrong?"
Current Open Projects:  STM32F411RE+ESP32+TFT for home IoT (NoT) projects.  Child's advent xmas countdown toy.  Digital audio routing board.
 

Offline phil from seattle

  • Super Contributor
  • ***
  • Posts: 1029
  • Country: us
Re: Atmega bit shifting
« Reply #49 on: January 19, 2018, 12:51:23 am »
I dunno, why not use Serial.print((0x0F & (myByte>>1)), BIN);
Granted, it doesn't suppress the lead 4 bits. Personally, I'd live with that.
 

Offline paulca

  • Super Contributor
  • ***
  • Posts: 4032
  • Country: gb
Re: Atmega bit shifting
« Reply #50 on: January 19, 2018, 07:38:56 am »
I dunno, why not use Serial.print((0x0F & (myByte>>1)), BIN);
Granted, it doesn't suppress the lead 4 bits. Personally, I'd live with that.

Pride and quality.
"What could possibly go wrong?"
Current Open Projects:  STM32F411RE+ESP32+TFT for home IoT (NoT) projects.  Child's advent xmas countdown toy.  Digital audio routing board.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf