Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I'm new to C and I am trying to understand the difference between
DDRB |= 0b00000001;
and
DDRB = 0b00000001;
Do the two lines have same effect of writing one to data register B ?
How are they different?
Just could register google search for "|" ..so needed some help in understanding it.
The first operation is called bitwise OR | and it works as follows imagining the numbers A=200 and B=184, which in binary will be, 11001000 and 10111000, respectively. The operator "|" will compare bit a bit of each of those numbers, and returns 1 when either of the bits is 1, 0 otherwise. So in your case:
11001000
| 10111000
--------
= 11111000
the result will be 248 (11111000 in binary). Therefore DDRB |= 0b00000001; is DDRB = DDRB | 0b00000001.
The second operation (e.g., DDRB = 0b00000001) is just an assignment of a value to a variable.
Do the two lines have same effect of writing one to data register B ?
No.
DDRB = 0b00000001;
writes one to bit-0 and zero to bits 1 to 7, while:
DDRB |= 0b00000001;
is a read-modify-write operation equivalent to:
DDRB = DDRB | 0b00000001;
so it writes a one to bit-0 as before and leaves all other bits unchanged.
So for example if DDRB's current value were 0b11110000 after:
DDRB = 0b00000001;
it will be 0b00000001 while after:
DDRB |= 0b00000001;
it will be 0b11110001.
So one sets DDRB to 1, while the other sets DDRB:Bit-0 to 1.
Related
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed last year.
Improve this question
I was following a tutorial I found to get a photocell to light an LED as a first step to building a morse coder/decoder. I only have an arduino UNO available instead of the ATmega328P chip itself to work with. I have connected the photocell to pinout A0 and the LED to pinout D~9 on the UNO. I tried to rewrite the code to be used for my current setup but It comes up with three errors and four warnings that I can not figure out how to solve. Any help or advice would be greatly appreciated. I'm using Atmel Studio 7 Gcc C.
#ifndef F_CPU
#define F_CPU 16000000UL
#endif
#include <avr/io.h>
#include <util/delay.h>
#define PHOTO1 0 //sets photocell to PORTC pinout A0
#define LED1 9 //sets LED to PORTB pinout 9
void init_ports_mcu()
{
DDRB = 0xFFu; //set all pins at PORTB as output
PORTB = 0x00u; // sets pins at PORTB as low - LED off
DDRC = 0xFFu; //sets all pins at PORTC as output
DDRC &= ~(1<<0); //Makes first pin at PORTC input
PORTC = 0x00u; //sets all pins at PORTC as low-turning off Photocell
}
int map(int x, int in_min, int in_max, int out_min, int out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
void ADC_init()
{
//Enable ADC sampling freq to set prescaler to max value
ADCSRA |= (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);
ADMUX = (1<<REFS0); //select required channel passed as input
}
uint16_t get_lightLevel()
{
_delay_ms 10; //wait for line in channel to get selected
ADCSRA |= (1<<ADSC); //start ADC conversion
while (ADCSRA & (1<<ADSC)); //wait for conversion to complete
_delay_ms 10;
return (ADC);
}
int main(void)
{
init_ports_mcu(); //setup microcontroller i/o ports
ADC_init(); //initialize ADC
while (1)
{
switch(map(get_lightLevel(), 0, 1023, 0, 3)){ //read and map ADC values
case 0: //high light intensifies - LED is off
PORTB &= ~(1<<LED1);
PORTC &= ~(1<<PHOTO1);
break;
case 1: //middle light intensifies - LED is on
PORTB = (1<<LED1);
PORTC &= ~(1<<PHOTO1);
break;
case 2: //low light intensifies - LED is on
PORTB = (1<<LED1);
PORTC = (1<<PHOTO1);
break;
}
}
return (0);
}
Errors:
Recipe for target 'main.o' failed - Line 76
expected ';' before numeric constant - Line 44
expected ';' before numeric constant - Line 49
Warnings:
Statement with no effect [wunused values] - Line 44
Statement with no effect [wunused values] - Line 49
Larger integer implicitly turnicated to unsigned type [wover flow] - Line 69
Larger integer implicitly turnicated to unsigned type [wover flow] - Line 73
The formatting of your delays is incorrect. According to util/delay.h (Convenience functions for busy-wait delay loops) here, two functions are available:
void _delay_ms (double __ms)
void _delay_us (double __us)
You should treat these as function calls, so you need to write:
_delay_ms(10);
I have experiences in AVR programming with CodeVisionAVR. Recently I switched to using Atmel Studio and found a minor but annoying problem: I can't control each PIN/PORT as easy as I did in CodeVisionAVR.
Firstly, let's initialize one certain port:
// Initialzing one port, for example PORT D:
// Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=Out
DDRD=0x01;
// State: Bit7=T Bit6=T Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=1
PORTD=(0<<PORTD7) | (0<<PORTD6) | (0<<PORTD5) | (0<<PORTD4) | (0<<PORTD3) | (0<<PORTD2) | (0<<PORTD1) | (1<<PORTD0);
// After initializing, Port D bit 0 should be the only pin set to out.
In CodeVisionAVR, I can do this:
PORTD.0 = 0; // Set Port D bit 0 to low
PORTD.0 = 1; // Or to high
But in Atmel Studio, addressing Port D bit 0 as PORTD.0 gives me an error. I have to do this instead:
PORTD = (1<<PORTD0); // Set Port D bit 0 to high
PORTD = (0<<PORTD0); // and low
As you can see, addressing by shifting bits is much less clean and harder to read / write. I thought CVAVR used something like a struct to imitate the dot (.) addressing method (in C we don't have classes), or some overloaded operators, or some macros, but after digging the included header files in CVAVR, I could only find this:
sfrb PORTD=0x12;
// ... other ports ...
sfrb PIND=0x10;
My question is, can I imitate the bit addressing method of CVAVR in Atmel Studio? If yes, how? Or was that some IDE-exclusive feature?
What you are saying about CodeVisionAVR
PORTD.0 = 0; // Set Port D bit 0 to low
PORTD.0 = 1; // Or to high
is not a valid C semantic, so if you didn't make a mistake on your predicate it must be a codevision compiler extension.
That kind of assignment in C represent an struct access, but you can not declare a struct member (or any other identifier) starting with a number, so PORTD.0 will produce an error.
Also when you do this:
PORTD = (1<<PORTD0); // Set Port D bit 0 to low
PORTD = (0<<PORTD0); // and high
you are not doing what you comment, you are assigning (assuming PORTD0==1) 0x1 to PORTD in the first expression and 0x0 in the second. If your intention is to manipulate only one bit, this is what you should do:
PORTD |= (1<<PORTD0); //sets bit PORTD0 high in PORTD
PORTD &= ~(1<<PORTD0); //sets bit PORTD0 low in PORTD
PORTD ^= (1<<PORTD0); //toggles PORTD0 in PORTD
You should read about bit manipulation in C, here is a post with more examples
Sometimes those actions are encapsulated in a macro, this an example of how you could do it:
#define BitSet(Port,Bit) (Port|=(1<<Bit))
#define BitClear(Port,Bit) (Port&=~(1<<Bit))
#define BitToggle(Port,Bit) (Port^=(1<<Bit))
#define SetBits(Port,BitMask) (Port|=BitMask)
#define ClearBits(Port,BitMask) (Port&=~BitMask)
#define ToggleBits(Port,BitMask) (Port^=BitMask)
//then you can use it
BitSet(PORTD,0) ; //Sets the bit0
BitSet(PORTD,1) ; //Sets the bit1
BitSet(PORTD,2) ; //Sets the bit2
// or
BitSet(PORTD,PORTD0) ; //Sets the bit0
BitSet(PORTD,PORTD1) ; //Sets the bit1
BitSet(PORTD,PORTD2) ; //Sets the bit2
...
SetBits(PORTD,0x55) ; //Sets the bits 0,2,4, and 6. Leaves the other unchanged
ClearBits(PORTD,0x55) ; //Clear the bits 0,2,4, and 6. Leaves the other unchanged
So I have an assignment that wants me to perform certain code when a button on PD2 is presed.
The problem i'am having right now is i don't really know what to check for neither do
i understand the underlying logic.
So this is the code i've come up with thus far.
DDRD=0x00; //PORTD pin 0 as input
PORTD=0x00;
DDRB=0xFF; //PORTB as output
PORTB=0x00;
while(1){
if (PIND & (1<<PD2)==1) // check if PD2 is pressed on PIND2
{
// modify bits on PORTB here
}
}
I'm using Atmega328 and running this on AtmelStudio 7
To set PD2 to an input, run this C/C++ code, which clears bit 2 in register DDRD. There is no need to modify entire registers:
DDRD &= ~(1 << 2);
(You could skip this because every pin will be an input by default after the AVR resets.)
I don't know how you wired your button. If the button is wired between the pin and GND, and there is no external pull-up resistor to pull your pin high, then you should enable the internal pull-up after the pin is an input by running this code, which sets bit 2 in register PORTD:
PORTD |= 1 << 2;
Now to read the state of the button, you can use this C/C++ expression, which will evaluate to 0 if the pin is low or non-zero if the pin is high:
PIND & (1 << 2)
The expression below also works. It has the advantage of always evaluating to 0 or 1:
PIND >> 2 & 1
Here's some (untested) code that ties it all together, reading from PD2 and writing the value of PD2 to an output on PB3:
#include <avr/io.h>
int main()
{
// Make PD2 an input, pulled high.
DDRD &= ~(1 << 2);
PORTD |= 1 << 2;
// Make PB3 an output.
DDRB |= 1 << 3;
while (1)
{
if (PIND >> 2 & 1)
{
// PD2 is high, so drive PB3 high.
PORTB |= 1 << 3;
}
else
{
// PD2 is low, so drive PB3 low.
PORTB &= ~(1 << 3);
}
}
}
You might have to adapt the part of the code that deals with the output. I don't actually know what pin your output is on and what kind of behavior you want, so I just did something simple.
This code is full of the C bitwise operators. It is important for you to get a good book about C and learn exactly what those operators do, and this answer would be too long if I attempted to teach you all of them. Here is a list of operators for you to learn: <<, >>, &, &=, |, |=, ~.
unsigned char input_byte;
while(1){
__no_operation(); /* using nop for synchronization */
input_byte = PIND; /* read entire PIND */
}
This way you should be able to read your inputs every program cycle. But I've not tested this. It's important to use __no_operation() before reading again PIND.
This question already has answers here:
How to set and clear different bits with a single line of code (C)
(2 answers)
Closed 6 years ago.
I recently started learning about the IAR embedded workbench 8051. Well, I am currently playing with the LED only. I am using CC2540 BLE chip to do this. Let's say I have 8 pins of LED but I only want to control only 2 pins by not affect other 6 pins, how to code it using bitwise operators? I set all the pin for GPIO using this code P1SEL = 0;, my friend told me if I type the code like this will affect others pins. What if I declare it P1SEL = 0xFC;? Will others pin be affected?
Actually, you can use & and | to set a specific bit.
P1SEL = P1SEL & (~(1 << i)) // set bit i to 0
P1SEL = P1SEL | (1 << i) // set bit i to 1
I am currently programming raspberry pi.
I wanted to get clear out some doubts, please can anybody help.
Here is the code snippet.
#define GPIO_BASE 0x20200000UL
gpio = (unsigned int*)GPIO_BASE; gpio[GPIO_GPFSEL1] |= (1 << 18);
This code is from http://www.valvers.com/embedded-linux/raspberry-pi/step01-bare-metal-programming-in-cpt1
I do understand the functionality of the code to switch on and switch off the LED .
I have problem understand the these statements
gpio = (unsigned int*)GPIO_BASE; gpio[GPIO_GPFSEL1] |= (1 << 18);
First you have some address in memory.
define GPIO_BASE 0x20200000UL
Under this address exists a control structure for GPIO. In your case it's just an array of ints. Writing a value to a certain field of that structure makes GPIO set its pins.
gpio = (unsigned int*)GPIO_BASE;
You select some register in your structure (the address (unsigned int*)GPIO_BASE + GPIO_GPFSEL1) and you set the 18th bit on.
gpio[GPIO_GPFSEL1] |= (1 < < 18);
The GPIO will likely respond with setting one of its pins to high state. The LED attached to that pin will start glowing.
Well ...
The first statement:
gpio = (unsigned int*)GPIO_BASE;
sets the pointer variable gpio equal to the value of GPIO_BASE, and also casts the latter to a pointer type.
The second
gpio[GPIO_GPFSEL1] |= (1 << 18);
does a bitwise OR of the value in gpio[GPIO_GPFSEL1] with the constant value 1 << 18. This "turns on" bit 18 (counting from 0) in the register GPIO_GPFSEL1.
Remember that in C, array indexing a[b] is the same as *(a + b), i.e. it's a pointer addition and dereferencing.
After
gpio = (unsigned int*)GPIO_BASE;
gpio points to 0x20200000 memory address. This is "The base address of the GPIO peripheral (ARM Physical Address)".
Article that you've linked says that:
Back to the processor manual and we see that the first thing we need
to do is set the GPIO pin to an output. This is done by setting the
function of GPIO16 to an output. Bits 18 to 20 in the ‘GPIO Function
Select 1′ register control the GPIO16 pin.
Statement
#define GPIO_GPFSEL1 1
gpio[GPIO_GPFSEL1] |= (1 << 18);
breaks down to:
gpio[1] = gpio[1] | (1 << 18);
So, address (0x20200000 + sizeof(unsigned int)) is dereferenced and OR operator sets the bit 18 to 1.