Atmega bit shifting - Page 1
Forum section: electronics / general

author: yalect
author_rank: Regular Contributor
timestamp: December 30, 2017, 07:24:20 am
content: 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);}}}

author: sleemanj
author_rank: Super Contributor
timestamp: December 30, 2017, 08:30:17 am
content: Your english is confusing as to exactly what you are trying to achieve, but I think your problem is ` >> count ` should be ` >> 1 `

author: yalect
author_rank: Regular Contributor
timestamp: December 30, 2017, 09:10:34 am
content: Hello,sorry, really that was an error I modified the program I want to shift bits 8 times not one time as it doesvoid 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);}}}

author: Bruce Abbott
author_rank: Frequent Contributor
timestamp: December 30, 2017, 09:54:53 am
content: There are several mistakes in your code:-Code: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:int bits = 100 ... // binary 0011 0000 0011 1001Binary 0011000000111001 = decimal 1234, not 100. If a comment doesn't match the code it'sworsethan useless!Code: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:void main(){int bits = 100; // = binary number 00000000 01100100int count, DATA;DDRC = 0xff;while(1){for (count = 0; count < 8; count++){DATA = (bits >> count); // output = number shifted right * countPORTC = DATA;Delay_ms(3000);}}}

author: yalect
author_rank: Regular Contributor
timestamp: December 30, 2017, 10:39:15 am
content: Thank you Bruceyou 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 replacecountwith1, and write thenDATA =(bits >> 1), it will work?Thank you

author: Nusa
author_rank: Super Contributor
timestamp: December 30, 2017, 11:28:42 am
content: 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/#msg1383938Your 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.

author: Bruce Abbott
author_rank: Frequent Contributor
timestamp: December 30, 2017, 06:59:56 pm
content: Quote from: yalect on December 30, 2017, 10:39:15 amNo. 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:DATA = bits; // load number into DATA _before_ entering the loopfor (count = 0; count < 8; count++){PORTC = DATA; // output current contents of DATADATA = (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 abarrel shifter, so shifting by more than 1 place has to be implemented as multiple 1 bit shifts.

author: rstofer
author_rank: Super Contributor
timestamp: December 31, 2017, 04:12:17 pm
content: Or, you can use the C switch statement inside the for () and not even mess with shifting.Code: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.

author: phil from seattle
author_rank: Super Contributor
timestamp: December 31, 2017, 05:15:55 pm
content: For a lot less code (at least, C code).Code:uint8_t bitmap = { 0x1,0x2,0x4,0x8,0x10,0x20,0x40,0x80};for(i=0;i<8;i++){PORTC = bitmap;// PORTC = 1<<i; // as an alternative, which ever gens the least code.}not sure the point of that sequence, though.

author: Bruce Abbott
author_rank: Frequent Contributor
timestamp: January 01, 2018, 06:34:34 am
content: Total code size with the algorithms presented so far (GCC 4.3.2 optimization level 0s):-My algo #1,Code:for (count = 0; count < 8; count++){DATA = (bits >> count);// shift right * countPORTC = DATA;}104 bytesMy algo #2,Code:for (count = 0; count < 8; count++){PORTC = DATA; // output current contents of DATADATA = (DATA >> 1); // shift DATA right * 1 (will be output next time through the loop)}94 bytesrstofer,Code: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 bytesphil from seattle#1,Code:uint8_t bitmap = { 0x1,0x2,0x4,0x8,0x10,0x20,0x40,0x80};for(count=0;count<8;count++){PORTC = bitmap;}156 bytesphil from seattle#2,Code:for(count=0;count<8;count++){PORTC = 1<<count;}104 bytesHowever, neitherrstofer's norphil from seattle's code does what is required, which is shifting anarbitrary 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 forreadability and understandingfirst, 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 thecompilertake care of optimizing your code.

author: Bruce Abbott
author_rank: Frequent Contributor
timestamp: January 01, 2018, 06:46:29 am
content: Quote from: Bruce Abbott on January 01, 2018, 06:34:34 amAnd as an example of 'messing up', in copy/pasting I missed a case statement!The correctrstofercode is:-Code: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.

author: phil from seattle
author_rank: Super Contributor
timestamp: January 01, 2018, 04:52:00 pm
content: Quote from: Bruce Abbott on January 01, 2018, 06:34:34 amI 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.

author: Bruce Abbott
author_rank: Frequent Contributor
timestamp: January 03, 2018, 08:46:36 am
content: Quote from: phil from seattle on January 01, 2018, 04:52:00 pmFair enough.QuoteWhen theintentionis 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 codeyouwant and let the compiler decide how to implement itQuotePointers are an abomination!

author: NorthGuy
author_rank: Super Contributor
timestamp: January 04, 2018, 05:58:43 am
content: Quote from: Bruce Abbott on January 01, 2018, 06:46:29 amEven The Queen couldn't make the code more complicated. This is equivalent to:Code:PORTC = 0x01;PORTC = 0x02;PORTC = 0x04;PORTC = 0x08;PORTC = 0x10;PORTC = 0x20;PORTC = 0x40;PORTC = 0x80;

author: yalect
author_rank: Regular Contributor
timestamp: January 04, 2018, 06:01:35 pm
content: Thank you Brucetalking about shifting to the right if we take state of bit forVarwithin the program let's saybitsif 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 ofbits) :**************************************************Number shifted * 1st bit * detected bit***************************************11100100 * 0 * 100110010 * 0 * 000011001 * 1 * 000001100 * 0 * 100000110 * 0 * 000000011 * 1 * 000000001 * 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 * countPORTC = DATA;Delay_ms(1000);if ((bits >> count) & compare){PORTD = (1<< PIND0);}else{PORTD = (1<< PIND1);}}}}maybe you have an Idea?thank you

author: Nusa
author_rank: Super Contributor
timestamp: January 04, 2018, 06:49:23 pm
content: 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.

author: rstofer
author_rank: Super Contributor
timestamp: January 04, 2018, 10:15:45 pm
content: Quote from: Bruce Abbott on January 01, 2018, 06:46:29 amNo 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.

author: NivagSwerdna
author_rank: Super Contributor
timestamp: January 04, 2018, 10:37:01 pm
content: Quote from: yalect on December 30, 2017, 07:24:20 amI'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);DDCCBBAA

author: rstofer
author_rank: Super Contributor
timestamp: January 05, 2018, 02:13:02 am
content: Quote from: NivagSwerdna on January 04, 2018, 10:37:01 pmIf 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:#include <stdio.h>#include <stdint.h>int main(void){union {uint32_t word;uint8_t bytes;} u;u.word = 0x11223344;for (int i = 3; i >= 0; i--) {printf("%4x\n",u.bytes);}}This printsCode:11223344ETA: To print the bytes LSB first, change the for loop:Code:for (int i = 0; i < 4; i++)The printf() part stays the same.

author: Bruce Abbott
author_rank: Frequent Contributor
timestamp: January 05, 2018, 04:38:45 am
content: Quote from: yalect on January 04, 2018, 06:01:35 pmI think your problem is here,Code: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:DDRD = (1<<PIND0)|(1<<PIND1); // D0 and D1 are outputs, all others inputsor this:-Code:DDRD = (1<<PIND0); // D0 is output, all others inputDDRD |=(1<<PIND1); // D1 is output, all others unchanged

author: hamster_nz
author_rank: Super Contributor
timestamp: January 05, 2018, 10:42:54 am
content: 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.

author: rstofer
author_rank: Super Contributor
timestamp: January 05, 2018, 05:56:22 pm
content: Quote from: hamster_nz on January 05, 2018, 10:42:54 amFor 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.

author: NorthGuy
author_rank: Super Contributor
timestamp: January 05, 2018, 07:30:54 pm
content: Quote from: rstofer on January 05, 2018, 05:56:22 pmPICs have built-in shadow variables called LAT.

author: rstofer
author_rank: Super Contributor
timestamp: January 05, 2018, 08:56:16 pm
content: Quote from: NorthGuy on January 05, 2018, 07:30:54 pmSome do, the PIC 16F family does not.Section 9.2 for examplehttp://ww1.microchip.com/downloads/en/devicedoc/33023a.pdfThe PIC 18 series does have the LAT registers.Page 3-18 for examplehttp://ww1.microchip.com/downloads/en/DeviceDoc/39500a.pdfThis 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.

author: NorthGuy
author_rank: Super Contributor
timestamp: January 05, 2018, 11:19:16 pm
content: Quote from: rstofer on January 05, 2018, 08:56:16 pmMost 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.

author: yalect
author_rank: Regular Contributor
timestamp: January 14, 2018, 12:42:28 pm
content: Hello,thank you for your replyI 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 * countPORTC = DATA;if( DATA & compare){PORTD = (1<< PIND0);}else{PORTD = (1<< PIND1);}Delay_ms(1000);}}}thank you

author: rstofer
author_rank: Super Contributor
timestamp: January 14, 2018, 04:10:00 pm
content: 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 declarationCode:int main(void){uint8_t bits = 0b01100100; //use an unsigned 8 bit data typeunsigned char compare = 0b00000001; // another style of unsigned 8 bit data typeuint8_t count, data;DDRC = 0xff;DDRD = (1 << PIND0) | (1 << PIND1); // see below re: PIND0 and PIND1while(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().

author: yalect
author_rank: Regular Contributor
timestamp: January 14, 2018, 06:21:18 pm
content: thank youyes, 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

author: rstofer
author_rank: Super Contributor
timestamp: January 14, 2018, 06:41:44 pm
content: Written for the Arduino UNO, the code looks like this:Code:void setup() {DDRC = 0xff;DDRD = (1 << PIND0) | (1 << PIND1);}void loop() {uint8_t bits = 0b01100100; //use an unsigned 8 bit data typeunsigned char compare = 0b00000001; // another style of unsigned 8 bit data typeuint8_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.

author: rstofer
author_rank: Super Contributor
timestamp: January 14, 2018, 06:56:36 pm
content: Quote from: yalect on January 14, 2018, 06:21:18 pmSimulation 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.

author: rstofer
author_rank: Super Contributor
timestamp: January 14, 2018, 09:32:07 pm
content: 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:void setup() {DDRC = 0xff;DDRD = (1 << PIND0) | (1 << PIND1);}void loop() {uint8_t bits = 0b01100100; //use an unsigned 8 bit data typeunsigned char compare = 0b00000001; // another style of unsigned 8 bit data typeuint8_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 outputif (data & compare) // set up least significant bit{PORTD = (1 << PIND0);}else{PORTD = (1 << PIND1);}delay(1000); // let the user see the patterndata = (bits >> count); // finally, shift the pattern}}You can clever up the for statement to include initializing data:Code:for (data = bits, count = 1; count < 8; count++)

author: Nusa
author_rank: Super Contributor
timestamp: January 14, 2018, 10:00:46 pm
content: Ok, I pulled out real hardware (Atmega328p uno board) and tried it. I'm using the Arduino IDE found atwww.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.

author: yalect
author_rank: Regular Contributor
timestamp: January 15, 2018, 10:04:18 am
content: thank youyes, 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.

author: Nusa
author_rank: Super Contributor
timestamp: January 15, 2018, 11:01:08 am
content: 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.

author: rstofer
author_rank: Super Contributor
timestamp: January 15, 2018, 04:40:07 pm
content: 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.

author: phil from seattle
author_rank: Super Contributor
timestamp: January 15, 2018, 05:41:47 pm
content: Quote from: Nusa on January 14, 2018, 10:00:46 pmI 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.

author: rstofer
author_rank: Super Contributor
timestamp: January 15, 2018, 07:06:17 pm
content: Quote from: phil from seattle on January 15, 2018, 05:41:47 pmThe 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...

author: phil from seattle
author_rank: Super Contributor
timestamp: January 15, 2018, 08:13:56 pm
content: Man, I hate those emojis that inadvertently warp a programming language construct.

author: rstofer
author_rank: Super Contributor
timestamp: January 15, 2018, 09:00:01 pm
content: Quote from: phil from seattle on January 15, 2018, 08:13:56 pmI didn't notice that earlier. Kind of a PITA. Anyway, I had too many semicolons..

author: Bruce Abbott
author_rank: Frequent Contributor
timestamp: January 16, 2018, 06:30:42 am
content: Quote from: yalect on January 14, 2018, 12:42:28 pmI 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.)

author: yalect
author_rank: Regular Contributor
timestamp: January 16, 2018, 08:04:58 pm
content: Hi,thank you bruceI 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

author: Bruce Abbott
author_rank: Frequent Contributor
timestamp: January 17, 2018, 01:08:14 pm
content: Quote from: yalect on January 16, 2018, 08:04:58 pmNo 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.

author: paulca
author_rank: Super Contributor
timestamp: January 17, 2018, 02:58:06 pm
content: 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: 1001When given the byte:00010010And the datasheet exert:Bits Purpose===========7-5: Status4-1: Data Rate0: Other StuffYou want to just print: 1001

author: rstofer
author_rank: Super Contributor
timestamp: January 17, 2018, 05:31:18 pm
content: mask = 0b00010000 // mask the high order bit firstfor bit = 0 to 3if (value & mask)print 1elseprint 0mask >>= 1 // mask the next lower bitend for

author: paulca
author_rank: Super Contributor
timestamp: January 17, 2018, 06:17:32 pm
content: Mine was a little more generic and ambitious, but flawed. This is actually version two.Code: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: 001As 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:Config register: 10000101 10000011 = 1000010110000011Status: 1Multiplex: 000PGA: 010Mode: 1Data Rate: 001Comparator Mode: 0Comparator Polarity: 0Comparator latch: 0Comparator queue: 11You can see the bug.

author: rstofer
author_rank: Super Contributor
timestamp: January 17, 2018, 06:50:49 pm
content: 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-fieldshttps://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.

author: rstofer
author_rank: Super Contributor
timestamp: January 17, 2018, 06:53:59 pm
content: 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.

author: Bruce Abbott
author_rank: Frequent Contributor
timestamp: January 17, 2018, 08:15:52 pm
content: Quote from: rstofer on January 17, 2018, 06:50:49 pmTwo 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.

author: paulca
author_rank: Super Contributor
timestamp: January 17, 2018, 09:16:52 pm
content: Quote from: Bruce Abbott on January 17, 2018, 08:15:52 pmI 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!

author: phil from seattle
author_rank: Super Contributor
timestamp: January 19, 2018, 12:51:23 am
content: 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.

author: paulca
author_rank: Super Contributor
timestamp: January 19, 2018, 07:38:56 am
content: Quote from: phil from seattle on January 19, 2018, 12:51:23 amPride and quality.