Setting Bits in C Microcontroller - c

I'm attempting to learn how to program micro-controllers in C and have a question regarding bit assignments. Say for example I were to declare an 8 bit number.
binary_number = 0b00000000;
Now, lets say I wanted to set bit 3 only. Example texts I have seen use an operation like the following:
binary_number |= (1<<4)
Am I understanding this correctly? We are taking binary_number and 'or-ing' it with essentially 0b00001000 and then assigning that outcome to binary_number?
Likewise, when resetting this bit:
binary_number &= ~(1<<4)
We are essentially taking binary_number (0b00001000) and 'and-ing' it with 0b11110111 and then assigning binary_number to the outcome of that expression?
Do I understand this correctly?

Yes, your understanding is correct! :)
but a little change...
For resetting or setting the bit 3, you need to left shift the 1 by 3 places only.
1<<4 : 0b00010000
1<<3 : 0b00001000
Use the bitwise OR operator (|) to set xth bit.
n |= 1 << x;
That will set bit x.
Use the bitwise AND operator (&) to reset xth bit.
n &= ~(1 << x);
That will reset bit x.

Yes, you are understanding it correctly. That is exactly what you have to do to set and unset bits. Looks pretty complicated I know but you could always write a helper function that you pack around with you.

As pointed out others, you are setting/resetting the 4th bit not the 3rd
Set mask: 1<<4 = 10000 = 0001 0000
Reset Mask: ~(1<<4) = ~(10000)= ~(0001 0000) = 1110 1111
So, binary_number |= (1<<4):
Original Number - 0000 0000
Mask to set 4th bit - (OR) 0001 0000
--------
Result 0001 0000 //4th bit set
And, binary_number &= ~(1<<4):
Original Number - 000X 0000 //4th bit could be a 1 or a 0; X =1/0
Mask to set 3rd bit - (AND) 1110 1111
--------
Result 0000 0000 //4th bit reset

If you seek efficiency the best way to do it is to define the bits individually:
#define BIT_0 0b00000001
#define BIT_1 0b00000010
#define BIT_2 0b00000100
#define BIT_3 0b00001000
#define BIT_4 0b00010000
#define BIT_5 0b00100000
#define BIT_6 0b01000000
#define BIT_7 0b10000000
and then to set the bit in a byte:
unsigned char byteWhoseBitsAreSetReset = 0;
//To Set bit 3
byteWhoseBitsAreSetReset |= BIT_3;
//To Set Multiple bits
byteWhoseBitsAreSetReset |= (BIT_3 + BIT_4 + BIT_5);
//OR
byteWhoseBitsAreSetReset |= (BIT_3 | BIT_4 | BIT_5);
//To reset bit 3
byteWhoseBitsAreSetReset &= ~(BIT_3);
//To reset Multiple bits
byteWhoseBitsAreSetReset &= ~(BIT_3 + BIT_4 + BIT_5);
//OR
byteWhoseBitsAreSetReset &= ~(BIT_3 | BIT_4 | BIT_5);

Related

Why bit shifting is written like this in C?

Maybe this question will be kinda stupid, but I wonder why
if we want to write 0 on some specific position in register
we have to write like this:
PORTB &= ~(1 << 2);
And not like this (cause it will not work):
PORTB &= (0 << 2);
Does 0 mean here like 0b00000000 (for 8-bit register)?
Let’s break this down step by step:
// PORTB &= ~(1 << 2);
int bit_position = 2;
int bit_mask = 1; // = 0000 0001
bit_mask <<= bit_position; // = 0000 0100
int inverted_mask = ~bit_mask; // = 1111 1011
int PORTB = 0x77; // 0111 0111
PORTB &= inverted_mask; // & 1111 1011
// = 0111 0011
And, your suggested alternative:
// PORTB &= (0 << 2);
int bit_position = 2;
int bit_mask = 0; // = 0000 0000
bit_mask <<= bit_position; // = 0000 0000
int PORTB = 0x77; // 0111 0111
PORTB &= bit_mask; // & 0000 0000
// = 0000 0000
The point being that the computer simply performs the operations one by one and on whole registers. It doesn’t know that it was supposed to care about a specific zero out of all the zeroes in that number. So you are not ANDing by “zero at position 2”, but simply by the number zero. And indeed, you are not shifting just one zero or one, but the entire number.
This is why to set a specific bit to zero, we have to AND with a mask that has ones in every position other than the one we wish zero. (ANDing with 1 does not change the bit, whereas ANDing with 0 makes it zero.)
Using a byte for simplicity, 0 << 2 is just equal to zero - 0b00000000. Any value you AND with this will also produce zero as a result.
1 << 2 is equal to 0b00000100
~(1 << 2) is equal to 0b11111011
Now you have a mask to AND with which will only set a specific bit to zero. The rest of the bits will be unchanged.
You can understand why, when you disassemble the code:
PORTB &= ~(1 << 2);
is translated like that:
PORTB = PORTB & (~(0b00000001 << 2));
to
PORTB = PORTB & (~(0b00000100));
to
PORTB = PORTB & ((0b11111011));
This means it will take the old value of PORTB and just write bit #2 of it to 0 while keeping the rest of the bits to their original values (whether they are 0 or 1)
This is done because you only want to change the value of PIN2 of PORTB while not changing any other pin value.
While the other line:
PORTB &= (0 << 2);
evalutes to
PORTB = PORTB & ((0b00000000));
Which in turn will reset all the PORTB pins to 0.
So it really depends on what exactly you want to do.
Another example is if you want to set PIN2 of PORTB to 1:
PORTB = PORTB | (0b00000100);
which can be written like that:
PORTB |= (1 << 2);
This will make sure to set only PIN2 and no other pin of PORTB to 1.

Need some bug identification with Bit Manipulation

The problem is SegmentOFF. For example if DATA[18] = 0x10 after calling SegmentON and I want to clear 6th bit of DATA[18]. Calling SegmentOFF clears all the bit and ends up DATA[18] = 0x00
What is wrong with the code.
unsigned char DATA[24];
unsigned int Segment2BitMap[48] =
{
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
0x0204, 0x0300, 0x0302, 0x0307, 0x0600, 0x0601, 0x0602, 0x0603,
0x0604, 0x0605, 0x0606, 0x0607, 0x0804, 0x0900, 0x0902, 0x0907,
0x0C00, 0x0C01, 0x0C02, 0x0C03, 0x0C04, 0x0C05, 0x0C06, 0x0C07,
0x0E04, 0x0F00, 0x0F02, 0x0F07, 0x1200, 0x1201, 0x1202, 0x1203,
0x1204, 0x1205, 0x1206, 0x1207, 0x1404, 0x1500, 0x1502, 0x1507
};
void SegmentON(unsigned char Number)
{
unsigned int Data = Segment2BitMap[Number];
unsigned char UpperByte = (Data/256); //upper byte
unsigned char LowerByte = (Data%256 & 0x07); //lower byte
DATA[UpperByte] |= (0x01<<LowerByte);
}
void SegmentOFF(unsigned char Number)
{
unsigned int Data = Segment2BitMap[Number];
unsigned char UpperByte = (Data/256); //upper byte
unsigned char LowerByte = (Data%256 & 0x07); //lower byte
DATA[UpperByte] &= (0x01<<LowerByte);
}
int main()
{
SegmentON(40);
SegmentOFF(42);
}
1010 & 0101 == 0000
If you want to clear a specific bit and the rest should not be changed you have to invert it.
For 8 bit:
var &= (1<<2)^0xFF
This would set the 3rd least significant bit (1<<2) == 0x04 and then invert it with xor everything with ones
And then you apply that mask to var to set the 3rd bit to zero and the rest stays unchanged
This would be
var = var & 0b11111011
Ok, I mostly do ruby but the bit-wise operators look the same. (thus I'm assuming they are the same)
Lets work with a random number say 201. The binary representation is as follows:
1100 1001
To turn a bit on you simply do an OR operation.
201 |= 1<<2
The machine then bit shifts 0000 0001 2 steps to the left creating 0000 0100 and then makes an OR operation, if either of the numbers has a 1 at the nth position the resulting number will have a 1 at the same position.
1100 1001 # first input
0000 0100 # second input
1100 1101 # output => 209
So far so good, but when you try to set a bit to 0 using the AND operator something goes wrong.
201 &= 1<<2
Same as before but now it performs an AND operation instead. If the number share a 1 at the nth position the resulting number will have a 1 at that same position.
1100 1001 # first input
0000 0100 # second input
0000 0000 # output => 0
This happens because they have no common 1s. This can be solved in 2 ways. (both using the XOR operation)
The 'conditional' way.
if 209&(1<<2) != 0
209 ^= 1<<2
end
This code will do the following. if 201 and 1<<2 (8) is not equal to 0 then perform an exclusive or operation. In this case it is not equal to 0 so it will do as follows. Wherever the bits are the same it will put a 0 and where they differ it will put a 1.
1100 1101 # first input (209)
0000 0100 # second input (8)
1100 1001 # output => 201
The 'pure bit-wise' solution.
209&(255^(1<<2))
This will generate the following operation.
1100 1101 # first input (209)
1111 1011 # second input number (247)
1100 1001 # output => 201
We end up doing one extra bit operation, but we also loose the conditional. So it should be a bit faster. Get it bit, hehe. The code here can't directly be implemented in c, but the principal should be the same.
PS Your definition of the lower byte looks a bit odd, you are aware that it will only return the first 3 bits, right?
Hope it helps.

moving bits from different ports and storing it in memory

I have this question, I got a dipswitch like a selector for different modes within my application. there are 3 bits to create the selector, but they are from different ports for example, the bit number 3 from portB, the bit number 1 from portC and the bit number 3 from portC, I want to move those 3 bits and storaged them in a register so that way I can create the selector, I already did it in assembler but i'm new into C programming, and till now the only similar answer was to move all the information from the entire port but anything related to a single bit. What's the command that I should use to move those bits from different ports?
In C, to get bit-level precision, you will need to use bitwise operators. For example, let's say you have an 8 bit container (which is also the smallest data type in C), but you're only interested in 1 bit; the best way to extract that bit would be to do a bitwise AND. In C, the bitwise AND is performed like this:
char c = 0x0B;
char bit = 0;
// Let's get the value of the second bit, so we must shift
// our bits to the right by one, then perform a bitwise AND
// to invalidate all other bits except the first.
bit = (c >> 1) & 0x01;
In binary, it would look like this:
00001011
Shift right once:
00000101
AND:
00000101 & 000000001
Yields: 000000001
To store different bits in the same memory location, you can use the bitwise-OR operator, which is the vertical pipe in C |. Here's an example:
char c = 0x00;
c = c | 0x01; /* c will now yield 0x01 */
c = c | 0xF0; /* c will now yield 0xF1 */
Final binary result: 11110001
With & and |, you can do some powerful things that are included in a lot of libraries to pass multiple options in one parameter. With 8 bits, you can store 8 different flags (or options), with 16 bits, 16 options. You could use this philosophy for your different ports. If you only have 4 bits worth of data in each port, you could use a 16-bit container, with 4 bits left that could simply be ignored. You'd do it like this:
short port_values = 0;
port_values = port_values | (port_a & 0x000F); // pretend port_a only has 4 bits of data and contains 0x0001
// port_values is now 0000 0000 0000 0001
// prepare to receive port_b by shifting the bits 4 to the left
port_values = port_values << 4;
// port_values is now 0000 0000 0001 0000
port_values = port_values | (port_b & 0x000F); // pretend port_b only has 4 bits of data and contains 0x000F
// port_values is now 0000 0000 0001 1111
// prepare to receive port_b by shifting the bits 4 to the left
port_values = port_values << 4;
// port_values is now 0000 0001 1111 0000
port_values = port_values | (port_c & 0x000F); // pretend port_c only has 4 bits of data and contains 0x0002
// port_values is now 0000 0001 1111 0010
I decide to do the following code, but when i'm running the the code it doesn't enter into the switch-case just retur after to set the last bit of "COMBINACION" what could be my error. i'm new is this world of C thanks for your time and consideration.
void SECUENCIA_1();
void SECUENCIA_2();
void SECUENCIA_3();
void SECUENCIA_4();
void SECUENCIA_5();
void SECUENCIA_6();
void SECUENCIA_ERROR();
void SALIDA_OK();
int i;
unsigned char COMBINACION;
void main(void) {
ADCON1 = 0x0F;
PORTA = 0x00;
TRISA = 0b00000;
PORTC = 0x00;
TRISC = 0b11100000;
PORTD = 0x00;
TRISD = 0b110000;
PORTE = 0x00;
TRISE = 0b000;
PORTB = 0x00;
TRISB = 0b11111111;
COMBINACION = 0x00;
COMBINACION = COMBINACION | (PORTCbits.RC5);
COMBINACION = COMBINACION << 1;
COMBINACION = COMBINACION | (PORTCbits.RC4);
COMBINACION = COMBINACION << 1;
COMBINACION = COMBINACION | (PORTDbits.RD3);
switch (COMBINACION)
{
case 0x0: SECUENCIA_ERROR; break;
case 0x1: SECUENCIA_1; break;
case 0x2: SECUENCIA_2; break;
case 0x3: SECUENCIA_3; break;
case 0x4: SECUENCIA_4; break;
case 0x5: SECUENCIA_5; break;
case 0x6: SECUENCIA_6; break;
default:SECUENCIA_ERROR;
}
}

GPIO button pressing in C

I'm relatively new in the embedded world, so I may be a little newbie asking this.
I'm having trouble to understand the syntax of an example program in C that checks if a button is pressed and then turning a LED on if so. I'm using a STM32F207VCT6 (Cortex-M3) microcontroller.
The part of the program that I'm having trouble to understand is the following:
if(!(GPIOA->IDR & (1<<4)))
Key=1;
Port 4 from GPIOA is set to be an input with pull-up register. The signal from the button goes to GND once it's pressed. IDR is the input data register.
So my question is:
I don't understand in this code why the NOT symbol, !, inside the if statement is needed. And I do not know what comparison is being made inside the if, since there is no sign of equal. Can someone help me with that?
PS: I already know that (1<<4) is the bit-wise operation for left shifting the bit 1 four times.
There are 16 pins per port in the STM32F207VCT6. This operation is trying to determine the state of a single pin, number 4, of port A. Let's expand each part to better understand what is going on.
We start with the expression:
if(!(GPIOA->IDR & (1<<4)))
We're working with a 16-bit number to account for the 16 pins. Expanding this we get:
if(!(GPIOA->IDR & ((0000 0000 0000 0001) << 4)))
You already know that << is a bitwise left shift. Applying this we get:
if(!(GPIOA->IDR & (0000 0000 0001 0000)))
Expanding the IDR, I will use X's for bits that we don't care about and a ? for the unknown bit we are testing for:
if(!((XXXX XXXX XXX? XXXX) & (0000 0000 0001 0000)))
Next we have a & which is the bitwise AND operator. If you remember your AND truth table:
& 0 1
- -
0 | 0 0
1 | 0 1
So we have the operation:
XXXX XXXX XXX? XXXX
& 0000 0000 0001 0000
---------------------
0000 0000 000? 0000
If Bit 4 in Port A is a 0, the the result will be 0000 0000 0000 0000. If Bit 4 in Port A is a 1, the the result will be 0000 0000 0001 0000.
If the switch is pressed, the input will be pulled to GND and Bit 4 will be set to 0. If the switch is unpressed, then the internal pull-up will pull the input high and Bit 4 will be set to 1.
So we have two possibilities:
//Button is pressed
if(!(0000 0000 0000 0000))
Or:
//Button is not pressed
if(!(0000 0000 0001 0000))
Now it's important to understand that ! is the Logical NOT operator. Which inverts true and false in conditional statements. It is also important to understand that in the C language:
Logical operators (&&, ||, !, etc.) and condition-testing
statements (if, while) assume that zero is false and all other
values are true.
Emphasis mine
So what we really have is:
//Button is pressed
if(!(false))
Or:
//Button is not pressed
if(!(true))
Applying the NOT:
//Button is pressed
if(true)
Key=1;
Or:
//Button is not pressed
if(false)
Key=1;
if(!(GPIOA->IDR & (1<<4))) Key=1;
is equivalent to
if((GPIOA->IDR & (1<<4)) == 0) Key=1;
In C, !E is equivalent to E == 0.
So here basically, Key = 1; statement is executed if the value of bit 4 of GPIOA->IDR is 0.
Assume GPIOA->IDR is a byte.
[1111 1111] would infer that no GIPOA->IDR bits are cleared (grounded)
[1111 1111] & [0000 1000] = 0000 1000 => != 0
If the button was pressed...
[1111 0111] & [0000 1000] = 0000 0000 => == 0
Bob's Your Uncle.

How to set bits in registers?

There is address of registry (first?) SPI1.
There is structure with offsets. I suppose it means that
SPI1_REG_BASE + offset = address of some SPI registry
#define SPI1_REG_BASE (0x01F0E000)
//-----------------------------------------------------
//Register Structure & Defines
//-----------------------------------------------------
typedef struct
{
volatile uint32_t SPIGCR0; // 0x0000
volatile uint32_t SPIGCR1; // 0x0004
volatile uint32_t SPIINT; // 0x0008
volatile uint32_t SPILVL; // 0x000C
volatile uint32_t SPIFLG; // 0x0010
volatile uint32_t SPIPC0; // 0x0014
volatile uint32_t SPIPC1; // 0x0018
volatile uint32_t SPIPC2; // 0x001C
volatile uint32_t SPIPC3; // 0x0020
volatile uint32_t SPIPC4; // 0x0024
volatile uint32_t SPIPC5; // 0x0028
volatile uint32_t RSVD0[3]; // 0x002C
volatile uint32_t SPIDAT0; // 0x0038
volatile uint32_t SPIDAT1; // 0x003C
volatile uint32_t SPIBUF; // 0x0040
volatile uint32_t SPIEMU; // 0x0044
volatile uint32_t SPIDELAY; // 0x0048
volatile uint32_t SPIDEF; // 0x004C
volatile uint32_t SPIFMT0; // 0x0050
volatile uint32_t SPIFMT1; // 0x0054
volatile uint32_t SPIFMT2; // 0x0058
volatile uint32_t SPIFMT3; // 0x005C
volatile uint32_t INTVEC0; // 0x0060
volatile uint32_t INTVEC1; // 0x0064
} spi_regs_t;
There are some definitions and the definition of pointer *spi
#define CSDEF0 (0x00000001) //bit 0
#define CSHOLD (0x10000000) //bit 28
spi_regs_t *spi = (spi_regs_t *)SPI1_REG_BASE;
I misunderstood setting of bits. For example,
spi->SPIDEF |= CSDEF0 //set 0 bit in the registry field
I understand that SPIDEF - is SPI register which has offset address 4Ch
(0x01F0E000 + 0x4C). But why CSDEF0 is bit 0 ?? There is a field CSDEF in SPIDEF registry (0-7 bits). Is it mean that 7 bit of CSDEF has address 0x00000008 ? and 5 bit has address 0x00000006?
But then why CSHOLD field of SPIDAT1 registry has address 0x10000000 ??
spi->SPIDAT1 |= CSHOLD //set bit 28
SPIDAT1 register has offset address 3Ch (0x01F0E000 + 0x3C)
It truly has field CSHOLD (28st bit)
How does |= work in this situation?
I'll be grateful for any help for figuring out... all this %)
I think you are misunderstanding the notions of address and value of the registers.
You are right (based on the structure description you gave) when you say that the CSDEF0 register of the SPI1 module is located at address 0x01F0E000 + 0x4C. This address will never change, it is defined by the hardware design.
Now with the following statements you are not manipulating addresses but values of the registers:
spi->SPIDEF |= CSDEF0; //set 0 bit in the registry field
spi->SPIDAT1 |= CSHOLD; //set bit 28
The |= operator is a bitwise OR and assign operator. It is equivalent to the following :
spi->SPIDEF = spi->SPIDEF | CSDEF0; //set 0 bit in the registry field
spi->SPIDAT1 = spi->SPIDAT1 | CSHOLD; //set bit 28
As CSDEF0 is defined to 0x00000001, in the first statement you are effectively setting the LSB bit of the SPIDEF register, leaving all other bits to their original value.
But why CSDEF0 is bit 0 ??
The purpose of this macro is to set bit-0 to 1. If this macro is ORed with any register, then that register's bit-0 is set to 1.
For example
Lets take spi->SPIDEF = 0x050A i.e 0x050A ==> 0000 0101 0000 1010
Now setting 0th bit of spi->SPIDEF using CSDEF0 .
0x050A ==> 0000 0101 0000 1010
CSDEF0 ==> 0000 0000 0000 0001
--------------------
spi->SPIDEF ==> 0000 0101 0000 1011
why CSHOLD field of SPIDAT1 registry has address 0x10000000??
Same-way how CSDEF0 is used to represent 0th bit, CSHOLD is used for 28th bit.
I guess you confused with Hexa-deciamal and binary representation of 0x000001 and 000001 (???).
0x01 is 01.
0x02 is 10.
0x100 is 1 0000 0000
0x1000 is 1 0000 0000 0000
0x10000000 is 1 0000 0000 0000 0000 0000 0000 0000
^-- Bit 28 starting from bit-0
But why CSDEF0 is bit 0 ?
Because of:
#define CSDEF0 (0x00000001) //bit 0
What they mean is not a "bit with value 0" but "the bit at position 0".
And concerning the:
#define CSHOLD (0x10000000) //bit 28
Take a look at converting hex-notation to binary-notation and it will become clear.
How does |= work in this situation?
The 1-bits AT those positions (0 and 28) are or'ed into the value that was previously in that variable.
Bits don't have individual addresses.
Instead a common practise in embedded world is to concatenate several small attributes to a larger register. e.g. one could define some internals of realtime scheduler as:
31 30 29 28 27 26 25 24 32 22 21 20 19 18 0
[ max_priority ] [ current_priority] [ reserved] [ address_xxxx ]
Here max_priority would be 5-bit unsigned integer having values 0-31;
One could as well define max_priority0 being the least significant bit of that value. All these parameters would be accessed within the same absolute address (REG_BASE + offset).

Resources