-
Atmega bit shifting
Posted by
yalect
on 30 Dec, 2017 07:24
-
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);
}
}
}
-
#1 Reply
Posted by
sleemanj
on 30 Dec, 2017 08:30
-
Your english is confusing as to exactly what you are trying to achieve, but I think your problem is ` >> count ` should be ` >> 1 `
-
#2 Reply
Posted by
yalect
on 30 Dec, 2017 09:10
-
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);
}
}
}
-
-
There are several mistakes in your 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.
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!
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:-
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);
}
}
}
-
#4 Reply
Posted by
yalect
on 30 Dec, 2017 10:39
-
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
-
#5 Reply
Posted by
Nusa
on 30 Dec, 2017 11:28
-
-
-
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:-
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.
-
#7 Reply
Posted by
rstofer
on 31 Dec, 2017 16:12
-
Or, you can use the C switch statement inside the for () and not even mess with shifting.
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.
-
-
For a lot less code (at least, C code).
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.
-
-
Total code size with the algorithms presented so far (GCC 4.3.2 optimization level 0s):-
My algo #1,
for (count = 0; count < 8; count++)
{
DATA = (bits >> count);// shift right * count
PORTC = DATA;
}
104 bytes
My algo #2,
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,
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,
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,
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.
-
-
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:-
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.
-
-
...
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.
-
-
I was simply responding to the prior posting with case statements
Fair enough.
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
I suppose you are against the use of pointers,
Pointers are an abomination!
-
#13 Reply
Posted by
NorthGuy
on 04 Jan, 2018 05:58
-
The correct rstofer code is:-
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:
PORTC = 0x01;
PORTC = 0x02;
PORTC = 0x04;
PORTC = 0x08;
PORTC = 0x10;
PORTC = 0x20;
PORTC = 0x40;
PORTC = 0x80;
-
#14 Reply
Posted by
yalect
on 04 Jan, 2018 18:01
-
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
-
#15 Reply
Posted by
Nusa
on 04 Jan, 2018 18:49
-
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.
-
#16 Reply
Posted by
rstofer
on 04 Jan, 2018 22:15
-
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:-
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.
-
-
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
-
#18 Reply
Posted by
rstofer
on 05 Jan, 2018 02:13
-
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.
#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
11
22
33
44
ETA: To print the bytes LSB first, change the for loop:
for (int i = 0; i < 4; i++)
The printf() part stays the same.
-
-
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,
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:-
DDRD = (1<<PIND0)|(1<<PIND1); // D0 and D1 are outputs, all others inputs
or this:-
DDRD = (1<<PIND0); // D0 is output, all others input
DDRD |=(1<<PIND1); // D1 is output, all others unchanged
-
#20 Reply
Posted by
hamster_nz
on 05 Jan, 2018 10:42
-
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.
-
#21 Reply
Posted by
rstofer
on 05 Jan, 2018 17:56
-
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.
-
#22 Reply
Posted by
NorthGuy
on 05 Jan, 2018 19:30
-
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.
-
#23 Reply
Posted by
rstofer
on 05 Jan, 2018 20:56
-
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.pdfThe PIC 18 series does have the LAT registers.
Page 3-18 for example
http://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.
-
#24 Reply
Posted by
NorthGuy
on 05 Jan, 2018 23:19
-
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.
-
#25 Reply
Posted by
yalect
on 14 Jan, 2018 12:42
-
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
-
#26 Reply
Posted by
rstofer
on 14 Jan, 2018 16:10
-
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
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().
-
#27 Reply
Posted by
yalect
on 14 Jan, 2018 18:21
-
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
-
#28 Reply
Posted by
rstofer
on 14 Jan, 2018 18:41
-
Written for the Arduino UNO, the code looks like this:
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.
-
#29 Reply
Posted by
rstofer
on 14 Jan, 2018 18:56
-
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.
-
#30 Reply
Posted by
rstofer
on 14 Jan, 2018 21:32
-
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.
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:
for (data = bits, count = 1; count < 8; count++)
-
#31 Reply
Posted by
Nusa
on 14 Jan, 2018 22:00
-
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.
-
#32 Reply
Posted by
yalect
on 15 Jan, 2018 10:04
-
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.
-
#33 Reply
Posted by
Nusa
on 15 Jan, 2018 11:01
-
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.
-
#34 Reply
Posted by
rstofer
on 15 Jan, 2018 16:40
-
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.
-
-
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.
-
#36 Reply
Posted by
rstofer
on 15 Jan, 2018 19:06
-
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...
-
-
Man, I hate those emojis that inadvertently warp a programming language construct.
-
#38 Reply
Posted by
rstofer
on 15 Jan, 2018 21:00
-
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..
-
-
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.)
-
#40 Reply
Posted by
yalect
on 16 Jan, 2018 20:04
-
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
-
-
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.
-
#42 Reply
Posted by
paulca
on 17 Jan, 2018 14:58
-
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
-
#43 Reply
Posted by
rstofer
on 17 Jan, 2018 17:31
-
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
-
#44 Reply
Posted by
paulca
on 17 Jan, 2018 18:17
-
Mine was a little more generic and ambitious, but flawed. This is actually version two.
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.
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.
-
#45 Reply
Posted by
rstofer
on 17 Jan, 2018 18:50
-
-
#46 Reply
Posted by
rstofer
on 17 Jan, 2018 18:53
-
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.
-
-
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.
-
#48 Reply
Posted by
paulca
on 17 Jan, 2018 21:16
-
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!
-
-
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.
-
#50 Reply
Posted by
paulca
on 19 Jan, 2018 07:38
-
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.